Skip to content

fix(task-lifecycle): preserve parent-child link when delegated subtask is interrupted (#560)#787

Merged
navedmerchant merged 7 commits into
mainfrom
issue/560
Jul 6, 2026
Merged

fix(task-lifecycle): preserve parent-child link when delegated subtask is interrupted (#560)#787
navedmerchant merged 7 commits into
mainfrom
issue/560

Conversation

@edelauna

@edelauna edelauna commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Related GitHub Issue

Closes: #560

Description

When a delegated subtask was cancelled mid-execution, cancelTask() immediately severed the parent–child link — parent transitioned from "delegated""active" with awaitingChildId cleared. When the user resumed the child and it called attempt_completion, the parent no longer awaited it, so it fell through to the standalone "Start New Task" flow instead of reporting back.

How it works

Before: cancel child → parent: delegated→active, awaitingChildId→undefined
        → child resumes → falls through to standalone "Start New Task"

After:  cancel child → child: active→interrupted, parent stays delegated
        → child resumes → delegates back to parent → parent completes

Changes

Core fix:

  • packages/types/src/history.ts — Add "interrupted" to HistoryItem status enum
  • packages/types/src/task.ts, src/core/task/Task.ts, src/core/task-persistence/taskMetadata.ts — Propagate "interrupted" through initialStatus types
  • src/core/webview/ClineProvider.ts#cancelTask — Mark cancelled delegated child as "interrupted" instead of severing parent link; await abortTask() promise before writing "interrupted" to prevent a late saveClineMessages write from downgrading the status back to "active"
  • src/core/webview/ClineProvider.ts#removeClineFromStack — Skip parent auto-repair when child history shows "interrupted" (parent must stay "delegated" for resume)
  • src/core/tools/AttemptCompletionTool.ts — Accept "interrupted" alongside "active" so resumed children can delegate back to parent

CLI/session type sync:

  • packages/core/src/task-history/index.ts — Add "interrupted" to session reader allow-list so persisted interrupted sessions are not silently dropped
  • apps/cli/src/ui/types.ts, apps/cli/src/ui/components/autocomplete/triggers/HistoryTrigger.tsx — Add "interrupted" to status unions; display interrupted tasks with ⏸ icon and cyan color

Test Procedure

Unit tests (3 files updated, 3 new tests added):

  • src/core/webview/__tests__/ClineProvider.flicker-free-cancel.spec.ts — Updated existing cancel tests; added tests asserting child is marked "interrupted" and parent stays "delegated"
  • src/__tests__/removeClineFromStack-delegation.spec.ts — Added test asserting parent is not auto-repaired when child is "interrupted"
  • src/core/tools/__tests__/attemptCompletionTool.spec.ts — Added test for interrupted child delegating back to parent
  • apps/cli/src/ui/components/autocomplete/triggers/__tests__/HistoryTrigger.test.tsx — Added test asserting ⏸ icon renders for interrupted status

E2E test:

  • apps/vscode-e2e/src/suite/subtasks.test.ts — New test: interrupt child mid-execution → resume → asserts child reports back to parent and parent completes with expected result

All unit tests pass: pnpm vitest run (408/408 files).

Pre-Submission Checklist

Summary by CodeRabbit

  • New Features
    • Added an interrupted task status across the app, including updated task creation/saving support and distinct history UI indicators.
    • Added an API method to get the persisted API conversation history length for a task.
  • Bug Fixes
    • Improved cancellation/delegation handling so interrupted child tasks resume correctly and complete back into parent flows.
    • Updated task-history normalization, transition rules, and status preservation to correctly handle interrupted states.
  • Tests
    • Expanded unit, integration, and end-to-end coverage for interrupted/resume scenarios and related edge cases.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 15c6085d-fc30-42a4-bd42-5fddbe0bc043

📥 Commits

Reviewing files that changed from the base of the PR and between 57ff033 and e876dd0.

📒 Files selected for processing (1)
  • webview-ui/src/components/settings/__tests__/SettingsView.change-detection.spec.tsx

📝 Walkthrough

Walkthrough

This PR adds "interrupted" as a task status across shared types, persistence, cancellation/delegation handling, CLI rendering, API support, and e2e coverage. Delegated child cancellation now preserves the parent-child relationship, and the webview context hook now uses React.useContext.

Changes

Interrupted status lifecycle

Layer / File(s) Summary
Type and API contracts
packages/types/src/history.ts, packages/types/src/task.ts, packages/types/src/api.ts, apps/cli/src/ui/types.ts, packages/core/src/task-history/index.ts, src/core/task-persistence/taskMetadata.ts, src/core/task/Task.ts, src/extension/api.ts, src/extension/__tests__/api-task-conversation-history-length.spec.ts
Status unions now include "interrupted", task-session extraction preserves it, and API#getTaskApiConversationHistoryLength is added with test coverage.
Task history transitions
src/core/task-persistence/TaskHistoryStore.ts, src/core/task-persistence/__tests__/TaskHistoryStore.reconciliation.spec.ts
The state machine allows active → interrupted, and transition/upsert tests cover interrupted cases.
Delegated cancellation persistence
src/core/webview/ClineProvider.ts, src/core/webview/__tests__/ClineProvider.flicker-free-cancel.spec.ts, src/__tests__/removeClineFromStack-delegation.spec.ts, src/core/task/__tests__/Task.persistence.spec.ts, src/__tests__/helpers/provider-stub.ts
Delegated child cancellation now persists "interrupted" without severing parent linkage, removeClineFromStack() skips repair for interrupted or in-flight cancellations, and regression tests cover the new behavior.
Delegation gate and history rendering
src/core/tools/AttemptCompletionTool.ts, src/core/tools/__tests__/attemptCompletionTool.spec.ts, apps/cli/src/ui/components/autocomplete/triggers/HistoryTrigger.tsx, apps/cli/src/ui/components/autocomplete/triggers/__tests__/HistoryTrigger.test.tsx
Interrupted children are accepted by the delegation path, and history items render the new status with matching CLI test coverage.
Subtask resume fixtures and tests
apps/vscode-e2e/src/fixtures/subtasks.ts, apps/vscode-e2e/src/suite/subtasks.test.ts
New interrupt-specific fixtures and e2e scenarios verify that an interrupted child resumes and completes through the parent.

React.useContext migration

Layer / File(s) Summary
React.useContext migration
webview-ui/src/context/ExtensionStateContext.tsx, webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx
The context hook switches to React.useContext, and the provider-boundary test is updated to mock it.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related issues

Possibly related PRs

Suggested labels: awaiting-review

Suggested reviewers: taltas, JamesRobert20, hannesrudolph, navedmerchant

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning Most of #560 is addressed, but the explicit user-abandon/detach path required by the linked issue is not shown in these changes. Add the user-initiated abandon flow that detaches an interrupted child, or clarify that this PR only covers interruption and resume behavior.
Out of Scope Changes check ⚠️ Warning The PR includes unrelated edits like the React hook import refactor and the SettingsView async timeout change, which do not support #560. Remove or split the unrelated context and test-timeout edits into a separate PR, or explain why they are required for this fix.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main fix: preserving the parent-child link when a delegated subtask is interrupted.
Description check ✅ Passed The PR description follows the template well and includes the required issue link, summary, test procedure, and checklist.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue/560

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@edelauna edelauna changed the title Issue/560 fix(task-lifecycle): preserve parent-child link when delegated subtask is interrupted (#560) Jul 2, 2026
@codecov

codecov Bot commented Jul 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.59459% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/core/tools/AttemptCompletionTool.ts 0.00% 0 Missing and 1 partial ⚠️
src/core/webview/ClineProvider.ts 94.73% 0 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@edelauna edelauna marked this pull request as ready for review July 4, 2026 01:52

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/core/webview/ClineProvider.ts (1)

3283-3309: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Keep rehydrate on cancel-persistence failure
throw historyError exits cancelTaskInternal() before createTaskWithHistoryItem(...), so a double failure can leave the task stack empty until reload. Log the error and fall through with the in-memory severed historyItem instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/webview/ClineProvider.ts` around lines 3283 - 3309, The cancel
persistence flow in ClineProvider’s cancelTaskInternal is rethrowing
historyError from updateTaskHistory, which aborts the rest of the recovery path
and can leave the task stack empty; change the catch around updateTaskHistory so
it logs the failure and continues using the already severed in-memory
historyItem instead of throwing. Keep the parentTask/rootTask clearing and
this.cancelledDelegationChildIds update, then allow the later
createTaskWithHistoryItem path to run even when persistence fails.
🧹 Nitpick comments (5)
webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx (1)

250-258: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Spying on React.useContext couples the test to an implementation detail.

Mocking React.useContext directly works here because useExtensionState now calls it via the namespace import, but this ties the test to that specific call style — if the hook reverts to a destructured useContext import, this mock silently stops exercising the intended path (the spy would still fire without error, since React.useContext is still a valid reference, but coupling remains implicit). Consider retaining/adding a render-based test (component rendered outside the provider) alongside or instead of this spy-based approach for a more implementation-agnostic guarantee.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx` around lines
250 - 258, The `useExtensionState` test is too tightly coupled to the hook’s
current `React.useContext` call style; instead of relying only on a direct spy,
add or keep a render-based test that renders a component using
`useExtensionState` outside `ExtensionStateContextProvider` and asserts the
thrown error, so the coverage stays valid even if the hook’s import style
changes.
apps/vscode-e2e/src/suite/subtasks.test.ts (1)

75-75: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Consider replacing the fixed sleep(1_500) with a condition-based waitFor.

The suite already uses waitFor-style polling elsewhere (e.g. line 372/564 waiting on getTaskApiConversationHistoryLength); a hard-coded sleep here is more prone to flakiness under slow CI and adds fixed latency regardless of actual readiness.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode-e2e/src/suite/subtasks.test.ts` at line 75, Replace the fixed
sleep in the test flow with condition-based polling using waitFor. In
subtasks.test.ts, locate the await sleep(1_500) call and switch it to a waitFor
pattern consistent with the existing getTaskApiConversationHistoryLength checks
so the test proceeds only when the expected state is ready. Keep the same
surrounding test logic, but poll for the specific readiness condition instead of
relying on a hard-coded delay.
apps/vscode-e2e/src/fixtures/subtasks.ts (1)

39-63: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated 3-tier fallback matching logic between completionAfterAnswer and the new interrupt fixture.

The new fixture at lines 316-340 re-implements the same "structured tool-result / call-id+answer / bare user-message" fallback chain already encapsulated in completionAfterAnswer (39-63), just against different marker/answer constants. Generalizing completionAfterAnswer to accept a marker/answer/exclusion list would let this new scenario reuse it instead of duplicating the logic.

♻️ Suggested generalization
-const completionAfterAnswer = (followupId: string, completionId: string) => ({
-	match: {
-		predicate: (req: ChatCompletionRequest) =>
-			!requestContains(req, [SUBTASK_INTERRUPT_CHILD_MARKER]) &&
-			!requestContains(req, [SUBTASK_INTERRUPT_PARENT_MARKER]) &&
-			(toolResultContains(req, followupId, [SUBTASK_CHILD_FOLLOWUP_ANSWER]) ||
-				requestContains(req, [followupId, SUBTASK_CHILD_FOLLOWUP_ANSWER]) ||
-				requestContains(req, [
-					SUBTASK_CHILD_MARKER,
-					`<user_message>\\n${SUBTASK_CHILD_FOLLOWUP_ANSWER}\\n</user_message>`,
-				])),
-	},
-	response: {
-		toolCalls: [{ name: "attempt_completion", arguments: JSON.stringify({ result: "9" }), id: completionId }],
-	},
-})
+const completionAfterAnswer = (
+	followupId: string,
+	completionId: string,
+	opts?: { marker?: string; answer?: string; excludeMarkers?: string[] },
+) => {
+	const marker = opts?.marker ?? SUBTASK_CHILD_MARKER
+	const answer = opts?.answer ?? SUBTASK_CHILD_FOLLOWUP_ANSWER
+	const excludeMarkers = opts?.excludeMarkers ?? [SUBTASK_INTERRUPT_CHILD_MARKER, SUBTASK_INTERRUPT_PARENT_MARKER]
+	return {
+		match: {
+			predicate: (req: ChatCompletionRequest) =>
+				excludeMarkers.every((m) => !requestContains(req, [m])) &&
+				(toolResultContains(req, followupId, [answer]) ||
+					requestContains(req, [followupId, answer]) ||
+					requestContains(req, [marker, `<user_message>\\n${answer}\\n</user_message>`])),
+		},
+		response: {
+			toolCalls: [{ name: "attempt_completion", arguments: JSON.stringify({ result: answer }), id: completionId }],
+		},
+	}
+}

Also applies to: 316-340

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode-e2e/src/fixtures/subtasks.ts` around lines 39 - 63, The fallback
matching logic for completion responses is duplicated between
completionAfterAnswer and the new interrupt fixture, so refactor
completionAfterAnswer to accept the marker, answer token, and exclusion markers
as parameters. Update the predicate in completionAfterAnswer to work with the
caller-provided constants while preserving the same three-tier match order, then
reuse it in the interrupt fixture instead of re-implementing the structured
tool-result, call-id+answer, and bare user-message checks.
apps/cli/src/ui/components/autocomplete/triggers/HistoryTrigger.tsx (1)

136-151: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider a status→{icon,color} lookup instead of nested ternaries.

Functionally correct, but the duplicated item.status === X chains for icon and color are getting hard to scan with 4 branches. A small lookup map would be more maintainable for future status additions.

♻️ Suggested refactor
+const STATUS_DISPLAY: Record<string, { icon: string; color: string }> = {
+	completed: { icon: "✓", color: "green" },
+	active: { icon: "●", color: "yellow" },
+	interrupted: { icon: "⏸", color: "cyan" },
+}
+
 renderItem: (item: HistoryResult, isSelected: boolean) => {
-	// Status indicator
-	const statusIcon =
-		item.status === "completed"
-			? "✓"
-			: item.status === "active"
-				? "●"
-				: item.status === "interrupted"
-					? "⏸"
-					: "○"
-	const statusColor =
-		item.status === "completed"
-			? "green"
-			: item.status === "active"
-				? "yellow"
-				: item.status === "interrupted"
-					? "cyan"
-					: "gray"
+	// Status indicator
+	const { icon: statusIcon, color: statusColor } = STATUS_DISPLAY[item.status ?? ""] ?? {
+		icon: "○",
+		color: "gray",
+	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/cli/src/ui/components/autocomplete/triggers/HistoryTrigger.tsx` around
lines 136 - 151, The `HistoryTrigger` status rendering logic uses duplicated
nested ternaries for `item.status` to derive `statusIcon` and `statusColor`,
which is hard to extend. Refactor this block into a single
status-to-presentation lookup in `HistoryTrigger.tsx` so both values come from
one mapping keyed by status, and keep the fallback behavior for unknown
statuses.
src/core/webview/ClineProvider.ts (1)

3271-3285: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider guarding the "interrupted" write with assertValidTransition.

Every other status-changing write in this file (line 567, 3583, 3834, 3839) calls assertValidTransition before persisting. This new historyItem.status = "interrupted" write skips that check. The awaitingChildId === task.taskId guard mitigates most invalid-transition risk (e.g., a completed child already clears awaitingChildId), but adding the explicit guard would keep this write consistent with the rest of the file's defensive pattern and catch any future edge case.

♻️ Suggested addition
 if (parentHistory?.status === "delegated" && parentHistory?.awaitingChildId === task.taskId) {
+    assertValidTransition(historyItem!.status, "interrupted")
     historyItem = { ...historyItem!, status: "interrupted" }
     await this.updateTaskHistory(historyItem)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/webview/ClineProvider.ts` around lines 3271 - 3285, The new
interrupted status write in ClineProvider’s cancel flow should be guarded the
same way as the other status updates in this file. Before setting
historyItem.status to "interrupted" and calling updateTaskHistory, add an
assertValidTransition check using the current historyItem status and the target
interrupted state so this path matches the defensive pattern used elsewhere in
ClineProvider and catches any future invalid transition edge cases.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/vscode-e2e/src/fixtures/subtasks.ts`:
- Around line 316-356: The fixtures in subtasks.ts are hardcoding result strings
that already exist as exported constants, which can drift from the test
expectations. Update the two attempt_completion responses in the mock.addFixture
blocks to reuse SUBTASK_INTERRUPT_CHILD_FOLLOWUP_ANSWER and
SUBTASK_INTERRUPT_PARENT_RESULT instead of literal values, keeping the fixture
responses aligned with subtasks.test.ts. Use the existing constants already
referenced in this file to locate the affected toolCalls payloads.

In `@packages/types/src/api.ts`:
- Around line 48-53: The contract for getTaskApiConversationHistoryLength is not
fully honored because the implementation in ApiService does not fall back to 0
when the history is unavailable. Update the getTaskApiConversationHistoryLength
path in src/extension/api.ts so it returns the persisted count when present and
explicitly returns 0 for missing/undefined/unavailable task history, matching
the JSDoc in the API interface.

In `@src/extension/api.ts`:
- Around line 243-247: getTaskApiConversationHistoryLength currently calls
getTaskWithId directly, so missing tasks throw instead of honoring the
documented 0 fallback. Update the getTaskApiConversationHistoryLength method in
src/extension/api.ts to match the same try/catch pattern used by
isTaskInHistory, and return 0 when getTaskWithId fails or the task is
unavailable. Keep the existing apiConversationHistory.length path for valid
tasks so the method matches the contract in packages/types/src/api.ts.

---

Outside diff comments:
In `@src/core/webview/ClineProvider.ts`:
- Around line 3283-3309: The cancel persistence flow in ClineProvider’s
cancelTaskInternal is rethrowing historyError from updateTaskHistory, which
aborts the rest of the recovery path and can leave the task stack empty; change
the catch around updateTaskHistory so it logs the failure and continues using
the already severed in-memory historyItem instead of throwing. Keep the
parentTask/rootTask clearing and this.cancelledDelegationChildIds update, then
allow the later createTaskWithHistoryItem path to run even when persistence
fails.

---

Nitpick comments:
In `@apps/cli/src/ui/components/autocomplete/triggers/HistoryTrigger.tsx`:
- Around line 136-151: The `HistoryTrigger` status rendering logic uses
duplicated nested ternaries for `item.status` to derive `statusIcon` and
`statusColor`, which is hard to extend. Refactor this block into a single
status-to-presentation lookup in `HistoryTrigger.tsx` so both values come from
one mapping keyed by status, and keep the fallback behavior for unknown
statuses.

In `@apps/vscode-e2e/src/fixtures/subtasks.ts`:
- Around line 39-63: The fallback matching logic for completion responses is
duplicated between completionAfterAnswer and the new interrupt fixture, so
refactor completionAfterAnswer to accept the marker, answer token, and exclusion
markers as parameters. Update the predicate in completionAfterAnswer to work
with the caller-provided constants while preserving the same three-tier match
order, then reuse it in the interrupt fixture instead of re-implementing the
structured tool-result, call-id+answer, and bare user-message checks.

In `@apps/vscode-e2e/src/suite/subtasks.test.ts`:
- Line 75: Replace the fixed sleep in the test flow with condition-based polling
using waitFor. In subtasks.test.ts, locate the await sleep(1_500) call and
switch it to a waitFor pattern consistent with the existing
getTaskApiConversationHistoryLength checks so the test proceeds only when the
expected state is ready. Keep the same surrounding test logic, but poll for the
specific readiness condition instead of relying on a hard-coded delay.

In `@src/core/webview/ClineProvider.ts`:
- Around line 3271-3285: The new interrupted status write in ClineProvider’s
cancel flow should be guarded the same way as the other status updates in this
file. Before setting historyItem.status to "interrupted" and calling
updateTaskHistory, add an assertValidTransition check using the current
historyItem status and the target interrupted state so this path matches the
defensive pattern used elsewhere in ClineProvider and catches any future invalid
transition edge cases.

In `@webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx`:
- Around line 250-258: The `useExtensionState` test is too tightly coupled to
the hook’s current `React.useContext` call style; instead of relying only on a
direct spy, add or keep a render-based test that renders a component using
`useExtensionState` outside `ExtensionStateContextProvider` and asserts the
thrown error, so the coverage stays valid even if the hook’s import style
changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 47b46968-67b0-4887-89e5-481bf53a8f18

📥 Commits

Reviewing files that changed from the base of the PR and between 1c728e7 and 46c1889.

📒 Files selected for processing (24)
  • apps/cli/src/ui/components/autocomplete/triggers/HistoryTrigger.tsx
  • apps/cli/src/ui/components/autocomplete/triggers/__tests__/HistoryTrigger.test.tsx
  • apps/cli/src/ui/types.ts
  • apps/vscode-e2e/src/fixtures/subtasks.ts
  • apps/vscode-e2e/src/suite/subtasks.test.ts
  • packages/core/src/task-history/index.ts
  • packages/types/src/api.ts
  • packages/types/src/history.ts
  • packages/types/src/task.ts
  • src/__tests__/helpers/provider-stub.ts
  • src/__tests__/removeClineFromStack-delegation.spec.ts
  • src/core/task-persistence/TaskHistoryStore.ts
  • src/core/task-persistence/__tests__/TaskHistoryStore.reconciliation.spec.ts
  • src/core/task-persistence/taskMetadata.ts
  • src/core/task/Task.ts
  • src/core/task/__tests__/Task.persistence.spec.ts
  • src/core/tools/AttemptCompletionTool.ts
  • src/core/tools/__tests__/attemptCompletionTool.spec.ts
  • src/core/webview/ClineProvider.ts
  • src/core/webview/__tests__/ClineProvider.flicker-free-cancel.spec.ts
  • src/core/webview/__tests__/ClineProvider.sticky-profile.spec.ts
  • src/extension/api.ts
  • webview-ui/src/context/ExtensionStateContext.tsx
  • webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx

Comment thread apps/vscode-e2e/src/fixtures/subtasks.ts
Comment thread packages/types/src/api.ts
Comment thread src/extension/api.ts Outdated
@github-actions github-actions Bot added the awaiting-review PR changes are ready and waiting for maintainer re-review label Jul 4, 2026
@github-actions github-actions Bot removed the awaiting-review PR changes are ready and waiting for maintainer re-review label Jul 4, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/extension/__tests__/api-task-conversation-history-length.spec.ts (1)

32-44: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding a test for missing/empty apiConversationHistory.

Current coverage handles the resolved-with-history and rejected cases, but not a resolved task lacking apiConversationHistory (e.g. undefined or []). Adding this would tighten coverage of the error/edge-handling path per the coding guideline for spec files.

As per coding guidelines, **/*.{test,spec}.{ts,tsx,js} should "Use package-local unit tests for pure logic, parsing, state transitions, validation, serialization, request construction, retry decisions, and error handling."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/extension/__tests__/api-task-conversation-history-length.spec.ts` around
lines 32 - 44, Add a spec in api-task-conversation-history-length.spec.ts for
the missing-edge case in getTaskApiConversationHistoryLength: when getTaskWithId
resolves to a task whose apiConversationHistory is undefined or an empty array,
the method should return 0 instead of throwing or miscounting. Reuse the
existing mockGetTaskWithId and api.getTaskApiConversationHistoryLength setup to
cover this resolved-but-empty path alongside the current history and rejection
tests.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/extension/__tests__/api-task-conversation-history-length.spec.ts`:
- Around line 32-44: Add a spec in api-task-conversation-history-length.spec.ts
for the missing-edge case in getTaskApiConversationHistoryLength: when
getTaskWithId resolves to a task whose apiConversationHistory is undefined or an
empty array, the method should return 0 instead of throwing or miscounting.
Reuse the existing mockGetTaskWithId and api.getTaskApiConversationHistoryLength
setup to cover this resolved-but-empty path alongside the current history and
rejection tests.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3e5da1eb-a36a-4ac3-9d51-98089f111e3a

📥 Commits

Reviewing files that changed from the base of the PR and between 46c1889 and 601d369.

📒 Files selected for processing (3)
  • apps/vscode-e2e/src/fixtures/subtasks.ts
  • src/extension/__tests__/api-task-conversation-history-length.spec.ts
  • src/extension/api.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/extension/api.ts
  • apps/vscode-e2e/src/fixtures/subtasks.ts

@github-actions github-actions Bot added the awaiting-review PR changes are ready and waiting for maintainer re-review label Jul 4, 2026
navedmerchant
navedmerchant previously approved these changes Jul 5, 2026
@github-actions github-actions Bot removed the awaiting-review PR changes are ready and waiting for maintainer re-review label Jul 5, 2026
@navedmerchant navedmerchant enabled auto-merge July 5, 2026 15:57
@navedmerchant navedmerchant added this pull request to the merge queue Jul 6, 2026
@github-actions github-actions Bot added the awaiting-review PR changes are ready and waiting for maintainer re-review label Jul 6, 2026
Merged via the queue into main with commit 737f27d Jul 6, 2026
16 checks passed
@navedmerchant navedmerchant deleted the issue/560 branch July 6, 2026 22:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting-review PR changes are ready and waiting for maintainer re-review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(task-lifecycle): preserve parent-child link when delegated subtask is interrupted

3 participants