-
Notifications
You must be signed in to change notification settings - Fork 469
feat: add mpp-vscode support #480
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Create project directory structure - Add package.json with VSCode extension configuration - Add tsconfig.json for TypeScript - Add README.md with TODO list and architecture overview Closes #31
Phase 2 - Core Services: - Add mpp-core bridge layer with LLMService, CodingAgent, ToolRegistry, CompletionManager, and DevInsCompiler wrappers - Implement extension.ts entry point with activation/deactivation Phase 3 - IDE Integration: - Implement IDE Server with Express HTTP endpoints - Add DiffManager for file diff operations - Support MCP protocol communication Phase 4 - Chat Interface: - Implement ChatViewProvider with webview - Add streaming LLM response support - Create embedded HTML chat UI Phase 5 - Commands: - Register autodev.chat, autodev.acceptDiff, autodev.cancelDiff, autodev.runAgent - Add keyboard shortcut (Cmd+Shift+A) Testing: - Add vitest configuration - Add unit tests for mpp-core bridge - Add unit tests for DiffManager - Add unit tests for IDEServer Refs #31
Phase 5 - Status Bar: - Add StatusBarManager with idle/thinking/streaming/error states - Animated status icons during LLM operations - Click to open chat command Phase 6 - DevIns Language Support: - Add TextMate grammar for syntax highlighting - Support commands (/), agents (@), variables ($) - Add language configuration (brackets, folding, etc.) - Implement DevInsCompletionProvider with built-in completions - Register completion triggers for /, @, $ characters Testing: - Add unit tests for StatusBarManager - Add unit tests for DevInsCompletionProvider - All 56 tests passing Refs #31
Phase 6 - React Webview UI: - Create webview React project with Vite build - Add MessageList component with Markdown rendering - Add ChatInput component with auto-resize textarea - Add useVSCode hook for extension communication - Integrate VSCode theme variables for consistent styling - Support streaming response with animated indicators - Add fallback inline HTML when React bundle not available - Update ChatViewProvider to load React bundle with CSP Components: - App.tsx - Main chat application - MessageList.tsx - Message display with Markdown support - ChatInput.tsx - Input with keyboard shortcuts - useVSCode.ts - VSCode API communication hook Testing: - Add ChatViewProvider tests - All 63 tests passing Refs #31
Extract MarkdownTextParser to a shared mpp-core module for reuse and improved testability across platforms. Update imports accordingly.
Phase 7 - Sketch Renderer System: - Add Timeline component mirroring mpp-ui's ComposeRenderer - Add SketchRenderer with specialized sub-renderers: - CodeBlockRenderer: syntax highlighting with Copy/Insert/Apply actions - DiffRenderer: diff display with Accept/Reject/View actions - ThinkingRenderer: collapsible thinking blocks - TerminalRenderer: terminal command and output display - MarkdownRenderer: GFM markdown with react-markdown - ToolCallRenderer: tool call information display - Add codeFence parser mirroring mpp-core's CodeFence.parseAll() - Add timeline types (TimelineItem, AgentState, ToolCallInfo, etc.) ChatViewProvider Refactoring: - Replace LLMService with CodingAgent for agent-based interactions - Add VSCodeRenderer implementing JsCodingAgentRenderer interface - Forward agent events (toolCall, toolResult, terminalOutput) to webview - Add action handlers (insert, apply, run-command, accept-diff, etc.) - Remove API key requirement - use helpful guidance for non-DevIns input All 63 tests passing. Refs #31
Phase 8 - Configuration Management Integration Changes: - Add ConfigManager service to load config from ~/.autodev/config.yaml - Refactor ChatViewProvider to use ConfigManager instead of VSCode settings - Mirror IdeaAgentViewModel's loadConfiguration() pattern - Add lazy initialization of CodingAgent with proper config validation - Create renderer that forwards events to webview (like TuiRenderer) - Add 'Open Config' button in header and config prompt - Support all LLM providers: openai, anthropic, deepseek, ollama, etc. - Auto-create config template when file doesn't exist Architecture: - ConfigManager.load() → AutoDevConfigWrapper → getActiveConfig() - isValid() check before agent initialization - JsKoogLLMService + JsCodingAgent from mpp-core - Renderer implements all JsCodingAgentRenderer methods All 63 tests passing. Refs #31
- Add ModelSelector component similar to IdeaModelSelector.kt - Update ChatInput with toolbar: ModelSelector on left, Stop/Send on right - Add config state management in App.tsx - Add sendConfigUpdate, stopExecution, selectConfig in chat-view.ts - Add new message types: configUpdate, stopExecution, selectConfig All 63 tests passing. Refs #31
- Acquire VSCode API in HTML before React loads to avoid duplicate acquisition error - Store API on window.vscodeApi for React to use - Remove debug logging from production code All 63 tests passing. Refs #31
User message was being added twice - once in handleSend for immediate feedback and again when receiving userMessage from extension. Refs #31
- Fix repository URL from phodal/auto-dev to phodal/auto-dev-sketch - Remove unused colors variable in status-bar.ts - Add platform detection for welcome message keybinding (Cmd vs Ctrl)
- Create project directory structure - Add package.json with VSCode extension configuration - Add tsconfig.json for TypeScript - Add README.md with TODO list and architecture overview Closes #31
Phase 2 - Core Services: - Add mpp-core bridge layer with LLMService, CodingAgent, ToolRegistry, CompletionManager, and DevInsCompiler wrappers - Implement extension.ts entry point with activation/deactivation Phase 3 - IDE Integration: - Implement IDE Server with Express HTTP endpoints - Add DiffManager for file diff operations - Support MCP protocol communication Phase 4 - Chat Interface: - Implement ChatViewProvider with webview - Add streaming LLM response support - Create embedded HTML chat UI Phase 5 - Commands: - Register autodev.chat, autodev.acceptDiff, autodev.cancelDiff, autodev.runAgent - Add keyboard shortcut (Cmd+Shift+A) Testing: - Add vitest configuration - Add unit tests for mpp-core bridge - Add unit tests for DiffManager - Add unit tests for IDEServer Refs #31
Phase 5 - Status Bar: - Add StatusBarManager with idle/thinking/streaming/error states - Animated status icons during LLM operations - Click to open chat command Phase 6 - DevIns Language Support: - Add TextMate grammar for syntax highlighting - Support commands (/), agents (@), variables ($) - Add language configuration (brackets, folding, etc.) - Implement DevInsCompletionProvider with built-in completions - Register completion triggers for /, @, $ characters Testing: - Add unit tests for StatusBarManager - Add unit tests for DevInsCompletionProvider - All 56 tests passing Refs #31
Phase 6 - React Webview UI: - Create webview React project with Vite build - Add MessageList component with Markdown rendering - Add ChatInput component with auto-resize textarea - Add useVSCode hook for extension communication - Integrate VSCode theme variables for consistent styling - Support streaming response with animated indicators - Add fallback inline HTML when React bundle not available - Update ChatViewProvider to load React bundle with CSP Components: - App.tsx - Main chat application - MessageList.tsx - Message display with Markdown support - ChatInput.tsx - Input with keyboard shortcuts - useVSCode.ts - VSCode API communication hook Testing: - Add ChatViewProvider tests - All 63 tests passing Refs #31
Extract MarkdownTextParser to a shared mpp-core module for reuse and improved testability across platforms. Update imports accordingly.
Phase 7 - Sketch Renderer System: - Add Timeline component mirroring mpp-ui's ComposeRenderer - Add SketchRenderer with specialized sub-renderers: - CodeBlockRenderer: syntax highlighting with Copy/Insert/Apply actions - DiffRenderer: diff display with Accept/Reject/View actions - ThinkingRenderer: collapsible thinking blocks - TerminalRenderer: terminal command and output display - MarkdownRenderer: GFM markdown with react-markdown - ToolCallRenderer: tool call information display - Add codeFence parser mirroring mpp-core's CodeFence.parseAll() - Add timeline types (TimelineItem, AgentState, ToolCallInfo, etc.) ChatViewProvider Refactoring: - Replace LLMService with CodingAgent for agent-based interactions - Add VSCodeRenderer implementing JsCodingAgentRenderer interface - Forward agent events (toolCall, toolResult, terminalOutput) to webview - Add action handlers (insert, apply, run-command, accept-diff, etc.) - Remove API key requirement - use helpful guidance for non-DevIns input All 63 tests passing. Refs #31
Phase 8 - Configuration Management Integration Changes: - Add ConfigManager service to load config from ~/.autodev/config.yaml - Refactor ChatViewProvider to use ConfigManager instead of VSCode settings - Mirror IdeaAgentViewModel's loadConfiguration() pattern - Add lazy initialization of CodingAgent with proper config validation - Create renderer that forwards events to webview (like TuiRenderer) - Add 'Open Config' button in header and config prompt - Support all LLM providers: openai, anthropic, deepseek, ollama, etc. - Auto-create config template when file doesn't exist Architecture: - ConfigManager.load() → AutoDevConfigWrapper → getActiveConfig() - isValid() check before agent initialization - JsKoogLLMService + JsCodingAgent from mpp-core - Renderer implements all JsCodingAgentRenderer methods All 63 tests passing. Refs #31
- Add ModelSelector component similar to IdeaModelSelector.kt - Update ChatInput with toolbar: ModelSelector on left, Stop/Send on right - Add config state management in App.tsx - Add sendConfigUpdate, stopExecution, selectConfig in chat-view.ts - Add new message types: configUpdate, stopExecution, selectConfig All 63 tests passing. Refs #31
- Acquire VSCode API in HTML before React loads to avoid duplicate acquisition error - Store API on window.vscodeApi for React to use - Remove debug logging from production code All 63 tests passing. Refs #31
User message was being added twice - once in handleSend for immediate feedback and again when receiving userMessage from extension. Refs #31
- Fix repository URL from phodal/auto-dev to phodal/auto-dev-sketch - Remove unused colors variable in status-bar.ts - Add platform detection for welcome message keybinding (Cmd vs Ctrl)
- Use mpp-core's JsCompletionManager for DevIn command completions - Add getCompletions and applyCompletion message handlers - Update CompletionPopup to support mpp-core CompletionItem format - Fix popup positioning by removing overflow:hidden from container - Add completion state management in App.tsx
feat(vscode): Enhanced Chat Input with DevIn Language Support
- Add SelectedFileItem, FileChip, TopToolbar, FileSearchPopup components - Add WorkspaceFileSearchProvider with pre-built file index for fast search - Add IndexingState enum for tracking indexing progress - Integrate file context into DevInEditorInput with buildAndSendMessage() - Add Prompt Enhancement button to BottomToolbar - Add AutoAwesome and History icons to AutoDevComposeIcons - Add FileContext to EditorCallbacks for file context submission Closes #35
* feat(mpp-ui): implement file context management with indexed search - Add SelectedFileItem, FileChip, TopToolbar, FileSearchPopup components - Add WorkspaceFileSearchProvider with pre-built file index for fast search - Add IndexingState enum for tracking indexing progress - Integrate file context into DevInEditorInput with buildAndSendMessage() - Add Prompt Enhancement button to BottomToolbar - Add AutoAwesome and History icons to AutoDevComposeIcons - Add FileContext to EditorCallbacks for file context submission Closes #35 * feat(mpp-core): add plan management data models and parser for task management - Add TaskStatus enum (TODO, IN_PROGRESS, COMPLETED, FAILED, BLOCKED) and PlanPhase enum (PDCA cycle) - Add CodeFileLink data class for markdown file link extraction - Add PlanStep, PlanTask, AgentPlan data models with serialization support - Add MarkdownPlanParser using pure Kotlin regex (no IntelliJ dependencies) - Add PlanStateService with StateFlow and listener pattern for reactive updates - Add PlanUpdateListener interface for UI notifications - Add comprehensive unit tests for parser and state service - Fix DocQLReturnAllTest missing Pending branch in when expressions Part of #37 * feat(mpp-core): add PlanManagementTool for AI agent task planning - Add PlanManagementTool with CREATE, UPDATE, COMPLETE_STEP, FAIL_STEP, VIEW actions - Add PlanManagementParams, PlanManagementSchema, PlanManagementInvocation - Add comprehensive unit tests for all tool actions - Tool integrates with PlanStateService for state management Part of #37 * feat(mpp-core): register PlanManagementTool in BuiltinToolsProvider - Add PlanManagementTool to BuiltinToolsProvider.provide() - Add executePlanManagementTool method in ToolOrchestrator - Add tests for plan and task-boundary tool registration Part of #37 * feat(mpp-ui): add PlanPanel UI component and integrate with ComposeRenderer - Create PlanPanel composable with task and step display - Add expandable task cards with progress tracking - Implement status icons and colors for plan visualization - Integrate plan state tracking in ComposeRenderer - Handle plan tool calls to update UI state Part of #37 * feat(mpp-core): add plan management guidance to system prompt and fix parameter parsing - Add Planning and Task Management section to CodingAgentTemplate (EN and ZH) - Document when to use planning, plan format, and plan actions - Update Task Completion Strategy to include planning step - Fix taskIndex/stepIndex parameter parsing in ToolOrchestrator to handle both Number and String types Part of #37 * refactor(mpp-core): remove TaskBoundaryTool in favor of PlanManagementTool - Remove TaskBoundaryTool.kt as PlanManagementTool provides superset functionality - Remove TaskBoundaryTool from BuiltinToolsProvider and ToolOrchestrator - Update ToolRegistryTest to remove task-boundary test - Update comments referencing task-boundary - Enhance PlanManagementTool with detailed KDoc documentation - Fix tuiEmoji to use proper emoji character Part of #37 * fix(executor): reduce shell command max timeout to 2 minutes Lower the maximum wait time for shell command execution to 2 minutes and pass it as a timeout to the orchestrator context.
- Add PlanSummaryData model in mpp-core for lightweight UI summary - Add PlanSummaryBar Compose component in mpp-ui - Add IdeaPlanSummaryBar with Jewel styling for mpp-idea - Add JewelRenderer plan tracking (currentPlan StateFlow) - Add PlanSummaryBar React component for mpp-vscode - Integrate PlanSummaryBar above input box in all platforms The PlanSummaryBar displays a collapsible summary of the current plan above the input box, showing progress, current step, and allowing users to expand for full plan details.
Simplifies schema by eliminating UPDATE action and clarifying usage of COMPLETE_STEP for progress updates.
Refactor rendering logic and update plan step handling across agent components to enhance orchestration and output formatting.
- PlanSummaryBar now expands upward instead of downward to avoid compressing content - Plan tool calls are no longer rendered in the message timeline (shown only in PlanSummaryBar) - Added renderToolCallWithParams method to pass parsed parameters directly - Fixed parameter parsing issues with complex values like planMarkdown containing JSON
Revise agent template to require codebase exploration before plan creation, add concrete examples, and update planning guidelines for both English and Chinese. Also update DevInEditorInput to use transparent text and default keyboard behavior.
Refine minHeight, maxHeight, and padding for iOS to improve input usability and avoid keyboard constraint issues.
Removed the linear progress indicator when content is not complete in SketchRenderer.
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds a multiplatform plan-management system (models, parser, reactive service, UI summaries), replaces TaskBoundaryTool with PlanManagementTool, integrates plan flows into agent executor and renderers, updates prompts to "Explore First, Then Plan", and adds a full VSCode extension and webview UI for plan and editor workflows. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Agent as CodingAgent
participant Orch as ToolOrchestrator
participant PlanTool as PlanManagementTool
participant PlanSvc as PlanStateService
participant Renderer
User->>Agent: submit request (explore-first mode)
Agent->>Orch: call exploration tools (glob/read/grep)
Orch->>Renderer: render tool results
Renderer->>User: show exploration output
User->>Agent: instruct "create plan" (planMarkdown)
Agent->>Orch: invoke plan tool
Orch->>PlanTool: execute(action=CREATE, planMarkdown)
PlanTool->>PlanSvc: createPlanFromMarkdown(markdown)
PlanSvc->>PlanSvc: parse → AgentPlan, notify listeners
PlanSvc-->>PlanTool: return plan summary
PlanTool-->>Orch: ToolResult(with plan summary)
Orch->>Renderer: renderToolCallWithParams(...) and renderPlanSummary(...)
Renderer->>User: show plan summary UI
loop iterate steps
User->>Agent: execute step
Agent->>Orch: invoke COMPLETE_STEP
Orch->>PlanTool: execute(action=COMPLETE_STEP, indices)
PlanTool->>PlanSvc: completeStep(taskId, stepId)
PlanSvc->>PlanSvc: update statuses, notify listeners
PlanSvc-->>PlanTool: updated plan summary
PlanTool-->>Orch: ToolResult(progress)
Orch->>Renderer: renderPlanSummary(updated)
Renderer->>User: show progress update
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60–90 minutes Areas requiring extra attention:
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request adds comprehensive VSCode extension support for the AutoDev multi-platform project (mpp). It introduces a React-based webview for the chat interface, VSCode extension services for IDE integration, and TypeScript/JavaScript infrastructure to bridge with the Kotlin multiplatform core (mpp-core).
Key changes:
- React webview application with Timeline-based UI architecture for agent interactions
- VSCode extension services: DiffManager, IDEServer (MCP protocol), StatusBarManager
- DevIns language support with syntax highlighting and completion
- Bridge to mpp-core for LLM services, tool execution, and agent capabilities
Reviewed changes
Copilot reviewed 121 out of 122 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| mpp-vscode/webview/vite.config.ts | Vite configuration for React webview build |
| mpp-vscode/webview/tsconfig.json | TypeScript config for webview with React JSX |
| mpp-vscode/webview/package.json | React dependencies and build scripts |
| mpp-vscode/webview/src/* | React components for Timeline, ChatInput, ModelSelector, etc. |
| mpp-vscode/src/extension.ts | Main extension entry point with service initialization |
| mpp-vscode/src/services/* | Core services: DiffManager, IDEServer, StatusBarManager |
| mpp-vscode/src/providers/* | ChatViewProvider and DevIns completion provider |
| mpp-vscode/test/* | Unit tests for services and providers |
| mpp-vscode/syntaxes/* | DevIns language syntax definitions |
| mpp-ui/src/jsMain/typescript/agents/render/CliRenderer.ts | Added plan summary rendering support |
The PR is well-structured with comprehensive test coverage, proper TypeScript typing, and follows VSCode extension best practices. The webview architecture mirrors the existing mpp-ui design for consistency across platforms.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
mpp-vscode/src/bridge/mpp-core.ts
Outdated
| JsCompletionManager, | ||
| JsDevInsCompiler, | ||
| JsToolRegistry, | ||
| JsCompressionConfig |
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused variable JsCompressionConfig.
| return; | ||
| } | ||
|
|
||
| const basePath = workspaceFolders[0].uri.fsPath; |
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused variable basePath.
| const styleUri = webview.asWebviewUri(vscode.Uri.joinPath(webviewPath, 'assets', 'index.css')); | ||
|
|
||
| // Use nonce for security | ||
| const nonce = this.getNonce(); |
Copilot
AI
Dec 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused variable nonce.
- Remove unused JsCompressionConfig import in mpp-core.ts - Remove unused basePath variable in chat-view.ts - Remove unused nonce variable and getNonce method in chat-view.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 19
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/renderer/JewelRenderer.kt (1)
498-510:clearTimeline()does not reset_currentPlan.When clearing the timeline state,
_currentPlanretains its value. This may cause stale plan data to persist across sessions.Add plan reset:
fun clearTimeline() { _timeline.value = emptyList() _currentStreamingOutput.value = "" _isProcessing.value = false _currentIteration.value = 0 _errorMessage.value = null _taskCompleted.value = false _totalTokenInfo.value = TokenInfo() _lastMessageTokenInfo = null _tasks.value = emptyList() + _currentPlan.value = null executionStartTime = 0L _currentExecutionTime.value = 0L }
♻️ Duplicate comments (1)
mpp-core/src/jvmTest/kotlin/cc/unitmesh/agent/tool/impl/DocQLReturnAllTest.kt (1)
171-176: Consistent Pending handling.The
Pendingcase is handled identically to the first when expression (lines 125-130), maintaining consistency across both test scenarios.
🟡 Minor comments (17)
mpp-ios/build-ios-app.sh-347-355 (1)
347-355: Fix UUID regex to be case-insensitive.Line 349's regex pattern
[0-9A-F]{8}-...only matches uppercase hex digits. Sincexcrun devicectl list devicescan return UUIDs in lowercase or mixed case, this will cause silent device detection failures.Use the
grep -iflag to make the pattern case-insensitive:- DEVICE_UUID=$(xcrun devicectl list devices 2>&1 | grep "connected" | grep -oE "[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}" | head -n 1) + DEVICE_UUID=$(xcrun devicectl list devices 2>&1 | grep "connected" | grep -ioE "[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}" | head -n 1)mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/render/RendererUtils.kt-99-99 (1)
99-99: Update comment to reflect actual parsing capabilities.The comment states "flat objects with string values" but the implementation also handles numbers (line 107) and unquoted words like booleans (line 108).
Apply this diff to make the comment more accurate:
- // Simple JSON parsing for flat objects with string values + // Simple JSON parsing for flat objects with string, number, or boolean valuesmpp-vscode/README.md-106-111 (1)
106-111: Replace hardcoded absolute path with relative path.Line 109 contains a hardcoded absolute path (
/Volumes/source/ai/autocrud) that is specific to a particular development environment and won't work for other users.Apply this diff to use a relative path:
### 构建 mpp-core ```bash -cd /Volumes/source/ai/autocrud +cd ../ # Navigate to repository root ./gradlew :mpp-core:assembleJsPackageAlternatively, clarify that this is an example path and users should adjust accordingly. </blockquote></details> <details> <summary>mpp-vscode/webview/src/components/plan/PlanSummaryBar.css-84-86 (1)</summary><blockquote> `84-86`: **Expand arrow rotation appears incorrect.** The `.expand-arrow.expanded` rule sets `transform: rotate(0deg)`, which is the default state and won't produce any visual change. Typically, an expanded arrow rotates (e.g., `rotate(90deg)` or `rotate(180deg)`) to indicate the expanded state. ```diff .expand-arrow.expanded { - transform: rotate(0deg); + transform: rotate(90deg); }mpp-vscode/test/services/diff-manager.test.ts-140-149 (1)
140-149: Test does not verify event emission behavior.This test only verifies that the events array starts empty but doesn't trigger any action that would emit a
DiffEvent. Consider either removing this test as it doesn't validate meaningful behavior, or expanding it to call methods likeshowDiff,acceptDiff, orcancelDiffthat would emit events.it('should emit events on diff changes', async () => { const { DiffManager, DiffContentProvider } = await import('../../src/services/diff-manager'); const contentProvider = new DiffContentProvider(); const manager = new DiffManager(mockLog, contentProvider); const events: any[] = []; manager.onDidChange((event) => events.push(event)); - expect(events).toHaveLength(0); + // TODO: Trigger an action that emits events (e.g., showDiff + acceptDiff) + // and verify the event payload + expect(events).toHaveLength(0); // Initially empty before any action });mpp-vscode/webview/src/components/sketch/SketchRenderer.tsx-108-137 (1)
108-137: MissingonActionprop on placeholder renderers.The Mermaid, DevIn, and Plan blocks use
CodeBlockRendererbut don't pass theonActioncallback, making Copy/Insert/Apply buttons non-functional for these block types. This inconsistency could confuse users.Apply this diff to pass
onActionconsistently:case 'mermaid': case 'mmd': // TODO: Implement MermaidRenderer return ( <CodeBlockRenderer code={block.text} language="mermaid" isComplete={isComplete} + onAction={onAction} /> ); case 'devin': // TODO: Implement DevInRenderer return ( <CodeBlockRenderer code={block.text} language="devin" isComplete={isComplete} + onAction={onAction} /> ); case 'plan': // TODO: Implement PlanRenderer return ( <CodeBlockRenderer code={block.text} language="plan" isComplete={isComplete} + onAction={onAction} /> );mpp-vscode/src/services/ide-server.ts-194-203 (1)
194-203: Port file not cleaned up on shutdown.The port file written to
~/.autodev/ide-server.jsonis not deleted when the server stops. Stale files with old auth tokens could cause confusion or security issues for external tools.Apply this diff to clean up the port file:
async stop(): Promise<void> { if (this.server) { return new Promise((resolve) => { this.server!.close(() => { this.log('IDE Server stopped'); + this.cleanupPortFile(); resolve(); }); }); } } + + private async cleanupPortFile(): Promise<void> { + if (this.portFile) { + try { + await fs.unlink(this.portFile); + this.log(`Port file removed: ${this.portFile}`); + } catch { + // Ignore errors during cleanup + } + } + }Committable suggestion skipped: line range outside the PR's diff.
mpp-vscode/src/providers/devins-completion.ts-52-61 (1)
52-61:completionManageris instantiated but never used.The
CompletionManageris created in the constructor (line 57) and stored inthis.completionManager, but none of the completion methods (getCommandCompletions,getAgentCompletions,getVariableCompletions) actually use it. All methods only use theBUILTIN_*arrays.This appears to be dead code. Either integrate the
CompletionManagerfor dynamic completions or remove the unused field:export class DevInsCompletionProvider implements vscode.CompletionItemProvider { - private completionManager: CompletionManager | undefined; - - constructor() { - try { - this.completionManager = new CompletionManager(); - } catch (e) { - // mpp-core not available, use built-in completions only - } - } + // Future: integrate CompletionManager for dynamic completions from mpp-coreOr implement the integration:
private getCommandCompletions(linePrefix: string): vscode.CompletionItem[] { // If CompletionManager is available, use it for dynamic completions if (this.completionManager) { const dynamicItems = this.completionManager.getCompletions(linePrefix, linePrefix.length); // ... convert and return } // Fallback to built-in completions // ... }mpp-vscode/src/providers/chat-view.ts-517-526 (1)
517-526: Variable declaration inside switch case can be accessed by other cases.The
editorconstant declared in theinsertcase can be accidentally accessed by subsequent cases. This is flagged by Biome static analysis.case 'insert': - // Insert code at cursor - const editor = vscode.window.activeTextEditor; - if (editor && data.code) { - await editor.edit(editBuilder => { - editBuilder.insert(editor.selection.active, data.code); - }); - } + { + // Insert code at cursor + const editor = vscode.window.activeTextEditor; + if (editor && data.code) { + await editor.edit(editBuilder => { + editBuilder.insert(editor.selection.active, data.code); + }); + } + } break;mpp-vscode/webview/src/App.tsx-363-365 (1)
363-365: Operator precedence issue inneedsConfigexpression.The expression mixes
&&and||without parentheses. Due to operator precedence,&&binds tighter than||, so this evaluates as:
(timeline.length === 0 && content.includes('No configuration found')) || content.includes('Configuration Required')This may not be the intended logic. If both conditions should require an empty timeline, add parentheses.
- const needsConfig = agentState.timeline.length === 0 && - agentState.currentStreamingContent.includes('No configuration found') || - agentState.currentStreamingContent.includes('Configuration Required'); + const needsConfig = agentState.timeline.length === 0 && ( + agentState.currentStreamingContent.includes('No configuration found') || + agentState.currentStreamingContent.includes('Configuration Required') + );mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/plan/AgentPlan.kt-88-99 (1)
88-99:touch()is called even when task is not found.Both
updateTaskStatusandcompleteStepcalltouch()unconditionally, even whengetTask(taskId)returns null. This updatesupdatedAtwithout any actual modification.fun updateTaskStatus(taskId: String, status: TaskStatus) { - getTask(taskId)?.updateStatus(status) - touch() + getTask(taskId)?.let { + it.updateStatus(status) + touch() + } } fun completeStep(taskId: String, stepId: String) { - getTask(taskId)?.completeStep(stepId) - touch() + getTask(taskId)?.let { + it.completeStep(stepId) + touch() + } }mpp-vscode/webview/src/App.tsx-118-138 (1)
118-138: Mutating timeline item directly instead of creating new object.The
toolResulthandler creates a shallow copy of the timeline array but then mutatesitem.toolCalldirectly (line 126). This violates React's immutability principle and could cause issues with re-renders or component memoization.case 'toolResult': if (msg.data) { setAgentState(prev => { - const timeline = [...prev.timeline]; - // Find the last tool call and update it - for (let i = timeline.length - 1; i >= 0; i--) { - if (timeline[i].type === 'tool_call') { - const item = timeline[i] as ToolCallTimelineItem; - item.toolCall = { - ...item.toolCall, - success: msg.data?.success as boolean | undefined, - output: msg.data?.output as string | undefined, - summary: msg.data?.summary as string | undefined - }; - break; - } - } + const timeline = prev.timeline.map((item, i, arr) => { + // Find the last tool call + if (item.type === 'tool_call') { + const isLast = !arr.slice(i + 1).some(t => t.type === 'tool_call'); + if (isLast) { + return { + ...item, + toolCall: { + ...(item as ToolCallTimelineItem).toolCall, + success: msg.data?.success as boolean | undefined, + output: msg.data?.output as string | undefined, + summary: msg.data?.summary as string | undefined + } + }; + } + } + return item; + }); return { ...prev, timeline }; }); } break;mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/renderer/JewelRenderer.kt-311-324 (1)
311-324: In-place mutation before StateFlow update may cause UI inconsistencies.The code mutates
step.complete()andtask.updateStatusFromSteps()in place (lines 318-319), then creates a new plan viacopy()(line 321). Since_currentPlan.valuestill references the sameplanobject during mutation, observers may see intermediate states.Consider creating immutable copies of the step and task before updating:
"COMPLETE_STEP" -> { if (taskIndex == null || stepIndex == null) return _currentPlan.value?.let { plan -> if (taskIndex in 1..plan.tasks.size) { val task = plan.tasks[taskIndex - 1] if (stepIndex in 1..task.steps.size) { - val step = task.steps[stepIndex - 1] - step.complete() - task.updateStatusFromSteps() - // Trigger recomposition by creating a new plan instance - _currentPlan.value = plan.copy(updatedAt = System.currentTimeMillis()) + // Create updated step and task immutably + val updatedStep = task.steps[stepIndex - 1].copy(status = TaskStatus.COMPLETED) + val updatedSteps = task.steps.toMutableList().apply { this[stepIndex - 1] = updatedStep } + // Would require PlanTask.copy with steps parameter + _currentPlan.value = plan.copy(updatedAt = System.currentTimeMillis()) } } } }Note: This requires
PlanTaskandPlanStepto support immutable copy operations with nested updates.Committable suggestion skipped: line range outside the PR's diff.
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/plan/PlanStep.kt-114-118 (1)
114-118: Thread-safety issue:idCounteris not synchronized.The
idCounteris a shared mutableLongthat can be accessed concurrently from multiple threads. In Kotlin Multiplatform, this could lead to duplicate IDs.For thread-safe ID generation, consider using
atomicfuor including more entropy:- private var idCounter = 0L - - private fun generateId(): String { - return "step_${++idCounter}_${currentTimeMillis()}" - } + private val random = kotlin.random.Random + + private fun generateId(): String { + return "step_${currentTimeMillis()}_${random.nextInt(0, Int.MAX_VALUE)}" + }This aligns with the pattern shown in
RendererModels.kt(line 203 in snippets).Committable suggestion skipped: line range outside the PR's diff.
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/plan/MarkdownPlanParser.kt-85-100 (1)
85-100: Potential false negative for malformed checkbox items.Line 90 skips items where
description.startsWith("["), intended to filter malformed checkbox items. However, this also skips legitimate steps like- [link text](url)that start with a markdown link.Consider a more precise check:
- // Skip if it looks like a checkbox item that didn't match - if (description.startsWith("[")) continue + // Skip if it looks like an incomplete checkbox item (e.g., "[ ]" or "[x]") + if (description.matches(Regex("^\\[.?\\].*"))) continuempp-core/src/commonMain/kotlin/cc/unitmesh/agent/plan/PlanTask.kt-149-153 (1)
149-153: Thread-safety issue withidCounterin concurrent environments.The
idCounteris a mutableLongincremented without synchronization. In a multiplatform context (especially JVM), concurrent calls togenerateId()may produce duplicate IDs due to race conditions.Consider using
AtomicLongon JVM or leveraging platform-specific atomics, or rely solely on the timestamp for uniqueness:- private var idCounter = 0L - fun generateId(): String { - return "task_${++idCounter}_${kotlinx.datetime.Clock.System.now().toEpochMilliseconds()}" + return "task_${kotlinx.datetime.Clock.System.now().toEpochMilliseconds()}_${(0..999999).random()}" }mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/editor/context/FileSearchPopup.kt-94-113 (1)
94-113: Debounce implementation may cause race conditions.Each keystroke launches a new coroutine with a 150ms delay. If the user types faster than 150ms between keystrokes, multiple search requests can execute concurrently and results may arrive out of order, showing stale data.
Consider canceling the previous search job before starting a new one:
+ var searchJob by remember { mutableStateOf<kotlinx.coroutines.Job?>(null) } + // Debounced search function fun performSearch(query: String) { if (query.length < 2 || currentWorkspace == null || indexingState != IndexingState.READY) { searchResults = emptyList() isLoading = false return } isLoading = true + searchJob?.cancel() - scope.launch { + searchJob = scope.launch { delay(150) // Debounce try { searchResults = searchProvider.searchFiles(query) } catch (e: Exception) { searchResults = emptyList() } finally { isLoading = false } } }
| */ | ||
| val currentPlan: StateFlow<AgentPlan?> = _currentPlan.asStateFlow() | ||
|
|
||
| private val listeners = mutableListOf<PlanUpdateListener>() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thread safety issue in listener management.
The listeners list is a regular MutableList that can be modified (addListener/removeListener) while being iterated in notify* methods. This could cause ConcurrentModificationException in multi-threaded scenarios.
- private val listeners = mutableListOf<PlanUpdateListener>()
+ private val listeners = java.util.concurrent.CopyOnWriteArrayList<PlanUpdateListener>()Or use a copy for iteration:
private fun notifyPlanCreated(plan: AgentPlan) {
- listeners.forEach { it.onPlanCreated(plan) }
+ listeners.toList().forEach { it.onPlanCreated(plan) }
}Also applies to: 130-139
| fun updatePlan(tasks: List<PlanTask>) { | ||
| val plan = _currentPlan.value | ||
| if (plan != null) { | ||
| plan.tasks.clear() | ||
| plan.tasks.addAll(tasks) | ||
| notifyPlanUpdated(plan) | ||
| } else { | ||
| createPlan(tasks) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
StateFlow won't emit on direct mutation of plan.tasks.
The updatePlan method directly mutates plan.tasks (via clear() and addAll()), but this doesn't trigger a new StateFlow emission since the reference to plan hasn't changed. Observers won't be notified of the update.
fun updatePlan(tasks: List<PlanTask>) {
val plan = _currentPlan.value
if (plan != null) {
- plan.tasks.clear()
- plan.tasks.addAll(tasks)
- notifyPlanUpdated(plan)
+ val updatedPlan = plan.copy(
+ tasks = tasks.toMutableList(),
+ updatedAt = kotlinx.datetime.Clock.System.now().toEpochMilliseconds()
+ )
+ _currentPlan.value = updatedPlan
+ notifyPlanUpdated(updatedPlan)
} else {
createPlan(tasks)
}
}This ensures the StateFlow emits a new value and observers are properly notified.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/plan/PlanStateService.kt
around lines 62 to 71, the code mutates plan.tasks in place which does not
produce a new StateFlow emission; instead construct a new Plan instance (or a
copy of the existing plan) with the updated tasks list, assign it to
_currentPlan.value, and then call notifyPlanUpdated(newPlan) (or notify with the
newly assigned value) so observers receive the updated Plan reference and
StateFlow emits the change.
| fun updateTaskStatus(taskId: String, status: TaskStatus) { | ||
| val plan = _currentPlan.value ?: return | ||
| val task = plan.getTask(taskId) ?: return | ||
| task.updateStatus(status) | ||
| notifyTaskUpdated(task) | ||
| } | ||
|
|
||
| /** | ||
| * Complete a step within a task. | ||
| */ | ||
| fun completeStep(taskId: String, stepId: String) { | ||
| val plan = _currentPlan.value ?: return | ||
| plan.completeStep(taskId, stepId) | ||
| notifyStepCompleted(taskId, stepId) | ||
| } | ||
|
|
||
| /** | ||
| * Update a step's status. | ||
| */ | ||
| fun updateStepStatus(taskId: String, stepId: String, status: TaskStatus) { | ||
| val plan = _currentPlan.value ?: return | ||
| val task = plan.getTask(taskId) ?: return | ||
| task.updateStepStatus(stepId, status) | ||
| notifyTaskUpdated(task) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mutations in updateTaskStatus, completeStep, and updateStepStatus don't trigger StateFlow emissions.
These methods modify nested task/step state but don't update _currentPlan.value, so observers won't be notified. Apply the same pattern as suggested for updatePlan:
fun completeStep(taskId: String, stepId: String) {
val plan = _currentPlan.value ?: return
plan.completeStep(taskId, stepId)
+ _currentPlan.value = plan.copy(updatedAt = kotlinx.datetime.Clock.System.now().toEpochMilliseconds())
notifyStepCompleted(taskId, stepId)
}
fun updateStepStatus(taskId: String, stepId: String, status: TaskStatus) {
val plan = _currentPlan.value ?: return
val task = plan.getTask(taskId) ?: return
task.updateStepStatus(stepId, status)
+ _currentPlan.value = plan.copy(updatedAt = kotlinx.datetime.Clock.System.now().toEpochMilliseconds())
notifyTaskUpdated(task)
}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/plan/PlanStateService.kt
around lines 93 to 117, the methods updateTaskStatus, completeStep, and
updateStepStatus mutate nested task/step state but do not update
_currentPlan.value so StateFlow observers are not emitted to; after performing
the in-place mutation in each method, reassign _currentPlan.value = plan (or
_currentPlan.value = plan.copy() if Plan is immutable) to force a StateFlow
emission, then proceed to call the existing notification methods.
| import cc.unitmesh.agent.tool.schema.ToolCategory | ||
| import kotlinx.serialization.Serializable | ||
|
|
||
| enum class PlanAction { CREATE, UPDATE, COMPLETE_STEP, FAIL_STEP, VIEW } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UPDATE action defined but not exposed in schema.
The PlanAction enum includes UPDATE, and updatePlan() is implemented (lines 100-114), but the schema on line 43 only lists ["CREATE", "COMPLETE_STEP", "FAIL_STEP", "VIEW"]. The LLM won't be able to use the UPDATE action since it's not in the schema.
Either add UPDATE to the schema or remove the dead code:
"action" to string(description = "Action: CREATE (new plan), COMPLETE_STEP (mark steps done), FAIL_STEP (mark steps failed), VIEW (show plan). Use COMPLETE_STEP to update progress - do NOT resend the full plan markdown to update progress.", required = true,
- enum = listOf("CREATE", "COMPLETE_STEP", "FAIL_STEP", "VIEW")),
+ enum = listOf("CREATE", "UPDATE", "COMPLETE_STEP", "FAIL_STEP", "VIEW")),Or if UPDATE is intentionally hidden, remove it from the enum and updatePlan() method.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/tool/impl/PlanManagementTool.kt
around line 14 (enum) and lines ~43 (schema) and ~100-114 (updatePlan
implementation): the PlanAction enum contains UPDATE but the schema array on
line 43 omits it, making the UPDATE action unusable; fix by either adding
"UPDATE" to the schema array so the enum and schema match, or remove the UPDATE
enum value and delete (or comment out) the updatePlan() method to eliminate dead
code, keeping both enum and schema consistent.
| val TaskStatus.planColor: Color | ||
| get() = when (this) { | ||
| TaskStatus.TODO -> Color(0xFF9E9E9E) | ||
| TaskStatus.IN_PROGRESS -> Color(0xFF2196F3) | ||
| TaskStatus.COMPLETED -> Color(0xFF4CAF50) | ||
| TaskStatus.FAILED -> Color(0xFFF44336) | ||
| TaskStatus.BLOCKED -> Color(0xFFFF9800) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hardcoded colors violate coding guidelines.
The planColor extension uses hardcoded Color(0xFF...) values. As per coding guidelines: "DO NOT hardcode colors... Always use design tokens for consistency across platforms."
Replace with MaterialTheme.colorScheme tokens:
val TaskStatus.planColor: Color
+ @Composable
get() = when (this) {
- TaskStatus.TODO -> Color(0xFF9E9E9E)
- TaskStatus.IN_PROGRESS -> Color(0xFF2196F3)
- TaskStatus.COMPLETED -> Color(0xFF4CAF50)
- TaskStatus.FAILED -> Color(0xFFF44336)
- TaskStatus.BLOCKED -> Color(0xFFFF9800)
+ TaskStatus.TODO -> MaterialTheme.colorScheme.outline
+ TaskStatus.IN_PROGRESS -> MaterialTheme.colorScheme.primary
+ TaskStatus.COMPLETED -> MaterialTheme.colorScheme.tertiary // or a success semantic color
+ TaskStatus.FAILED -> MaterialTheme.colorScheme.error
+ TaskStatus.BLOCKED -> MaterialTheme.colorScheme.secondary // or a warning semantic color
}Note: This will require updating usages to be within @Composable context, which they already are.
| isValid(): boolean { | ||
| const active = this.getActiveConfig(); | ||
| if (!active) return false; | ||
|
|
||
| // Ollama doesn't require API key | ||
| if (active.provider === 'ollama') { | ||
| return !!active.model; | ||
| } | ||
|
|
||
| // Custom OpenAI-compatible providers require baseUrl, apiKey, and model | ||
| if (active.provider === 'custom-openai-base') { | ||
| return !!active.baseUrl && !!active.apiKey && !!active.model; | ||
| } | ||
|
|
||
| return !!active.provider && !!active.apiKey && !!active.model; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# Find the LLMProvider type definition
rg "type LLMProvider|interface LLMProvider|enum LLMProvider" --type ts --type tsxRepository: unit-mesh/auto-dev
Length of output: 89
🏁 Script executed:
# Search for how qwen, kimi, and glm are configured in the codebase
rg "qwen|kimi|glm" -i --type ts --type tsx -A 3 -B 3Repository: unit-mesh/auto-dev
Length of output: 89
🏁 Script executed:
# Check the config-manager.ts file to understand all provider handling
cat -n mpp-vscode/src/services/config-manager.ts | head -150Repository: unit-mesh/auto-dev
Length of output: 135
🏁 Script executed:
# Find the config-manager.ts file
fd "config-manager" --type fRepository: unit-mesh/auto-dev
Length of output: 44
🏁 Script executed:
# Check the repository structure
ls -la | head -20Repository: unit-mesh/auto-dev
Length of output: 1223
🏁 Script executed:
# Search for LLMProvider type with correct flags
rg "type LLMProvider|interface LLMProvider|enum LLMProvider" -t tsRepository: unit-mesh/auto-dev
Length of output: 263
🏁 Script executed:
# Find isValid() method in the codebase
rg "isValid\(\)" -A 20 -B 2Repository: unit-mesh/auto-dev
Length of output: 50374
🏁 Script executed:
# Find all config-manager related files
fd "config-manager|ConfigManager" --type fRepository: unit-mesh/auto-dev
Length of output: 661
🏁 Script executed:
# Check the ConfigManager.ts file for isValid() and provider handling
rg "qwen|kimi|glm" -A 5 -B 5Repository: unit-mesh/auto-dev
Length of output: 50374
🌐 Web query:
Qwen LLM API baseUrl custom endpoint requirements
💡 Result:
Summary of requirements for using a custom/baseUrl with Qwen (OpenAI‑compatible endpoints)
-
Base URL must point at the Qwen-compatible API root (OpenAI-compatible path usually ends with /v1 or /compatible-mode/v1). Example regional base URLs: Singapore (international) https://dashscope-intl.aliyuncs.com/compatible-mode/v1 and Beijing (China) https://dashscope.aliyuncs.com/compatible-mode/v1. [1][2]
-
When using an OpenAI SDK set the SDK’s api_base/api_base_url to that base URL so the SDK will call e.g. {BASE_URL}/chat/completions. For raw HTTP calls use the full endpoint (POST {BASE_URL}/chat/completions). [1][2]
-
Authentication: include the Qwen API key (usually sk-... style) in the Authorization header (Bearer) / SDK api_key; keys are region‑tied so use the matching base URL for your key. [2][3]
-
Model parameter: supply the Qwen model name in the model field (e.g., "qwen-plus", "qwen-turbo" or Qwen3 model ids). Some client integrations expect a model_server or api_base config field for custom servers. [0][4]
-
If using a third‑party/custom server that implements an OpenAI‑compatible interface (vLLM, SGLang, etc.), ensure it exposes the same request/response shapes (chat/completions or chat responses) and the /v1 path; some tooling (Qwen-Agent, liteLLM, etc.) expects model_server/model name conventions (e.g., set api_base/model_server and sometimes prefix model with "custom/"). Validate your custom endpoint returns OpenAI‑compatible JSON fields (id, model, choices, usage) or the adapter will fail. [0][3][4]
Sources
- Alibaba Cloud Model Studio — Qwen OpenAI‑compatible usage and base URLs. [1]
- Alibaba Cloud Model Studio — Qwen API details (regional base_url and endpoints). [2]
- Qwen / Qwen‑Agent examples (custom model_server / api_base usage). [0]
- liteLLM custom-provider docs (example expectations when using custom OpenAI‑compatible endpoints). [3]
If you want, tell me which SDK or client you plan to use (OpenAI SDK, Qwen Agent, liteLLM, or a custom server) and I’ll give exact example code and any adapter settings.
🌐 Web query:
Kimi LLM API baseUrl configuration requirements
💡 Result:
Short checklist for configuring Kimi (Moonshot) LLM API baseUrl
- Use the Kimi/Moonshot API base endpoint (recommended): https://api.moonshot.ai/v1 or https://api.moonshot.cn/v1 (service-specific). [1][6]
- Must be an HTTPS URL with a valid TLS certificate (same format as OpenAI-compatible endpoints). [1][2]
- Point your client’s “base_url” / “baseURL” / “api_base” config to that URL (include the /v1 path if your client expects it). Examples: client.base_url="https://api.moonshot.ai/v1". [1][2][3]
- Keep OpenAI-compatible request paths (e.g., /chat/completions) — most OpenAI SDKs work by only changing baseUrl + API key. [1][3]
- Supply API key via Authorization: Bearer or provider-specific config (env var like MOONSHOT_API_KEY) per SDK. [3][2]
- If calling from a browser, ensure the endpoint supports CORS or route through a backend proxy. [4]
- If using an SDK option name, check package-specific field: base_url / baseURL / api_base / WithBaseURL etc. (names vary by client). [2][3][5]
Sources: Kimi API docs and examples, plus community SDK docs. [1][2][3][4][5]
🏁 Script executed:
# View the actual isValid() implementation in ConfigManager.ts
cat -n mpp-ui/src/jsMain/typescript/config/ConfigManager.ts | sed -n '90,110p'Repository: unit-mesh/auto-dev
Length of output: 927
🏁 Script executed:
# Search for isValid() method in ConfigManager.ts
grep -n "isValid" mpp-ui/src/jsMain/typescript/config/ConfigManager.tsRepository: unit-mesh/auto-dev
Length of output: 88
🏁 Script executed:
# View the isValid() method
cat -n mpp-ui/src/jsMain/typescript/config/ConfigManager.ts | sed -n '279,300p'Repository: unit-mesh/auto-dev
Length of output: 839
🏁 Script executed:
# Verify the provider configs one more time for clarity
rg "glm|qwen|kimi" mpp-ui/src/jsMain/typescript/ui/ModelConfigForm.tsx -A 1 -B 1 | head -20Repository: unit-mesh/auto-dev
Length of output: 1005
Add baseUrl validation for glm, qwen, and kimi providers.
The isValid() method only enforces baseUrl validation for custom-openai-base, but glm, qwen, and kimi are OpenAI-compatible providers that also require baseUrl configuration (as confirmed by ModelConfigForm.tsx and config.yaml.example). These providers should have the same validation logic as custom-openai-base to prevent invalid configurations from passing validation.
🤖 Prompt for AI Agents
In mpp-vscode/src/services/config-manager.ts around lines 90 to 105, the
isValid() method currently only requires baseUrl for 'custom-openai-base' but
must also require baseUrl for the 'glm', 'qwen', and 'kimi' providers; update
the validation so that for providers 'custom-openai-base', 'glm', 'qwen', and
'kimi' you check that active.baseUrl, active.apiKey, and active.model are all
truthy, and keep the existing special-case for 'ollama' (only model required)
and the fallback for other providers unchanged.
| const rightDoc = await vscode.workspace.openTextDocument(rightDocUri); | ||
| const modifiedContent = rightDoc.getText(); | ||
|
|
||
| // Write the content to the original file | ||
| const fileUri = vscode.Uri.file(diffInfo.originalFilePath); | ||
| await vscode.workspace.fs.writeFile(fileUri, Buffer.from(modifiedContent, 'utf8')); | ||
|
|
||
| await this.closeDiffEditor(rightDocUri); | ||
|
|
||
| this.onDidChangeEmitter.fire({ | ||
| type: 'accepted', | ||
| filePath: diffInfo.originalFilePath, | ||
| content: modifiedContent | ||
| }); | ||
|
|
||
| this.log(`Accepted diff for: ${diffInfo.originalFilePath}`); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing error handling for file write operation.
The acceptDiff method writes to the file system (line 145) without try-catch. If the write fails (permissions, disk full, etc.), the error propagates unhandled, and the diff state becomes inconsistent—the editor is closed but the file isn't updated.
async acceptDiff(rightDocUri: vscode.Uri): Promise<void> {
const diffInfo = this.diffDocuments.get(rightDocUri.toString());
if (!diffInfo) {
return;
}
const rightDoc = await vscode.workspace.openTextDocument(rightDocUri);
const modifiedContent = rightDoc.getText();
// Write the content to the original file
const fileUri = vscode.Uri.file(diffInfo.originalFilePath);
+ try {
await vscode.workspace.fs.writeFile(fileUri, Buffer.from(modifiedContent, 'utf8'));
+ } catch (error) {
+ this.log(`Failed to write diff for ${diffInfo.originalFilePath}: ${error}`);
+ throw error; // Re-throw to let caller handle
+ }
await this.closeDiffEditor(rightDocUri);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const rightDoc = await vscode.workspace.openTextDocument(rightDocUri); | |
| const modifiedContent = rightDoc.getText(); | |
| // Write the content to the original file | |
| const fileUri = vscode.Uri.file(diffInfo.originalFilePath); | |
| await vscode.workspace.fs.writeFile(fileUri, Buffer.from(modifiedContent, 'utf8')); | |
| await this.closeDiffEditor(rightDocUri); | |
| this.onDidChangeEmitter.fire({ | |
| type: 'accepted', | |
| filePath: diffInfo.originalFilePath, | |
| content: modifiedContent | |
| }); | |
| this.log(`Accepted diff for: ${diffInfo.originalFilePath}`); | |
| } | |
| const rightDoc = await vscode.workspace.openTextDocument(rightDocUri); | |
| const modifiedContent = rightDoc.getText(); | |
| // Write the content to the original file | |
| const fileUri = vscode.Uri.file(diffInfo.originalFilePath); | |
| try { | |
| await vscode.workspace.fs.writeFile(fileUri, Buffer.from(modifiedContent, 'utf8')); | |
| } catch (error) { | |
| this.log(`Failed to write diff for ${diffInfo.originalFilePath}: ${error}`); | |
| throw error; // Re-throw to let caller handle | |
| } | |
| await this.closeDiffEditor(rightDocUri); | |
| this.onDidChangeEmitter.fire({ | |
| type: 'accepted', | |
| filePath: diffInfo.originalFilePath, | |
| content: modifiedContent | |
| }); | |
| this.log(`Accepted diff for: ${diffInfo.originalFilePath}`); | |
| } |
🤖 Prompt for AI Agents
In mpp-vscode/src/services/diff-manager.ts around lines 140 to 156, the code
writes modifiedContent to disk without error handling which can leave the editor
closed while the file wasn't updated; wrap the writeFile (and subsequent
close/editor state changes and event firing) in a try/catch so the sequence is:
attempt vscode.workspace.fs.writeFile(fileUri,
Buffer.from(modifiedContent,'utf8')) inside try, only on success call
closeDiffEditor, fire onDidChangeEmitter and log; in catch log the error, show a
user-facing message (vscode.window.showErrorMessage) explaining the save failed,
and avoid closing or mark the diff as unaccepted so state remains consistent;
ensure the catch rethrows or returns appropriately so callers can handle
failures if needed.
| app.post('/file/read', async (req: Request, res: Response) => { | ||
| try { | ||
| const { filePath } = req.body; | ||
| if (!filePath) { | ||
| return res.status(400).json({ error: 'filePath is required' }); | ||
| } | ||
|
|
||
| const uri = vscode.Uri.file(filePath); | ||
| const content = await vscode.workspace.fs.readFile(uri); | ||
| res.json({ success: true, content: Buffer.from(content).toString('utf8') }); | ||
| } catch (error) { | ||
| const message = error instanceof Error ? error.message : String(error); | ||
| res.status(500).json({ error: message }); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Path traversal vulnerability in file read endpoint.
The /file/read endpoint accepts arbitrary filePath without validation, allowing potential access to files outside the workspace (e.g., /etc/passwd, ~/.ssh/). Even with auth token protection, this is a security risk if the token is compromised.
Apply this diff to validate paths are within workspace bounds:
app.post('/file/read', async (req: Request, res: Response) => {
try {
const { filePath } = req.body;
if (!filePath) {
return res.status(400).json({ error: 'filePath is required' });
}
+
+ // Validate path is within workspace
+ const workspaceFolders = vscode.workspace.workspaceFolders;
+ if (!workspaceFolders?.some(f => filePath.startsWith(f.uri.fsPath))) {
+ return res.status(403).json({ error: 'Path outside workspace' });
+ }
const uri = vscode.Uri.file(filePath);
const content = await vscode.workspace.fs.readFile(uri);🤖 Prompt for AI Agents
In mpp-vscode/src/services/ide-server.ts around lines 139–153, the endpoint
reads an arbitrary filePath which allows path traversal; validate that the
requested file is inside one of the opened workspace folders before reading. Fix
by: obtain workspace folder root(s) (vscode.workspace.workspaceFolders), use
Node's path.resolve/normalize against each workspace folder path to compute the
absolute target path, then compare the resolved target to the resolved workspace
root(s) using a startsWith check (or path.relative and ensure it does not start
with '..'); additionally resolve symlinks (fs.promises.realpath) for both root
and target to prevent symlink escape, and return 400/403 if the file is outside
workspace or workspaceFolders is undefined; only then call vscode.Uri.file and
vscode.workspace.fs.readFile.
| // Write file endpoint | ||
| app.post('/file/write', async (req: Request, res: Response) => { | ||
| try { | ||
| const { filePath, content } = req.body; | ||
| if (!filePath || content === undefined) { | ||
| return res.status(400).json({ error: 'filePath and content are required' }); | ||
| } | ||
|
|
||
| const uri = vscode.Uri.file(filePath); | ||
| await vscode.workspace.fs.writeFile(uri, Buffer.from(content, 'utf8')); | ||
| res.json({ success: true }); | ||
| } catch (error) { | ||
| const message = error instanceof Error ? error.message : String(error); | ||
| res.status(500).json({ error: message }); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Path traversal vulnerability in file write endpoint.
Same issue as /file/read — arbitrary file paths allow writing outside the workspace, which is more dangerous as it enables arbitrary file modification.
Apply this diff to validate paths:
app.post('/file/write', async (req: Request, res: Response) => {
try {
const { filePath, content } = req.body;
if (!filePath || content === undefined) {
return res.status(400).json({ error: 'filePath and content are required' });
}
+
+ // Validate path is within workspace
+ const workspaceFolders = vscode.workspace.workspaceFolders;
+ if (!workspaceFolders?.some(f => filePath.startsWith(f.uri.fsPath))) {
+ return res.status(403).json({ error: 'Path outside workspace' });
+ }
const uri = vscode.Uri.file(filePath);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Write file endpoint | |
| app.post('/file/write', async (req: Request, res: Response) => { | |
| try { | |
| const { filePath, content } = req.body; | |
| if (!filePath || content === undefined) { | |
| return res.status(400).json({ error: 'filePath and content are required' }); | |
| } | |
| const uri = vscode.Uri.file(filePath); | |
| await vscode.workspace.fs.writeFile(uri, Buffer.from(content, 'utf8')); | |
| res.json({ success: true }); | |
| } catch (error) { | |
| const message = error instanceof Error ? error.message : String(error); | |
| res.status(500).json({ error: message }); | |
| } | |
| }); | |
| // Write file endpoint | |
| app.post('/file/write', async (req: Request, res: Response) => { | |
| try { | |
| const { filePath, content } = req.body; | |
| if (!filePath || content === undefined) { | |
| return res.status(400).json({ error: 'filePath and content are required' }); | |
| } | |
| // Validate path is within workspace | |
| const workspaceFolders = vscode.workspace.workspaceFolders; | |
| if (!workspaceFolders?.some(f => filePath.startsWith(f.uri.fsPath))) { | |
| return res.status(403).json({ error: 'Path outside workspace' }); | |
| } | |
| const uri = vscode.Uri.file(filePath); | |
| await vscode.workspace.fs.writeFile(uri, Buffer.from(content, 'utf8')); | |
| res.json({ success: true }); | |
| } catch (error) { | |
| const message = error instanceof Error ? error.message : String(error); | |
| res.status(500).json({ error: message }); | |
| } | |
| }); |
| "dependencies": { | ||
| "react": "^18.2.0", | ||
| "react-dom": "^18.2.0", | ||
| "react-markdown": "^9.0.1", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
react-markdown 9.0.1 stability compatibility 2025
💡 Result:
Short answer: react-markdown@9.0.1 (published Nov 13, 2023) is a stable release but is older and may lack compatibility with newer ecosystems in 2025 (notably React 19 typings and newer major release features). (releasealert.dev)
Details:
- Release & stability: 9.0.1 is tagged stable (Nov 13, 2023). (releasealert.dev)
- Node / bundlers: v9 is ESM-only and intended to work on maintained Node.js versions (Node 16+ recommended). (npmjs.com)
- React 19 / types: upstream issue tracking React 19 compatibility (JSX global / @types/react changes) — react-markdown has active discussion and later 10.x releases add more modern compatibility. If you target React 19, prefer v10 (or check that typings are patched). (github.com)
- Security/health: No direct vulnerabilities reported for 9.0.1 in Snyk; nevertheless, using the latest maintained release is recommended for fixes and compatibility. (security.snyk.io)
Recommendation: For new projects in 2025 use the latest 10.x release (or at least test 9.0.1 against your React/TypeScript toolchain). If you must stay on 9.0.1, verify TypeScript/@types/react compatibility (React 19 issues) and Node/ESM build pipelines. (github.com)
Citations:
- 1: https://releasealert.dev/npm/_/react-markdown?utm_source=openai
- 2: https://releasealert.dev/npm/_/react-markdown?utm_source=openai
- 3: https://www.npmjs.com/package/react-markdown/v/9.0.1?utm_source=openai
- 4: React 19 support remarkjs/react-markdown#877
- 5: https://security.snyk.io/package/npm/react-markdown/9.0.1?utm_source=openai
- 6: React 19 support remarkjs/react-markdown#877
🌐 Web query:
react-markdown remark-gfm compatibility issues 2024 2025
💡 Result:
Summary of known compatibility issues (2024–2025) and how to handle them:
-
remark-gfm v4 (released 2023) introduced breaking changes (ESM-only and AST changes) that caused table rendering errors and incompatibility with older react-markdown setups; many users reverted to remark-gfm@3.x or adjusted rehype/remark options. [1][2][3]
-
remark-gfm is ESM-only (requires Node 16+); that change can break toolchains or CommonJS projects and plugins expecting CJS. Align your bundler/node target or use older remark-gfm if you must stay CJS. [6][2]
-
react-markdown’s types and peer-deps have tripped users upgrading to React 18.3+/React 19 because @types/react/@jsx typing changes removed global JSX; react-markdown maintainers tracked React 19 support in issues (type/defaultProps/peerDep friction). Expect to need updated react-markdown releases or adjusted TS config/@types. [1][4]
-
Many concrete breakages arise from mismatched major versions across react-markdown, remark-gfm, remark-rehype/rehype-raw, and rehype plugins. The usual fix: align compatible majors (either downgrade remark-gfm to 3.x for older react-markdown, or upgrade react-markdown and all remark/rehype plugins to ESM-compatible/latest). Examples and discussion on Stack Overflow and community threads. [2][3]
-
Practical checklist:
- Check react-markdown and remark-gfm release notes and peerDependencies for your project’s React and Node versions. [4][6]
- If seeing table/“inTable” errors, try remark-gfm@3.0.1 with react-markdown v8, or upgrade react-markdown + plugins to versions that explicitly support remark-gfm v4/ESM. [2][3]
- Ensure your build (Next/webpack/rollup) supports ESM dependencies, or keep plugin versions that remain CJS-compatible. [6][2]
Sources:
[1] react-markdown GitHub issue — React 19 support.
[2] Stack Overflow thread on react-markdown + remark-gfm (table errors).
[3] Blog post: “remark-gfm v4.0.0 appears to break table-rendering.”
[4] react-markdown GitHub repo (project/compatibility notes).
[6] remark-gfm GitHub README (ESM-only / install notes).
Consider upgrading to react-markdown 10.x for better long-term compatibility.
You're using react-markdown@9.0.1 (Nov 2023) paired with remark-gfm@4.0.0. While 9.0.1 is stable, it's becoming outdated for new projects. remark-gfm v4 introduced breaking changes and has known table rendering issues with certain react-markdown configurations. For a new webview project in 2025, upgrading to react-markdown 10.x (the latest maintained release) provides better ESM compatibility, fixes, and forward compatibility. If you must stay on 9.0.1, test the markdown rendering thoroughly—particularly tables and complex formatting—to ensure remark-gfm 4.0.0 works as expected in your specific use case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (4)
mpp-vscode/src/providers/chat-view.ts (2)
32-54: Resource leak:editorChangeDisposableis never disposed.The
editorChangeDisposablecreated at line 49 is never cleaned up, causing a memory leak. When the webview is disposed, this listener remains active.Apply this diff to dispose the listener when the webview is disposed:
async resolveWebviewView( webviewView: vscode.WebviewView, _context: vscode.WebviewViewResolveContext, _token: vscode.CancellationToken ): Promise<void> { this.webviewView = webviewView; webviewView.webview.options = { enableScripts: true, localResourceRoots: [ vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'webview') ] }; webviewView.webview.html = this.getHtmlContent(webviewView.webview); + + // Dispose editor change listener when webview is disposed + webviewView.onDidDispose(() => { + this.editorChangeDisposable?.dispose(); + });
776-790: Security risk: Absolute paths allow reading files outside workspace.The code accepts absolute paths and converts them to
vscode.Uriwithout validating they're within the workspace. This allows the webview to read arbitrary files on the system.Apply this diff to restrict file access to workspace paths:
try { // Convert relative path to absolute if needed let uri: vscode.Uri; if (filePath.startsWith('/') || filePath.match(/^[a-zA-Z]:\\/)) { - // Already absolute path - uri = vscode.Uri.file(filePath); + // Absolute path - validate it's within workspace + const workspaceFolder = vscode.workspace.workspaceFolders?.[0]; + if (!workspaceFolder) { + this.postMessage({ type: 'fileContentResult', data: { content: null, error: 'No workspace folder' } }); + return; + } + uri = vscode.Uri.file(filePath); + // Ensure the path is within the workspace + const normalizedUri = uri.fsPath.toLowerCase(); + const normalizedWorkspace = workspaceFolder.uri.fsPath.toLowerCase(); + if (!normalizedUri.startsWith(normalizedWorkspace)) { + this.postMessage({ type: 'fileContentResult', data: { content: null, error: 'Path outside workspace' } }); + return; + } } else {mpp-vscode/src/bridge/mpp-core.ts (2)
25-33: Incomplete provider type mappings.The
ProviderTypesmapping is missing entries for'glm','qwen', and'kimi'which are supported in the Kotlin layer but not mapped here. This will cause errors when users try to use these providers.Apply this diff to add the missing mappings:
export const ProviderTypes: Record<string, string> = { 'openai': 'OPENAI', 'anthropic': 'ANTHROPIC', 'google': 'GOOGLE', 'deepseek': 'DEEPSEEK', 'ollama': 'OLLAMA', 'openrouter': 'OPENROUTER', - 'custom-openai-base': 'CUSTOM_OPENAI_BASE' + 'custom-openai-base': 'CUSTOM_OPENAI_BASE', + 'glm': 'GLM', + 'qwen': 'QWEN', + 'kimi': 'KIMI' };
92-107: Error in callback won't reject the Promise.The error callback at line 100 throws an error, but this executes asynchronously inside the Kotlin callback and won't propagate to the caller. The Promise will resolve successfully even when an error occurs.
Apply this diff to properly capture and propagate errors:
async streamMessage( message: string, onChunk: (chunk: string) => void ): Promise<string> { this.chatHistory.push({ role: 'user', content: message }); const historyMessages = this.chatHistory.slice(0, -1).map(msg => new JsMessage(msg.role, msg.content) ); let fullResponse = ''; + let streamError: Error | null = null; await this.koogService.streamPrompt( message, historyMessages, (chunk: string) => { fullResponse += chunk; onChunk(chunk); }, (error: any) => { - throw new Error(`LLM Error: ${error.message || error}`); + streamError = new Error(`LLM Error: ${error.message || error}`); }, () => { /* complete */ } ); + if (streamError) { + throw streamError; + } + this.chatHistory.push({ role: 'assistant', content: fullResponse }); return fullResponse; }
🧹 Nitpick comments (1)
mpp-vscode/src/providers/chat-view.ts (1)
69-71: Extract binary extensions to a constant to avoid duplication.The binary extensions array is duplicated at lines 69 and 679. Extract this to a class-level constant for maintainability.
Apply this diff:
export class ChatViewProvider implements vscode.WebviewViewProvider { + private static readonly BINARY_EXTENSIONS = [ + 'jar', 'class', 'exe', 'dll', 'so', 'dylib', + 'png', 'jpg', 'jpeg', 'gif', 'ico', 'pdf', + 'zip', 'tar', 'gz', 'rar', '7z' + ]; + private webviewView: vscode.WebviewView | undefined;Then use
ChatViewProvider.BINARY_EXTENSIONSat both locations.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
mpp-vscode/src/bridge/mpp-core.ts(1 hunks)mpp-vscode/src/providers/chat-view.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{kt,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-vscode/src/bridge/mpp-core.tsmpp-vscode/src/providers/chat-view.ts
🧠 Learnings (2)
📚 Learning: 2025-12-01T15:41:32.195Z
Learnt from: CR
Repo: unit-mesh/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-01T15:41:32.195Z
Learning: Applies to mpp-ui/src/jsMain/typescript/**/*.ts : In CLI/TUI (TypeScript): Use `mpp-ui/src/jsMain/typescript/design-system/` and import `semanticInk` / `semanticChalk`
Applied to files:
mpp-vscode/src/bridge/mpp-core.ts
📚 Learning: 2025-12-01T15:41:32.195Z
Learnt from: CR
Repo: unit-mesh/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-01T15:41:32.195Z
Learning: Applies to **/*.kt : In Kotlin/JS JsExport: Avoid `Flow`, use `Promise` instead
Applied to files:
mpp-vscode/src/bridge/mpp-core.ts
🧬 Code graph analysis (1)
mpp-vscode/src/providers/chat-view.ts (1)
mpp-vscode/src/services/config-manager.ts (3)
AutoDevConfigWrapper(56-106)ConfigManager(111-176)LLMConfig(18-26)
🪛 Biome (2.1.2)
mpp-vscode/src/providers/chat-view.ts
[error] 520-521: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
⏰ 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). (3)
- GitHub Check: Test mpp-core (KMP)
- GitHub Check: Build (223)
- GitHub Check: Build (241)
| case 'insert': | ||
| // Insert code at cursor | ||
| const editor = vscode.window.activeTextEditor; | ||
| if (editor && data.code) { | ||
| await editor.edit(editBuilder => { | ||
| editBuilder.insert(editor.selection.active, data.code); | ||
| }); | ||
| } | ||
| break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix variable scoping in switch statement.
The variable editor at line 520 can be accessed by other switch cases, which Biome flags as an error. Wrap the case in a block.
Apply this diff:
switch (action) {
- case 'insert':
+ case 'insert': {
// Insert code at cursor
const editor = vscode.window.activeTextEditor;
if (editor && data.code) {
await editor.edit(editBuilder => {
editBuilder.insert(editor.selection.active, data.code);
});
}
break;
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| case 'insert': | |
| // Insert code at cursor | |
| const editor = vscode.window.activeTextEditor; | |
| if (editor && data.code) { | |
| await editor.edit(editBuilder => { | |
| editBuilder.insert(editor.selection.active, data.code); | |
| }); | |
| } | |
| break; | |
| case 'insert': { | |
| // Insert code at cursor | |
| const editor = vscode.window.activeTextEditor; | |
| if (editor && data.code) { | |
| await editor.edit(editBuilder => { | |
| editBuilder.insert(editor.selection.active, data.code); | |
| }); | |
| } | |
| break; | |
| } |
🧰 Tools
🪛 Biome (2.1.2)
[error] 520-521: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
🤖 Prompt for AI Agents
In mpp-vscode/src/providers/chat-view.ts around lines 518 to 526, the variable
`editor` declared in the 'insert' switch case has function-level scope and is
visible to other cases; wrap the case body in its own block by adding an opening
brace immediately after `case 'insert':` and a closing brace just before
`break;`, then move the `const editor = ...` and the `if (editor && data.code) {
... }` logic inside that block (preserve the await editor.edit call and the
break); adjust indentation accordingly so `editor` is scoped to the block only.
Summary by CodeRabbit
New Features
Tests
✏️ Tip: You can customize this high-level summary in your review settings.