Skip to content

Commit bce4dfc

Browse files
committed
fix: address PR #40 review comments
- Add error handling for plan markdown parsing in JewelRenderer - Restore OutputDisplay in IdeaTerminalRenderer (was commented out) - Fix root-level files edge case in IdeaFileChangeItem - Cancel planStateObserverJob in IdeaAgentViewModel.dispose() - Add dispose() method to ChatViewProvider for cleanup - Add type guard validation for PlanData in App.tsx - Replace println with Logger in IdeaFileChangeSummary - Simplify StateFlow update in PlanStateService (use direct reassignment)
1 parent 2a5de66 commit bce4dfc

File tree

8 files changed

+56
-20
lines changed

8 files changed

+56
-20
lines changed

mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/plan/PlanStateService.kt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -94,31 +94,31 @@ class PlanStateService {
9494
val plan = _currentPlan.value ?: return
9595
val task = plan.getTask(taskId) ?: return
9696
task.updateStatus(status)
97-
// Trigger StateFlow update by creating a new plan instance with updated timestamp
98-
_currentPlan.value = plan.copy(updatedAt = kotlinx.datetime.Clock.System.now().toEpochMilliseconds())
97+
// Trigger StateFlow update by reassigning the plan object
98+
_currentPlan.value = plan
9999
notifyTaskUpdated(task)
100100
}
101-
101+
102102
/**
103103
* Complete a step within a task.
104104
*/
105105
fun completeStep(taskId: String, stepId: String) {
106106
val plan = _currentPlan.value ?: return
107107
plan.completeStep(taskId, stepId)
108-
// Trigger StateFlow update by creating a new plan instance with updated timestamp
109-
_currentPlan.value = plan.copy(updatedAt = kotlinx.datetime.Clock.System.now().toEpochMilliseconds())
108+
// Trigger StateFlow update by reassigning the plan object
109+
_currentPlan.value = plan
110110
notifyStepCompleted(taskId, stepId)
111111
}
112-
112+
113113
/**
114114
* Update a step's status.
115115
*/
116116
fun updateStepStatus(taskId: String, stepId: String, status: TaskStatus) {
117117
val plan = _currentPlan.value ?: return
118118
val task = plan.getTask(taskId) ?: return
119119
task.updateStepStatus(stepId, status)
120-
// Trigger StateFlow update by creating a new plan instance with updated timestamp
121-
_currentPlan.value = plan.copy(updatedAt = kotlinx.datetime.Clock.System.now().toEpochMilliseconds())
120+
// Trigger StateFlow update by reassigning the plan object
121+
_currentPlan.value = plan
122122
notifyTaskUpdated(task)
123123
}
124124

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/renderer/JewelRenderer.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,14 @@ class JewelRenderer : BaseRenderer() {
323323
when (action) {
324324
"CREATE", "UPDATE" -> {
325325
if (planMarkdown.isNotBlank()) {
326-
val plan = MarkdownPlanParser.parseToPlan(planMarkdown)
327-
jewelRendererLogger.info("Parsed plan: ${plan.tasks.size} tasks")
328-
_currentPlan.value = plan
326+
try {
327+
val plan = MarkdownPlanParser.parseToPlan(planMarkdown)
328+
jewelRendererLogger.info("Parsed plan: ${plan.tasks.size} tasks")
329+
_currentPlan.value = plan
330+
} catch (e: Exception) {
331+
jewelRendererLogger.warn("Failed to parse plan markdown", e)
332+
// Keep previous valid plan on parse failure
333+
}
329334
}
330335
}
331336
"COMPLETE_STEP" -> {

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/renderer/sketch/IdeaTerminalRenderer.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ fun IdeaTerminalRenderer(
7777
// Command display
7878
CommandDisplay(command = command, isDangerous = isDangerous, dangerReason = dangerReason)
7979
// Output (if available)
80-
// if (showOutput && executionResult != null) {
81-
// OutputDisplay(result = executionResult!!)
82-
// }
80+
if (showOutput && executionResult != null) {
81+
OutputDisplay(result = executionResult!!)
82+
}
8383
}
8484
}
8585

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentViewModel.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,7 @@ class IdeaAgentViewModel(
576576

577577
override fun dispose() {
578578
currentJob?.cancel()
579+
planStateObserverJob?.cancel()
579580
coroutineScope.cancel()
580581
}
581582
}

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/changes/IdeaFileChangeItem.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ fun IdeaFileChangeItem(
8989
)
9090

9191
// Parent path
92-
val parentPath = change.filePath.substringBeforeLast('/')
93-
if (parentPath.isNotEmpty()) {
92+
val parentPath = change.filePath.substringBeforeLast('/', "")
93+
if (parentPath.isNotEmpty() && parentPath != change.filePath) {
9494
Text(
9595
text = parentPath.substringAfterLast('/'),
9696
style = JewelTheme.defaultTextStyle.copy(

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/changes/IdeaFileChangeSummary.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import cc.unitmesh.agent.diff.FileChangeTracker
2323
import cc.unitmesh.devins.ui.compose.theme.AutoDevColors
2424
import com.intellij.openapi.application.ApplicationManager
2525
import com.intellij.openapi.application.runWriteAction
26+
import com.intellij.openapi.diagnostic.Logger
2627
import com.intellij.openapi.fileEditor.FileDocumentManager
2728
import com.intellij.openapi.project.Project
2829
import com.intellij.openapi.vfs.LocalFileSystem
@@ -32,6 +33,8 @@ import org.jetbrains.jewel.ui.component.IconButton
3233
import org.jetbrains.jewel.ui.component.Text
3334
import org.jetbrains.jewel.ui.icons.AllIconsKeys
3435

36+
private val logger = Logger.getInstance("IdeaFileChangeSummary")
37+
3538
/**
3639
* File Change Summary Component for IntelliJ IDEA using Jewel components.
3740
*
@@ -254,7 +257,7 @@ private fun undoChange(project: Project, change: FileChange) {
254257
}
255258
}
256259
} catch (e: Exception) {
257-
println("Failed to undo change for ${change.filePath}: ${e.message}")
260+
logger.error("Failed to undo change for ${change.filePath}", e)
258261
}
259262
}
260263
}

mpp-vscode/src/providers/chat-view.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const KotlinCC = MppCore.cc.unitmesh;
2121
/**
2222
* Chat View Provider for the sidebar webview
2323
*/
24-
export class ChatViewProvider implements vscode.WebviewViewProvider {
24+
export class ChatViewProvider implements vscode.WebviewViewProvider, vscode.Disposable {
2525
private webviewView: vscode.WebviewView | undefined;
2626
private codingAgent: any = null;
2727
private llmService: any = null;
@@ -32,6 +32,17 @@ export class ChatViewProvider implements vscode.WebviewViewProvider {
3232
private editorChangeDisposable: vscode.Disposable | undefined;
3333
private planStateUnsubscribe: (() => void) | null = null;
3434

35+
/**
36+
* Dispose of resources when the provider is no longer needed.
37+
*/
38+
dispose(): void {
39+
if (this.planStateUnsubscribe) {
40+
this.planStateUnsubscribe();
41+
this.planStateUnsubscribe = null;
42+
}
43+
this.editorChangeDisposable?.dispose();
44+
}
45+
3546
constructor(
3647
private readonly context: vscode.ExtensionContext,
3748
private readonly log: (message: string) => void

mpp-vscode/webview/src/App.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,22 @@ import { useVSCode, ExtensionMessage } from './hooks/useVSCode';
1616
import type { AgentState, ToolCallInfo, TerminalOutput, ToolCallTimelineItem } from './types/timeline';
1717
import './App.css';
1818

19+
/**
20+
* Type guard to validate PlanData structure from extension messages.
21+
*/
22+
function isPlanData(data: unknown): data is PlanData {
23+
if (!data || typeof data !== 'object') return false;
24+
const plan = data as Record<string, unknown>;
25+
return (
26+
typeof plan.planId === 'string' &&
27+
typeof plan.title === 'string' &&
28+
typeof plan.totalSteps === 'number' &&
29+
typeof plan.completedSteps === 'number' &&
30+
typeof plan.progressPercent === 'number' &&
31+
Array.isArray(plan.tasks)
32+
);
33+
}
34+
1935
interface ConfigState {
2036
availableConfigs: ModelConfig[];
2137
currentConfigName: string | null;
@@ -260,8 +276,8 @@ const App: React.FC = () => {
260276

261277
// Plan update from mpp-core PlanStateService
262278
case 'planUpdate':
263-
if (msg.data) {
264-
setCurrentPlan(msg.data as unknown as PlanData);
279+
if (msg.data && isPlanData(msg.data)) {
280+
setCurrentPlan(msg.data);
265281
} else {
266282
setCurrentPlan(null);
267283
}

0 commit comments

Comments
 (0)