Skip to content

Commit dc4cdb1

Browse files
authored
Add MCP-backed project tools to IntelliJ plugin (#3152)
* Add MCP-backed project tools to IntelliJ plugin * Fix IntelliJ plugin test runtime * Harden project resource extraction * Address project service static analysis feedback
1 parent 0cc3c3c commit dc4cdb1

12 files changed

Lines changed: 761 additions & 1 deletion

File tree

shaft-intellij/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ dependencies {
2020
}
2121
implementation("com.google.code.gson:gson:2.14.0")
2222
testImplementation("org.junit.jupiter:junit-jupiter:6.1.0")
23+
testRuntimeOnly("junit:junit:4.13.2")
24+
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
2325
}
2426

2527
java {

shaft-intellij/src/main/java/com/shaft/intellij/ui/ShaftToolWindowPanel.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public ShaftToolWindowPanel(@NotNull Project project) {
2525
tabs.addTab("Doctor", new ShaftFeaturePanel(project, ToolTemplates.doctor()));
2626
tabs.addTab("Healer", new ShaftFeaturePanel(project, ToolTemplates.healer()));
2727
tabs.addTab("Inspector", new ShaftFeaturePanel(project, ToolTemplates.inspector()));
28+
tabs.addTab("Projects", new ShaftFeaturePanel(project, ToolTemplates.projects()));
2829
tabs.addTab("MCP", new ShaftFeaturePanel(project, ToolTemplates.mcp()));
2930
tabs.addTab("Guide", new ShaftFeaturePanel(project, ToolTemplates.guide()));
3031
if (ShaftSettingsState.getInstance().getState().autobotEnabled) {

shaft-intellij/src/main/java/com/shaft/intellij/ui/ToolTemplates.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,53 @@ static List<ToolTemplate> guide() {
248248
"""));
249249
}
250250

251+
static List<ToolTemplate> projects() {
252+
return List.of(
253+
template("Create SHAFT Project", "shaft_project_create",
254+
"""
255+
{
256+
"outputDirectory": "shaft-web-testng",
257+
"runner": "TestNG",
258+
"platform": "web",
259+
"groupId": "io.github.yourUsername",
260+
"artifactId": "shaft-web-testng",
261+
"version": "1.0.0",
262+
"optionalModules": [],
263+
"includeGithubActions": true,
264+
"includeDependabot": true,
265+
"overwrite": false
266+
}
267+
"""),
268+
template("Preview Current Project Upgrade", "shaft_project_upgrade",
269+
"""
270+
{
271+
"projectRoot": ".",
272+
"upgradeType": "basic",
273+
"dryRun": true,
274+
"approve": false,
275+
"shaftVersion": "",
276+
"compileCommand": "",
277+
"compileTimeout": 900,
278+
"skipBaselineCompile": false,
279+
"allowAiRepair": false
280+
}
281+
"""),
282+
template("Apply Current Project Upgrade", "shaft_project_upgrade",
283+
"""
284+
{
285+
"projectRoot": ".",
286+
"upgradeType": "basic",
287+
"dryRun": false,
288+
"approve": true,
289+
"shaftVersion": "",
290+
"compileCommand": "",
291+
"compileTimeout": 900,
292+
"skipBaselineCompile": false,
293+
"allowAiRepair": false
294+
}
295+
"""));
296+
}
297+
251298
private static ToolTemplate template(String label, String toolName, String arguments) {
252299
return new ToolTemplate(label, toolName, arguments.stripIndent().trim());
253300
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.shaft.intellij.ui;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import java.util.Map;
6+
import java.util.stream.Collectors;
7+
8+
import static org.junit.jupiter.api.Assertions.assertEquals;
9+
import static org.junit.jupiter.api.Assertions.assertTrue;
10+
11+
class ToolTemplatesTest {
12+
@Test
13+
void projectsExposeCreatePreviewAndApplyTemplates() {
14+
Map<String, ToolTemplate> templates = ToolTemplates.projects().stream()
15+
.collect(Collectors.toMap(ToolTemplate::label, template -> template));
16+
17+
assertEquals("shaft_project_create", templates.get("Create SHAFT Project").toolName());
18+
assertTrue(templates.get("Create SHAFT Project").arguments().contains("\"runner\": \"TestNG\""));
19+
assertEquals("shaft_project_upgrade", templates.get("Preview Current Project Upgrade").toolName());
20+
assertTrue(templates.get("Preview Current Project Upgrade").arguments().contains("\"dryRun\": true"));
21+
assertEquals("shaft_project_upgrade", templates.get("Apply Current Project Upgrade").toolName());
22+
assertTrue(templates.get("Apply Current Project Upgrade").arguments().contains("\"approve\": true"));
23+
}
24+
}

shaft-mcp/pom.xml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,19 @@
116116
<directory>src/main/resources</directory>
117117
<filtering>true</filtering>
118118
</resource>
119+
<resource>
120+
<directory>${project.basedir}/../shaft-engine/src/main/resources/examples</directory>
121+
<targetPath>META-INF/shaft-mcp/examples</targetPath>
122+
<filtering>false</filtering>
123+
</resource>
124+
<resource>
125+
<directory>${project.basedir}/../shaft-upgrader</directory>
126+
<targetPath>META-INF/shaft-mcp</targetPath>
127+
<includes>
128+
<include>upgrade_to_modular_shaft.py</include>
129+
</includes>
130+
<filtering>false</filtering>
131+
</resource>
119132
</resources>
120133
<plugins>
121134
<plugin>
@@ -163,7 +176,7 @@
163176
</archive>
164177
<includes>
165178
<include>com/**</include>
166-
<include>META-INF/shaft-mcp/*</include>
179+
<include>META-INF/shaft-mcp/**</include>
167180
<include>application*.properties</include>
168181
<include>logback-spring.xml</include>
169182
</includes>
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.shaft.mcp;
2+
3+
import java.nio.file.Path;
4+
import java.util.List;
5+
6+
/**
7+
* Result returned after generating a SHAFT project through MCP.
8+
*
9+
* @param schemaVersion result schema version
10+
* @param projectDirectory generated project directory
11+
* @param pomPath generated Maven POM path
12+
* @param runner selected test runner
13+
* @param platform selected starting platform
14+
* @param templateProject reused SHAFT example project
15+
* @param addedModules SHAFT modules added to the generated POM
16+
* @param warnings non-fatal generation warnings
17+
*/
18+
public record McpShaftProjectGenerationResult(
19+
String schemaVersion,
20+
Path projectDirectory,
21+
Path pomPath,
22+
String runner,
23+
String platform,
24+
String templateProject,
25+
List<String> addedModules,
26+
List<String> warnings) {
27+
/**
28+
* Current result schema version.
29+
*/
30+
public static final String CURRENT_SCHEMA_VERSION = "1.0";
31+
32+
/**
33+
* Creates an immutable project generation result.
34+
*/
35+
public McpShaftProjectGenerationResult {
36+
schemaVersion = text(schemaVersion).isBlank() ? CURRENT_SCHEMA_VERSION : text(schemaVersion);
37+
runner = text(runner);
38+
platform = text(platform);
39+
templateProject = text(templateProject);
40+
addedModules = addedModules == null ? List.of() : List.copyOf(addedModules);
41+
warnings = warnings == null ? List.of() : List.copyOf(warnings);
42+
}
43+
44+
private static String text(String value) {
45+
return value == null ? "" : value.trim();
46+
}
47+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.shaft.mcp;
2+
3+
import java.nio.file.Path;
4+
import java.util.List;
5+
6+
/**
7+
* Result returned after invoking the SHAFT modular project upgrader through MCP.
8+
*
9+
* @param schemaVersion result schema version
10+
* @param projectRoot upgraded project root
11+
* @param reportPath optional upgrader report path
12+
* @param dryRun whether the upgrader was run in dry-run mode
13+
* @param exitCode upgrader process exit code
14+
* @param stdout captured standard output
15+
* @param stderr captured standard error
16+
* @param timedOut whether the process exceeded the timeout
17+
* @param command executed command
18+
*/
19+
public record McpShaftProjectUpgradeResult(
20+
String schemaVersion,
21+
Path projectRoot,
22+
Path reportPath,
23+
boolean dryRun,
24+
int exitCode,
25+
String stdout,
26+
String stderr,
27+
boolean timedOut,
28+
List<String> command) {
29+
/**
30+
* Current result schema version.
31+
*/
32+
public static final String CURRENT_SCHEMA_VERSION = "1.0";
33+
34+
/**
35+
* Creates an immutable project upgrade result.
36+
*/
37+
public McpShaftProjectUpgradeResult {
38+
schemaVersion = text(schemaVersion).isBlank() ? CURRENT_SCHEMA_VERSION : text(schemaVersion);
39+
stdout = text(stdout);
40+
stderr = text(stderr);
41+
command = command == null ? List.of() : List.copyOf(command);
42+
}
43+
44+
private static String text(String value) {
45+
return value == null ? "" : value.trim();
46+
}
47+
}

shaft-mcp/src/main/java/com/shaft/mcp/ShaftMcpApplication.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ public List<ToolCallback> shaftTools(
6363
TraceService traceService,
6464
HealerService healerService,
6565
GuideService guideService,
66+
ShaftProjectService shaftProjectService,
6667
TestAutomationService testAutomationService,
6768
AutobotService autobotService) {
6869
var engineServiceList = List.of(ToolCallbacks.from(engineService));
@@ -76,6 +77,7 @@ public List<ToolCallback> shaftTools(
7677
var traceServiceList = List.of(ToolCallbacks.from(traceService));
7778
var healerServiceList = List.of(ToolCallbacks.from(healerService));
7879
var guideServiceList = List.of(ToolCallbacks.from(guideService));
80+
var shaftProjectServiceList = List.of(ToolCallbacks.from(shaftProjectService));
7981
var testAutomationServiceList = List.of(ToolCallbacks.from(testAutomationService));
8082
var autobotServiceList = List.of(ToolCallbacks.from(autobotService));
8183

@@ -91,6 +93,7 @@ public List<ToolCallback> shaftTools(
9193
serviceList.addAll(traceServiceList);
9294
serviceList.addAll(healerServiceList);
9395
serviceList.addAll(guideServiceList);
96+
serviceList.addAll(shaftProjectServiceList);
9497
serviceList.addAll(testAutomationServiceList);
9598
serviceList.addAll(autobotServiceList);
9699
return serviceList;

0 commit comments

Comments
 (0)