diff --git a/src/core/tools/attemptCompletionTool.ts b/src/core/tools/attemptCompletionTool.ts index 5074d7f4e8..8df9cc6fc8 100644 --- a/src/core/tools/attemptCompletionTool.ts +++ b/src/core/tools/attemptCompletionTool.ts @@ -95,7 +95,9 @@ export async function attemptCompletionTool( TelemetryService.instance.captureTaskCompleted(cline.taskId) cline.emit(RooCodeEventName.TaskCompleted, cline.taskId, cline.getTokenUsage(), cline.toolUsage) - if (cline.parentTask) { + // Check both parentTask (direct reference) and parentTaskId (persisted ID) + // This handles cases where VSCode was closed and the direct reference was lost + if (cline.parentTask || cline.parentTaskId) { const didApprove = await askFinishSubTaskApproval() if (!didApprove) { diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 91b8687966..b259da0e0c 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -482,12 +482,37 @@ export class ClineProvider // This is used when a subtask is finished and the parent task needs to be // resumed. async finishSubTask(lastMessage: string) { + // Get the current task before removing it from the stack + const currentTask = this.getCurrentTask() + const parentTaskId = currentTask?.parentTaskId + // Remove the last cline instance from the stack (this is the finished // subtask). await this.removeClineFromStack() - // Resume the last cline instance in the stack (if it exists - this is - // the 'parent' calling task). - await this.getCurrentTask()?.completeSubtask(lastMessage) + + // Check if there's a parent task in the stack + let parentTask = this.getCurrentTask() + + // If no parent task in stack but we have a parentTaskId, + // we need to restore the parent task (happens when VSCode was closed) + if (!parentTask && parentTaskId) { + try { + // Restore the parent task from history + const { historyItem } = await this.getTaskWithId(parentTaskId) + parentTask = await this.createTaskWithHistoryItem(historyItem) + this.log(`[finishSubTask] Restored parent task ${parentTaskId} from history to receive subtask result`) + } catch (error) { + this.log( + `[finishSubTask] Failed to restore parent task ${parentTaskId}: ${error instanceof Error ? error.message : String(error)}`, + ) + // Even if parent restoration fails, we should still show completion + // The user can manually resume the parent from task history + return + } + } + + // Resume the parent task with the subtask result + await parentTask?.completeSubtask(lastMessage) } // Pending Edit Operations Management