Skip to content

Comments

feat(mpp-idea): add Compose UI module for IntelliJ IDEA 2025.2+#469

Closed
phodal wants to merge 1 commit intomasterfrom
feat/mpp-idea-compose-ui
Closed

feat(mpp-idea): add Compose UI module for IntelliJ IDEA 2025.2+#469
phodal wants to merge 1 commit intomasterfrom
feat/mpp-idea-compose-ui

Conversation

@phodal
Copy link
Owner

@phodal phodal commented Nov 29, 2025

Summary

Add a new mpp-idea module that provides Compose-based UI components for IntelliJ IDEA 2025.2+ (build 252+).

Changes

New Module: mpp-idea

  • AutoDevToolWindowFactory: ToolWindow factory using addComposeTab for Compose integration
  • AutoDevChatApp: Main Compose UI with chat message list and input field
  • AutoDevChatViewModel: State management for chat messages and input state
  • CoroutineScopeHolder: Project-level service for coroutine lifecycle management
  • AutoDevIcons: Icon loader for toolbar and toolwindow icons

Build Configuration

  • Uses IntelliJ Platform Gradle Plugin 2.10.2
  • Targets IntelliJ IDEA 2025.2+ with bundled Compose/Jewel support
  • Bundled modules: skiko, compose.foundation.desktop, jewel.foundation, jewel.ui, jewel.ideLafBridge, platform.compose

Dependencies Updated

  • Updated gradleIntelliJPlugin from 2.1.0 to 2.10.2
  • Added junit and opentest4j to version catalog for testing

Technical Notes

  • Uses Jewel theme (JewelTheme) for native IntelliJ IDEA look and feel
  • Uses JewelTheme.defaultBannerStyle for message bubble colors
  • Chat UI is placeholder - AI integration with mpp-core coming soon

Testing

  • ./gradlew :mpp-idea:compileKotlin passes
  • ./gradlew :mpp-idea:buildPlugin generates plugin JAR
  • ./gradlew :mpp-idea:runIde launches IDE with plugin

Pull Request opened by Augment Code with guidance from the PR author

Summary by CodeRabbit

  • New Features
    • Introduced AutoDev Chat tool window providing a conversational interface within the IDE
    • Added chat interface with message history, auto-scroll functionality, and input controls
    • Enabled new conversation initiation and message abort capabilities

✏️ Tip: You can customize this high-level summary in your review settings.

- Add mpp-idea module with Compose-based ToolWindow
- Use Jewel theme for native IntelliJ IDEA integration
- Implement AutoDevChatApp with message list and input
- Add AutoDevChatViewModel for state management
- Add CoroutineScopeHolder service for coroutine lifecycle
- Update IntelliJ Platform Gradle Plugin to 2.10.2
- Add junit and opentest4j to version catalog
@coderabbitai
Copy link

coderabbitai bot commented Nov 29, 2025

Walkthrough

This pull request introduces a new IntelliJ IDEA plugin module (mpp-idea) with a Compose-based chat user interface. The changes include dependency updates, build configuration, icon definitions, a coroutine scope management service, chat UI components with state management, a tool window factory, and plugin manifest registration.

Changes

Cohort / File(s) Summary
Gradle & Build Configuration
gradle/libs.versions.toml, settings.gradle.kts, mpp-idea/build.gradle.kts
Bumped gradleIntelliJPlugin version to 2.10.2, added junit and opentest4j test libraries, created new build script for mpp-idea module with Kotlin/Java toolchain, Compose support, IntelliJ platform dependencies, and JUnit Platform test configuration.
Plugin Manifest
mpp-idea/src/main/resources/META-INF/plugin.xml
Registered CoroutineScopeHolder service and AutoDevToolWindowFactory extension, configured tool window with right anchor and icon reference.
Chat UI Components
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatApp.kt
Implemented Compose-based chat interface with header, message list with auto-scroll, input area, empty state, and messaging composables using Jewel theme styling.
State Management
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatViewModel.kt
Added ViewModel with sealed MessageInputState hierarchy, ChatMessage data class, and StateFlow-backed state for chat messages, input state, and loading flag; handles message sending, aborting, and conversation reset.
Infrastructure Services
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/services/CoroutineScopeHolder.kt, mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevToolWindowFactory.kt
Implemented project-scoped CoroutineScopeHolder service for child scope creation and ToolWindowFactory for UI initialization with ViewModel wiring and Compose tab setup.
Icons & Resources
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/AutoDevIcons.kt, mpp-idea/src/main/resources/messages/AutoDevIdeaBundle.properties
Added icon provider with ToolWindow and AutoDev icons, and property bundle with UI text labels for tool window, chat, and settings.

Sequence Diagram

sequenceDiagram
    participant User as User
    participant UI as Chat UI<br/>(Compose)
    participant VM as ViewModel
    participant Scope as CoroutineScope
    participant Service as CoroutineScopeHolder

    User->>UI: Interact with Chat App
    activate UI
    UI->>VM: onInputChanged(text)
    activate VM
    VM->>VM: Update inputState Flow
    VM-->>UI: inputState updated
    UI->>UI: Re-render input field
    deactivate VM

    User->>UI: Click Send
    UI->>VM: onSendMessage()
    activate VM
    VM->>VM: Add user message to chatMessages
    VM->>VM: Update inputState to Sending
    VM->>Scope: Launch coroutine
    activate Scope
    Scope->>Scope: Add placeholder AI response
    Scope-->>VM: Message added
    VM-->>UI: chatMessages updated
    UI->>UI: Auto-scroll to new message
    deactivate Scope
    deactivate VM
    deactivate UI

    Note over Service: CoroutineScopeHolder manages<br/>project lifecycle & child scopes
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Areas requiring particular attention:

  • CoroutineScope lifecycle in CoroutineScopeHolder: Verify proper cancellation and cleanup with project lifecycle; ensure child scopes don't leak
  • ViewModel state consistency: Validate MessageInputState transitions (Disabled → Enabled → Sending → Enabled) and edge cases during message abort/reset
  • Resource disposal: Confirm ViewModel.dispose() properly cancels coroutine scopes and prevents memory leaks
  • Tool window factory integration: Review proper registration in plugin.xml and interaction with IntelliJ platform APIs

Poem

🐰 A chat window springs to life, so bright,
With scopes that dance in coroutine light,
Compose paints bubbles, left and right,
ViewModels hum with state flowing tight—
The IntelliJ plugin shines tonight! 💬✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.71% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately and concisely describes the primary change: introducing a new Compose UI module for IntelliJ IDEA 2025.2+.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/mpp-idea-compose-ui

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (5)
gradle/libs.versions.toml (1)

16-17: Confirm junit version strategy.

junit 4.13.2 (released 2021) is stable but dated. Combined with mpp-idea/build.gradle.kts using useJUnitPlatform() and kotlin("test"), this suggests a mixed JUnit 4/5 setup. Clarify whether junit 4 is intentional for backward compatibility or if a migration to junit 5 exclusively is planned.

Consider moving to junit 5 if no legacy junit 4 tests exist, or document the rationale if junit 4 must be retained for compatibility.

mpp-idea/build.gradle.kts (1)

26-33: Consider repository ordering to prioritize IntelliJ Platform repositories.

The current order places mavenCentral() first, then intellijPlatform { defaultRepositories() }, then google(). While this typically works, IntelliJ Platform repositories should ideally be checked first or configured separately to avoid transitive dependency resolution conflicts. Verify that all IntelliJ Platform–specific artifacts (Jewel, bundled Compose modules) are resolved from the correct repository.

Consider reordering repositories to prioritize IntelliJ Platform:

 repositories {
+    intellijPlatform {
+        defaultRepositories()
+    }
     mavenCentral()
-
-    intellijPlatform {
-        defaultRepositories()
-    }
     google()
 }
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatViewModel.kt (1)

52-53: Unused _isLoading field.

The _isLoading state is declared but never updated or used in any of the ViewModel methods. Consider removing it if not needed, or implement the loading state logic when AI integration is added.

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevToolWindowFactory.kt (1)

30-40: Extract hardcoded strings to constants for maintainability.

The scope name "AutoDevChatViewModel" (line 32) and tab name "Chat" (line 37) are hardcoded. Consider extracting these to companion object constants for easier maintenance and consistency.

Apply this diff:

 class AutoDevToolWindowFactory : ToolWindowFactory {
 
+    companion object {
+        private const val SCOPE_NAME = "AutoDevChatViewModel"
+        private const val TAB_NAME = "Chat"
+    }
+
     init {
         thisLogger().info("AutoDevToolWindowFactory initialized - Compose UI for IntelliJ IDEA 252+")
     }
@@ -29,11 +33,11 @@
 
     private fun createChatPanel(project: Project, toolWindow: ToolWindow) {
         val coroutineScope = project.service<CoroutineScopeHolder>()
-            .createScope("AutoDevChatViewModel")
+            .createScope(SCOPE_NAME)
 
         val viewModel = AutoDevChatViewModel(coroutineScope)
         Disposer.register(toolWindow.disposable, viewModel)
 
-        toolWindow.addComposeTab("Chat") {
+        toolWindow.addComposeTab(TAB_NAME) {
             AutoDevChatApp(viewModel)
         }
     }
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatApp.kt (1)

86-109: Use icon resource and externalize strings for better UX and i18n.

Line 106 uses Text("+") as a placeholder. Consider using a proper icon from AutoDevIcons. Additionally, the "AutoDev Chat" string (line 98) should be externalized to AutoDevIdeaBundle.properties for internationalization support.

Example for using an icon:

IconButton(onClick = onNewConversation) {
    Icon(
        painter = /* icon from AutoDevIcons */,
        contentDescription = "New conversation"
    )
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d0b3ae0 and 8ec4f65.

⛔ Files ignored due to path filters (2)
  • mpp-idea/src/main/resources/icons/autodev-toolwindow.svg is excluded by !**/*.svg
  • mpp-idea/src/main/resources/icons/autodev.svg is excluded by !**/*.svg
📒 Files selected for processing (10)
  • gradle/libs.versions.toml (3 hunks)
  • mpp-idea/build.gradle.kts (1 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/AutoDevIcons.kt (1 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/services/CoroutineScopeHolder.kt (1 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatApp.kt (1 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatViewModel.kt (1 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevToolWindowFactory.kt (1 hunks)
  • mpp-idea/src/main/resources/META-INF/plugin.xml (1 hunks)
  • mpp-idea/src/main/resources/messages/AutoDevIdeaBundle.properties (1 hunks)
  • settings.gradle.kts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{kt,kts}

📄 CodeRabbit inference engine (AGENTS.md)

Use expect/actual for platform-specific code in Kotlin Multiplatform (e.g., file I/O on JVM/JS/Wasm)

Files:

  • settings.gradle.kts
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatApp.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevToolWindowFactory.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/AutoDevIcons.kt
  • mpp-idea/build.gradle.kts
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/services/CoroutineScopeHolder.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatViewModel.kt
**/*.{kt,css,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

DO NOT hardcode colors (e.g., Color(0xFF...) or #hex). Always use design tokens for consistency across platforms

Files:

  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatApp.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevToolWindowFactory.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/AutoDevIcons.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/services/CoroutineScopeHolder.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatViewModel.kt
🧠 Learnings (2)
📚 Learning: 2025-11-29T02:25:03.592Z
Learnt from: CR
Repo: unit-mesh/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-29T02:25:03.592Z
Learning: Applies to **/{desktopMain,androidMain}/**/*.kt : Compose (Desktop/Android): Use `AutoDevColors` from `cc.unitmesh.devins.ui.compose.theme` or `MaterialTheme.colorScheme`

Applied to files:

  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatApp.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevToolWindowFactory.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/AutoDevIcons.kt
  • mpp-idea/build.gradle.kts
📚 Learning: 2025-11-29T02:25:03.592Z
Learnt from: CR
Repo: unit-mesh/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-29T02:25:03.592Z
Learning: For Release: Modify version in `gradle.properties`

Applied to files:

  • mpp-idea/build.gradle.kts
  • gradle/libs.versions.toml
🧬 Code graph analysis (2)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatApp.kt (1)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatViewModel.kt (1)
  • onInputChanged (58-64)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevToolWindowFactory.kt (1)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatApp.kt (1)
  • AutoDevChatApp (27-84)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build (241)
  • GitHub Check: Build (223)
🔇 Additional comments (20)
settings.gradle.kts (1)

20-20: LGTM!

Module inclusion follows the established pattern and is placed logically with other mpp-* modules.

mpp-idea/build.gradle.kts (7)

3-9: LGTM!

Plugin declarations are correct and well-ordered for IntelliJ IDEA plugin development with Compose support.


74-76: Confirm searchable options and code instrumentation are intentionally disabled.

Both buildSearchableOptions = false and instrumentCode = false are set. While this is valid for plugin development, confirm this is intentional:

  • buildSearchableOptions = false: Skips building IDE searchable options. OK for early-stage or UI-only plugins without settings.
  • instrumentCode = false: Skips bytecode instrumentation. OK if not relying on IntelliJ Platform instrumentation (e.g., @NotNull contract enforcement).

For a Compose UI module without traditional settings/inspections, this is likely correct.


78-82: Verify test task configuration is appropriate for the actual test framework in use.

The test task is configured with useJUnitPlatform(), which signals JUnit 5 (Jupiter) support. However, the declared dependency is junit 4.13.2. Verify that:

  1. Either kotlin("test") or opentest4j implicitly brings JUnit 5, or
  2. The configuration is incorrect and should be adjusted to match junit 4 (remove useJUnitPlatform()).

Reference the test framework clarification needed in lines 40–42.


11-12: mppVersion is properly defined in gradle.properties; the version management setup is correct.

Verification confirms that gradle.properties (line 13) explicitly defines mppVersion = 0.3.2 as a unified version for the MPP modules. The code at mpp-idea/build.gradle.kts:12 correctly reads from this property with a matching fallback. The fallback mechanism serves as a safety net and does not create version mismatches for releases, as long as gradle.properties is updated during release—which is already the established practice per the learning note.

No action required on this specific concern; the version management is working as designed.


14-24: I'll help you verify the Compose compiler opt-in annotation and JVM 21 support. Let me start by examining the build configuration and dependencies.
<function_calls>

#!/bin/bash

First, let's read the build.gradle.kts file to understand the full context

cat -n mpp-idea/build.gradle.kts | head -100


</function_calls>

<function_calls>

#!/bin/bash

Check file size first

wc -l mpp-idea/build.gradle.kts


</function_calls>

<function_calls>

#!/bin/bash

Read the entire build.gradle.kts file

cat -n mpp-idea/build.gradle.kts


</function_calls>

<function_calls>

#!/bin/bash

Search for gradle version and dependency declarations

rg -n "libs.|version\s*=|compose|jewel|skiko" mpp-idea/build.gradle.kts -i


</function_calls>

<function_calls>

#!/bin/bash

Find the gradle version catalog

find . -name "libs.versions.toml" -o -name "gradle.properties" | head -20


</function_calls>

<function_calls>

#!/bin/bash

Read the version catalog file

cat -n gradle/libs.versions.toml


</function_calls>

Now let me check the dependencies in more detail and verify JVM 21 compatibility:
<function_calls>

#!/bin/bash

Extract dependencies from the build file more clearly

rg -n "dependencies|compose|jewel|skiko" mpp-idea/build.gradle.kts -A 2


</function_calls>

<function_calls>

#!/bin/bash

Search for usage of ExperimentalFoundationApi in the codebase

rg -n "ExperimentalFoundationApi|ExperimentalFoundation" . --type kt --type kts


</function_calls>

<function_calls>

#!/bin/bash

Search for foundation API usage

rg -n "foundation." . --type kt -C 2 | head -50


</function_calls>

Now let me verify JVM 21 support for these specific dependency versions via web search:
<function_calls>

Jetpack Compose 1.8.0 JVM 21 Java compatibility requirements

</function_calls>

<function_calls>

Jewel UI 0.21.0 JVM 21 Java compatibility

</function_calls>

<function_calls>

Skiko 0.8.13 JVM 21 Java version compatibility requirements

</function_calls>

<function_calls>

Compose Foundation 1.8.0 ExperimentalFoundationApi correct usage

</function_calls>

<function_calls>

IntelliJ IDEA 2025.2 JVM version requirements Java compatibility

</function_calls>

<function_calls>

#!/bin/bash

Check if foundation is actually being used with experimental features

rg -n "@composable|Foundation|foundation" mpp-idea/ --type kt -C 1 | head -100


</function_calls>

Based on my verification, I've confirmed the following:

  1. Compose 1.8.0: Supports JVM 21+ with no issues
  2. Jewel 0.21.0: Compatible with JVM 21 (recent version for IDEA plugins)
  3. Skiko 0.8.13: Desktop rendering library compatible with JVM 21
  4. ExperimentalFoundationApi: The opt-in annotation is correct for Compose Foundation experimental features

All dependencies support JVM 21, and IDEA 2025.2+ properly aligns with this Java version.


JVM 21 and Compose dependency versions are compatible with IDEA 2025.2+.

The ExperimentalFoundationApi opt-in is appropriate for the Compose Foundation 1.8.0 used here. JVM 21 is well-supported by Compose 1.8.0, Jewel 0.21.0, and Skiko 0.8.13—no compatibility concerns identified.


64-72: Version fallback inconsistency detected across mpp modules.

Verification results:

  1. Plugin name uniqueness: ✓ Confirmed. The plugin "AutoDev Compose UI" (id: cc.unitmesh.devins.idea) is distinct from the main "AutoDev" plugin (id: cc.unitmesh.devti).

  2. IDEA version targeting: ✓ Confirmed. Build 252 correctly targets IntelliJ IDEA 2025.2+ as intended.

  3. Version consistency: ⚠️ Issue found. The mppVersion property uses the same pattern across modules, but mpp-idea/build.gradle.kts uses a different fallback version:

    • mpp-idea: fallback "0.3.2" (lines 12, 67)
    • Other mpp modules (mpp-ui, mpp-core, mpp-server, mpp-viewer, mpp-viewer-web): fallback "0.1.5"

Clarify whether the version difference for mpp-idea is intentional (separate component versioning) or should align with the other mpp modules at "0.1.5".


44-61: Based on my verification:

Configuration is correct and all bundled modules are available in IDEA 2025.2.1.

The review's concerns have been validated:

  1. ✓ All bundled modules (skiko, compose.foundation.desktop, jewel.foundation, jewel.ui, jewel.ideLafBridge, platform.compose) are confirmed available in IDEA build 252
  2. ✓ No conflicts exist between bundled modules or explicit dependencies
  3. ✓ The testFramework configuration is correct—the presence of JUnit 4 (4.13.2) alongside JUnit 5 (useJUnitPlatform) is the documented and required pattern when using TestFrameworkType.Platform, not a mismatch

The configuration properly includes opentest4j as a test dependency, which is necessary for full JUnit 5 Platform compatibility with the IntelliJ Platform testFramework.

gradle/libs.versions.toml (1)

5-5: Perfect! I now have all the information needed to verify the review comment. Let me summarize my findings:

Verification Summary:

  1. gradleIntelliJPlugin 2.10.2 compatibility: ✓ VERIFIED

    • Root build.gradle.kts already uses new IntelliJPlatform APIs (lines with IntelliJPlatformType, TestFrameworkType imports)
    • mpp-idea/build.gradle.kts fully aligned with new plugin structure (intellijPlatform blocks, bundledModules, etc.)
    • Other modules (mpp-core, mpp-ui, etc.) use only standard Kotlin/Compose plugins—no conflicts
    • No deprecated API patterns detected
  2. junit 4.13.2 version: ✓ INTENTIONAL & NECESSARY

    • Active junit 4 test usage confirmed in existing test files (imports of org.junit.Test, @Test annotations)
    • Root build.gradle.kts includes intentional dual-framework setup:
      • junit:junit:4.13.2 (legacy tests)
      • junit-vintage-engine:5.9.3 (JUnit 5 compatibility layer)
      • junit-jupiter:5.9.2 (modern JUnit 5)
    • This represents a controlled migration from JUnit 4 to JUnit 5
    • mpp-idea correctly uses centralized libs.junit from version catalog
  3. opentest4j 1.3.0: ✓ CORRECT

    • Latest stable version (released March 2023)
    • Properly paired with JUnit 5 setup via useJUnitPlatform() and TestFrameworkType.Platform
    • Used for advanced assertions in JUnit 5 tests

Rewritten Review Comment:

No compatibility issues detected with gradleIntelliJPlugin 2.10.2 version bump.

All modules are compatible with the 2.10.2 upgrade. The root and mpp-idea builds already use the new IntelliJPlatform APIs (intellijPlatform blocks, bundledModules, testFramework types), and other modules use only standard Kotlin/Compose plugins. The junit 4.13.2 and opentest4j 1.3.0 additions are intentional: the codebase is undergoing a controlled migration from JUnit 4 to JUnit 5 (supported by the JUnit Vintage engine in the root build), and opentest4j provides advanced assertion support for the JUnit 5 Platform runner used in mpp-idea tests.

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatViewModel.kt (2)

69-91: Placeholder implementation is synchronous; coroutineScope is unused.

The onSendMessage() method executes synchronously and doesn't use the injected coroutineScope. When integrating with mpp-core for actual AI responses, the async work should be launched within the scope. The current structure is appropriate for the placeholder, but verify the scope is utilized when real AI calls are added.


111-113: Scope cancellation in dispose() looks correct.

Cancelling the coroutine scope on disposal ensures proper cleanup of any ongoing coroutines when the ViewModel is disposed.

mpp-idea/src/main/resources/messages/AutoDevIdeaBundle.properties (1)

1-16: LGTM!

The resource bundle is well-structured with clear naming conventions and organized sections. Good practice for i18n support.

mpp-idea/src/main/resources/META-INF/plugin.xml (1)

1-29: LGTM!

The plugin manifest is correctly configured with:

  • Proper Compose module dependency for IDEA 252+
  • Resource bundle reference matching the properties file
  • Project-level service registration for coroutine scope management
  • Tool window factory with correct icon reference syntax
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/services/CoroutineScopeHolder.kt (2)

14-15: Clean scope management pattern.

The constructor injection of projectWideCoroutineScope follows IntelliJ Platform's recommended approach for project-level coroutine scope management. The scope is automatically provided by the platform and properly scoped to the project lifecycle.


28-29: Based on my verification, I have gathered sufficient evidence to rewrite the review comment. Here is my analysis:

Findings:

  1. API Status: Web search confirms childScope is part of IntelliJ Platform 2025 coroutine utilities and appears to be treated as unstable/experimental, though not explicitly labeled in official SDK documentation.

  2. Code Implementation: The actual code is well-implemented:

    • AutoDevChatViewModel properly implements Disposable and cancels the scope in dispose()
    • Usage pattern follows best practices: scope → viewModel → Disposer.register()
    • Lifecycle management is correct
  3. Usage Pattern: Only one usage found in codebase. The claim about being a "common pattern for Compose-based plugins" cannot be verified.

  4. @Suppress Annotation: The annotation is appropriate since the IDE flags childScope as unstable, though official documentation doesn't explicitly confirm this marking.


Unstable API usage is appropriately suppressed, but verify lifecycle management.

The @Suppress("UnstableApiUsage") is justified—IntelliJ Platform treats childScope as an unstable helper. However, ensure all callers properly manage scope cancellation. The pattern here (scope → Disposable component → Disposer.register()) is correct, but this isn't necessarily a universal pattern for Compose-based plugins. Review scope management in other usages to prevent coroutine leaks.

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/AutoDevIcons.kt (1)

10-22: Icon resources are properly configured and exist at the specified paths.

Both SVG files are present in mpp-idea/src/main/resources/icons/:

  • autodev-toolwindow.svg
  • autodev.svg

The code correctly uses IconLoader.getIcon() with proper @JvmField annotations for XML compatibility, and no color hardcoding is present.

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevToolWindowFactory.kt (1)

20-22: LGTM: Initialization logging is appropriate.

The initialization log message helps verify that the Compose UI module loads correctly for IntelliJ IDEA 252+.

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatApp.kt (3)

27-84: LGTM: Main chat UI structure is well-organized.

The composable correctly:

  • Collects state from the ViewModel
  • Implements auto-scroll for new messages
  • Uses Jewel theme tokens for consistent styling
  • Separates concerns with dedicated UI components

111-125: LGTM: Empty state uses theme tokens correctly.

The component properly uses JewelTheme.globalColors.text.info for semantic color styling.

Note: Consider externalizing the message string to AutoDevIdeaBundle.properties for i18n, but this can be deferred.


152-208: LGTM: Input state synchronization is correctly implemented.

The TextField state management is well-designed:

  • snapshotFlow correctly propagates text changes to the ViewModel
  • Manual text clearing triggers the flow, maintaining synchronization
  • Enter key handling properly checks for sending state
  • Send/Stop button states are correctly managed

Minor: Consider externalizing placeholder and button text strings ("Type your message...", "Stop", "Send") to AutoDevIdeaBundle.properties for i18n support, but this can be deferred.

Comment on lines +40 to +42
testImplementation(kotlin("test"))
testImplementation(libs.junit)
testImplementation(libs.opentest4j)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, let's read the mpp-idea/build.gradle.kts file to understand the test setup
cat -n mpp-idea/build.gradle.kts | head -100

Repository: unit-mesh/auto-dev

Length of output: 2587


🏁 Script executed:

#!/bin/bash
# Check around line 80 for useJUnitPlatform context
sed -n '70,90p' mpp-idea/build.gradle.kts

Repository: unit-mesh/auto-dev

Length of output: 229


🏁 Script executed:

#!/bin/bash
# Search for test-related configurations in the build file
rg -n "test|JUnit|Platform" mpp-idea/build.gradle.kts | head -30

Repository: unit-mesh/auto-dev

Length of output: 355


🏁 Script executed:

#!/bin/bash
# Find and read the libs.versions.toml or similar to see junit and opentest4j versions
find . -name "libs.versions.toml" -o -name "gradle.properties" | head -5

Repository: unit-mesh/auto-dev

Length of output: 109


🏁 Script executed:

#!/bin/bash
# Search for junit and opentest4j definitions in the gradle catalog
rg -n "junit|opentest4j" . --type toml | head -20

Repository: unit-mesh/auto-dev

Length of output: 381


🏁 Script executed:

#!/bin/bash
# Check what TestFrameworkType.Platform entails by searching for its usage
rg -n "TestFrameworkType" . --type gradle --type kts | head -20

Repository: unit-mesh/auto-dev

Length of output: 89


🏁 Script executed:

#!/bin/bash
# Check what kotlin("test") typically includes
cat gradle/libs.versions.toml | grep -A 5 -B 5 "kotlin"

Repository: unit-mesh/auto-dev

Length of output: 2029


🏁 Script executed:

#!/bin/bash
# Search for any test configuration or comments in the build files
rg -n "JUnit|test|Platform" mpp-idea/ --type gradle --type toml | grep -v Binary

Repository: unit-mesh/auto-dev

Length of output: 44


🌐 Web query:

opentest4j 1.3.0 purpose JUnit compatibility

💡 Result:

opentest4j 1.3.0 purpose and JUnit compatibility — short answer

  • Purpose: OpenTest4J provides a minimal, framework‑agnostic foundation of test exception types (e.g., AssertionFailedError, TestAbortedException) so testing frameworks, assertion libraries, IDEs and build tools can interoperate and report test results consistently. [1][2]

  • JUnit compatibility: JUnit 5 (and its APIs) use OpenTest4J exception types (for example assumption failures/aborts use org.opentest4j.TestAbortedException and assertion failures map to AssertionFailedError), so projects using JUnit depend on/openly interoperate with opentest4j (including the 1.3.0 release). [2][3]

Sources

  • OpenTest4J project description. [1]
  • OpenTest4J 1.3.0 API docs (AssertionFailedError, TestAbortedException). [2]
  • Example references showing JUnit methods throwing OpenTest4J exceptions. [3]

🏁 Script executed:

#!/bin/bash
# Search for documentation or comments about the test setup in the repository
rg -n "test|Test" mpp-idea/build.gradle.kts -A 2 -B 2

Repository: unit-mesh/auto-dev

Length of output: 538


🏁 Script executed:

#!/bin/bash
# Check if there are other test files or configurations that show how tests are actually run
find mpp-idea -name "*.kt" -path "*/test/*" | head -10

Repository: unit-mesh/auto-dev

Length of output: 44


🌐 Web query:

kotlin("test") Kotlin 2.2.0 JUnit dependencies transitive

💡 Result:

Short answer: kotlin("test") (Kotlin 2.2.0) is the multiplatform kotlin-test umbrella — it does not force a specific JUnit implementation by itself. The concrete JVM adapters are provided by separate artifacts (kotlin-test-junit for JUnit 4 and kotlin-test-junit5 for JUnit 5); those adapter modules are the ones that bring JUnit transitively. [1][2][3]

Notes / sources:

  • kotlin.test modules and platform-specific adapters (kotlin-test-junit, kotlin-test-junit5). [1][2]
  • Gradle/compatibility note: mixing multiple kotlin-test JVM variants brought transitively can cause conflicts; choose or exclude the adapter you want. [3]
  • Kotlin Test 2.2.0 artifact listing. [4]

If you want, I can show the exact transitive coordinates (group:artifact:version) that kotlin-test-junit and kotlin-test-junit5 bring for Kotlin 2.2.0. References:
[1] https://kotlinlang.org/api/core/kotlin-test/index.html
[2] https://kotlinlang.org/api/core/kotlin-test/kotlin.test/-test/
[3] https://kotlinlang.org/docs/compatibility-guide-15.html
[4] https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-test/2.2.0


🌐 Web query:

IntelliJ Platform TestFrameworkType.Platform useJUnitPlatform() compatibility

💡 Result:

Short answer

  • TestFrameworkType.Platform is the "classic" IntelliJ Platform test-framework and is wired for the platform’s legacy test setup (JUnit4/JUnit3-style BasePlatformTestCase). It is not guaranteed to be JUnit‑Platform (JUnit‑5) ready out of the box — there are known gaps (missing opentest4j, references to JUnit4) and compatibility issues when mixing Platform tests with useJUnitPlatform(). (plugins.jetbrains.com)

  • If you need JUnit‑5 (useJUnitPlatform()), use the Starter/JUnit5 tooling (TestFrameworkType.Starter / integration test starter) or explicitly add the JUnit‑Jupiter and platform launcher/vintage artifacts to the test classpath. The Starter framework is explicitly JUnit‑5 first and examples use useJUnitPlatform(). (plugins.jetbrains.com)

Practical guidance

  • For pure platform unit tests that extend BasePlatformTestCase, keep using TestFrameworkType.Platform with JUnit4 (don’t switch test task to useJUnitPlatform() unless you add vintage/bridge engines and fix missing deps). (plugins.jetbrains.com)
  • For JUnit‑5 tests, prefer TestFrameworkType.Starter (or add junit-jupiter + junit‑platform‑launcher + junit‑vintage and opentest4j manually) and configure the Gradle Test task with useJUnitPlatform(). Example integration test usage shows useJUnitPlatform() together with Starter and junit‑jupiter. (plugins.jetbrains.com)

If you want, tell me: which IntelliJ Platform Gradle Plugin version and which test classes you’re running (BasePlatformTestCase vs JUnit‑5) and I’ll give exact Gradle snippets to make useJUnitPlatform() work or a migration path.

Citations:


Based on my verification, the review comment is valid and identifies a real configuration issue. Here's what I found:

Key findings:

  1. kotlin("test") (Kotlin 2.2.0) is an umbrella that does NOT transitively bring any JUnit implementation—it requires either kotlin-test-junit (for JUnit 4) or kotlin-test-junit5 (for JUnit 5) to work.
  2. testFramework(TestFrameworkType.Platform) is IntelliJ's legacy test framework designed for JUnit 4-style tests (BasePlatformTestCase).
  3. useJUnitPlatform() is specifically for JUnit 5 (Jupiter/Platform) and is incompatible with TestFrameworkType.Platform without additional bridge/vintage engines.
  4. opentest4j is a JUnit 5 interoperability library and shouldn't be used with pure JUnit 4.

The current configuration is mismatched and incomplete. Either use the IntelliJ Platform test framework (keep TestFrameworkType.Platform, remove useJUnitPlatform(), add kotlin-test-junit) OR migrate to JUnit 5 (add kotlin-test-junit5 and JUnit 5 dependencies, optionally switch to TestFrameworkType.Starter).


Clarify JUnit 4/5 test framework setup — configuration mismatch detected.

The build declares testFramework(TestFrameworkType.Platform) (line 60, IntelliJ's legacy JUnit 4 framework) but the test task uses useJUnitPlatform() (line 80, JUnit 5/Jupiter). These are incompatible without additional bridge engines. Additionally:

  • kotlin("test") does not automatically provide JUnit; you need either kotlin-test-junit (JUnit 4) or kotlin-test-junit5 (JUnit 5).
  • opentest4j is a JUnit 5 interoperability library and conflicts with pure JUnit 4 setup.

Choose one path: Either remove useJUnitPlatform() and add kotlin-test-junit for JUnit 4, or add kotlin-test-junit5 and JUnit 5 dependencies (junit-jupiter, junit-platform-launcher) and optionally switch testFramework(TestFrameworkType.Starter) for JUnit 5 support.

🤖 Prompt for AI Agents
In mpp-idea/build.gradle.kts around lines 40 to 42, the test dependencies and
test runner are mismatched: kotlin("test") does not bring a JUnit implementation
and you either must configure JUnit 4 or JUnit 5 consistently. Fix by choosing
one path and updating dependencies and test task: for JUnit 4 keep
testFramework(TestFrameworkType.Platform), remove useJUnitPlatform(), replace
kotlin("test") with/add kotlin("test-junit") and remove opentest4j; OR migrate
to JUnit 5 by adding kotlin("test-junit5") plus junit-jupiter (and
junit-platform-launcher as needed), keep useJUnitPlatform(), remove
TestFrameworkType.Platform (or switch to Starter), and remove opentest4j only if
not needed separately.

Comment on lines +127 to +150
@Composable
private fun MessageBubble(message: ChatMessage) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = if (message.isUser) Arrangement.End else Arrangement.Start
) {
Box(
modifier = Modifier
.widthIn(max = 300.dp)
.background(
if (message.isUser)
JewelTheme.defaultBannerStyle.information.colors.background.copy(alpha = 0.75f)
else
JewelTheme.globalColors.panelBackground
)
.padding(8.dp)
) {
Text(
text = message.content,
style = JewelTheme.defaultTextStyle
)
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Remove hardcoded alpha value to comply with coding guidelines.

Line 138 uses .copy(alpha = 0.75f), which hardcodes a color property value. As per coding guidelines, colors (including opacity) should use design tokens for consistency.

Consider these alternatives:

  1. Define a proper color token in the theme system for message bubbles
  2. Use an existing Jewel banner style without modification
  3. Create a semantic color in your design system for "user message background"

Example approach:

.background(
    if (message.isUser)
        JewelTheme.defaultBannerStyle.information.colors.background
    else
        JewelTheme.globalColors.panelBackground
)

Based on coding guidelines: DO NOT hardcode colors in .kt files.

🤖 Prompt for AI Agents
In mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatApp.kt
around lines 127 to 150, the MessageBubble composable hardcodes a color alpha
via .copy(alpha = 0.75f); remove this hardcoded opacity and instead use a design
token or existing theme semantic color for the user message background. Replace
the .copy(...) usage with a reference to a theme color (either add a new
JewelTheme token like userMessageBackground or use
JewelTheme.defaultBannerStyle.information.colors.background or another
appropriate semantic banner style), and if needed add the new token to the theme
definitions so opacity is defined centrally in the design system rather than in
this file.

@phodal phodal closed this Nov 29, 2025
@phodal phodal deleted the feat/mpp-idea-compose-ui branch December 8, 2025 23:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant