Skip to content

Conversation

@phodal
Copy link
Member

@phodal phodal commented Nov 29, 2025

Summary

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

Key Changes

Build Configuration

  • Use composite build (includeBuild) instead of include to isolate mpp-idea's plugin version
  • mpp-idea uses IntelliJ Platform Gradle Plugin 2.10.2 for IDEA 252+ Compose support
  • Main project continues to use plugin version 2.1.0 for compatibility with existing modules

New Components

  • AutoDevToolWindowFactory: ToolWindow factory using addComposeTab for Compose UI
  • AutoDevChatApp: Main Compose UI component with chat interface
  • AutoDevChatViewModel: ViewModel for managing chat state
  • CoroutineScopeHolder: Project-level service for coroutine scope management
  • AutoDevIcons: Icon loader for plugin icons

Technical Details

  • Target: IntelliJ IDEA 2025.2.1 (build 252)
  • Uses Jewel theme for native IntelliJ IDEA look and feel
  • JDK 21 toolchain required
  • Bundled Compose modules: skiko, compose.foundation.desktop, jewel.foundation, jewel.ui, jewel.ideLafBridge, platform.compose

Why Composite Build?

Gradle does not allow the same plugin with different versions in a single build. By using includeBuild("mpp-idea") instead of include("mpp-idea"), mpp-idea becomes an isolated Gradle project that can use its own plugin versions without affecting the main project.

Testing

  • ./gradlew buildPlugin - Main project builds successfully
  • ./gradlew :mpp-idea:buildPlugin - mpp-idea module builds successfully
  • ./gradlew :core:compileKotlin - Core module compiles without git4idea errors

Related

Closes the CI failure from PR #469 which was caused by globally upgrading the IntelliJ Platform Gradle Plugin version.


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

Summary by CodeRabbit

  • New Features
    • Added AutoDev Chat tool window accessible from the right sidebar.
    • Features include a chat interface with message history, message bubbles, and auto-scroll to latest messages.
    • Provides send, abort, and new conversation controls for managing chat interactions.

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

- Add mpp-idea module as a composite build (includeBuild) to avoid plugin version conflicts
- Use IntelliJ Platform Gradle Plugin 2.10.2 for IDEA 252+ Compose support
- Main project continues to use plugin version 2.1.0 for compatibility
- Add ToolWindow with Compose UI using Jewel theme
- Add ChatApp, ChatViewModel, and CoroutineScopeHolder components
- Target IntelliJ IDEA 2025.2.1 (build 252)

The composite build approach allows mpp-idea to use a different version of the
IntelliJ Platform Gradle Plugin without affecting other modules.
@coderabbitai
Copy link

coderabbitai bot commented Nov 29, 2025

Walkthrough

This PR introduces a new IntelliJ IDEA plugin module (mpp-idea) with a Compose-based chat UI tool window. The module includes Gradle build configuration, a project-scoped coroutine scope service, icon resources, Compose UI components (chat interface and view model), tool window factory integration, plugin descriptor, and localization resources. The root build is updated to include the new composite build module.

Changes

Cohort / File(s) Summary
Build Configuration
mpp-idea/build.gradle.kts, mpp-idea/settings.gradle.kts
Configures Kotlin Gradle build for IntelliJ Compose UI project with JVM toolchain (Java 21), dependencies for Kotlinx serialization/coroutines, and IntelliJ platform plugin targeting IC 2025.2.1. Establishes repository sources for plugin/dependency resolution.
Core Services
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/services/CoroutineScopeHolder.kt, mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/AutoDevIcons.kt
Introduces project-scoped CoroutineScopeHolder service for creating child coroutine scopes. Adds AutoDevIcons singleton that loads ToolWindow and AutoDev icons from resources.
Compose UI & State Management
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatViewModel.kt, mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatApp.kt
Implements AutoDevChatViewModel with state flows (chatMessages, inputState, isLoading) and methods for input handling, message sending, abort, and conversation reset. Creates AutoDevChatApp Compose-based UI with header, message list, empty state, and input area bound to ViewModel.
Tool Window Integration
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevToolWindowFactory.kt
Implements IntelliJ ToolWindowFactory that creates Compose chat panel by wiring CoroutineScopeHolder, ViewModel, and AutoDevChatApp UI into a tool window tab.
Plugin Metadata
mpp-idea/src/main/resources/META-INF/plugin.xml, mpp-idea/src/main/resources/messages/AutoDevIdeaBundle.properties
Defines plugin descriptor with service and tool window extensions, Compose dependency, and resource bundle. Resource bundle provides UI strings for tool window metadata, chat labels, placeholders, and AI provider settings.
Root Build
settings.gradle.kts
Includes mpp-idea as composite build in root configuration.

Sequence Diagram

sequenceDiagram
    participant IDE as IntelliJ IDE
    participant Factory as ToolWindowFactory
    participant Services as CoroutineScopeHolder
    participant ViewModel as AutoDevChatViewModel
    participant UI as AutoDevChatApp (Compose)
    
    IDE->>Factory: createToolWindowContent(project, toolWindow)
    Factory->>Services: project.service(CoroutineScopeHolder)
    Services-->>Factory: projectWideCoroutineScope
    Factory->>Factory: createScope("AutoDevChat")
    Factory->>ViewModel: AutoDevChatViewModel(childScope)
    ViewModel-->>Factory: viewModel instance
    Factory->>Factory: toolWindow.addComposeTab("Chat")
    Factory->>UI: AutoDevChatApp(viewModel)
    UI->>ViewModel: collectAsState(chatMessages)
    UI->>ViewModel: collectAsState(inputState)
    Note over UI,ViewModel: User interactions trigger callbacks
    UI->>ViewModel: onInputChanged(text)
    UI->>ViewModel: onSendMessage()
    ViewModel-->>UI: state updates flow back
    UI->>UI: render updated UI
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • ViewModel state transitions: Verify input state machine logic (Disabled → Enabled → Sending → SendFailed) and edge cases
  • Compose UI lifecycle: Check auto-scroll behavior on new messages and proper state collection patterns
  • CoroutineScope management: Confirm proper creation, disposal, and cancellation of child scopes; verify no resource leaks
  • Plugin.xml correctness: Validate extension registration, service/tool window IDs, and icon references
  • Resource bundle completeness: Ensure all UI strings and property keys are present and localization-ready

Poem

🐰 A chat tool springs to life with compose so bright,
With scopes and states and icons done just right,
The IDE now talks, through Kotlin so clean,
The loveliest chat tool e'er to be seen! ✨

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 title accurately describes the main change: adding a new Compose UI module (mpp-idea) for IntelliJ IDEA 2025.2+, which aligns with the core objective of introducing Compose UI support.
✨ 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-v2

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

@phodal
Copy link
Member Author

phodal commented Nov 29, 2025

augmentcode review

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: 0

🧹 Nitpick comments (4)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatApp.kt (1)

152-208: Consider extracting the send-and-clear logic.

The text field clearing logic is duplicated in two places (lines 183 and 200). Consider extracting this into a helper function to improve maintainability.

Apply this refactor:

+    val sendAndClear = {
+        onSend()
+        textFieldState.edit { replace(0, length, "") }
+    }
+
     Row(
         modifier = Modifier
             .fillMaxWidth()
             .padding(8.dp),
         horizontalArrangement = Arrangement.spacedBy(8.dp),
         verticalAlignment = Alignment.CenterVertically
     ) {
         TextField(
             state = textFieldState,
             placeholder = { Text("Type your message...") },
             modifier = Modifier
                 .weight(1f)
                 .onPreviewKeyEvent { keyEvent ->
                     if (keyEvent.key == Key.Enter && keyEvent.type == KeyEventType.KeyDown && !isSending) {
-                        onSend()
-                        textFieldState.edit { replace(0, length, "") }
+                        sendAndClear()
                         true
                     } else {
                         false
                     }
                 },
             enabled = !isSending
         )

         if (isSending) {
             DefaultButton(onClick = onAbort) {
                 Text("Stop")
             }
         } else {
             DefaultButton(
-                onClick = {
-                    onSend()
-                    textFieldState.edit { replace(0, length, "") }
-                },
+                onClick = sendAndClear,
                 enabled = inputState is MessageInputState.Enabled
             ) {
                 Text("Send")
             }
         }
     }
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevToolWindowFactory.kt (1)

20-22: Consider using DEBUG level for initialization logging.

INFO-level logging in the init block will emit a message every time the factory is instantiated, which may be noisy in production logs. Consider using thisLogger().debug(...) instead, or removing this log if it's only useful during development.

     init {
-        thisLogger().info("AutoDevToolWindowFactory initialized - Compose UI for IntelliJ IDEA 252+")
+        thisLogger().debug("AutoDevToolWindowFactory initialized - Compose UI for IntelliJ IDEA 252+")
     }
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatViewModel.kt (2)

52-53: isLoading StateFlow is declared but never updated.

The _isLoading StateFlow is defined but not used anywhere in the current implementation. If it's intended for future AI integration, consider either removing it until needed or adding a TODO comment to clarify its purpose.

Either remove the unused state:

-    private val _isLoading = MutableStateFlow(false)
-    val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()

Or add a clarifying comment:

+    // TODO: Update isLoading during AI response generation
     private val _isLoading = MutableStateFlow(false)
     val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()

96-101: Consider simplifying with ifEmpty.

Minor readability improvement using Kotlin's ifEmpty extension.

     fun onAbortMessage() {
-        _inputState.value = when (val text = _inputState.value.inputText) {
-            "" -> MessageInputState.Disabled
-            else -> MessageInputState.Enabled(text)
+        val text = _inputState.value.inputText
+        _inputState.value = text.ifEmpty { null }?.let { MessageInputState.Enabled(it) }
+            ?: MessageInputState.Disabled
         }
-    }

Alternatively, keep the current when expression as it's clear and explicit.

📜 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 89cb64a.

⛔ 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)
  • mpp-idea/build.gradle.kts (1 hunks)
  • mpp-idea/settings.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:

  • mpp-idea/settings.gradle.kts
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatApp.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/AutoDevIcons.kt
  • settings.gradle.kts
  • mpp-idea/build.gradle.kts
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatViewModel.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/services/CoroutineScopeHolder.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevToolWindowFactory.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/AutoDevIcons.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevChatViewModel.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/services/CoroutineScopeHolder.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevToolWindowFactory.kt
🧠 Learnings (3)
📚 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/AutoDevIcons.kt
  • mpp-idea/build.gradle.kts
  • mpp-idea/src/main/resources/META-INF/plugin.xml
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/AutoDevToolWindowFactory.kt
📚 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: Build MPP Core: `cd /Volumes/source/ai/autocrud && ./gradlew :mpp-core:assembleJsPackage`

Applied to files:

  • settings.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: Applies to **/*.{kt,kts} : Use `expect`/`actual` for platform-specific code in Kotlin Multiplatform (e.g., file I/O on JVM/JS/Wasm)

Applied to files:

  • mpp-idea/build.gradle.kts
🧬 Code graph analysis (1)
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 (14)
settings.gradle.kts (1)

20-20: LGTM! Composite build correctly configured.

The includeBuild("mpp-idea") enables the new mpp-idea module as a composite build, which appropriately isolates its IntelliJ Platform Gradle Plugin version from the main project.

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

1-16: LGTM! Standard Gradle settings configuration.

The settings file correctly configures repositories for plugin management and dependency resolution.

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

1-80: LGTM! Build configuration is well-structured.

The build file correctly configures:

  • Kotlin 2.2.0 with Compose plugin support
  • IntelliJ Platform Plugin 2.10.2 for IDEA 252+ support
  • JDK 21 toolchain (required for IDEA 2025.2+)
  • All necessary bundled Compose modules
  • Appropriate compiler options for experimental Compose APIs
mpp-idea/src/main/resources/messages/AutoDevIdeaBundle.properties (1)

1-17: LGTM! Resource bundle is well-organized.

The property keys and values are clearly defined for UI localization.

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

27-84: LGTM! Well-structured Compose UI with proper state management.

The main composable correctly:

  • Collects state from the ViewModel
  • Implements auto-scroll behavior when new messages arrive
  • Uses Jewel theme colors (no hardcoded colors - complies with coding guidelines)
  • Organizes UI into logical sections (header, messages, input)

86-125: LGTM! Header and empty state are cleanly implemented.

Both composables use Jewel theme tokens for consistent styling.


127-150: LGTM! Message bubble styling uses theme tokens correctly.

The bubble correctly differentiates user vs. assistant messages using Jewel theme colors, complying with the coding guideline against hardcoded colors.

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

14-30: LGTM! Coroutine scope service correctly implemented.

The service properly:

  • Uses constructor injection for the project-wide scope
  • Creates child scopes with proper parent-child lifecycle management
  • Documents the cancellation requirements clearly

The @Suppress("UnstableApiUsage") annotation is appropriate for the childScope extension.

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

1-30: LGTM! Plugin descriptor is correctly configured.

The plugin.xml properly:

  • Declares the required Compose module dependency
  • Registers the CoroutineScopeHolder project service
  • Configures the tool window with correct factory, anchor, and icon references
  • Links the resource bundle for localization
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/AutoDevIcons.kt (1)

10-22: Icon resources verified successfully.

The icon files referenced in the code exist at the expected paths:

  • mpp-idea/src/main/resources/icons/autodev-toolwindow.svg
  • mpp-idea/src/main/resources/icons/autodev.svg

The IconLoader.getIcon() calls will resolve correctly to these resources at runtime.

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

30-40: LGTM!

The MVVM wiring is well-structured: the coroutine scope is properly scoped via CoroutineScopeHolder, the viewModel is registered with the tool window's disposable for lifecycle management, and the Compose tab is correctly added via Jewel's addComposeTab.

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

13-25: LGTM!

The MessageInputState sealed class is well-designed with clear state variants. Using data object for Disabled is idiomatic Kotlin for singleton-like states.


30-35: LGTM!

Clean data class definition with sensible defaults.


111-113: LGTM!

Proper cleanup by cancelling the coroutine scope on disposal.

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.

2 participants