Skip to content

Commit 8c6d995

Browse files
authored
Merge pull request #473 from phodal/master
feat: add basic MPP IDEA support #471
2 parents b7eeeae + ec45f40 commit 8c6d995

File tree

24 files changed

+3897
-396
lines changed

24 files changed

+3897
-396
lines changed

AGENTS.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,27 @@ Rest:
4343
1. Build MPP Core: `cd /Volumes/source/ai/autocrud && ./gradlew :mpp-core:assembleJsPackage`
4444
2. Build and run MPP CLI: `cd mpp-ui && npm run build && npm run start`
4545

46+
## IntelliJ IDEA Plugin (mpp-idea)
47+
48+
`mpp-idea` is a standalone Gradle project with `includeBuild` dependency on parent project.
49+
50+
**Build Commands:**
51+
```bash
52+
# Compile (from project root)
53+
cd mpp-idea && ../gradlew compileKotlin
54+
55+
# Run tests (JewelRendererTest uses JUnit 5, no IntelliJ Platform required)
56+
cd mpp-idea && ../gradlew test --tests "cc.unitmesh.devins.idea.renderer.JewelRendererTest"
57+
58+
# Build plugin
59+
cd mpp-idea && ../gradlew buildPlugin
60+
```
61+
62+
**Notes:**
63+
- Do NOT use `./gradlew :mpp-idea:compileKotlin` from root - use `cd mpp-idea && ../gradlew` instead
64+
- `IdeaAgentViewModelTest` requires IntelliJ Platform Test Framework
65+
- `JewelRendererTest` can run standalone with JUnit 5
66+
4667
## Release
4768

4869
1. modify version in `gradle.properties`

core/src/main/kotlin/cc/unitmesh/devti/gui/chat/ui/AutoDevInput.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import com.intellij.openapi.command.CommandProcessor
1111
import com.intellij.openapi.command.WriteCommandAction
1212
import com.intellij.openapi.editor.Document
1313
import com.intellij.openapi.editor.Editor
14+
import com.intellij.openapi.editor.EditorFactory
1415
import com.intellij.openapi.editor.EditorModificationUtil
1516
import com.intellij.openapi.editor.actions.EnterAction
1617
import com.intellij.openapi.editor.actions.IncrementalFindAction
@@ -181,7 +182,9 @@ class AutoDevInput(
181182
val id = UUID.randomUUID()
182183
val file = LightVirtualFile("AutoDevInput-$id", language, "")
183184

184-
val document = file.findDocument() ?: throw IllegalStateException("Can't create in-memory document")
185+
val document = ReadAction.compute<Document, Throwable> {
186+
EditorFactory.getInstance().createDocument("")
187+
}
185188

186189
initializeDocumentListeners(document)
187190
setDocument(document)

mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/orchestrator/ToolOrchestrator.kt

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -585,13 +585,28 @@ class ToolOrchestrator(
585585
context: cc.unitmesh.agent.tool.ToolExecutionContext
586586
): ToolResult {
587587
return try {
588-
// Cast to ExecutableTool (all new tools should implement this)
588+
// For SubAgent, we need to validate input first
589+
if (tool is cc.unitmesh.agent.core.SubAgent<*, *>) {
590+
@Suppress("UNCHECKED_CAST")
591+
val subAgent = tool as cc.unitmesh.agent.core.SubAgent<Any, ToolResult>
592+
593+
// Validate and convert Map to proper input type
594+
val validatedInput = subAgent.validateInput(params)
595+
596+
// Create invocation with validated input
597+
val invocation = subAgent.createInvocation(validatedInput)
598+
599+
// Execute the tool
600+
return invocation.execute(context)
601+
}
602+
603+
// For other ExecutableTools, use params directly
589604
@Suppress("UNCHECKED_CAST")
590605
val executableTool = tool as? ExecutableTool<Any, ToolResult>
591606
?: return ToolResult.Error("Tool ${tool.name} does not implement ExecutableTool interface")
592607

593608
val invocation = executableTool.createInvocation(params)
594-
609+
595610
// Execute the tool
596611
invocation.execute(context)
597612
} catch (e: Exception) {

mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/subagent/DomainDictAgent.kt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,10 +341,14 @@ class DomainDictAgent(
341341
/**
342342
* Extract package path from file path
343343
* e.g., "src/main/kotlin/cc/unitmesh/agent/Tool.kt" -> "cc/unitmesh/agent"
344+
* Handles both Unix (/) and Windows (\) path separators.
344345
*/
345346
private fun extractPackagePath(filePath: String): String {
347+
// Normalize path separators to forward slash for cross-platform compatibility
348+
val normalizedPath = filePath.replace('\\', '/')
349+
346350
// Remove common source prefixes
347-
val cleanPath = filePath
351+
val cleanPath = normalizedPath
348352
.replace(Regex("^.*/src/(main|common)/(kotlin|java|scala)/"), "")
349353
.replace(Regex("^.*/src/"), "")
350354
.replace(Regex("^src/(main|common)/(kotlin|java|scala)/"), "")
@@ -368,7 +372,10 @@ class DomainDictAgent(
368372
val prioritizedFiles = if (importantPackages.isNotEmpty()) {
369373
insights.hotFiles.sortedByDescending { file ->
370374
val pkg = extractPackagePath(file.path)
371-
if (importantPackages.any { pkg.startsWith(it) || it.startsWith(pkg) }) 2 else 1
375+
// Skip empty package paths to avoid matching all entries
376+
if (pkg.isEmpty()) 1
377+
else if (importantPackages.any { pkg.startsWith(it) || it.startsWith(pkg) }) 2
378+
else 1
372379
}
373380
} else {
374381
insights.hotFiles

mpp-idea/build.gradle.kts

Lines changed: 141 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@ import org.jetbrains.intellij.platform.gradle.TestFrameworkType
22

33
plugins {
44
id("java")
5-
kotlin("jvm") version "2.2.0"
6-
id("org.jetbrains.intellij.platform") version "2.10.2"
7-
kotlin("plugin.compose") version "2.2.0"
8-
kotlin("plugin.serialization") version "2.2.0"
5+
kotlin("jvm")
6+
id("org.jetbrains.intellij.platform")
7+
kotlin("plugin.compose")
8+
kotlin("plugin.serialization")
99
}
1010

1111
group = "cc.unitmesh.devins"
12-
version = project.findProperty("mppVersion") as String? ?: "0.3.2"
12+
val mppVersion = project.findProperty("mppVersion") as String? ?: "0.3.2"
13+
version = mppVersion
1314

1415
kotlin {
1516
jvmToolchain(21)
@@ -25,19 +26,96 @@ kotlin {
2526

2627
repositories {
2728
mavenCentral()
29+
google()
30+
// Required for mpp-ui's webview dependencies (jogamp)
31+
maven("https://jogamp.org/deployment/maven")
32+
maven("https://oss.sonatype.org/content/repositories/snapshots/")
33+
maven("https://packages.jetbrains.team/maven/p/ij/intellij-dependencies/")
2834

2935
intellijPlatform {
3036
defaultRepositories()
3137
}
32-
google()
3338
}
3439

3540
dependencies {
36-
// Kotlinx serialization for JSON
37-
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
38-
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1")
41+
// Depend on mpp-ui and mpp-core JVM targets for shared UI components and ConfigManager
42+
// For KMP projects, we need to depend on the JVM target specifically
43+
// IMPORTANT: Exclude ALL transitive dependencies that conflict with IntelliJ's bundled libraries
44+
implementation("cc.unitmesh.devins:mpp-ui-jvm") {
45+
// Exclude all Compose dependencies - IntelliJ provides its own via bundledModules
46+
exclude(group = "org.jetbrains.compose")
47+
exclude(group = "org.jetbrains.compose.runtime")
48+
exclude(group = "org.jetbrains.compose.foundation")
49+
exclude(group = "org.jetbrains.compose.material3")
50+
exclude(group = "org.jetbrains.compose.material")
51+
exclude(group = "org.jetbrains.compose.ui")
52+
exclude(group = "org.jetbrains.compose.desktop")
53+
exclude(group = "org.jetbrains.compose.components")
54+
exclude(group = "org.jetbrains.compose.animation")
55+
exclude(group = "org.jetbrains.skiko")
56+
// Exclude kotlinx libraries - IntelliJ provides its own
57+
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-coroutines-core")
58+
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-coroutines-core-jvm")
59+
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-coroutines-swing")
60+
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-serialization-json")
61+
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-serialization-json-jvm")
62+
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-serialization-json-io")
63+
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-serialization-json-io-jvm")
64+
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-serialization-core")
65+
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-serialization-core-jvm")
66+
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-io-core")
67+
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-io-core-jvm")
68+
// Exclude webview/KCEF - not needed in IntelliJ and causes issues
69+
exclude(group = "io.github.kevinnzou")
70+
exclude(group = "dev.datlag")
71+
// Exclude other UI libraries that may conflict
72+
exclude(group = "com.mohamedrejeb.richeditor")
73+
exclude(group = "cafe.adriel.bonsai")
74+
exclude(group = "com.mikepenz")
75+
exclude(group = "org.jetbrains.jediterm")
76+
exclude(group = "org.jetbrains.pty4j")
77+
exclude(group = "io.github.vinceglb")
78+
// Exclude SQLDelight - not needed in IntelliJ plugin
79+
exclude(group = "app.cash.sqldelight")
80+
}
81+
implementation("cc.unitmesh.devins:mpp-core-jvm") {
82+
// Exclude Compose dependencies from mpp-core as well
83+
exclude(group = "org.jetbrains.compose")
84+
exclude(group = "org.jetbrains.compose.runtime")
85+
exclude(group = "org.jetbrains.compose.foundation")
86+
exclude(group = "org.jetbrains.compose.material3")
87+
exclude(group = "org.jetbrains.compose.material")
88+
exclude(group = "org.jetbrains.compose.ui")
89+
exclude(group = "org.jetbrains.skiko")
90+
// Exclude kotlinx libraries - IntelliJ provides its own
91+
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-coroutines-core")
92+
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-coroutines-core-jvm")
93+
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-serialization-json")
94+
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-serialization-json-jvm")
95+
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-serialization-json-io")
96+
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-serialization-json-io-jvm")
97+
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-serialization-core")
98+
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-serialization-core-jvm")
99+
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-io-core")
100+
exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-io-core-jvm")
101+
}
102+
103+
// Use platform-provided kotlinx libraries to avoid classloader conflicts
104+
compileOnly("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
105+
compileOnly("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1")
106+
107+
// Ktor HTTP Client for LLM API calls - use compileOnly for libraries that may conflict
108+
compileOnly("io.ktor:ktor-client-core:3.2.2")
109+
compileOnly("io.ktor:ktor-client-cio:3.2.2")
110+
compileOnly("io.ktor:ktor-client-content-negotiation:3.2.2")
111+
compileOnly("io.ktor:ktor-serialization-kotlinx-json:3.2.2")
112+
compileOnly("io.ktor:ktor-client-logging:3.2.2")
39113

40114
testImplementation(kotlin("test"))
115+
testImplementation("org.junit.jupiter:junit-jupiter-api:5.11.4")
116+
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.11.4")
117+
// JUnit 4 is required by IntelliJ Platform test infrastructure (JUnit5TestEnvironmentInitializer)
118+
testRuntimeOnly("junit:junit:4.13.2")
41119

42120
intellijPlatform {
43121
// Target IntelliJ IDEA 2025.2+ for Compose support
@@ -55,14 +133,19 @@ dependencies {
55133
"intellij.platform.compose"
56134
)
57135

58-
testFramework(TestFrameworkType.Platform)
136+
// Note: testFramework(TestFrameworkType.Platform) is removed because:
137+
// 1. It requires JUnit 4 (junit.framework.TestCase) which conflicts with JUnit 5
138+
// 2. JewelRendererTest uses JUnit 5 and doesn't need IntelliJ Platform
139+
// 3. IdeaAgentViewModelTest (which needs Platform) is temporarily disabled
140+
// To run platform tests, uncomment testFramework and add JUnit 4 dependency
141+
// testFramework(TestFrameworkType.Platform)
59142
}
60143
}
61144

62145
intellijPlatform {
63146
pluginConfiguration {
64147
name = "AutoDev Compose UI"
65-
version = project.findProperty("mppVersion") as String? ?: "0.3.2"
148+
version = mppVersion
66149

67150
ideaVersion {
68151
sinceBuild = "252"
@@ -77,4 +160,51 @@ tasks {
77160
test {
78161
useJUnitPlatform()
79162
}
163+
164+
// Task to verify no conflicting dependencies are included
165+
register("verifyNoDuplicateDependencies") {
166+
group = "verification"
167+
description = "Verifies that no Compose/Kotlinx dependencies are included that would conflict with IntelliJ's bundled versions"
168+
169+
doLast {
170+
val forbiddenPatterns = listOf(
171+
"org.jetbrains.compose",
172+
"org.jetbrains.skiko",
173+
"kotlinx-coroutines-core",
174+
"kotlinx-coroutines-swing",
175+
"kotlinx-serialization-json",
176+
"kotlinx-serialization-core"
177+
)
178+
179+
val runtimeClasspath = configurations.getByName("runtimeClasspath")
180+
val violations = mutableListOf<String>()
181+
182+
runtimeClasspath.resolvedConfiguration.resolvedArtifacts.forEach { artifact ->
183+
val id = artifact.moduleVersion.id
184+
val fullName = "${id.group}:${id.name}:${id.version}"
185+
forbiddenPatterns.forEach { pattern ->
186+
if (fullName.contains(pattern)) {
187+
violations.add(fullName)
188+
}
189+
}
190+
}
191+
192+
if (violations.isNotEmpty()) {
193+
throw GradleException("""
194+
|DEPENDENCY CONFLICT DETECTED!
195+
|The following dependencies will conflict with IntelliJ's bundled libraries:
196+
|${violations.joinToString("\n") { " - $it" }}
197+
|
198+
|These dependencies must be excluded from mpp-ui and mpp-core.
199+
""".trimMargin())
200+
} else {
201+
println("✓ No conflicting dependencies found in runtime classpath")
202+
}
203+
}
204+
}
205+
206+
// Run verification before build
207+
named("build") {
208+
dependsOn("verifyNoDuplicateDependencies")
209+
}
80210
}

mpp-idea/settings.gradle.kts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,28 @@
11
rootProject.name = "mpp-idea"
22

3+
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
4+
35
pluginManagement {
46
repositories {
57
google()
68
mavenCentral()
79
gradlePluginPortal()
810
}
11+
12+
plugins {
13+
kotlin("jvm") version "2.1.20"
14+
kotlin("plugin.compose") version "2.1.20"
15+
kotlin("plugin.serialization") version "2.1.20"
16+
id("org.jetbrains.intellij.platform") version "2.10.2"
17+
}
918
}
1019

11-
dependencyResolutionManagement {
12-
repositories {
13-
google()
14-
mavenCentral()
20+
// Include mpp-ui from parent project for shared UI components and ConfigManager
21+
// For KMP projects, we substitute the JVM target artifacts
22+
includeBuild("..") {
23+
dependencySubstitution {
24+
substitute(module("cc.unitmesh.devins:mpp-ui-jvm")).using(project(":mpp-ui"))
25+
substitute(module("cc.unitmesh.devins:mpp-core-jvm")).using(project(":mpp-core"))
1526
}
1627
}
28+

0 commit comments

Comments
 (0)