Skip to content
This repository was archived by the owner on May 15, 2026. It is now read-only.

Commit 1997697

Browse files
committed
feat: consolidate Phase 7 + wire replay view for background tasks + add interrupted tooltip
- Consolidate Phase 7a (FileLockManager), 7b (LockGuardedToolExecutor + tool runner integration), and 7c (persistent background task history) into single branch - Wire background task clicks in History view to open the read-only BackgroundTaskReplayView instead of creating a resumable task - Add StandardTooltip on interrupted background tasks explaining they were interrupted due to VS Code closing - Add interruptedTooltip i18n key across all locales - Add tests for replay view routing and tooltip rendering Addresses feedback from #12330
1 parent 145263b commit 1997697

25 files changed

Lines changed: 108 additions & 25 deletions

File tree

packages/types/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export * from "./mode.js"
2121
export * from "./model.js"
2222
export * from "./provider-settings.js"
2323
export * from "./task.js"
24-
export * from "./task-context.js"
24+
export { taskContextSchema, type TaskContext, mergePermissions } from "./task-context.js"
2525
export * from "./task-permissions.js"
2626
export * from "./todo.js"
2727
export * from "./skills.js"

packages/types/src/vscode-extension-host.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -573,8 +573,7 @@ export interface WebviewMessage {
573573
text?: string
574574
taskId?: string
575575
editedMessageContent?: string
576-
tab?: "settings" | "history" | "mcp" | "modes" | "chat" | "cloud"
577-
tab?: "settings" | "history" | "mcp" | "modes" | "chat" | "bgTaskReplay" | "bgTask"
576+
tab?: "settings" | "history" | "mcp" | "modes" | "chat" | "cloud" | "bgTaskReplay" | "bgTask"
578577
disabled?: boolean
579578
context?: string
580579
dataUri?: string

src/core/prompts/tools/native-tools/new_task.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export default {
4444
permissions: {
4545
type: ["string", "null"],
4646
description: PERMISSIONS_PARAMETER_DESCRIPTION,
47+
},
4748
background: {
4849
type: ["string", "null"],
4950
description: BACKGROUND_PARAMETER_DESCRIPTION,

webview-ui/src/components/history/TaskItem.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ const TaskItem = ({
3535
const handleClick = () => {
3636
if (isSelectionMode && onToggleSelection) {
3737
onToggleSelection(item.id, !isSelected)
38+
} else if (item.background) {
39+
// Background tasks open in the read-only replay view
40+
vscode.postMessage({ type: "switchTab", tab: "bgTaskReplay", values: { taskId: item.id } })
3841
} else {
3942
vscode.postMessage({ type: "showTaskWithId", text: item.id })
4043
}

webview-ui/src/components/history/TaskItemFooter.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,18 @@ const TaskItemFooter: React.FC<TaskItemFooterProps> = ({
3232
{item.background && (
3333
<>
3434
{item.status === "interrupted" ? (
35-
<AlertTriangle className="size-3 text-vscode-editorWarning-foreground" />
35+
<StandardTooltip content={t("history:interruptedTooltip")}>
36+
<span className="inline-flex items-center gap-1 text-vscode-editorWarning-foreground">
37+
<AlertTriangle className="size-3" />
38+
{t("history:interruptedTag")}
39+
</span>
40+
</StandardTooltip>
3641
) : (
37-
<Layers className="size-3" />
42+
<>
43+
<Layers className="size-3" />
44+
<span>{t("history:backgroundTag")}</span>
45+
</>
3846
)}
39-
<span>
40-
{item.status === "interrupted" ? t("history:interruptedTag") : t("history:backgroundTag")}
41-
</span>
4247
<span>&middot;</span>
4348
</>
4449
)}

webview-ui/src/components/history/__tests__/TaskItem.spec.tsx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,48 @@ describe("TaskItem", () => {
109109
const taskItem = screen.getByTestId("task-item-1")
110110
expect(taskItem).toHaveClass("hover:text-vscode-foreground")
111111
})
112+
113+
it("sends switchTab message for background tasks to open replay view", async () => {
114+
const { vscode } = await import("@/utils/vscode")
115+
const backgroundTask = { ...mockTask, id: "bg-1", background: true }
116+
117+
render(
118+
<TaskItem
119+
item={backgroundTask}
120+
variant="full"
121+
isSelected={false}
122+
onToggleSelection={vi.fn()}
123+
isSelectionMode={false}
124+
/>,
125+
)
126+
127+
fireEvent.click(screen.getByTestId("task-item-bg-1"))
128+
129+
expect(vscode.postMessage).toHaveBeenCalledWith({
130+
type: "switchTab",
131+
tab: "bgTaskReplay",
132+
values: { taskId: "bg-1" },
133+
})
134+
})
135+
136+
it("sends showTaskWithId message for non-background tasks", async () => {
137+
const { vscode } = await import("@/utils/vscode")
138+
139+
render(
140+
<TaskItem
141+
item={mockTask}
142+
variant="full"
143+
isSelected={false}
144+
onToggleSelection={vi.fn()}
145+
isSelectionMode={false}
146+
/>,
147+
)
148+
149+
fireEvent.click(screen.getByTestId("task-item-1"))
150+
151+
expect(vscode.postMessage).toHaveBeenCalledWith({
152+
type: "showTaskWithId",
153+
text: "1",
154+
})
155+
})
112156
})

webview-ui/src/components/history/__tests__/TaskItemFooter.spec.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,17 @@ describe("TaskItemFooter", () => {
123123
expect(screen.getByText("history:backgroundTag")).toBeInTheDocument()
124124
expect(screen.queryByText("history:interruptedTag")).not.toBeInTheDocument()
125125
})
126+
127+
it("wraps interrupted tag in a tooltip explaining VS Code was closed", () => {
128+
const interruptedItem = { ...mockItem, background: true, status: "interrupted" as const }
129+
render(<TaskItemFooter item={interruptedItem} variant="full" />)
130+
131+
// The interrupted tag should be present
132+
expect(screen.getByText("history:interruptedTag")).toBeInTheDocument()
133+
// The tooltip trigger wraps the tag -- verify the tooltip content key is used
134+
// StandardTooltip renders a trigger element with the content as a prop
135+
const tagElement = screen.getByText("history:interruptedTag")
136+
// The tag and icon should be grouped inside a styled span
137+
expect(tagElement.closest("span")).toHaveClass("text-vscode-editorWarning-foreground")
138+
})
126139
})

webview-ui/src/i18n/locales/ca/history.json

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

webview-ui/src/i18n/locales/de/history.json

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

webview-ui/src/i18n/locales/en/history.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"collapseSubtasks": "Collapse subtasks",
5151
"backgroundTag": "Background",
5252
"interruptedTag": "Interrupted",
53+
"interruptedTooltip": "This background task was interrupted because VS Code was closed while it was still running.",
5354
"showBackgroundTasks": "Show background tasks",
5455
"hideBackgroundTasks": "Hide background tasks",
5556
"filter": {

0 commit comments

Comments
 (0)