@astralyn/pi 0.84.14 → 0.84.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/core/agent-session.d.ts.map +1 -1
  3. package/dist/core/agent-session.js +12 -6
  4. package/dist/core/agent-session.js.map +1 -1
  5. package/dist/core/extensions/types.d.ts +4 -1
  6. package/dist/core/extensions/types.d.ts.map +1 -1
  7. package/dist/core/extensions/types.js.map +1 -1
  8. package/dist/core/tools/bash.d.ts +1 -0
  9. package/dist/core/tools/bash.d.ts.map +1 -1
  10. package/dist/core/tools/bash.js +4 -1
  11. package/dist/core/tools/bash.js.map +1 -1
  12. package/dist/core/tools/find.d.ts +2 -0
  13. package/dist/core/tools/find.d.ts.map +1 -1
  14. package/dist/core/tools/find.js +18 -15
  15. package/dist/core/tools/find.js.map +1 -1
  16. package/dist/extensions/background/actions.d.ts.map +1 -1
  17. package/dist/extensions/background/actions.js +3 -2
  18. package/dist/extensions/background/actions.js.map +1 -1
  19. package/dist/extensions/background/manager.d.ts.map +1 -1
  20. package/dist/extensions/background/manager.js +8 -9
  21. package/dist/extensions/background/manager.js.map +1 -1
  22. package/dist/extensions/background/registry.d.ts +4 -1
  23. package/dist/extensions/background/registry.d.ts.map +1 -1
  24. package/dist/extensions/background/registry.js +30 -17
  25. package/dist/extensions/background/registry.js.map +1 -1
  26. package/dist/extensions/background/task-view.d.ts +6 -0
  27. package/dist/extensions/background/task-view.d.ts.map +1 -1
  28. package/dist/extensions/background/task-view.js +11 -6
  29. package/dist/extensions/background/task-view.js.map +1 -1
  30. package/dist/extensions/deepwiki/client.d.ts.map +1 -1
  31. package/dist/extensions/deepwiki/client.js +3 -0
  32. package/dist/extensions/deepwiki/client.js.map +1 -1
  33. package/dist/extensions/deepwiki/execute.d.ts +2 -1
  34. package/dist/extensions/deepwiki/execute.d.ts.map +1 -1
  35. package/dist/extensions/deepwiki/execute.js +17 -2
  36. package/dist/extensions/deepwiki/execute.js.map +1 -1
  37. package/dist/extensions/deepwiki/http.d.ts +1 -0
  38. package/dist/extensions/deepwiki/http.d.ts.map +1 -1
  39. package/dist/extensions/deepwiki/http.js +16 -2
  40. package/dist/extensions/deepwiki/http.js.map +1 -1
  41. package/dist/extensions/deepwiki/schema.d.ts +1 -1
  42. package/dist/extensions/deepwiki/schema.d.ts.map +1 -1
  43. package/dist/extensions/deepwiki/schema.js +8 -2
  44. package/dist/extensions/deepwiki/schema.js.map +1 -1
  45. package/dist/extensions/question/dialog.d.ts.map +1 -1
  46. package/dist/extensions/question/dialog.js +80 -9
  47. package/dist/extensions/question/dialog.js.map +1 -1
  48. package/dist/extensions/question/index.d.ts.map +1 -1
  49. package/dist/extensions/question/index.js +8 -0
  50. package/dist/extensions/question/index.js.map +1 -1
  51. package/dist/extensions/question/schema.d.ts +2 -2
  52. package/dist/extensions/question/schema.d.ts.map +1 -1
  53. package/dist/extensions/question/schema.js +41 -11
  54. package/dist/extensions/question/schema.js.map +1 -1
  55. package/dist/extensions/question/types.d.ts +1 -1
  56. package/dist/extensions/question/types.d.ts.map +1 -1
  57. package/dist/extensions/question/types.js.map +1 -1
  58. package/dist/extensions/router/probe.d.ts.map +1 -1
  59. package/dist/extensions/router/probe.js +10 -29
  60. package/dist/extensions/router/probe.js.map +1 -1
  61. package/dist/extensions/router/register.d.ts.map +1 -1
  62. package/dist/extensions/router/register.js +16 -6
  63. package/dist/extensions/router/register.js.map +1 -1
  64. package/dist/extensions/router/store.d.ts.map +1 -1
  65. package/dist/extensions/router/store.js +108 -51
  66. package/dist/extensions/router/store.js.map +1 -1
  67. package/dist/extensions/router/ui.d.ts +6 -0
  68. package/dist/extensions/router/ui.d.ts.map +1 -1
  69. package/dist/extensions/router/ui.js +14 -6
  70. package/dist/extensions/router/ui.js.map +1 -1
  71. package/dist/extensions/statusline/index.d.ts.map +1 -1
  72. package/dist/extensions/statusline/index.js +40 -43
  73. package/dist/extensions/statusline/index.js.map +1 -1
  74. package/dist/extensions/subagent/activity.d.ts +7 -1
  75. package/dist/extensions/subagent/activity.d.ts.map +1 -1
  76. package/dist/extensions/subagent/activity.js +69 -6
  77. package/dist/extensions/subagent/activity.js.map +1 -1
  78. package/dist/extensions/subagent/agents-command.js +1 -1
  79. package/dist/extensions/subagent/agents-command.js.map +1 -1
  80. package/dist/extensions/subagent/agents.d.ts.map +1 -1
  81. package/dist/extensions/subagent/agents.js +0 -3
  82. package/dist/extensions/subagent/agents.js.map +1 -1
  83. package/dist/extensions/subagent/budget.d.ts.map +1 -1
  84. package/dist/extensions/subagent/budget.js +29 -2
  85. package/dist/extensions/subagent/budget.js.map +1 -1
  86. package/dist/extensions/subagent/cancellation.d.ts +4 -4
  87. package/dist/extensions/subagent/cancellation.d.ts.map +1 -1
  88. package/dist/extensions/subagent/cancellation.js +31 -13
  89. package/dist/extensions/subagent/cancellation.js.map +1 -1
  90. package/dist/extensions/subagent/constants.d.ts +1 -0
  91. package/dist/extensions/subagent/constants.d.ts.map +1 -1
  92. package/dist/extensions/subagent/constants.js +1 -0
  93. package/dist/extensions/subagent/constants.js.map +1 -1
  94. package/dist/extensions/subagent/index.d.ts.map +1 -1
  95. package/dist/extensions/subagent/index.js +1 -0
  96. package/dist/extensions/subagent/index.js.map +1 -1
  97. package/dist/extensions/subagent/render.d.ts +8 -1
  98. package/dist/extensions/subagent/render.d.ts.map +1 -1
  99. package/dist/extensions/subagent/render.js +148 -178
  100. package/dist/extensions/subagent/render.js.map +1 -1
  101. package/dist/extensions/subagent/runner.d.ts +1 -0
  102. package/dist/extensions/subagent/runner.d.ts.map +1 -1
  103. package/dist/extensions/subagent/runner.js +53 -44
  104. package/dist/extensions/subagent/runner.js.map +1 -1
  105. package/dist/extensions/subagent/sdk-runner.d.ts.map +1 -1
  106. package/dist/extensions/subagent/sdk-runner.js +0 -3
  107. package/dist/extensions/subagent/sdk-runner.js.map +1 -1
  108. package/dist/extensions/subagent/settings.d.ts +1 -1
  109. package/dist/extensions/subagent/settings.d.ts.map +1 -1
  110. package/dist/extensions/subagent/settings.js +74 -25
  111. package/dist/extensions/subagent/settings.js.map +1 -1
  112. package/dist/extensions/subagent/state.d.ts +1 -0
  113. package/dist/extensions/subagent/state.d.ts.map +1 -1
  114. package/dist/extensions/subagent/state.js +46 -16
  115. package/dist/extensions/subagent/state.js.map +1 -1
  116. package/dist/extensions/subagent/types.d.ts +0 -7
  117. package/dist/extensions/subagent/types.d.ts.map +1 -1
  118. package/dist/extensions/subagent/types.js.map +1 -1
  119. package/dist/extensions/subagent/ui/agents-dialog.js +1 -1
  120. package/dist/extensions/subagent/ui/agents-dialog.js.map +1 -1
  121. package/dist/extensions/subagent/ui/model-list.d.ts.map +1 -1
  122. package/dist/extensions/subagent/ui/model-list.js +3 -4
  123. package/dist/extensions/subagent/ui/model-list.js.map +1 -1
  124. package/dist/extensions/subagent/ui/model-picker.d.ts.map +1 -1
  125. package/dist/extensions/subagent/ui/model-picker.js +2 -1
  126. package/dist/extensions/subagent/ui/model-picker.js.map +1 -1
  127. package/dist/extensions/web-search/format.d.ts.map +1 -1
  128. package/dist/extensions/web-search/format.js +36 -15
  129. package/dist/extensions/web-search/format.js.map +1 -1
  130. package/dist/extensions/web-search/index.d.ts.map +1 -1
  131. package/dist/extensions/web-search/index.js +11 -8
  132. package/dist/extensions/web-search/index.js.map +1 -1
  133. package/dist/extensions/web-search/providers/deepseek.d.ts.map +1 -1
  134. package/dist/extensions/web-search/providers/deepseek.js +36 -5
  135. package/dist/extensions/web-search/providers/deepseek.js.map +1 -1
  136. package/dist/extensions/web-search/providers/http.d.ts +2 -7
  137. package/dist/extensions/web-search/providers/http.d.ts.map +1 -1
  138. package/dist/extensions/web-search/providers/http.js +12 -57
  139. package/dist/extensions/web-search/providers/http.js.map +1 -1
  140. package/dist/extensions/web-search/providers/minimax.d.ts.map +1 -1
  141. package/dist/extensions/web-search/providers/minimax.js +18 -6
  142. package/dist/extensions/web-search/providers/minimax.js.map +1 -1
  143. package/dist/extensions/web-search/render.d.ts.map +1 -1
  144. package/dist/extensions/web-search/render.js +16 -5
  145. package/dist/extensions/web-search/render.js.map +1 -1
  146. package/dist/extensions/web-search/results.d.ts +10 -3
  147. package/dist/extensions/web-search/results.d.ts.map +1 -1
  148. package/dist/extensions/web-search/results.js +25 -7
  149. package/dist/extensions/web-search/results.js.map +1 -1
  150. package/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  151. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  152. package/dist/modes/interactive/components/tool-execution.js +7 -0
  153. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  154. package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
  155. package/dist/modes/interactive/components/tool-group.js +10 -0
  156. package/dist/modes/interactive/components/tool-group.js.map +1 -1
  157. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  158. package/dist/modes/interactive/interactive-mode.js +3 -40
  159. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  160. package/dist/modes/interactive/theme/theme.d.ts +0 -4
  161. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  162. package/dist/modes/interactive/theme/theme.js +16 -23
  163. package/dist/modes/interactive/theme/theme.js.map +1 -1
  164. package/dist/utils/http-response.d.ts +10 -0
  165. package/dist/utils/http-response.d.ts.map +1 -0
  166. package/dist/utils/http-response.js +68 -0
  167. package/dist/utils/http-response.js.map +1 -0
  168. package/docs/bundled/extensions/background.md +2 -1
  169. package/docs/bundled/extensions/deepwiki.md +7 -5
  170. package/docs/bundled/extensions/question.md +6 -4
  171. package/docs/bundled/extensions/router.md +1 -1
  172. package/docs/bundled/extensions/statusline.md +1 -0
  173. package/docs/bundled/extensions/subagent.md +29 -39
  174. package/docs/bundled/extensions/web-search.md +3 -3
  175. package/docs/development.md +7 -2
  176. package/docs/extensions.md +2 -2
  177. package/npm-shrinkwrap.json +2 -2
  178. package/package.json +1 -1
@@ -8,7 +8,7 @@ import { stripTerminalSequences, truncateToWidth } from "@earendil-works/pi-tui"
8
8
  import { formatSize } from "../../core/tools/truncate.js";
9
9
  import { keyLabel } from "../../modes/interactive/components/keybinding-hints.js";
10
10
  import { sanitizeBinaryOutput } from "../../utils/shell.js";
11
- import { exitSuffix, runtimeLabel, statusColor, statusGlyph, taskLabel } from "./task-view.js";
11
+ import { exitSuffix, formatTaskCounts, runtimeLabel, statusColor, statusGlyph, taskLabel } from "./task-view.js";
12
12
  import { fileNameOf } from "./text.js";
13
13
  const POLL_INTERVAL_MS = 1000;
14
14
  const VIEW_TAIL_BYTES = 128 * 1024;
@@ -43,6 +43,7 @@ export class BackgroundTasksMenu {
43
43
  this.selectedTaskId = this.tasks[0]?.id;
44
44
  void this.tick();
45
45
  this.pollTimer = setInterval(() => void this.tick(), this.pollIntervalMs);
46
+ this.pollTimer.unref?.();
46
47
  }
47
48
  get focused() {
48
49
  return this._focused;
@@ -195,16 +196,14 @@ export class BackgroundTasksMenu {
195
196
  }
196
197
  countsLabel() {
197
198
  let running = 0;
198
- for (const task of this.tasks)
199
+ let stalled = 0;
200
+ for (const task of this.tasks) {
199
201
  if (task.status === "running")
200
202
  running++;
201
- const ended = this.tasks.length - running;
202
- const parts = [];
203
- if (running > 0)
204
- parts.push(`${running} running`);
205
- if (ended > 0)
206
- parts.push(`${ended} done`);
207
- return parts.join(" · ");
203
+ if (task.stalled)
204
+ stalled++;
205
+ }
206
+ return formatTaskCounts({ running, stalled, total: this.tasks.length }) ?? "";
208
207
  }
209
208
  // ── detail view ────────────────────────────────────────────────────────
210
209
  renderDetail(width) {
@@ -1 +1 @@
1
- {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../src/extensions/background/manager.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * /bg task manager — an inline, /model-style menu that mounts in the editor\n * slot. Two views in one component: a task list, and a live output viewport\n * for the selected task (Enter to open, Esc to go back). The host dependency\n * is narrowed to three callbacks so the component stays testable.\n */\n\nimport { type Component, type Focusable, stripTerminalSequences, truncateToWidth } from \"@earendil-works/pi-tui\";\nimport type { KeybindingsManager } from \"../../core/keybindings.ts\";\nimport { formatSize } from \"../../core/tools/truncate.ts\";\nimport { keyLabel } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { sanitizeBinaryOutput } from \"../../utils/shell.ts\";\nimport type { OutputSlice } from \"./output-file.ts\";\nimport type { BgTask } from \"./registry.ts\";\nimport { exitSuffix, runtimeLabel, statusColor, statusGlyph, taskLabel } from \"./task-view.ts\";\nimport { fileNameOf } from \"./text.ts\";\n\nconst POLL_INTERVAL_MS = 1000;\nconst VIEW_TAIL_BYTES = 128 * 1024;\nconst MAX_VIEW_LINES = 2000;\nconst LIST_MAX_VISIBLE = 10;\nconst LIST_MIN_VISIBLE = 3;\n/** Rows outside the task list itself (borders, title, counter, footer, padding). */\nconst LIST_RESERVED_ROWS = 14;\n\nexport interface BackgroundManagerHost {\n\tlistTasks(): BgTask[];\n\tkillTask(id: string): { killed: boolean };\n\treadSlice(filePath: string, options: { mode: \"tail\"; maxBytes: number }): Promise<OutputSlice>;\n}\n\ninterface MenuTui {\n\trequestRender(): void;\n\tterminal: { rows: number; columns: number };\n}\n\nexport interface BackgroundTasksMenuOptions {\n\ttui: MenuTui;\n\ttheme: Theme;\n\tkeybindings: Pick<KeybindingsManager, \"matches\" | \"getKeys\">;\n\thost: BackgroundManagerHost;\n\tonClose: () => void;\n\tpollIntervalMs?: number;\n}\n\ninterface TailCache {\n\ttaskId: string;\n\tlines: string[];\n\ttotalBytes: number;\n\t/** True once a terminal task's final output has been read; skips re-reads. */\n\tsettledRead?: boolean;\n\terror?: string;\n}\n\n/** Truncate to an exact visible width, padding short lines with spaces. */\nfunction padLine(line: string, width: number): string {\n\treturn truncateToWidth(line, width, \"…\", true);\n}\n\nexport class BackgroundTasksMenu implements Component, Focusable {\n\tprivate readonly tui: MenuTui;\n\tprivate readonly theme: Theme;\n\tprivate readonly keybindings: Pick<KeybindingsManager, \"matches\" | \"getKeys\">;\n\tprivate readonly host: BackgroundManagerHost;\n\tprivate readonly onClose: () => void;\n\tprivate readonly pollIntervalMs: number;\n\n\tprivate view: \"list\" | \"detail\" = \"list\";\n\tprivate tasks: BgTask[] = [];\n\tprivate selectedTaskId: string | undefined;\n\tprivate listScrollTop = 0;\n\tprivate follow = true;\n\tprivate tailOffsetLines = 0;\n\tprivate tailCache: TailCache | undefined;\n\tprivate killFeedback: string | undefined;\n\t/** Task whose settle expires killFeedback; undefined = persists until the next key. */\n\tprivate killFeedbackTaskId: string | undefined;\n\t/** Last tick's render signature; unchanged means nothing visible moved. */\n\tprivate lastSignature = \"\";\n\tprivate pollTimer: ReturnType<typeof setInterval> | undefined;\n\tprivate readBusy = false;\n\tprivate disposed = false;\n\tprivate _focused = false;\n\n\tconstructor(options: BackgroundTasksMenuOptions) {\n\t\tthis.tui = options.tui;\n\t\tthis.theme = options.theme;\n\t\tthis.keybindings = options.keybindings;\n\t\tthis.host = options.host;\n\t\tthis.onClose = options.onClose;\n\t\tthis.pollIntervalMs = options.pollIntervalMs ?? POLL_INTERVAL_MS;\n\n\t\tthis.tasks = this.host.listTasks();\n\t\tthis.selectedTaskId = this.tasks[0]?.id;\n\t\tvoid this.tick();\n\t\tthis.pollTimer = setInterval(() => void this.tick(), this.pollIntervalMs);\n\t}\n\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t}\n\n\tinvalidate(): void {\n\t\t// No cached render state; the poller drives refresh.\n\t}\n\n\tdispose(): void {\n\t\tthis.disposed = true;\n\t\tif (this.pollTimer !== undefined) {\n\t\t\tclearInterval(this.pollTimer);\n\t\t\tthis.pollTimer = undefined;\n\t\t}\n\t}\n\n\thandleInput(data: string): void {\n\t\tif (this.killFeedback !== undefined) {\n\t\t\tthis.killFeedback = undefined;\n\t\t\tthis.killFeedbackTaskId = undefined;\n\t\t\tthis.tui.requestRender();\n\t\t}\n\t\tif (this.keybindings.matches(data, \"tui.select.cancel\")) {\n\t\t\tif (this.view === \"detail\") {\n\t\t\t\tthis.view = \"list\";\n\t\t\t\tthis.tui.requestRender();\n\t\t\t} else {\n\t\t\t\tthis.onClose();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (this.keybindings.matches(data, \"app.backgroundTasks.kill\")) {\n\t\t\tthis.killSelected();\n\t\t\treturn;\n\t\t}\n\t\tif (this.view === \"list\") this.handleListInput(data);\n\t\telse this.handleDetailInput(data);\n\t}\n\n\tprivate handleListInput(data: string): void {\n\t\tif (this.keybindings.matches(data, \"tui.select.up\")) {\n\t\t\tthis.moveSelection(-1);\n\t\t\treturn;\n\t\t}\n\t\tif (this.keybindings.matches(data, \"tui.select.down\")) {\n\t\t\tthis.moveSelection(1);\n\t\t\treturn;\n\t\t}\n\t\tif (this.keybindings.matches(data, \"tui.select.confirm\")) {\n\t\t\tif (!this.selectedTask()) return;\n\t\t\tthis.view = \"detail\";\n\t\t\tthis.resetFollow();\n\t\t\tthis.tui.requestRender();\n\t\t}\n\t}\n\n\tprivate handleDetailInput(data: string): void {\n\t\tif (this.keybindings.matches(data, \"tui.select.pageUp\")) {\n\t\t\tthis.scrollDetail(Math.max(1, this.detailBodyHeight()));\n\t\t\treturn;\n\t\t}\n\t\tif (this.keybindings.matches(data, \"tui.select.pageDown\")) {\n\t\t\tif (!this.follow) this.scrollDetail(-Math.max(1, this.detailBodyHeight()));\n\t\t\treturn;\n\t\t}\n\t\tif (this.keybindings.matches(data, \"tui.select.up\")) {\n\t\t\tthis.scrollDetail(1);\n\t\t\treturn;\n\t\t}\n\t\tif (this.keybindings.matches(data, \"tui.select.down\")) {\n\t\t\tif (!this.follow) this.scrollDetail(-1);\n\t\t}\n\t}\n\n\t/** Scroll the detail viewport by `lines` (positive = back through history). */\n\tprivate scrollDetail(lines: number): void {\n\t\tif (lines > 0) {\n\t\t\tconst max = this.maxTailOffset();\n\t\t\tif (max === 0) return; // Nothing above the viewport to scroll back to.\n\t\t\tthis.follow = false;\n\t\t\tthis.tailOffsetLines = Math.min(max, this.tailOffsetLines + lines);\n\t\t} else {\n\t\t\tif (this.follow) return;\n\t\t\tthis.tailOffsetLines = Math.max(0, this.tailOffsetLines + lines);\n\t\t\tif (this.tailOffsetLines === 0) {\n\t\t\t\tthis.follow = true;\n\t\t\t\tvoid this.refreshViewport();\n\t\t\t}\n\t\t}\n\t\tthis.tui.requestRender();\n\t}\n\n\trender(width: number): string[] {\n\t\tconst body = this.view === \"list\" ? this.renderList(width) : this.renderDetail(width);\n\t\tconst border = this.theme.fg(\"border\", \"─\".repeat(Math.max(1, width)));\n\t\treturn [border, ...body, padLine(this.footerLine(), width), border];\n\t}\n\n\t// ── list view ──────────────────────────────────────────────────────────\n\n\t/** Task rows the terminal can spare; short windows trade rows for the transcript. */\n\tprivate listMaxVisible(): number {\n\t\treturn Math.min(LIST_MAX_VISIBLE, Math.max(LIST_MIN_VISIBLE, this.tui.terminal.rows - LIST_RESERVED_ROWS));\n\t}\n\n\tprivate renderList(width: number): string[] {\n\t\tconst lines: string[] = [];\n\t\tconst counts = this.countsLabel();\n\t\tconst title = counts ? `Background tasks — ${counts}` : \"Background tasks\";\n\t\tlines.push(padLine(this.theme.fg(\"accent\", this.theme.bold(title)), width));\n\n\t\tif (this.tasks.length === 0) {\n\t\t\tlines.push(padLine(this.theme.fg(\"muted\", \" (no tasks)\"), width));\n\t\t\treturn lines;\n\t\t}\n\n\t\tconst selected = this.selectedTask();\n\t\tconst maxVisible = this.listMaxVisible();\n\t\tconst visible = this.tasks.slice(this.listScrollTop, this.listScrollTop + maxVisible);\n\t\tlet seenRunning = false;\n\t\tfor (const task of visible) {\n\t\t\t// listTasks() orders running first, finished after: one separator at the boundary.\n\t\t\tif (seenRunning && task.status !== \"running\") {\n\t\t\t\tlines.push(padLine(this.theme.fg(\"muted\", \" ── finished ──\"), width));\n\t\t\t\tseenRunning = false;\n\t\t\t}\n\t\t\tif (task.status === \"running\") seenRunning = true;\n\t\t\tlines.push(this.renderTaskRow(task, task === selected, width));\n\t\t}\n\t\tif (this.tasks.length > maxVisible) {\n\t\t\tconst index = this.tasks.findIndex((task) => task.id === this.selectedTaskId);\n\t\t\tlines.push(padLine(this.theme.fg(\"muted\", ` (${index + 1}/${this.tasks.length})`), width));\n\t\t}\n\t\treturn lines;\n\t}\n\n\tprivate renderTaskRow(task: BgTask, isSelected: boolean, width: number): string {\n\t\tconst duration = runtimeLabel(task);\n\t\tconst label = taskLabel(task);\n\t\tif (isSelected) {\n\t\t\t// Pad to full width before styling so the selection background spans the row.\n\t\t\tconst plain = padLine(`→ ${statusGlyph(task.status, task.stalled)} ${task.id} ${duration} ${label}`, width);\n\t\t\treturn this.theme.bg(\"selectedBg\", this.theme.fg(\"text\", plain));\n\t\t}\n\t\tconst glyph = this.theme.fg(statusColor(task.status, task.stalled), statusGlyph(task.status, task.stalled));\n\t\tconst id = this.theme.fg(\"accent\", task.id);\n\t\tconst rest = this.theme.fg(\"muted\", `${duration} ${label}`);\n\t\treturn padLine(` ${glyph} ${id} ${rest}`, width);\n\t}\n\n\tprivate countsLabel(): string {\n\t\tlet running = 0;\n\t\tfor (const task of this.tasks) if (task.status === \"running\") running++;\n\t\tconst ended = this.tasks.length - running;\n\t\tconst parts: string[] = [];\n\t\tif (running > 0) parts.push(`${running} running`);\n\t\tif (ended > 0) parts.push(`${ended} done`);\n\t\treturn parts.join(\" · \");\n\t}\n\n\t// ── detail view ────────────────────────────────────────────────────────\n\n\tprivate renderDetail(width: number): string[] {\n\t\tconst task = this.selectedTask();\n\t\tconst lines: string[] = [padLine(this.detailHeader(task), width)];\n\t\tconst height = this.detailBodyHeight();\n\t\tconst cache = task && this.tailCache?.taskId === task.id ? this.tailCache : undefined;\n\t\tif (cache?.error) {\n\t\t\tlines.push(padLine(this.theme.fg(\"error\", `Cannot read output: ${cache.error}`), width));\n\t\t\tfor (let row = 1; row < height; row++) lines.push(padLine(\"\", width));\n\t\t\treturn lines;\n\t\t}\n\t\tconst content = cache?.lines ?? [];\n\t\tconst fromEnd = this.follow ? 0 : this.tailOffsetLines;\n\t\tconst start = content.length - height - fromEnd;\n\t\tfor (let row = 0; row < height; row++) {\n\t\t\tconst line = content[start + row];\n\t\t\tlines.push(line === undefined ? padLine(\"\", width) : padLine(this.theme.fg(\"toolOutput\", line), width));\n\t\t}\n\t\treturn lines;\n\t}\n\n\tprivate detailHeader(task: BgTask | undefined): string {\n\t\tif (!task) return this.theme.fg(\"muted\", \"(no task selected)\");\n\t\tconst duration = runtimeLabel(task);\n\t\tconst exit = exitSuffix(task.exitCode, \" \");\n\t\tconst resumeLabel = keyLabel(\"tui.select.pageDown\", { keybindings: this.keybindings });\n\t\tconst paused = this.follow ? \"\" : resumeLabel ? ` — paused (${resumeLabel} to follow)` : \" — paused\";\n\t\tconst fileName = fileNameOf(task.outputPath);\n\t\tconst glyph = this.theme.fg(statusColor(task.status, task.stalled), statusGlyph(task.status, task.stalled));\n\t\tconst statusLabel = task.stalled ? \"running, waiting for input\" : task.status;\n\t\tconst header = `${task.id} · ${statusLabel}${exit} · ${duration} · ${formatSize(task.outputBytes)} · ${fileName}${paused}`;\n\t\treturn `${glyph} ${this.theme.fg(\"muted\", header)}`;\n\t}\n\n\tprivate detailBodyHeight(): number {\n\t\t// Inline component: keep the chat transcript visible above the menu.\n\t\treturn Math.min(20, Math.max(4, this.tui.terminal.rows - 8));\n\t}\n\n\t// ── shared behavior ────────────────────────────────────────────────────\n\n\tprivate footerLine(): string {\n\t\tif (this.killFeedback) return this.theme.fg(\"warning\", this.killFeedback);\n\t\tconst opts = { keybindings: this.keybindings };\n\t\tconst parts =\n\t\t\tthis.view === \"list\"\n\t\t\t\t? [\n\t\t\t\t\t\t`${keyLabel(\"tui.select.up\", opts)}/${keyLabel(\"tui.select.down\", opts)} select`,\n\t\t\t\t\t\t`${keyLabel(\"tui.select.confirm\", opts)} output`,\n\t\t\t\t\t\t`${keyLabel(\"app.backgroundTasks.kill\", opts)} kill`,\n\t\t\t\t\t\t`${keyLabel(\"tui.select.cancel\", opts)} close`,\n\t\t\t\t\t]\n\t\t\t\t: [\n\t\t\t\t\t\t`${keyLabel(\"tui.select.up\", opts)}/${keyLabel(\"tui.select.down\", opts)} scroll`,\n\t\t\t\t\t\t`${keyLabel(\"tui.select.pageUp\", opts)}/${keyLabel(\"tui.select.pageDown\", opts)} page`,\n\t\t\t\t\t\t`${keyLabel(\"app.backgroundTasks.kill\", opts)} kill`,\n\t\t\t\t\t\t`${keyLabel(\"tui.select.cancel\", opts)} back`,\n\t\t\t\t\t];\n\t\treturn this.theme.fg(\"dim\", parts.join(\" · \"));\n\t}\n\n\tprivate selectedTask(): BgTask | undefined {\n\t\treturn this.tasks.find((task) => task.id === this.selectedTaskId);\n\t}\n\n\tprivate moveSelection(offset: -1 | 1): void {\n\t\tif (this.tasks.length === 0) return;\n\t\tconst current = this.tasks.findIndex((task) => task.id === this.selectedTaskId);\n\t\tconst next = (current + offset + this.tasks.length) % this.tasks.length;\n\t\tconst task = this.tasks[next];\n\t\tif (!task) return;\n\t\tthis.selectedTaskId = task.id;\n\t\tif (next < this.listScrollTop) this.listScrollTop = next;\n\t\tif (next >= this.listScrollTop + this.listMaxVisible()) {\n\t\t\tthis.listScrollTop = next - this.listMaxVisible() + 1;\n\t\t}\n\t\tthis.resetFollow();\n\t\tthis.tui.requestRender();\n\t}\n\n\tprivate resetFollow(): void {\n\t\tthis.follow = true;\n\t\tthis.tailOffsetLines = 0;\n\t\tthis.tailCache = undefined;\n\t\tvoid this.refreshViewport();\n\t}\n\n\tprivate currentLines(): string[] {\n\t\tconst task = this.selectedTask();\n\t\tconst cache = this.tailCache;\n\t\treturn task && cache && cache.taskId === task.id ? cache.lines : [];\n\t}\n\n\tprivate maxTailOffset(): number {\n\t\treturn Math.max(0, this.currentLines().length - this.detailBodyHeight());\n\t}\n\n\tprivate killSelected(): void {\n\t\tconst task = this.selectedTask();\n\t\tif (!task) return;\n\t\tif (task.status !== \"running\") {\n\t\t\tthis.killFeedback = `${task.id} is not running`;\n\t\t\tthis.tui.requestRender();\n\t\t\treturn;\n\t\t}\n\t\tthis.host.killTask(task.id);\n\t\t// Terminal state lands on the next poll; the feedback expires with it (tick).\n\t\tthis.killFeedback = `stopping ${task.id}…`;\n\t\tthis.killFeedbackTaskId = task.id;\n\t\tthis.tui.requestRender();\n\t}\n\n\tprivate async tick(): Promise<void> {\n\t\tif (this.disposed) return;\n\t\tthis.tasks = this.host.listTasks();\n\t\tif (!this.selectedTask() && this.tasks[0]) this.selectedTaskId = this.tasks[0].id;\n\t\tthis.expireKillFeedback();\n\t\t// A pending re-read counts as a change: refreshViewport may skip this tick\n\t\t// (readBusy), and the signature alone would let that retry be dropped.\n\t\tconst needsRead = this.view === \"detail\" && this.follow && this.detailOutputChanged();\n\t\tif (!needsRead && this.renderSignature() === this.lastSignature) return; // Nothing visible changed.\n\t\tif (needsRead) await this.refreshViewport();\n\t\tthis.lastSignature = this.renderSignature();\n\t\tthis.tui.requestRender();\n\t}\n\n\t/** Drop \"stopping\" feedback once its task has settled. */\n\tprivate expireKillFeedback(): void {\n\t\tif (this.killFeedbackTaskId === undefined) return;\n\t\tconst task = this.tasks.find((candidate) => candidate.id === this.killFeedbackTaskId);\n\t\tif (!task || task.status !== \"running\") {\n\t\t\tthis.killFeedback = undefined;\n\t\t\tthis.killFeedbackTaskId = undefined;\n\t\t}\n\t}\n\n\t/** Everything the rendered output depends on; equal signatures need no redraw. */\n\tprivate renderSignature(): string {\n\t\tconst parts = [\n\t\t\tthis.view,\n\t\t\tthis.selectedTaskId ?? \"\",\n\t\t\tString(this.listScrollTop),\n\t\t\tString(this.follow),\n\t\t\tString(this.tailOffsetLines),\n\t\t\tthis.killFeedback ?? \"\",\n\t\t\tthis.tailCache\n\t\t\t\t? `${this.tailCache.taskId}:${this.tailCache.lines.length}:${this.tailCache.totalBytes}:${this.tailCache.error ?? \"\"}:${String(this.tailCache.settledRead ?? false)}`\n\t\t\t\t: \"\",\n\t\t];\n\t\tfor (const task of this.tasks) {\n\t\t\tconst duration = runtimeLabel(task);\n\t\t\tparts.push(\n\t\t\t\t`${task.id}:${task.status}:${String(task.stalled)}:${task.outputBytes}:${task.exitCode ?? \"\"}:${duration}`,\n\t\t\t);\n\t\t}\n\t\treturn parts.join(\"|\");\n\t}\n\n\t/** True when the detail viewport must re-read the output file this tick. */\n\tprivate detailOutputChanged(): boolean {\n\t\tconst task = this.selectedTask();\n\t\tif (!task) return false;\n\t\tconst cache = this.tailCache;\n\t\tif (!cache || cache.taskId !== task.id) return true;\n\t\tif (cache.error !== undefined) return true; // Keep retrying; failed reads are cheap.\n\t\tif (task.status !== \"running\") {\n\t\t\t// Terminal task: the file is final — read it once, then never again.\n\t\t\treturn cache.settledRead !== true;\n\t\t}\n\t\treturn cache.totalBytes !== task.outputBytes;\n\t}\n\n\tprivate async refreshViewport(): Promise<void> {\n\t\tif (this.readBusy) return;\n\t\tconst task = this.selectedTask();\n\t\tif (!task) return;\n\t\tthis.readBusy = true;\n\t\ttry {\n\t\t\tconst slice = await this.host.readSlice(task.outputPath, { mode: \"tail\", maxBytes: VIEW_TAIL_BYTES });\n\t\t\tif (this.disposed || this.selectedTaskId !== task.id || !this.follow) return;\n\t\t\tthis.tailCache = {\n\t\t\t\ttaskId: task.id,\n\t\t\t\tlines: toViewLines(slice.text),\n\t\t\t\ttotalBytes: slice.totalBytes,\n\t\t\t\tsettledRead: task.status !== \"running\",\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tif (this.disposed || this.selectedTaskId !== task.id) return;\n\t\t\tthis.tailCache = {\n\t\t\t\ttaskId: task.id,\n\t\t\t\tlines: [],\n\t\t\t\ttotalBytes: task.outputBytes,\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t};\n\t\t} finally {\n\t\t\tthis.readBusy = false;\n\t\t}\n\t}\n}\n\nfunction toViewLines(text: string): string[] {\n\t// Strip ANSI first: sanitize would remove the escape bytes alone, leaving\n\t// orphaned \"[31m\" fragments that strip can no longer see.\n\tconst lines = sanitizeBinaryOutput(stripTerminalSequences(text)).split(\"\\n\");\n\t// Drop the trailing empty line produced by a final newline, then bound the\n\t// window: a 128KB slice of one-byte lines must never become 128k rows.\n\twhile (lines.length > 0 && lines[lines.length - 1] === \"\") lines.pop();\n\treturn lines.slice(-MAX_VIEW_LINES);\n}\n"]}
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../src/extensions/background/manager.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * /bg task manager — an inline, /model-style menu that mounts in the editor\n * slot. Two views in one component: a task list, and a live output viewport\n * for the selected task (Enter to open, Esc to go back). The host dependency\n * is narrowed to three callbacks so the component stays testable.\n */\n\nimport { type Component, type Focusable, stripTerminalSequences, truncateToWidth } from \"@earendil-works/pi-tui\";\nimport type { KeybindingsManager } from \"../../core/keybindings.ts\";\nimport { formatSize } from \"../../core/tools/truncate.ts\";\nimport { keyLabel } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { sanitizeBinaryOutput } from \"../../utils/shell.ts\";\nimport type { OutputSlice } from \"./output-file.ts\";\nimport type { BgTask } from \"./registry.ts\";\nimport { exitSuffix, formatTaskCounts, runtimeLabel, statusColor, statusGlyph, taskLabel } from \"./task-view.ts\";\nimport { fileNameOf } from \"./text.ts\";\n\nconst POLL_INTERVAL_MS = 1000;\nconst VIEW_TAIL_BYTES = 128 * 1024;\nconst MAX_VIEW_LINES = 2000;\nconst LIST_MAX_VISIBLE = 10;\nconst LIST_MIN_VISIBLE = 3;\n/** Rows outside the task list itself (borders, title, counter, footer, padding). */\nconst LIST_RESERVED_ROWS = 14;\n\nexport interface BackgroundManagerHost {\n\tlistTasks(): BgTask[];\n\tkillTask(id: string): { killed: boolean };\n\treadSlice(filePath: string, options: { mode: \"tail\"; maxBytes: number }): Promise<OutputSlice>;\n}\n\ninterface MenuTui {\n\trequestRender(): void;\n\tterminal: { rows: number; columns: number };\n}\n\nexport interface BackgroundTasksMenuOptions {\n\ttui: MenuTui;\n\ttheme: Theme;\n\tkeybindings: Pick<KeybindingsManager, \"matches\" | \"getKeys\">;\n\thost: BackgroundManagerHost;\n\tonClose: () => void;\n\tpollIntervalMs?: number;\n}\n\ninterface TailCache {\n\ttaskId: string;\n\tlines: string[];\n\ttotalBytes: number;\n\t/** True once a terminal task's final output has been read; skips re-reads. */\n\tsettledRead?: boolean;\n\terror?: string;\n}\n\n/** Truncate to an exact visible width, padding short lines with spaces. */\nfunction padLine(line: string, width: number): string {\n\treturn truncateToWidth(line, width, \"…\", true);\n}\n\nexport class BackgroundTasksMenu implements Component, Focusable {\n\tprivate readonly tui: MenuTui;\n\tprivate readonly theme: Theme;\n\tprivate readonly keybindings: Pick<KeybindingsManager, \"matches\" | \"getKeys\">;\n\tprivate readonly host: BackgroundManagerHost;\n\tprivate readonly onClose: () => void;\n\tprivate readonly pollIntervalMs: number;\n\n\tprivate view: \"list\" | \"detail\" = \"list\";\n\tprivate tasks: BgTask[] = [];\n\tprivate selectedTaskId: string | undefined;\n\tprivate listScrollTop = 0;\n\tprivate follow = true;\n\tprivate tailOffsetLines = 0;\n\tprivate tailCache: TailCache | undefined;\n\tprivate killFeedback: string | undefined;\n\t/** Task whose settle expires killFeedback; undefined = persists until the next key. */\n\tprivate killFeedbackTaskId: string | undefined;\n\t/** Last tick's render signature; unchanged means nothing visible moved. */\n\tprivate lastSignature = \"\";\n\tprivate pollTimer: ReturnType<typeof setInterval> | undefined;\n\tprivate readBusy = false;\n\tprivate disposed = false;\n\tprivate _focused = false;\n\n\tconstructor(options: BackgroundTasksMenuOptions) {\n\t\tthis.tui = options.tui;\n\t\tthis.theme = options.theme;\n\t\tthis.keybindings = options.keybindings;\n\t\tthis.host = options.host;\n\t\tthis.onClose = options.onClose;\n\t\tthis.pollIntervalMs = options.pollIntervalMs ?? POLL_INTERVAL_MS;\n\n\t\tthis.tasks = this.host.listTasks();\n\t\tthis.selectedTaskId = this.tasks[0]?.id;\n\t\tvoid this.tick();\n\t\tthis.pollTimer = setInterval(() => void this.tick(), this.pollIntervalMs);\n\t\tthis.pollTimer.unref?.();\n\t}\n\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t}\n\n\tinvalidate(): void {\n\t\t// No cached render state; the poller drives refresh.\n\t}\n\n\tdispose(): void {\n\t\tthis.disposed = true;\n\t\tif (this.pollTimer !== undefined) {\n\t\t\tclearInterval(this.pollTimer);\n\t\t\tthis.pollTimer = undefined;\n\t\t}\n\t}\n\n\thandleInput(data: string): void {\n\t\tif (this.killFeedback !== undefined) {\n\t\t\tthis.killFeedback = undefined;\n\t\t\tthis.killFeedbackTaskId = undefined;\n\t\t\tthis.tui.requestRender();\n\t\t}\n\t\tif (this.keybindings.matches(data, \"tui.select.cancel\")) {\n\t\t\tif (this.view === \"detail\") {\n\t\t\t\tthis.view = \"list\";\n\t\t\t\tthis.tui.requestRender();\n\t\t\t} else {\n\t\t\t\tthis.onClose();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (this.keybindings.matches(data, \"app.backgroundTasks.kill\")) {\n\t\t\tthis.killSelected();\n\t\t\treturn;\n\t\t}\n\t\tif (this.view === \"list\") this.handleListInput(data);\n\t\telse this.handleDetailInput(data);\n\t}\n\n\tprivate handleListInput(data: string): void {\n\t\tif (this.keybindings.matches(data, \"tui.select.up\")) {\n\t\t\tthis.moveSelection(-1);\n\t\t\treturn;\n\t\t}\n\t\tif (this.keybindings.matches(data, \"tui.select.down\")) {\n\t\t\tthis.moveSelection(1);\n\t\t\treturn;\n\t\t}\n\t\tif (this.keybindings.matches(data, \"tui.select.confirm\")) {\n\t\t\tif (!this.selectedTask()) return;\n\t\t\tthis.view = \"detail\";\n\t\t\tthis.resetFollow();\n\t\t\tthis.tui.requestRender();\n\t\t}\n\t}\n\n\tprivate handleDetailInput(data: string): void {\n\t\tif (this.keybindings.matches(data, \"tui.select.pageUp\")) {\n\t\t\tthis.scrollDetail(Math.max(1, this.detailBodyHeight()));\n\t\t\treturn;\n\t\t}\n\t\tif (this.keybindings.matches(data, \"tui.select.pageDown\")) {\n\t\t\tif (!this.follow) this.scrollDetail(-Math.max(1, this.detailBodyHeight()));\n\t\t\treturn;\n\t\t}\n\t\tif (this.keybindings.matches(data, \"tui.select.up\")) {\n\t\t\tthis.scrollDetail(1);\n\t\t\treturn;\n\t\t}\n\t\tif (this.keybindings.matches(data, \"tui.select.down\")) {\n\t\t\tif (!this.follow) this.scrollDetail(-1);\n\t\t}\n\t}\n\n\t/** Scroll the detail viewport by `lines` (positive = back through history). */\n\tprivate scrollDetail(lines: number): void {\n\t\tif (lines > 0) {\n\t\t\tconst max = this.maxTailOffset();\n\t\t\tif (max === 0) return; // Nothing above the viewport to scroll back to.\n\t\t\tthis.follow = false;\n\t\t\tthis.tailOffsetLines = Math.min(max, this.tailOffsetLines + lines);\n\t\t} else {\n\t\t\tif (this.follow) return;\n\t\t\tthis.tailOffsetLines = Math.max(0, this.tailOffsetLines + lines);\n\t\t\tif (this.tailOffsetLines === 0) {\n\t\t\t\tthis.follow = true;\n\t\t\t\tvoid this.refreshViewport();\n\t\t\t}\n\t\t}\n\t\tthis.tui.requestRender();\n\t}\n\n\trender(width: number): string[] {\n\t\tconst body = this.view === \"list\" ? this.renderList(width) : this.renderDetail(width);\n\t\tconst border = this.theme.fg(\"border\", \"─\".repeat(Math.max(1, width)));\n\t\treturn [border, ...body, padLine(this.footerLine(), width), border];\n\t}\n\n\t// ── list view ──────────────────────────────────────────────────────────\n\n\t/** Task rows the terminal can spare; short windows trade rows for the transcript. */\n\tprivate listMaxVisible(): number {\n\t\treturn Math.min(LIST_MAX_VISIBLE, Math.max(LIST_MIN_VISIBLE, this.tui.terminal.rows - LIST_RESERVED_ROWS));\n\t}\n\n\tprivate renderList(width: number): string[] {\n\t\tconst lines: string[] = [];\n\t\tconst counts = this.countsLabel();\n\t\tconst title = counts ? `Background tasks — ${counts}` : \"Background tasks\";\n\t\tlines.push(padLine(this.theme.fg(\"accent\", this.theme.bold(title)), width));\n\n\t\tif (this.tasks.length === 0) {\n\t\t\tlines.push(padLine(this.theme.fg(\"muted\", \" (no tasks)\"), width));\n\t\t\treturn lines;\n\t\t}\n\n\t\tconst selected = this.selectedTask();\n\t\tconst maxVisible = this.listMaxVisible();\n\t\tconst visible = this.tasks.slice(this.listScrollTop, this.listScrollTop + maxVisible);\n\t\tlet seenRunning = false;\n\t\tfor (const task of visible) {\n\t\t\t// listTasks() orders running first, finished after: one separator at the boundary.\n\t\t\tif (seenRunning && task.status !== \"running\") {\n\t\t\t\tlines.push(padLine(this.theme.fg(\"muted\", \" ── finished ──\"), width));\n\t\t\t\tseenRunning = false;\n\t\t\t}\n\t\t\tif (task.status === \"running\") seenRunning = true;\n\t\t\tlines.push(this.renderTaskRow(task, task === selected, width));\n\t\t}\n\t\tif (this.tasks.length > maxVisible) {\n\t\t\tconst index = this.tasks.findIndex((task) => task.id === this.selectedTaskId);\n\t\t\tlines.push(padLine(this.theme.fg(\"muted\", ` (${index + 1}/${this.tasks.length})`), width));\n\t\t}\n\t\treturn lines;\n\t}\n\n\tprivate renderTaskRow(task: BgTask, isSelected: boolean, width: number): string {\n\t\tconst duration = runtimeLabel(task);\n\t\tconst label = taskLabel(task);\n\t\tif (isSelected) {\n\t\t\t// Pad to full width before styling so the selection background spans the row.\n\t\t\tconst plain = padLine(`→ ${statusGlyph(task.status, task.stalled)} ${task.id} ${duration} ${label}`, width);\n\t\t\treturn this.theme.bg(\"selectedBg\", this.theme.fg(\"text\", plain));\n\t\t}\n\t\tconst glyph = this.theme.fg(statusColor(task.status, task.stalled), statusGlyph(task.status, task.stalled));\n\t\tconst id = this.theme.fg(\"accent\", task.id);\n\t\tconst rest = this.theme.fg(\"muted\", `${duration} ${label}`);\n\t\treturn padLine(` ${glyph} ${id} ${rest}`, width);\n\t}\n\n\tprivate countsLabel(): string {\n\t\tlet running = 0;\n\t\tlet stalled = 0;\n\t\tfor (const task of this.tasks) {\n\t\t\tif (task.status === \"running\") running++;\n\t\t\tif (task.stalled) stalled++;\n\t\t}\n\t\treturn formatTaskCounts({ running, stalled, total: this.tasks.length }) ?? \"\";\n\t}\n\n\t// ── detail view ────────────────────────────────────────────────────────\n\n\tprivate renderDetail(width: number): string[] {\n\t\tconst task = this.selectedTask();\n\t\tconst lines: string[] = [padLine(this.detailHeader(task), width)];\n\t\tconst height = this.detailBodyHeight();\n\t\tconst cache = task && this.tailCache?.taskId === task.id ? this.tailCache : undefined;\n\t\tif (cache?.error) {\n\t\t\tlines.push(padLine(this.theme.fg(\"error\", `Cannot read output: ${cache.error}`), width));\n\t\t\tfor (let row = 1; row < height; row++) lines.push(padLine(\"\", width));\n\t\t\treturn lines;\n\t\t}\n\t\tconst content = cache?.lines ?? [];\n\t\tconst fromEnd = this.follow ? 0 : this.tailOffsetLines;\n\t\tconst start = content.length - height - fromEnd;\n\t\tfor (let row = 0; row < height; row++) {\n\t\t\tconst line = content[start + row];\n\t\t\tlines.push(line === undefined ? padLine(\"\", width) : padLine(this.theme.fg(\"toolOutput\", line), width));\n\t\t}\n\t\treturn lines;\n\t}\n\n\tprivate detailHeader(task: BgTask | undefined): string {\n\t\tif (!task) return this.theme.fg(\"muted\", \"(no task selected)\");\n\t\tconst duration = runtimeLabel(task);\n\t\tconst exit = exitSuffix(task.exitCode, \" \");\n\t\tconst resumeLabel = keyLabel(\"tui.select.pageDown\", { keybindings: this.keybindings });\n\t\tconst paused = this.follow ? \"\" : resumeLabel ? ` — paused (${resumeLabel} to follow)` : \" — paused\";\n\t\tconst fileName = fileNameOf(task.outputPath);\n\t\tconst glyph = this.theme.fg(statusColor(task.status, task.stalled), statusGlyph(task.status, task.stalled));\n\t\tconst statusLabel = task.stalled ? \"running, waiting for input\" : task.status;\n\t\tconst header = `${task.id} · ${statusLabel}${exit} · ${duration} · ${formatSize(task.outputBytes)} · ${fileName}${paused}`;\n\t\treturn `${glyph} ${this.theme.fg(\"muted\", header)}`;\n\t}\n\n\tprivate detailBodyHeight(): number {\n\t\t// Inline component: keep the chat transcript visible above the menu.\n\t\treturn Math.min(20, Math.max(4, this.tui.terminal.rows - 8));\n\t}\n\n\t// ── shared behavior ────────────────────────────────────────────────────\n\n\tprivate footerLine(): string {\n\t\tif (this.killFeedback) return this.theme.fg(\"warning\", this.killFeedback);\n\t\tconst opts = { keybindings: this.keybindings };\n\t\tconst parts =\n\t\t\tthis.view === \"list\"\n\t\t\t\t? [\n\t\t\t\t\t\t`${keyLabel(\"tui.select.up\", opts)}/${keyLabel(\"tui.select.down\", opts)} select`,\n\t\t\t\t\t\t`${keyLabel(\"tui.select.confirm\", opts)} output`,\n\t\t\t\t\t\t`${keyLabel(\"app.backgroundTasks.kill\", opts)} kill`,\n\t\t\t\t\t\t`${keyLabel(\"tui.select.cancel\", opts)} close`,\n\t\t\t\t\t]\n\t\t\t\t: [\n\t\t\t\t\t\t`${keyLabel(\"tui.select.up\", opts)}/${keyLabel(\"tui.select.down\", opts)} scroll`,\n\t\t\t\t\t\t`${keyLabel(\"tui.select.pageUp\", opts)}/${keyLabel(\"tui.select.pageDown\", opts)} page`,\n\t\t\t\t\t\t`${keyLabel(\"app.backgroundTasks.kill\", opts)} kill`,\n\t\t\t\t\t\t`${keyLabel(\"tui.select.cancel\", opts)} back`,\n\t\t\t\t\t];\n\t\treturn this.theme.fg(\"dim\", parts.join(\" · \"));\n\t}\n\n\tprivate selectedTask(): BgTask | undefined {\n\t\treturn this.tasks.find((task) => task.id === this.selectedTaskId);\n\t}\n\n\tprivate moveSelection(offset: -1 | 1): void {\n\t\tif (this.tasks.length === 0) return;\n\t\tconst current = this.tasks.findIndex((task) => task.id === this.selectedTaskId);\n\t\tconst next = (current + offset + this.tasks.length) % this.tasks.length;\n\t\tconst task = this.tasks[next];\n\t\tif (!task) return;\n\t\tthis.selectedTaskId = task.id;\n\t\tif (next < this.listScrollTop) this.listScrollTop = next;\n\t\tif (next >= this.listScrollTop + this.listMaxVisible()) {\n\t\t\tthis.listScrollTop = next - this.listMaxVisible() + 1;\n\t\t}\n\t\tthis.resetFollow();\n\t\tthis.tui.requestRender();\n\t}\n\n\tprivate resetFollow(): void {\n\t\tthis.follow = true;\n\t\tthis.tailOffsetLines = 0;\n\t\tthis.tailCache = undefined;\n\t\tvoid this.refreshViewport();\n\t}\n\n\tprivate currentLines(): string[] {\n\t\tconst task = this.selectedTask();\n\t\tconst cache = this.tailCache;\n\t\treturn task && cache && cache.taskId === task.id ? cache.lines : [];\n\t}\n\n\tprivate maxTailOffset(): number {\n\t\treturn Math.max(0, this.currentLines().length - this.detailBodyHeight());\n\t}\n\n\tprivate killSelected(): void {\n\t\tconst task = this.selectedTask();\n\t\tif (!task) return;\n\t\tif (task.status !== \"running\") {\n\t\t\tthis.killFeedback = `${task.id} is not running`;\n\t\t\tthis.tui.requestRender();\n\t\t\treturn;\n\t\t}\n\t\tthis.host.killTask(task.id);\n\t\t// Terminal state lands on the next poll; the feedback expires with it (tick).\n\t\tthis.killFeedback = `stopping ${task.id}…`;\n\t\tthis.killFeedbackTaskId = task.id;\n\t\tthis.tui.requestRender();\n\t}\n\n\tprivate async tick(): Promise<void> {\n\t\tif (this.disposed) return;\n\t\tthis.tasks = this.host.listTasks();\n\t\tif (!this.selectedTask() && this.tasks[0]) this.selectedTaskId = this.tasks[0].id;\n\t\tthis.expireKillFeedback();\n\t\t// A pending re-read counts as a change: refreshViewport may skip this tick\n\t\t// (readBusy), and the signature alone would let that retry be dropped.\n\t\tconst needsRead = this.view === \"detail\" && this.follow && this.detailOutputChanged();\n\t\tif (!needsRead && this.renderSignature() === this.lastSignature) return; // Nothing visible changed.\n\t\tif (needsRead) await this.refreshViewport();\n\t\tthis.lastSignature = this.renderSignature();\n\t\tthis.tui.requestRender();\n\t}\n\n\t/** Drop \"stopping\" feedback once its task has settled. */\n\tprivate expireKillFeedback(): void {\n\t\tif (this.killFeedbackTaskId === undefined) return;\n\t\tconst task = this.tasks.find((candidate) => candidate.id === this.killFeedbackTaskId);\n\t\tif (!task || task.status !== \"running\") {\n\t\t\tthis.killFeedback = undefined;\n\t\t\tthis.killFeedbackTaskId = undefined;\n\t\t}\n\t}\n\n\t/** Everything the rendered output depends on; equal signatures need no redraw. */\n\tprivate renderSignature(): string {\n\t\tconst parts = [\n\t\t\tthis.view,\n\t\t\tthis.selectedTaskId ?? \"\",\n\t\t\tString(this.listScrollTop),\n\t\t\tString(this.follow),\n\t\t\tString(this.tailOffsetLines),\n\t\t\tthis.killFeedback ?? \"\",\n\t\t\tthis.tailCache\n\t\t\t\t? `${this.tailCache.taskId}:${this.tailCache.lines.length}:${this.tailCache.totalBytes}:${this.tailCache.error ?? \"\"}:${String(this.tailCache.settledRead ?? false)}`\n\t\t\t\t: \"\",\n\t\t];\n\t\tfor (const task of this.tasks) {\n\t\t\tconst duration = runtimeLabel(task);\n\t\t\tparts.push(\n\t\t\t\t`${task.id}:${task.status}:${String(task.stalled)}:${task.outputBytes}:${task.exitCode ?? \"\"}:${duration}`,\n\t\t\t);\n\t\t}\n\t\treturn parts.join(\"|\");\n\t}\n\n\t/** True when the detail viewport must re-read the output file this tick. */\n\tprivate detailOutputChanged(): boolean {\n\t\tconst task = this.selectedTask();\n\t\tif (!task) return false;\n\t\tconst cache = this.tailCache;\n\t\tif (!cache || cache.taskId !== task.id) return true;\n\t\tif (cache.error !== undefined) return true; // Keep retrying; failed reads are cheap.\n\t\tif (task.status !== \"running\") {\n\t\t\t// Terminal task: the file is final — read it once, then never again.\n\t\t\treturn cache.settledRead !== true;\n\t\t}\n\t\treturn cache.totalBytes !== task.outputBytes;\n\t}\n\n\tprivate async refreshViewport(): Promise<void> {\n\t\tif (this.readBusy) return;\n\t\tconst task = this.selectedTask();\n\t\tif (!task) return;\n\t\tthis.readBusy = true;\n\t\ttry {\n\t\t\tconst slice = await this.host.readSlice(task.outputPath, { mode: \"tail\", maxBytes: VIEW_TAIL_BYTES });\n\t\t\tif (this.disposed || this.selectedTaskId !== task.id || !this.follow) return;\n\t\t\tthis.tailCache = {\n\t\t\t\ttaskId: task.id,\n\t\t\t\tlines: toViewLines(slice.text),\n\t\t\t\ttotalBytes: slice.totalBytes,\n\t\t\t\tsettledRead: task.status !== \"running\",\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tif (this.disposed || this.selectedTaskId !== task.id) return;\n\t\t\tthis.tailCache = {\n\t\t\t\ttaskId: task.id,\n\t\t\t\tlines: [],\n\t\t\t\ttotalBytes: task.outputBytes,\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t};\n\t\t} finally {\n\t\t\tthis.readBusy = false;\n\t\t}\n\t}\n}\n\nfunction toViewLines(text: string): string[] {\n\t// Strip ANSI first: sanitize would remove the escape bytes alone, leaving\n\t// orphaned \"[31m\" fragments that strip can no longer see.\n\tconst lines = sanitizeBinaryOutput(stripTerminalSequences(text)).split(\"\\n\");\n\t// Drop the trailing empty line produced by a final newline, then bound the\n\t// window: a 128KB slice of one-byte lines must never become 128k rows.\n\twhile (lines.length > 0 && lines[lines.length - 1] === \"\") lines.pop();\n\treturn lines.slice(-MAX_VIEW_LINES);\n}\n"]}
@@ -92,6 +92,8 @@ export interface BackgroundRegistryOptions {
92
92
  /** Called whenever a task starts or reaches a terminal state. */
93
93
  onChange: () => void;
94
94
  now?: () => number;
95
+ /** Test hook for deterministic collision coverage. */
96
+ createTaskId?: () => string;
95
97
  }
96
98
  export type ResolveTaskResult = {
97
99
  ok: true;
@@ -114,6 +116,7 @@ export declare class BackgroundTaskRegistry {
114
116
  private readonly stallTailBytes;
115
117
  private readonly onChange;
116
118
  private readonly now;
119
+ private readonly createTaskId;
117
120
  private readonly tasks;
118
121
  private readonly runtimes;
119
122
  private shuttingDown;
@@ -175,7 +178,7 @@ export declare class BackgroundTaskRegistry {
175
178
  private probeStallTail;
176
179
  /** The one place a notification payload is shaped, for either kind. */
177
180
  private emit;
178
- private newTaskId;
181
+ private allocateTaskOutput;
179
182
  private run;
180
183
  private handleData;
181
184
  private finalize;
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/extensions/background/registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/extensions/background/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG/D,OAAO,EAA+B,KAAK,WAAW,EAAY,MAAM,kBAAkB,CAAC;AAG3F,eAAO,MAAM,wBAAwB,QAAmB,CAAC;AACzD,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAC3C,eAAO,MAAM,yBAAyB,QAAW,CAAC;AAKlD,sEAAsE;AACtE,eAAO,MAAM,sBAAsB,OAAQ,CAAC;AAC5C,eAAO,MAAM,kBAAkB,QAAS,CAAC;AACzC,eAAO,MAAM,gBAAgB,OAAQ,CAAC;AAkBtC,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGrD;AAED,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAErF,MAAM,WAAW,MAAM;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,wFAAwF;IACxF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,OAAO,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,eAAe,EAAE,OAAO,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yFAAyF;IACzF,QAAQ,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,IAAI,EAAE,WAAW,GAAG,SAAS,CAAC;IAC9B,gFAAgF;IAChF,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,iFAAiF;AACjF,MAAM,MAAM,WAAW,GAAG;IAAE,OAAO,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvG,MAAM,WAAW,yBAAyB;IACzC,UAAU,EAAE,cAAc,CAAC;IAC3B,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2FAA2F;IAC3F,QAAQ,EAAE,CAAC,YAAY,EAAE,cAAc,KAAK,IAAI,CAAC;IACjD;;;OAGG;IACH,KAAK,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,KAAK,CAAC;IACtF,iEAAiE;IACjE,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,sDAAsD;IACtD,YAAY,CAAC,EAAE,MAAM,MAAM,CAAC;CAC5B;AAoBD,MAAM,MAAM,iBAAiB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAE1E,qBAAa,sBAAsB;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAiB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyC;IAClE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAU;IACvC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAC7C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAa;IACtC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAE5C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA6B;IACnD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;IAC3D,OAAO,CAAC,YAAY,CAAS;gBAEjB,OAAO,EAAE,yBAAyB;IAiB9C,IAAI,cAAc,IAAI,OAAO,CAE5B;IAED,SAAS,CAAC,KAAK,EAAE;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;QACZ,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;KACxB,GAAG,MAAM;IA6DV,8EAA8E;IAC9E,SAAS,IAAI,MAAM,EAAE;IASrB,iFAAiF;IACjF,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB;IAchD;;;;OAIG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE;IAUzC,MAAM,IAAI,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAU3E,gFAAgF;IAC1E,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAO9C;;;;;;;;;;;;OAYG;IACG,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IA2C9F;;;OAGG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAsB/B;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,UAAU;YAiBJ,cAAc;IAyB5B,uEAAuE;IACvE,OAAO,CAAC,IAAI;IAcZ,OAAO,CAAC,kBAAkB;YAkBZ,GAAG;IAgBjB,OAAO,CAAC,UAAU;YAmBJ,QAAQ;IAmCtB,OAAO,CAAC,eAAe;YA4BT,gBAAgB;CAM9B"}
@@ -22,6 +22,7 @@ export const DEFAULT_MAX_OUTPUT_BYTES = 20 * 1024 * 1024;
22
22
  export const DEFAULT_MAX_RUNNING_TASKS = 8;
23
23
  export const DEFAULT_NOTIFY_TAIL_BYTES = 4 * 1024;
24
24
  const SHUTDOWN_GRACE_MS = 2_000;
25
+ const TASK_ID_ALLOCATION_ATTEMPTS = 100;
25
26
  /** Stall watchdog defaults, matching Claude Code's CC-1175 tuning. */
26
27
  export const STALL_POLL_INTERVAL_MS = 5_000;
27
28
  export const STALL_THRESHOLD_MS = 45_000;
@@ -63,6 +64,7 @@ export class BackgroundTaskRegistry {
63
64
  this.stallTailBytes = stall?.tailBytes ?? STALL_TAIL_BYTES;
64
65
  this.onChange = options.onChange;
65
66
  this.now = options.now ?? Date.now;
67
+ this.createTaskId = options.createTaskId ?? (() => `bg-${randomBytes(3).toString("hex")}`);
66
68
  }
67
69
  get isShuttingDown() {
68
70
  return this.shuttingDown;
@@ -76,7 +78,7 @@ export class BackgroundTaskRegistry {
76
78
  const list = running.map((task) => ` ${task.id} ${firstCommandLine(task.command)}`).join("\n");
77
79
  throw new Error(`Too many running background tasks (limit ${this.maxRunningTasks}). Kill one first (bg action kill):\n${list}`);
78
80
  }
79
- const id = this.newTaskId();
81
+ const { id, outputPath } = this.allocateTaskOutput();
80
82
  const task = {
81
83
  id,
82
84
  command: input.command,
@@ -85,7 +87,7 @@ export class BackgroundTaskRegistry {
85
87
  status: "running",
86
88
  startedAt: this.now(),
87
89
  exitCode: undefined,
88
- outputPath: join(this.outputDir, `pi-${id}.log`),
90
+ outputPath,
89
91
  outputBytes: 0,
90
92
  outputTruncated: false,
91
93
  timeoutSeconds: input.timeoutSeconds,
@@ -96,11 +98,6 @@ export class BackgroundTaskRegistry {
96
98
  const done = new Promise((resolve) => {
97
99
  resolveDone = resolve;
98
100
  });
99
- // Create the file synchronously so read/wait and the /bg viewer never see
100
- // ENOENT between task start and the stream's async open. The exclusive
101
- // 'wx' flag fails on any existing path — including a symlink — so creation
102
- // can never truncate a file a stale id (or an attacker-planted link) points at.
103
- createOutputFileExclusively(task.outputPath);
104
101
  const runtime = {
105
102
  controller: new AbortController(),
106
103
  stream: createWriteStream(task.outputPath, { flags: "a" }),
@@ -318,11 +315,14 @@ export class BackgroundTaskRegistry {
318
315
  const { slice, error } = await readTail(task.outputPath, this.stallTailBytes);
319
316
  if (runtime.finalized || this.shuttingDown)
320
317
  return;
321
- // Merely slow: not prompt-shaped. Reset so the next check is a full
322
- // threshold window out instead of re-probing on every tick. A tail that
323
- // could not be read is reported, not dismissed as slow. Matched on the
324
- // raw text — sanitizing is for delivery, not for detection.
325
- if (slice && !looksLikePrompt(slice.text)) {
318
+ // A read failure is not evidence of an interactive prompt. Retry after a
319
+ // full threshold window without changing task state or notifying. Detection
320
+ // uses raw text; sanitizing is only for delivery.
321
+ if (error) {
322
+ runtime.stallLastGrowthAt = this.now();
323
+ return;
324
+ }
325
+ if (!slice || !looksLikePrompt(slice.text)) {
326
326
  runtime.stallLastGrowthAt = this.now();
327
327
  return;
328
328
  }
@@ -350,12 +350,25 @@ export class BackgroundTaskRegistry {
350
350
  // there is no retry path, so the delivery record stands.
351
351
  }
352
352
  }
353
- newTaskId() {
354
- while (true) {
355
- const id = `bg-${randomBytes(3).toString("hex")}`;
356
- if (!this.tasks.has(id))
357
- return id;
353
+ allocateTaskOutput() {
354
+ for (let attempt = 0; attempt < TASK_ID_ALLOCATION_ATTEMPTS; attempt++) {
355
+ const id = this.createTaskId();
356
+ if (this.tasks.has(id))
357
+ continue;
358
+ const outputPath = join(this.outputDir, `pi-${id}.log`);
359
+ try {
360
+ // Create synchronously before returning the task so read/wait and /bg
361
+ // never see ENOENT. `wx` also protects stale logs and symlinks.
362
+ createOutputFileExclusively(outputPath);
363
+ return { id, outputPath };
364
+ }
365
+ catch (error) {
366
+ if (error.code === "EEXIST")
367
+ continue;
368
+ throw error;
369
+ }
358
370
  }
371
+ throw new Error(`Could not allocate a unique background task id after ${TASK_ID_ALLOCATION_ATTEMPTS} attempts.`);
359
372
  }
360
373
  async run(task, runtime, env) {
361
374
  let outcome;
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/extensions/background/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAoB,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,2BAA2B,EAAoB,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC3F,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AACzD,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC;AAC3C,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,GAAG,IAAI,CAAC;AAElD,MAAM,iBAAiB,GAAG,KAAK,CAAC;AAEhC,sEAAsE;AACtE,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,CAAC;AAC5C,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AACzC,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAEtC;;;;;GAKG;AACH,MAAM,qBAAqB,GAAa;IACvC,WAAW,EAAE,eAAe;IAC5B,WAAW,EAAE,eAAe;IAC5B,cAAc;IACd,gEAAgE,EAAE,qBAAqB;IACvF,wBAAwB;IACxB,aAAa;IACb,cAAc;CACd,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,IAAY;IAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;IACxD,OAAO,qBAAqB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AACxE,CAAC;AA4FD,MAAM,OAAO,sBAAsB;IAkBlC,YAAY,OAAkC;QAJ7B,UAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;QAClC,aAAQ,GAAG,IAAI,GAAG,EAAuB,CAAC;QACnD,iBAAY,GAAG,KAAK,CAAC;QAG5B,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QACrC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,MAAM,EAAE,CAAC;QAC/C,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,wBAAwB,CAAC;QACzE,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,yBAAyB,CAAC;QAC5E,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,yBAAyB,CAAC;QAC5E,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;QAClE,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,KAAK,KAAK,KAAK,CAAC;QAC5C,IAAI,CAAC,mBAAmB,GAAG,KAAK,EAAE,cAAc,IAAI,sBAAsB,CAAC;QAC3E,IAAI,CAAC,gBAAgB,GAAG,KAAK,EAAE,WAAW,IAAI,kBAAkB,CAAC;QACjE,IAAI,CAAC,cAAc,GAAG,KAAK,EAAE,SAAS,IAAI,gBAAgB,CAAC;QAC3D,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACpC,CAAC;IAED,IAAI,cAAc;QACjB,OAAO,IAAI,CAAC,YAAY,CAAC;IAC1B,CAAC;IAED,SAAS,CAAC,KAMT;QACA,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACtE,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;QAC7E,IAAI,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YAC5C,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,CAAC,EAAE,KAAK,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjG,MAAM,IAAI,KAAK,CACd,4CAA4C,IAAI,CAAC,eAAe,wCAAwC,IAAI,EAAE,CAC9G,CAAC;QACH,CAAC;QAED,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAW;YACpB,EAAE;YACF,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,MAAM,EAAE,SAAS;YACjB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,QAAQ,EAAE,SAAS;YACnB,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC;YAChD,WAAW,EAAE,CAAC;YACd,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,KAAK;SACd,CAAC;QAEF,IAAI,WAAwB,CAAC;QAC7B,MAAM,IAAI,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YAC1C,WAAW,GAAG,OAAO,CAAC;QACvB,CAAC,CAAC,CAAC;QACH,0EAA0E;QAC1E,uEAAuE;QACvE,2EAA2E;QAC3E,gFAAgF;QAChF,2BAA2B,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC7C,MAAM,OAAO,GAAgB;YAC5B,UAAU,EAAE,IAAI,eAAe,EAAE;YACjC,MAAM,EAAE,iBAAiB,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;YAC1D,aAAa,EAAE,KAAK;YACpB,QAAQ,EAAE,KAAK;YACf,SAAS,EAAE,KAAK;YAChB,OAAO,EAAE,CAAC;YACV,UAAU,EAAE,SAAS;YACrB,aAAa,EAAE,CAAC;YAChB,iBAAiB,EAAE,IAAI,CAAC,GAAG,EAAE;YAC7B,aAAa,EAAE,KAAK;YACpB,IAAI;YACJ,WAAW;SACX,CAAC;QACF,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YACpC,IAAI,OAAO,CAAC,SAAS;gBAAE,OAAO;YAC9B,OAAO,CAAC,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC;YACpC,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QACzB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC/B,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACrC,KAAK,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QACxC,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,8EAA8E;IAC9E,SAAS;QACR,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QACrC,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;QAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;QAC9D,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;QAC9E,OAAO,CAAC,GAAG,OAAO,EAAE,GAAG,KAAK,CAAC,CAAC;IAC/B,CAAC;IAED,iFAAiF;IACjF,WAAW,CAAC,QAAgB;QAC3B,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;QACvE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC;QACvE,IAAI,KAAK;YAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QAC5C,MAAM,UAAU,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CACjD,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,MAAM,EAAE,CAAC,CAC1E,CAAC;QACF,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK;YAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QACvE,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;QACvF,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC;IACvD,CAAC;IAED;;;;OAIG;IACH,QAAQ,CAAC,EAAU;QAClB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACtC,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;QAChD,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,OAAO,CAAC,SAAS;YAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;QAC7E,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;QAC7B,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QAC3B,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACzB,CAAC;IAED,MAAM;QACL,MAAM,MAAM,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;QACpG,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACtB,MAAM,CAAC,KAAK,EAAE,CAAC;YACf,IAAI,IAAI,CAAC,OAAO;gBAAE,MAAM,CAAC,OAAO,EAAE,CAAC;QACpC,CAAC;QACD,OAAO,MAAM,CAAC;IACf,CAAC;IAED,gFAAgF;IAChF,KAAK,CAAC,WAAW,CAAC,EAAU;QAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,EAAE,EAAE,CAAC,CAAC;QAC7D,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC;QAClC,OAAO,IAAI,CAAC;IACb,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,aAAa,CAAC,EAAU,EAAE,SAAiB,EAAE,MAAoB;QACtE,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,EAAE,EAAE,CAAC,CAAC;QAC7D,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACtC,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,EAAE,EAAE,CAAC,CAAC;QAChE,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;YAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;QAEpE,OAAO,CAAC,OAAO,EAAE,CAAC;QAClB,IAAI,KAAgD,CAAC;QACrD,qEAAqE;QACrE,oEAAoE;QACpE,IAAI,OAAiC,CAAC;QACtC,IAAI,CAAC;YACJ,MAAM,QAAQ,GAAG,MAAM,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;gBACvD,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;gBACnD,KAAK,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;gBAC7C,OAAO,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBAC9B,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5D,CAAC,CAAC,CAAC;YACH,IAAI,MAAM,EAAE,OAAO;gBAAE,MAAM,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;YAChD,qEAAqE;YACrE,mEAAmE;YACnE,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC5C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;gBACrB,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;YACtC,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QACrC,CAAC;gBAAS,CAAC;YACV,OAAO,CAAC,OAAO,EAAE,CAAC;YAClB,uEAAuE;YACvE,qEAAqE;YACrE,qEAAqE;YACrE,mEAAmE;YACnE,wEAAwE;YACxE,kCAAkC;YAClC,IAAI,OAAO,CAAC,OAAO,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAC1E,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;YACnC,CAAC;YACD,IAAI,KAAK,KAAK,SAAS;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;YAC7C,IAAI,OAAO,KAAK,SAAS;gBAAE,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC1E,CAAC;IACF,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,QAAQ;QACb,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,MAAM,OAAO,GAAoB,EAAE,CAAC;QACpC,KAAK,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAChC,IAAI,IAAI,EAAE,MAAM,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;gBACtD,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;gBAC7B,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;YAC5B,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;QACD,IAAI,KAAgD,CAAC;QACrD,MAAM,KAAK,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YAC3C,KAAK,GAAG,UAAU,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;QACH,IAAI,CAAC;YACJ,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;QAChF,CAAC;gBAAS,CAAC;YACV,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACK,gBAAgB,CAAC,IAAY,EAAE,OAAoB;QAC1D,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO;QAC/B,OAAO,CAAC,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACjG,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,CAAC;IAC9B,CAAC;IAEO,kBAAkB,CAAC,OAAoB;QAC9C,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACtC,aAAa,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YAClC,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;QAChC,CAAC;IACF,CAAC;IAEO,UAAU,CAAC,IAAY,EAAE,OAAoB;QACpD,IAAI,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,YAAY;YAAE,OAAO;QACnD,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC;QAC9B,IAAI,IAAI,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;YAClC,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;YAC7B,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBAClB,gEAAgE;gBAChE,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;gBACrB,IAAI,CAAC,QAAQ,EAAE,CAAC;YACjB,CAAC;YACD,OAAO;QACR,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,gBAAgB;YAAE,OAAO;QAC3E,KAAK,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,IAAY,EAAE,OAAoB;QAC9D,yEAAyE;QACzE,IAAI,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,YAAY;YAAE,OAAO;QACnD,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;QAC9E,IAAI,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,YAAY;YAAE,OAAO;QACnD,oEAAoE;QACpE,wEAAwE;QACxE,uEAAuE;QACvE,4DAA4D;QAC5D,IAAI,KAAK,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3C,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvC,OAAO;QACR,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACnB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,IAAI,CAAC,QAAQ,EAAE,CAAC;QACjB,CAAC;QACD,IAAI,OAAO,CAAC,aAAa;YAAE,OAAO;QAClC,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;QAC7B,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IACxC,CAAC;IAED,uEAAuE;IAC/D,IAAI,CAAC,IAA4B,EAAE,IAAY,EAAE,KAA8B,EAAE,SAAkB;QAC1G,IAAI,CAAC;YACJ,IAAI,CAAC,QAAQ,CAAC;gBACb,IAAI;gBACJ,IAAI;gBACJ,IAAI,EAAE,KAAK,IAAI,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;gBACnE,SAAS;aACT,CAAC,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACR,6EAA6E;YAC7E,yDAAyD;QAC1D,CAAC;IACF,CAAC;IAEO,SAAS;QAChB,OAAO,IAAI,EAAE,CAAC;YACb,MAAM,EAAE,GAAG,MAAM,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAClD,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,OAAO,EAAE,CAAC;QACpC,CAAC;IACF,CAAC;IAEO,KAAK,CAAC,GAAG,CAAC,IAAY,EAAE,OAAoB,EAAE,GAAuB;QAC5E,IAAI,OAAsD,CAAC;QAC3D,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE;gBACjE,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC;gBACtD,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,MAAM;gBACjC,OAAO,EAAE,IAAI,CAAC,cAAc;gBAC5B,GAAG;aACH,CAAC,CAAC;YACH,OAAO,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;QACzC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,OAAO,GAAG,EAAE,KAAK,EAAE,CAAC;QACrB,CAAC;QACD,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;IAEO,UAAU,CAAC,IAAY,EAAE,OAAoB,EAAE,IAAY;QAClE,IAAI,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS;YAAE,OAAO;QACvF,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC;QAC5C,IAAI,IAAI,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC3B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YACxB,OAAO;QACR,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,WAAW,CAAC;QACtD,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;YAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;YAC/C,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,cAAc,CAAC;QACxC,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,2BAA2B,CAAC,CAAC;QACpG,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC5B,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;QACxB,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IAC5B,CAAC;IAEO,KAAK,CAAC,QAAQ,CACrB,IAAY,EACZ,OAAoB,EACpB,OAAsD;QAEtD,IAAI,OAAO,CAAC,SAAS;YAAE,OAAO;QAC9B,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;QACjC,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QAErB,qEAAqE;QACrE,4DAA4D;QAC5D,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YACnC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAC9B,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;gBACtB,OAAO,EAAE,CAAC;gBACV,OAAO;YACR,CAAC;YACD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC5B,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACvD,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;YAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC5D,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC1B,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,2EAA2E;QAC3E,kEAAkE;QAClE,6DAA6D;QAC7D,IAAI,OAAO,CAAC,OAAO,KAAK,CAAC;YAAE,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAC7D,OAAO,CAAC,WAAW,EAAE,CAAC;IACvB,CAAC;IAEO,eAAe,CACtB,OAAoB,EACpB,OAAsD;QAEtD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACtB,OAAO;gBACN,MAAM,EAAE,QAAQ;gBAChB,KAAK,EAAE,uBAAuB,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,8BAA8B;aAC3F,CAAC;QACH,CAAC;QACD,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;YACvC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,sBAAsB,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;QACjF,CAAC;QACD,IAAI,OAAO,CAAC,aAAa;YAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;QACvD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC5B,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC5B,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;gBAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;YAC7D,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC1C,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,mBAAmB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACpG,CAAC;YACD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;QACnD,CAAC;QACD,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3E,IAAI,OAAO,CAAC,QAAQ,KAAK,CAAC;YAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;QAC3D,IAAI,OAAO,CAAC,QAAQ,KAAK,IAAI;YAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,qCAAqC,EAAE,CAAC;QACzG,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,4BAA4B,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;IACpF,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAAC,IAAY;QAC1C,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC/C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;QAC/E,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IAC7C,CAAC;CACD","sourcesContent":["/**\n * Background task registry: process lifecycle, output capture, completion\n * notification. Pure logic — no UI imports, dependencies injected for tests.\n *\n * Discipline (mirrors the reference implementation this extension distills):\n * - Output streams straight to a file; memory holds only a byte counter.\n * - Finalization is idempotent and strictly ordered: flush stream, set\n * terminal state, then notify. A notification is only sent once the output\n * file holds the complete truth.\n * - Kill goes through AbortController; the shared bash operations kill the\n * whole process tree cross-platform.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport { createWriteStream, type WriteStream } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { BashOperations } from \"../../core/tools/bash.ts\";\nimport { formatSize } from \"../../core/tools/truncate.ts\";\nimport { sanitizeBinaryOutput } from \"../../utils/shell.ts\";\nimport { createOutputFileExclusively, type OutputSlice, readTail } from \"./output-file.ts\";\nimport { firstCommandLine } from \"./text.ts\";\n\nexport const DEFAULT_MAX_OUTPUT_BYTES = 20 * 1024 * 1024;\nexport const DEFAULT_MAX_RUNNING_TASKS = 8;\nexport const DEFAULT_NOTIFY_TAIL_BYTES = 4 * 1024;\n\nconst SHUTDOWN_GRACE_MS = 2_000;\n\n/** Stall watchdog defaults, matching Claude Code's CC-1175 tuning. */\nexport const STALL_POLL_INTERVAL_MS = 5_000;\nexport const STALL_THRESHOLD_MS = 45_000;\nexport const STALL_TAIL_BYTES = 1_024;\n\n/**\n * Last-line patterns that suggest a command is blocked waiting for keyboard\n * input. Used to gate the stall notification: a task that is merely slow\n * (git log -S, long silent builds) stays silent — only a tail that looks like\n * a prompt the model can act on triggers a notification.\n */\nconst STALL_PROMPT_PATTERNS: RegExp[] = [\n\t/\\(y\\/n\\)/i, // (Y/n), (y/N)\n\t/\\[y\\/n\\]/i, // [Y/n], [y/N]\n\t/\\(yes\\/no\\)/i,\n\t/\\b(?:Do you|Would you|Shall I|Are you sure|Ready to)\\b.*\\? *$/i, // directed questions\n\t/Press (any key|Enter)/i,\n\t/Continue\\?/i,\n\t/Overwrite\\?/i,\n];\n\nexport function looksLikePrompt(tail: string): boolean {\n\tconst lastLine = tail.trimEnd().split(\"\\n\").pop() ?? \"\";\n\treturn STALL_PROMPT_PATTERNS.some((pattern) => pattern.test(lastLine));\n}\n\nexport type BgTaskStatus = \"running\" | \"completed\" | \"failed\" | \"killed\" | \"timeout\";\n\nexport interface BgTask {\n\tid: string;\n\tcommand: string;\n\t/** Optional model-provided label (e.g. \"dev server\") shown in /bg and notifications. */\n\tdescription?: string;\n\tcwd: string;\n\tstatus: BgTaskStatus;\n\tstartedAt: number;\n\tendedAt?: number;\n\t/** True when the stall watchdog flagged this task as waiting for input. */\n\tstalled: boolean;\n\t/**\n\t * Process exit code; null when reaped by a signal, undefined while running\n\t * or when the run produced none (spawn failure, kill, timeout).\n\t */\n\texitCode: number | null | undefined;\n\toutputPath: string;\n\t/** Bytes accepted into the output file (excludes the overflow notice). */\n\toutputBytes: number;\n\t/** True when output hit the byte limit and the task was killed for it. */\n\toutputTruncated: boolean;\n\terror?: string;\n\ttimeoutSeconds?: number;\n\t/** Delivery happened: a notification was sent, or a waiter returned this task inline. */\n\tnotified: boolean;\n}\n\n/**\n * What a settled or stalled task hands to the extension for delivery.\n *\n * One shape with one discriminant, because both are delivered the same way and\n * carry the same payload; only the registry cares about the difference (a\n * completion participates in the delivery claim, a stall is informational and\n * bypasses it).\n */\nexport interface BgNotification {\n\tkind: \"completion\" | \"stall\";\n\ttask: BgTask;\n\t/** Sanitized tail of the output file; absent when it could not be read. */\n\ttail: OutputSlice | undefined;\n\t/** Set when the output file could not be read; the notification still fires. */\n\ttailError?: string;\n}\n\n/** Outcome of a bounded wait: terminal delivery, or the wait window expiring. */\nexport type WaitOutcome = { outcome: \"terminal\"; task: BgTask } | { outcome: \"timeout\"; task: BgTask };\n\nexport interface BackgroundRegistryOptions {\n\toperations: BashOperations;\n\t/** Directory for task output files. Defaults to the system temp directory. */\n\toutputDir?: string;\n\tmaxOutputBytes?: number;\n\tmaxRunningTasks?: number;\n\tnotifyTailBytes?: number;\n\t/** Called at most once per task per kind; synchronous throws do not prevent settlement. */\n\tonNotify: (notification: BgNotification) => void;\n\t/**\n\t * Stall watchdog tuning; `false` disables the watchdog outright. Defaults\n\t * follow Claude Code's CC-1175 (5s/45s/1KB).\n\t */\n\tstall?: { pollIntervalMs?: number; thresholdMs?: number; tailBytes?: number } | false;\n\t/** Called whenever a task starts or reaches a terminal state. */\n\tonChange: () => void;\n\tnow?: () => number;\n}\n\ninterface TaskRuntime {\n\tcontroller: AbortController;\n\tstream: WriteStream;\n\tkillRequested: boolean;\n\toverflow: boolean;\n\tstreamError?: string;\n\tfinalized: boolean;\n\t/** Live waitForResult callers; the last one out sends the followUp if none delivered. */\n\twaiters: number;\n\tstallTimer: ReturnType<typeof setInterval> | undefined;\n\tstallLastSize: number;\n\tstallLastGrowthAt: number;\n\t/** One-shot latch: the stall notification fires at most once per task. */\n\tstallNotified: boolean;\n\tdone: Promise<void>;\n\tresolveDone: () => void;\n}\n\nexport type ResolveTaskResult =\n\t| { ok: true; task: BgTask }\n\t| { ok: false; reason: \"not-found\" | \"ambiguous\"; candidates: BgTask[] };\n\nexport class BackgroundTaskRegistry {\n\tprivate readonly operations: BashOperations;\n\tprivate readonly outputDir: string;\n\tprivate readonly maxOutputBytes: number;\n\tprivate readonly maxRunningTasks: number;\n\tprivate readonly notifyTailBytes: number;\n\tprivate readonly onNotify: (notification: BgNotification) => void;\n\tprivate readonly stallEnabled: boolean;\n\tprivate readonly stallPollIntervalMs: number;\n\tprivate readonly stallThresholdMs: number;\n\tprivate readonly stallTailBytes: number;\n\tprivate readonly onChange: () => void;\n\tprivate readonly now: () => number;\n\n\tprivate readonly tasks = new Map<string, BgTask>();\n\tprivate readonly runtimes = new Map<string, TaskRuntime>();\n\tprivate shuttingDown = false;\n\n\tconstructor(options: BackgroundRegistryOptions) {\n\t\tthis.operations = options.operations;\n\t\tthis.outputDir = options.outputDir ?? tmpdir();\n\t\tthis.maxOutputBytes = options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;\n\t\tthis.maxRunningTasks = options.maxRunningTasks ?? DEFAULT_MAX_RUNNING_TASKS;\n\t\tthis.notifyTailBytes = options.notifyTailBytes ?? DEFAULT_NOTIFY_TAIL_BYTES;\n\t\tthis.onNotify = options.onNotify;\n\t\tconst stall = options.stall === false ? undefined : options.stall;\n\t\tthis.stallEnabled = options.stall !== false;\n\t\tthis.stallPollIntervalMs = stall?.pollIntervalMs ?? STALL_POLL_INTERVAL_MS;\n\t\tthis.stallThresholdMs = stall?.thresholdMs ?? STALL_THRESHOLD_MS;\n\t\tthis.stallTailBytes = stall?.tailBytes ?? STALL_TAIL_BYTES;\n\t\tthis.onChange = options.onChange;\n\t\tthis.now = options.now ?? Date.now;\n\t}\n\n\tget isShuttingDown(): boolean {\n\t\treturn this.shuttingDown;\n\t}\n\n\tstartTask(input: {\n\t\tcommand: string;\n\t\tcwd: string;\n\t\tdescription?: string;\n\t\ttimeoutSeconds?: number;\n\t\tenv?: NodeJS.ProcessEnv;\n\t}): BgTask {\n\t\tif (this.shuttingDown) {\n\t\t\tthrow new Error(\"Pi is shutting down; background task not started.\");\n\t\t}\n\t\tconst running = this.listTasks().filter((task) => task.status === \"running\");\n\t\tif (running.length >= this.maxRunningTasks) {\n\t\t\tconst list = running.map((task) => ` ${task.id} ${firstCommandLine(task.command)}`).join(\"\\n\");\n\t\t\tthrow new Error(\n\t\t\t\t`Too many running background tasks (limit ${this.maxRunningTasks}). Kill one first (bg action kill):\\n${list}`,\n\t\t\t);\n\t\t}\n\n\t\tconst id = this.newTaskId();\n\t\tconst task: BgTask = {\n\t\t\tid,\n\t\t\tcommand: input.command,\n\t\t\tdescription: input.description,\n\t\t\tcwd: input.cwd,\n\t\t\tstatus: \"running\",\n\t\t\tstartedAt: this.now(),\n\t\t\texitCode: undefined,\n\t\t\toutputPath: join(this.outputDir, `pi-${id}.log`),\n\t\t\toutputBytes: 0,\n\t\t\toutputTruncated: false,\n\t\t\ttimeoutSeconds: input.timeoutSeconds,\n\t\t\tnotified: false,\n\t\t\tstalled: false,\n\t\t};\n\n\t\tlet resolveDone!: () => void;\n\t\tconst done = new Promise<void>((resolve) => {\n\t\t\tresolveDone = resolve;\n\t\t});\n\t\t// Create the file synchronously so read/wait and the /bg viewer never see\n\t\t// ENOENT between task start and the stream's async open. The exclusive\n\t\t// 'wx' flag fails on any existing path — including a symlink — so creation\n\t\t// can never truncate a file a stale id (or an attacker-planted link) points at.\n\t\tcreateOutputFileExclusively(task.outputPath);\n\t\tconst runtime: TaskRuntime = {\n\t\t\tcontroller: new AbortController(),\n\t\t\tstream: createWriteStream(task.outputPath, { flags: \"a\" }),\n\t\t\tkillRequested: false,\n\t\t\toverflow: false,\n\t\t\tfinalized: false,\n\t\t\twaiters: 0,\n\t\t\tstallTimer: undefined,\n\t\t\tstallLastSize: 0,\n\t\t\tstallLastGrowthAt: this.now(),\n\t\t\tstallNotified: false,\n\t\t\tdone,\n\t\t\tresolveDone,\n\t\t};\n\t\truntime.stream.on(\"error\", (error) => {\n\t\t\tif (runtime.finalized) return;\n\t\t\truntime.streamError = error.message;\n\t\t\truntime.controller.abort();\n\t\t});\n\n\t\tthis.tasks.set(id, task);\n\t\tthis.runtimes.set(id, runtime);\n\t\tthis.armStallWatchdog(task, runtime);\n\t\tvoid this.run(task, runtime, input.env);\n\t\tthis.onChange();\n\t\treturn task;\n\t}\n\n\t/** Running tasks first (oldest first), then finished tasks (newest first). */\n\tlistTasks(): BgTask[] {\n\t\tconst all = [...this.tasks.values()];\n\t\tconst running = all.filter((task) => task.status === \"running\");\n\t\trunning.sort((a, b) => a.startedAt - b.startedAt);\n\t\tconst ended = all.filter((task) => task.status !== \"running\");\n\t\tended.sort((a, b) => (b.endedAt ?? b.startedAt) - (a.endedAt ?? a.startedAt));\n\t\treturn [...running, ...ended];\n\t}\n\n\t/** Resolve a task by id or unique id prefix; the \"bg-\" prefix may be omitted. */\n\tresolveTask(idPrefix: string): ResolveTaskResult {\n\t\tconst needle = idPrefix.trim();\n\t\tif (!needle) return { ok: false, reason: \"not-found\", candidates: [] };\n\t\tconst exact = this.tasks.get(needle) ?? this.tasks.get(`bg-${needle}`);\n\t\tif (exact) return { ok: true, task: exact };\n\t\tconst candidates = [...this.tasks.values()].filter(\n\t\t\t(task) => task.id.startsWith(needle) || task.id.startsWith(`bg-${needle}`),\n\t\t);\n\t\tconst first = candidates[0];\n\t\tif (candidates.length === 1 && first) return { ok: true, task: first };\n\t\tif (candidates.length === 0) return { ok: false, reason: \"not-found\", candidates: [] };\n\t\treturn { ok: false, reason: \"ambiguous\", candidates };\n\t}\n\n\t/**\n\t * Request a kill. Reports only whether one was issued: why it was not is\n\t * already on the task (an unknown id cannot reach here through the tool,\n\t * which resolves first, and a settled task carries its own status).\n\t */\n\tkillTask(id: string): { killed: boolean } {\n\t\tconst task = this.tasks.get(id);\n\t\tconst runtime = this.runtimes.get(id);\n\t\tif (!task || !runtime) return { killed: false };\n\t\tif (task.status !== \"running\" || runtime.finalized) return { killed: false };\n\t\truntime.killRequested = true;\n\t\truntime.controller.abort();\n\t\treturn { killed: true };\n\t}\n\n\tcounts(): Record<BgTaskStatus, number> & { total: number; stalled: number } {\n\t\tconst counts = { running: 0, completed: 0, failed: 0, killed: 0, timeout: 0, total: 0, stalled: 0 };\n\t\tfor (const task of this.tasks.values()) {\n\t\t\tcounts[task.status]++;\n\t\t\tcounts.total++;\n\t\t\tif (task.stalled) counts.stalled++;\n\t\t}\n\t\treturn counts;\n\t}\n\n\t/** Resolves once the task has finalized, including its notification attempt. */\n\tasync waitForTask(id: string): Promise<BgTask> {\n\t\tconst task = this.tasks.get(id);\n\t\tif (!task) throw new Error(`Unknown background task: ${id}`);\n\t\tawait this.runtimes.get(id)?.done;\n\t\treturn task;\n\t}\n\n\t/**\n\t * Bounded model-facing wait. Delivery is claimed by whoever actually\n\t * delivers: a waiter that returns a terminal task marks it notified, so\n\t * finalize's followUp is skipped and the completion is delivered exactly\n\t * once, inline here.\n\t *\n\t * Nothing claims on behalf of anyone else, which is what makes an\n\t * interrupted wait safe: an aborted waiter never marks the task notified,\n\t * and the last waiter to leave without delivering sends the followUp itself.\n\t * A waiter that arrives after the task already settled returns immediately\n\t * without registering — the followUp may also arrive, an idempotent repeat\n\t * rather than a lie.\n\t */\n\tasync waitForResult(id: string, timeoutMs: number, signal?: AbortSignal): Promise<WaitOutcome> {\n\t\tconst task = this.tasks.get(id);\n\t\tif (!task) throw new Error(`Unknown background task: ${id}`);\n\t\tconst runtime = this.runtimes.get(id);\n\t\tif (!runtime) throw new Error(`Unknown background task: ${id}`);\n\t\tif (task.status !== \"running\") return { outcome: \"terminal\", task };\n\n\t\truntime.waiters++;\n\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\t\t// Named so it can be removed: the signal outlives this wait, and one\n\t\t// orphaned listener per bg wait trips Node's max-listeners warning.\n\t\tlet onAbort: (() => void) | undefined;\n\t\ttry {\n\t\t\tconst timedOut = await new Promise<boolean>((resolve) => {\n\t\t\t\ttimer = setTimeout(() => resolve(true), timeoutMs);\n\t\t\t\tvoid runtime.done.then(() => resolve(false));\n\t\t\t\tonAbort = () => resolve(true);\n\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t});\n\t\t\tif (signal?.aborted) throw new Error(\"aborted\");\n\t\t\t// done may resolve right after the timer fired (race window); a task\n\t\t\t// that reached a terminal state during the wait is delivered here.\n\t\t\tif (!timedOut || task.status !== \"running\") {\n\t\t\t\ttask.notified = true;\n\t\t\t\treturn { outcome: \"terminal\", task };\n\t\t\t}\n\t\t\treturn { outcome: \"timeout\", task };\n\t\t} finally {\n\t\t\truntime.waiters--;\n\t\t\t// Last one out and nobody delivered — the task settled while this wait\n\t\t\t// was in flight and the wait was then aborted, so send the followUp.\n\t\t\t// Gated on the terminal status, not runtime.finalized: finalize sets\n\t\t\t// that flag before the stream flush, while the task still reads as\n\t\t\t// running. A wait aborted inside that window is left to finalize, which\n\t\t\t// will see waiters === 0 by then.\n\t\t\tif (runtime.waiters === 0 && task.status !== \"running\" && !task.notified) {\n\t\t\t\tawait this.notifyCompletion(task);\n\t\t\t}\n\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t\tif (onAbort !== undefined) signal?.removeEventListener(\"abort\", onAbort);\n\t\t}\n\t}\n\n\t/**\n\t * Mute notifications, refuse new tasks, abort every running task, and wait\n\t * (bounded) for their finalization.\n\t */\n\tasync shutdown(): Promise<void> {\n\t\tthis.shuttingDown = true;\n\t\tconst pending: Promise<void>[] = [];\n\t\tfor (const [id, runtime] of this.runtimes) {\n\t\t\tconst task = this.tasks.get(id);\n\t\t\tif (task?.status === \"running\" && !runtime.finalized) {\n\t\t\t\truntime.killRequested = true;\n\t\t\t\truntime.controller.abort();\n\t\t\t}\n\t\t\tpending.push(runtime.done);\n\t\t}\n\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\t\tconst grace = new Promise<void>((resolve) => {\n\t\t\ttimer = setTimeout(resolve, SHUTDOWN_GRACE_MS);\n\t\t});\n\t\ttry {\n\t\t\tawait Promise.race([Promise.allSettled(pending).then(() => undefined), grace]);\n\t\t} finally {\n\t\t\tif (timer) clearTimeout(timer);\n\t\t}\n\t}\n\n\t/**\n\t * Stall watchdog (Claude Code CC-1175): poll the output file; when output\n\t * stops growing past the threshold AND the tail looks like an interactive\n\t * prompt, flag the task and fire a one-shot notification. Merely-slow tasks\n\t * never match; recovery clears the flag (the notification never re-fires).\n\t */\n\tprivate armStallWatchdog(task: BgTask, runtime: TaskRuntime): void {\n\t\tif (!this.stallEnabled) return;\n\t\truntime.stallTimer = setInterval(() => this.checkStall(task, runtime), this.stallPollIntervalMs);\n\t\truntime.stallTimer.unref?.();\n\t}\n\n\tprivate clearStallWatchdog(runtime: TaskRuntime): void {\n\t\tif (runtime.stallTimer !== undefined) {\n\t\t\tclearInterval(runtime.stallTimer);\n\t\t\truntime.stallTimer = undefined;\n\t\t}\n\t}\n\n\tprivate checkStall(task: BgTask, runtime: TaskRuntime): void {\n\t\tif (runtime.finalized || this.shuttingDown) return;\n\t\tconst size = task.outputBytes;\n\t\tif (size > runtime.stallLastSize) {\n\t\t\truntime.stallLastSize = size;\n\t\t\truntime.stallLastGrowthAt = this.now();\n\t\t\tif (task.stalled) {\n\t\t\t\t// Output resumed: reflect reality in listings, never re-notify.\n\t\t\t\ttask.stalled = false;\n\t\t\t\tthis.onChange();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (this.now() - runtime.stallLastGrowthAt < this.stallThresholdMs) return;\n\t\tvoid this.probeStallTail(task, runtime);\n\t}\n\n\tprivate async probeStallTail(task: BgTask, runtime: TaskRuntime): Promise<void> {\n\t\t// Re-check inside the async boundary: finalize may have raced the probe.\n\t\tif (runtime.finalized || this.shuttingDown) return;\n\t\tconst { slice, error } = await readTail(task.outputPath, this.stallTailBytes);\n\t\tif (runtime.finalized || this.shuttingDown) return;\n\t\t// Merely slow: not prompt-shaped. Reset so the next check is a full\n\t\t// threshold window out instead of re-probing on every tick. A tail that\n\t\t// could not be read is reported, not dismissed as slow. Matched on the\n\t\t// raw text — sanitizing is for delivery, not for detection.\n\t\tif (slice && !looksLikePrompt(slice.text)) {\n\t\t\truntime.stallLastGrowthAt = this.now();\n\t\t\treturn;\n\t\t}\n\t\tif (!task.stalled) {\n\t\t\ttask.stalled = true;\n\t\t\tthis.onChange();\n\t\t}\n\t\tif (runtime.stallNotified) return;\n\t\truntime.stallNotified = true;\n\t\tthis.emit(\"stall\", task, slice, error);\n\t}\n\n\t/** The one place a notification payload is shaped, for either kind. */\n\tprivate emit(kind: BgNotification[\"kind\"], task: BgTask, slice: OutputSlice | undefined, tailError?: string): void {\n\t\ttry {\n\t\t\tthis.onNotify({\n\t\t\t\tkind,\n\t\t\t\ttask,\n\t\t\t\ttail: slice && { ...slice, text: sanitizeBinaryOutput(slice.text) },\n\t\t\t\ttailError,\n\t\t\t});\n\t\t} catch {\n\t\t\t// Notification failures must not undo task completion or prevent settlement;\n\t\t\t// there is no retry path, so the delivery record stands.\n\t\t}\n\t}\n\n\tprivate newTaskId(): string {\n\t\twhile (true) {\n\t\t\tconst id = `bg-${randomBytes(3).toString(\"hex\")}`;\n\t\t\tif (!this.tasks.has(id)) return id;\n\t\t}\n\t}\n\n\tprivate async run(task: BgTask, runtime: TaskRuntime, env?: NodeJS.ProcessEnv): Promise<void> {\n\t\tlet outcome: { exitCode?: number | null; error?: unknown };\n\t\ttry {\n\t\t\tconst result = await this.operations.exec(task.command, task.cwd, {\n\t\t\t\tonData: (data) => this.handleData(task, runtime, data),\n\t\t\t\tsignal: runtime.controller.signal,\n\t\t\t\ttimeout: task.timeoutSeconds,\n\t\t\t\tenv,\n\t\t\t});\n\t\t\toutcome = { exitCode: result.exitCode };\n\t\t} catch (error) {\n\t\t\toutcome = { error };\n\t\t}\n\t\tawait this.finalize(task, runtime, outcome);\n\t}\n\n\tprivate handleData(task: BgTask, runtime: TaskRuntime, data: Buffer): void {\n\t\tif (runtime.finalized || runtime.overflow || runtime.streamError !== undefined) return;\n\t\tconst next = task.outputBytes + data.length;\n\t\tif (next <= this.maxOutputBytes) {\n\t\t\truntime.stream.write(data);\n\t\t\ttask.outputBytes = next;\n\t\t\treturn;\n\t\t}\n\t\tconst budget = this.maxOutputBytes - task.outputBytes;\n\t\tif (budget > 0) {\n\t\t\truntime.stream.write(data.subarray(0, budget));\n\t\t\ttask.outputBytes = this.maxOutputBytes;\n\t\t}\n\t\truntime.stream.write(`\\n[output limit ${formatSize(this.maxOutputBytes)} exceeded; task killed]\\n`);\n\t\ttask.outputTruncated = true;\n\t\truntime.overflow = true;\n\t\truntime.controller.abort();\n\t}\n\n\tprivate async finalize(\n\t\ttask: BgTask,\n\t\truntime: TaskRuntime,\n\t\toutcome: { exitCode?: number | null; error?: unknown },\n\t): Promise<void> {\n\t\tif (runtime.finalized) return;\n\t\truntime.finalized = true;\n\t\tthis.clearStallWatchdog(runtime);\n\t\ttask.stalled = false;\n\n\t\t// Flush before setting terminal state: the output file must hold the\n\t\t// complete truth by the time anyone is told the task ended.\n\t\tawait new Promise<void>((resolve) => {\n\t\t\tconst stream = runtime.stream;\n\t\t\tif (stream.destroyed) {\n\t\t\t\tresolve();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstream.on(\"close\", resolve);\n\t\t\tstream.end(() => resolve());\n\t\t});\n\n\t\tconst verdict = this.classifyOutcome(runtime, outcome);\n\t\ttask.status = verdict.status;\n\t\tif (verdict.error !== undefined) task.error = verdict.error;\n\t\ttask.exitCode = outcome.exitCode;\n\t\ttask.endedAt = this.now();\n\t\tthis.onChange();\n\t\t// Nothing is claimed on anyone's behalf: if a waiter is registered it gets\n\t\t// first refusal, and whichever of them leaves last without having\n\t\t// delivered sends the followUp from waitForResult's finally.\n\t\tif (runtime.waiters === 0) await this.notifyCompletion(task);\n\t\truntime.resolveDone();\n\t}\n\n\tprivate classifyOutcome(\n\t\truntime: TaskRuntime,\n\t\toutcome: { exitCode?: number | null; error?: unknown },\n\t): { status: BgTaskStatus; error?: string } {\n\t\tif (runtime.overflow) {\n\t\t\treturn {\n\t\t\t\tstatus: \"failed\",\n\t\t\t\terror: `Output exceeded the ${formatSize(this.maxOutputBytes)} limit; the task was killed.`,\n\t\t\t};\n\t\t}\n\t\tif (runtime.streamError !== undefined) {\n\t\t\treturn { status: \"failed\", error: `Output file error: ${runtime.streamError}` };\n\t\t}\n\t\tif (runtime.killRequested) return { status: \"killed\" };\n\t\tconst error = outcome.error;\n\t\tif (error instanceof Error) {\n\t\t\tif (error.message === \"aborted\") return { status: \"killed\" };\n\t\t\tif (error.message.startsWith(\"timeout:\")) {\n\t\t\t\treturn { status: \"timeout\", error: `Timed out after ${error.message.slice(\"timeout:\".length)}s.` };\n\t\t\t}\n\t\t\treturn { status: \"failed\", error: error.message };\n\t\t}\n\t\tif (error !== undefined) return { status: \"failed\", error: String(error) };\n\t\tif (outcome.exitCode === 0) return { status: \"completed\" };\n\t\tif (outcome.exitCode === null) return { status: \"failed\", error: \"Command was terminated by a signal.\" };\n\t\treturn { status: \"failed\", error: `Command exited with code ${outcome.exitCode}` };\n\t}\n\n\tprivate async notifyCompletion(task: BgTask): Promise<void> {\n\t\tif (this.shuttingDown || task.notified) return;\n\t\ttask.notified = true;\n\t\tconst { slice, error } = await readTail(task.outputPath, this.notifyTailBytes);\n\t\tthis.emit(\"completion\", task, slice, error);\n\t}\n}\n"]}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/extensions/background/registry.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Background task registry: process lifecycle, output capture, completion\n * notification. Pure logic — no UI imports, dependencies injected for tests.\n *\n * Discipline (mirrors the reference implementation this extension distills):\n * - Output streams straight to a file; memory holds only a byte counter.\n * - Finalization is idempotent and strictly ordered: flush stream, set\n * terminal state, then notify. A notification is only sent once the output\n * file holds the complete truth.\n * - Kill goes through AbortController; the shared bash operations kill the\n * whole process tree cross-platform.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport { createWriteStream, type WriteStream } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { BashOperations } from \"../../core/tools/bash.ts\";\nimport { formatSize } from \"../../core/tools/truncate.ts\";\nimport { sanitizeBinaryOutput } from \"../../utils/shell.ts\";\nimport { createOutputFileExclusively, type OutputSlice, readTail } from \"./output-file.ts\";\nimport { firstCommandLine } from \"./text.ts\";\n\nexport const DEFAULT_MAX_OUTPUT_BYTES = 20 * 1024 * 1024;\nexport const DEFAULT_MAX_RUNNING_TASKS = 8;\nexport const DEFAULT_NOTIFY_TAIL_BYTES = 4 * 1024;\n\nconst SHUTDOWN_GRACE_MS = 2_000;\nconst TASK_ID_ALLOCATION_ATTEMPTS = 100;\n\n/** Stall watchdog defaults, matching Claude Code's CC-1175 tuning. */\nexport const STALL_POLL_INTERVAL_MS = 5_000;\nexport const STALL_THRESHOLD_MS = 45_000;\nexport const STALL_TAIL_BYTES = 1_024;\n\n/**\n * Last-line patterns that suggest a command is blocked waiting for keyboard\n * input. Used to gate the stall notification: a task that is merely slow\n * (git log -S, long silent builds) stays silent — only a tail that looks like\n * a prompt the model can act on triggers a notification.\n */\nconst STALL_PROMPT_PATTERNS: RegExp[] = [\n\t/\\(y\\/n\\)/i, // (Y/n), (y/N)\n\t/\\[y\\/n\\]/i, // [Y/n], [y/N]\n\t/\\(yes\\/no\\)/i,\n\t/\\b(?:Do you|Would you|Shall I|Are you sure|Ready to)\\b.*\\? *$/i, // directed questions\n\t/Press (any key|Enter)/i,\n\t/Continue\\?/i,\n\t/Overwrite\\?/i,\n];\n\nexport function looksLikePrompt(tail: string): boolean {\n\tconst lastLine = tail.trimEnd().split(\"\\n\").pop() ?? \"\";\n\treturn STALL_PROMPT_PATTERNS.some((pattern) => pattern.test(lastLine));\n}\n\nexport type BgTaskStatus = \"running\" | \"completed\" | \"failed\" | \"killed\" | \"timeout\";\n\nexport interface BgTask {\n\tid: string;\n\tcommand: string;\n\t/** Optional model-provided label (e.g. \"dev server\") shown in /bg and notifications. */\n\tdescription?: string;\n\tcwd: string;\n\tstatus: BgTaskStatus;\n\tstartedAt: number;\n\tendedAt?: number;\n\t/** True when the stall watchdog flagged this task as waiting for input. */\n\tstalled: boolean;\n\t/**\n\t * Process exit code; null when reaped by a signal, undefined while running\n\t * or when the run produced none (spawn failure, kill, timeout).\n\t */\n\texitCode: number | null | undefined;\n\toutputPath: string;\n\t/** Bytes accepted into the output file (excludes the overflow notice). */\n\toutputBytes: number;\n\t/** True when output hit the byte limit and the task was killed for it. */\n\toutputTruncated: boolean;\n\terror?: string;\n\ttimeoutSeconds?: number;\n\t/** Delivery happened: a notification was sent, or a waiter returned this task inline. */\n\tnotified: boolean;\n}\n\n/**\n * What a settled or stalled task hands to the extension for delivery.\n *\n * One shape with one discriminant, because both are delivered the same way and\n * carry the same payload; only the registry cares about the difference (a\n * completion participates in the delivery claim, a stall is informational and\n * bypasses it).\n */\nexport interface BgNotification {\n\tkind: \"completion\" | \"stall\";\n\ttask: BgTask;\n\t/** Sanitized tail of the output file; absent when it could not be read. */\n\ttail: OutputSlice | undefined;\n\t/** Set when the output file could not be read; the notification still fires. */\n\ttailError?: string;\n}\n\n/** Outcome of a bounded wait: terminal delivery, or the wait window expiring. */\nexport type WaitOutcome = { outcome: \"terminal\"; task: BgTask } | { outcome: \"timeout\"; task: BgTask };\n\nexport interface BackgroundRegistryOptions {\n\toperations: BashOperations;\n\t/** Directory for task output files. Defaults to the system temp directory. */\n\toutputDir?: string;\n\tmaxOutputBytes?: number;\n\tmaxRunningTasks?: number;\n\tnotifyTailBytes?: number;\n\t/** Called at most once per task per kind; synchronous throws do not prevent settlement. */\n\tonNotify: (notification: BgNotification) => void;\n\t/**\n\t * Stall watchdog tuning; `false` disables the watchdog outright. Defaults\n\t * follow Claude Code's CC-1175 (5s/45s/1KB).\n\t */\n\tstall?: { pollIntervalMs?: number; thresholdMs?: number; tailBytes?: number } | false;\n\t/** Called whenever a task starts or reaches a terminal state. */\n\tonChange: () => void;\n\tnow?: () => number;\n\t/** Test hook for deterministic collision coverage. */\n\tcreateTaskId?: () => string;\n}\n\ninterface TaskRuntime {\n\tcontroller: AbortController;\n\tstream: WriteStream;\n\tkillRequested: boolean;\n\toverflow: boolean;\n\tstreamError?: string;\n\tfinalized: boolean;\n\t/** Live waitForResult callers; the last one out sends the followUp if none delivered. */\n\twaiters: number;\n\tstallTimer: ReturnType<typeof setInterval> | undefined;\n\tstallLastSize: number;\n\tstallLastGrowthAt: number;\n\t/** One-shot latch: the stall notification fires at most once per task. */\n\tstallNotified: boolean;\n\tdone: Promise<void>;\n\tresolveDone: () => void;\n}\n\nexport type ResolveTaskResult =\n\t| { ok: true; task: BgTask }\n\t| { ok: false; reason: \"not-found\" | \"ambiguous\"; candidates: BgTask[] };\n\nexport class BackgroundTaskRegistry {\n\tprivate readonly operations: BashOperations;\n\tprivate readonly outputDir: string;\n\tprivate readonly maxOutputBytes: number;\n\tprivate readonly maxRunningTasks: number;\n\tprivate readonly notifyTailBytes: number;\n\tprivate readonly onNotify: (notification: BgNotification) => void;\n\tprivate readonly stallEnabled: boolean;\n\tprivate readonly stallPollIntervalMs: number;\n\tprivate readonly stallThresholdMs: number;\n\tprivate readonly stallTailBytes: number;\n\tprivate readonly onChange: () => void;\n\tprivate readonly now: () => number;\n\tprivate readonly createTaskId: () => string;\n\n\tprivate readonly tasks = new Map<string, BgTask>();\n\tprivate readonly runtimes = new Map<string, TaskRuntime>();\n\tprivate shuttingDown = false;\n\n\tconstructor(options: BackgroundRegistryOptions) {\n\t\tthis.operations = options.operations;\n\t\tthis.outputDir = options.outputDir ?? tmpdir();\n\t\tthis.maxOutputBytes = options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;\n\t\tthis.maxRunningTasks = options.maxRunningTasks ?? DEFAULT_MAX_RUNNING_TASKS;\n\t\tthis.notifyTailBytes = options.notifyTailBytes ?? DEFAULT_NOTIFY_TAIL_BYTES;\n\t\tthis.onNotify = options.onNotify;\n\t\tconst stall = options.stall === false ? undefined : options.stall;\n\t\tthis.stallEnabled = options.stall !== false;\n\t\tthis.stallPollIntervalMs = stall?.pollIntervalMs ?? STALL_POLL_INTERVAL_MS;\n\t\tthis.stallThresholdMs = stall?.thresholdMs ?? STALL_THRESHOLD_MS;\n\t\tthis.stallTailBytes = stall?.tailBytes ?? STALL_TAIL_BYTES;\n\t\tthis.onChange = options.onChange;\n\t\tthis.now = options.now ?? Date.now;\n\t\tthis.createTaskId = options.createTaskId ?? (() => `bg-${randomBytes(3).toString(\"hex\")}`);\n\t}\n\n\tget isShuttingDown(): boolean {\n\t\treturn this.shuttingDown;\n\t}\n\n\tstartTask(input: {\n\t\tcommand: string;\n\t\tcwd: string;\n\t\tdescription?: string;\n\t\ttimeoutSeconds?: number;\n\t\tenv?: NodeJS.ProcessEnv;\n\t}): BgTask {\n\t\tif (this.shuttingDown) {\n\t\t\tthrow new Error(\"Pi is shutting down; background task not started.\");\n\t\t}\n\t\tconst running = this.listTasks().filter((task) => task.status === \"running\");\n\t\tif (running.length >= this.maxRunningTasks) {\n\t\t\tconst list = running.map((task) => ` ${task.id} ${firstCommandLine(task.command)}`).join(\"\\n\");\n\t\t\tthrow new Error(\n\t\t\t\t`Too many running background tasks (limit ${this.maxRunningTasks}). Kill one first (bg action kill):\\n${list}`,\n\t\t\t);\n\t\t}\n\n\t\tconst { id, outputPath } = this.allocateTaskOutput();\n\t\tconst task: BgTask = {\n\t\t\tid,\n\t\t\tcommand: input.command,\n\t\t\tdescription: input.description,\n\t\t\tcwd: input.cwd,\n\t\t\tstatus: \"running\",\n\t\t\tstartedAt: this.now(),\n\t\t\texitCode: undefined,\n\t\t\toutputPath,\n\t\t\toutputBytes: 0,\n\t\t\toutputTruncated: false,\n\t\t\ttimeoutSeconds: input.timeoutSeconds,\n\t\t\tnotified: false,\n\t\t\tstalled: false,\n\t\t};\n\n\t\tlet resolveDone!: () => void;\n\t\tconst done = new Promise<void>((resolve) => {\n\t\t\tresolveDone = resolve;\n\t\t});\n\t\tconst runtime: TaskRuntime = {\n\t\t\tcontroller: new AbortController(),\n\t\t\tstream: createWriteStream(task.outputPath, { flags: \"a\" }),\n\t\t\tkillRequested: false,\n\t\t\toverflow: false,\n\t\t\tfinalized: false,\n\t\t\twaiters: 0,\n\t\t\tstallTimer: undefined,\n\t\t\tstallLastSize: 0,\n\t\t\tstallLastGrowthAt: this.now(),\n\t\t\tstallNotified: false,\n\t\t\tdone,\n\t\t\tresolveDone,\n\t\t};\n\t\truntime.stream.on(\"error\", (error) => {\n\t\t\tif (runtime.finalized) return;\n\t\t\truntime.streamError = error.message;\n\t\t\truntime.controller.abort();\n\t\t});\n\n\t\tthis.tasks.set(id, task);\n\t\tthis.runtimes.set(id, runtime);\n\t\tthis.armStallWatchdog(task, runtime);\n\t\tvoid this.run(task, runtime, input.env);\n\t\tthis.onChange();\n\t\treturn task;\n\t}\n\n\t/** Running tasks first (oldest first), then finished tasks (newest first). */\n\tlistTasks(): BgTask[] {\n\t\tconst all = [...this.tasks.values()];\n\t\tconst running = all.filter((task) => task.status === \"running\");\n\t\trunning.sort((a, b) => a.startedAt - b.startedAt);\n\t\tconst ended = all.filter((task) => task.status !== \"running\");\n\t\tended.sort((a, b) => (b.endedAt ?? b.startedAt) - (a.endedAt ?? a.startedAt));\n\t\treturn [...running, ...ended];\n\t}\n\n\t/** Resolve a task by id or unique id prefix; the \"bg-\" prefix may be omitted. */\n\tresolveTask(idPrefix: string): ResolveTaskResult {\n\t\tconst needle = idPrefix.trim();\n\t\tif (!needle) return { ok: false, reason: \"not-found\", candidates: [] };\n\t\tconst exact = this.tasks.get(needle) ?? this.tasks.get(`bg-${needle}`);\n\t\tif (exact) return { ok: true, task: exact };\n\t\tconst candidates = [...this.tasks.values()].filter(\n\t\t\t(task) => task.id.startsWith(needle) || task.id.startsWith(`bg-${needle}`),\n\t\t);\n\t\tconst first = candidates[0];\n\t\tif (candidates.length === 1 && first) return { ok: true, task: first };\n\t\tif (candidates.length === 0) return { ok: false, reason: \"not-found\", candidates: [] };\n\t\treturn { ok: false, reason: \"ambiguous\", candidates };\n\t}\n\n\t/**\n\t * Request a kill. Reports only whether one was issued: why it was not is\n\t * already on the task (an unknown id cannot reach here through the tool,\n\t * which resolves first, and a settled task carries its own status).\n\t */\n\tkillTask(id: string): { killed: boolean } {\n\t\tconst task = this.tasks.get(id);\n\t\tconst runtime = this.runtimes.get(id);\n\t\tif (!task || !runtime) return { killed: false };\n\t\tif (task.status !== \"running\" || runtime.finalized) return { killed: false };\n\t\truntime.killRequested = true;\n\t\truntime.controller.abort();\n\t\treturn { killed: true };\n\t}\n\n\tcounts(): Record<BgTaskStatus, number> & { total: number; stalled: number } {\n\t\tconst counts = { running: 0, completed: 0, failed: 0, killed: 0, timeout: 0, total: 0, stalled: 0 };\n\t\tfor (const task of this.tasks.values()) {\n\t\t\tcounts[task.status]++;\n\t\t\tcounts.total++;\n\t\t\tif (task.stalled) counts.stalled++;\n\t\t}\n\t\treturn counts;\n\t}\n\n\t/** Resolves once the task has finalized, including its notification attempt. */\n\tasync waitForTask(id: string): Promise<BgTask> {\n\t\tconst task = this.tasks.get(id);\n\t\tif (!task) throw new Error(`Unknown background task: ${id}`);\n\t\tawait this.runtimes.get(id)?.done;\n\t\treturn task;\n\t}\n\n\t/**\n\t * Bounded model-facing wait. Delivery is claimed by whoever actually\n\t * delivers: a waiter that returns a terminal task marks it notified, so\n\t * finalize's followUp is skipped and the completion is delivered exactly\n\t * once, inline here.\n\t *\n\t * Nothing claims on behalf of anyone else, which is what makes an\n\t * interrupted wait safe: an aborted waiter never marks the task notified,\n\t * and the last waiter to leave without delivering sends the followUp itself.\n\t * A waiter that arrives after the task already settled returns immediately\n\t * without registering — the followUp may also arrive, an idempotent repeat\n\t * rather than a lie.\n\t */\n\tasync waitForResult(id: string, timeoutMs: number, signal?: AbortSignal): Promise<WaitOutcome> {\n\t\tconst task = this.tasks.get(id);\n\t\tif (!task) throw new Error(`Unknown background task: ${id}`);\n\t\tconst runtime = this.runtimes.get(id);\n\t\tif (!runtime) throw new Error(`Unknown background task: ${id}`);\n\t\tif (task.status !== \"running\") return { outcome: \"terminal\", task };\n\n\t\truntime.waiters++;\n\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\t\t// Named so it can be removed: the signal outlives this wait, and one\n\t\t// orphaned listener per bg wait trips Node's max-listeners warning.\n\t\tlet onAbort: (() => void) | undefined;\n\t\ttry {\n\t\t\tconst timedOut = await new Promise<boolean>((resolve) => {\n\t\t\t\ttimer = setTimeout(() => resolve(true), timeoutMs);\n\t\t\t\tvoid runtime.done.then(() => resolve(false));\n\t\t\t\tonAbort = () => resolve(true);\n\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t});\n\t\t\tif (signal?.aborted) throw new Error(\"aborted\");\n\t\t\t// done may resolve right after the timer fired (race window); a task\n\t\t\t// that reached a terminal state during the wait is delivered here.\n\t\t\tif (!timedOut || task.status !== \"running\") {\n\t\t\t\ttask.notified = true;\n\t\t\t\treturn { outcome: \"terminal\", task };\n\t\t\t}\n\t\t\treturn { outcome: \"timeout\", task };\n\t\t} finally {\n\t\t\truntime.waiters--;\n\t\t\t// Last one out and nobody delivered — the task settled while this wait\n\t\t\t// was in flight and the wait was then aborted, so send the followUp.\n\t\t\t// Gated on the terminal status, not runtime.finalized: finalize sets\n\t\t\t// that flag before the stream flush, while the task still reads as\n\t\t\t// running. A wait aborted inside that window is left to finalize, which\n\t\t\t// will see waiters === 0 by then.\n\t\t\tif (runtime.waiters === 0 && task.status !== \"running\" && !task.notified) {\n\t\t\t\tawait this.notifyCompletion(task);\n\t\t\t}\n\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t\tif (onAbort !== undefined) signal?.removeEventListener(\"abort\", onAbort);\n\t\t}\n\t}\n\n\t/**\n\t * Mute notifications, refuse new tasks, abort every running task, and wait\n\t * (bounded) for their finalization.\n\t */\n\tasync shutdown(): Promise<void> {\n\t\tthis.shuttingDown = true;\n\t\tconst pending: Promise<void>[] = [];\n\t\tfor (const [id, runtime] of this.runtimes) {\n\t\t\tconst task = this.tasks.get(id);\n\t\t\tif (task?.status === \"running\" && !runtime.finalized) {\n\t\t\t\truntime.killRequested = true;\n\t\t\t\truntime.controller.abort();\n\t\t\t}\n\t\t\tpending.push(runtime.done);\n\t\t}\n\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\t\tconst grace = new Promise<void>((resolve) => {\n\t\t\ttimer = setTimeout(resolve, SHUTDOWN_GRACE_MS);\n\t\t});\n\t\ttry {\n\t\t\tawait Promise.race([Promise.allSettled(pending).then(() => undefined), grace]);\n\t\t} finally {\n\t\t\tif (timer) clearTimeout(timer);\n\t\t}\n\t}\n\n\t/**\n\t * Stall watchdog (Claude Code CC-1175): poll the output file; when output\n\t * stops growing past the threshold AND the tail looks like an interactive\n\t * prompt, flag the task and fire a one-shot notification. Merely-slow tasks\n\t * never match; recovery clears the flag (the notification never re-fires).\n\t */\n\tprivate armStallWatchdog(task: BgTask, runtime: TaskRuntime): void {\n\t\tif (!this.stallEnabled) return;\n\t\truntime.stallTimer = setInterval(() => this.checkStall(task, runtime), this.stallPollIntervalMs);\n\t\truntime.stallTimer.unref?.();\n\t}\n\n\tprivate clearStallWatchdog(runtime: TaskRuntime): void {\n\t\tif (runtime.stallTimer !== undefined) {\n\t\t\tclearInterval(runtime.stallTimer);\n\t\t\truntime.stallTimer = undefined;\n\t\t}\n\t}\n\n\tprivate checkStall(task: BgTask, runtime: TaskRuntime): void {\n\t\tif (runtime.finalized || this.shuttingDown) return;\n\t\tconst size = task.outputBytes;\n\t\tif (size > runtime.stallLastSize) {\n\t\t\truntime.stallLastSize = size;\n\t\t\truntime.stallLastGrowthAt = this.now();\n\t\t\tif (task.stalled) {\n\t\t\t\t// Output resumed: reflect reality in listings, never re-notify.\n\t\t\t\ttask.stalled = false;\n\t\t\t\tthis.onChange();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (this.now() - runtime.stallLastGrowthAt < this.stallThresholdMs) return;\n\t\tvoid this.probeStallTail(task, runtime);\n\t}\n\n\tprivate async probeStallTail(task: BgTask, runtime: TaskRuntime): Promise<void> {\n\t\t// Re-check inside the async boundary: finalize may have raced the probe.\n\t\tif (runtime.finalized || this.shuttingDown) return;\n\t\tconst { slice, error } = await readTail(task.outputPath, this.stallTailBytes);\n\t\tif (runtime.finalized || this.shuttingDown) return;\n\t\t// A read failure is not evidence of an interactive prompt. Retry after a\n\t\t// full threshold window without changing task state or notifying. Detection\n\t\t// uses raw text; sanitizing is only for delivery.\n\t\tif (error) {\n\t\t\truntime.stallLastGrowthAt = this.now();\n\t\t\treturn;\n\t\t}\n\t\tif (!slice || !looksLikePrompt(slice.text)) {\n\t\t\truntime.stallLastGrowthAt = this.now();\n\t\t\treturn;\n\t\t}\n\t\tif (!task.stalled) {\n\t\t\ttask.stalled = true;\n\t\t\tthis.onChange();\n\t\t}\n\t\tif (runtime.stallNotified) return;\n\t\truntime.stallNotified = true;\n\t\tthis.emit(\"stall\", task, slice, error);\n\t}\n\n\t/** The one place a notification payload is shaped, for either kind. */\n\tprivate emit(kind: BgNotification[\"kind\"], task: BgTask, slice: OutputSlice | undefined, tailError?: string): void {\n\t\ttry {\n\t\t\tthis.onNotify({\n\t\t\t\tkind,\n\t\t\t\ttask,\n\t\t\t\ttail: slice && { ...slice, text: sanitizeBinaryOutput(slice.text) },\n\t\t\t\ttailError,\n\t\t\t});\n\t\t} catch {\n\t\t\t// Notification failures must not undo task completion or prevent settlement;\n\t\t\t// there is no retry path, so the delivery record stands.\n\t\t}\n\t}\n\n\tprivate allocateTaskOutput(): { id: string; outputPath: string } {\n\t\tfor (let attempt = 0; attempt < TASK_ID_ALLOCATION_ATTEMPTS; attempt++) {\n\t\t\tconst id = this.createTaskId();\n\t\t\tif (this.tasks.has(id)) continue;\n\t\t\tconst outputPath = join(this.outputDir, `pi-${id}.log`);\n\t\t\ttry {\n\t\t\t\t// Create synchronously before returning the task so read/wait and /bg\n\t\t\t\t// never see ENOENT. `wx` also protects stale logs and symlinks.\n\t\t\t\tcreateOutputFileExclusively(outputPath);\n\t\t\t\treturn { id, outputPath };\n\t\t\t} catch (error) {\n\t\t\t\tif ((error as NodeJS.ErrnoException).code === \"EEXIST\") continue;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\tthrow new Error(`Could not allocate a unique background task id after ${TASK_ID_ALLOCATION_ATTEMPTS} attempts.`);\n\t}\n\n\tprivate async run(task: BgTask, runtime: TaskRuntime, env?: NodeJS.ProcessEnv): Promise<void> {\n\t\tlet outcome: { exitCode?: number | null; error?: unknown };\n\t\ttry {\n\t\t\tconst result = await this.operations.exec(task.command, task.cwd, {\n\t\t\t\tonData: (data) => this.handleData(task, runtime, data),\n\t\t\t\tsignal: runtime.controller.signal,\n\t\t\t\ttimeout: task.timeoutSeconds,\n\t\t\t\tenv,\n\t\t\t});\n\t\t\toutcome = { exitCode: result.exitCode };\n\t\t} catch (error) {\n\t\t\toutcome = { error };\n\t\t}\n\t\tawait this.finalize(task, runtime, outcome);\n\t}\n\n\tprivate handleData(task: BgTask, runtime: TaskRuntime, data: Buffer): void {\n\t\tif (runtime.finalized || runtime.overflow || runtime.streamError !== undefined) return;\n\t\tconst next = task.outputBytes + data.length;\n\t\tif (next <= this.maxOutputBytes) {\n\t\t\truntime.stream.write(data);\n\t\t\ttask.outputBytes = next;\n\t\t\treturn;\n\t\t}\n\t\tconst budget = this.maxOutputBytes - task.outputBytes;\n\t\tif (budget > 0) {\n\t\t\truntime.stream.write(data.subarray(0, budget));\n\t\t\ttask.outputBytes = this.maxOutputBytes;\n\t\t}\n\t\truntime.stream.write(`\\n[output limit ${formatSize(this.maxOutputBytes)} exceeded; task killed]\\n`);\n\t\ttask.outputTruncated = true;\n\t\truntime.overflow = true;\n\t\truntime.controller.abort();\n\t}\n\n\tprivate async finalize(\n\t\ttask: BgTask,\n\t\truntime: TaskRuntime,\n\t\toutcome: { exitCode?: number | null; error?: unknown },\n\t): Promise<void> {\n\t\tif (runtime.finalized) return;\n\t\truntime.finalized = true;\n\t\tthis.clearStallWatchdog(runtime);\n\t\ttask.stalled = false;\n\n\t\t// Flush before setting terminal state: the output file must hold the\n\t\t// complete truth by the time anyone is told the task ended.\n\t\tawait new Promise<void>((resolve) => {\n\t\t\tconst stream = runtime.stream;\n\t\t\tif (stream.destroyed) {\n\t\t\t\tresolve();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstream.on(\"close\", resolve);\n\t\t\tstream.end(() => resolve());\n\t\t});\n\n\t\tconst verdict = this.classifyOutcome(runtime, outcome);\n\t\ttask.status = verdict.status;\n\t\tif (verdict.error !== undefined) task.error = verdict.error;\n\t\ttask.exitCode = outcome.exitCode;\n\t\ttask.endedAt = this.now();\n\t\tthis.onChange();\n\t\t// Nothing is claimed on anyone's behalf: if a waiter is registered it gets\n\t\t// first refusal, and whichever of them leaves last without having\n\t\t// delivered sends the followUp from waitForResult's finally.\n\t\tif (runtime.waiters === 0) await this.notifyCompletion(task);\n\t\truntime.resolveDone();\n\t}\n\n\tprivate classifyOutcome(\n\t\truntime: TaskRuntime,\n\t\toutcome: { exitCode?: number | null; error?: unknown },\n\t): { status: BgTaskStatus; error?: string } {\n\t\tif (runtime.overflow) {\n\t\t\treturn {\n\t\t\t\tstatus: \"failed\",\n\t\t\t\terror: `Output exceeded the ${formatSize(this.maxOutputBytes)} limit; the task was killed.`,\n\t\t\t};\n\t\t}\n\t\tif (runtime.streamError !== undefined) {\n\t\t\treturn { status: \"failed\", error: `Output file error: ${runtime.streamError}` };\n\t\t}\n\t\tif (runtime.killRequested) return { status: \"killed\" };\n\t\tconst error = outcome.error;\n\t\tif (error instanceof Error) {\n\t\t\tif (error.message === \"aborted\") return { status: \"killed\" };\n\t\t\tif (error.message.startsWith(\"timeout:\")) {\n\t\t\t\treturn { status: \"timeout\", error: `Timed out after ${error.message.slice(\"timeout:\".length)}s.` };\n\t\t\t}\n\t\t\treturn { status: \"failed\", error: error.message };\n\t\t}\n\t\tif (error !== undefined) return { status: \"failed\", error: String(error) };\n\t\tif (outcome.exitCode === 0) return { status: \"completed\" };\n\t\tif (outcome.exitCode === null) return { status: \"failed\", error: \"Command was terminated by a signal.\" };\n\t\treturn { status: \"failed\", error: `Command exited with code ${outcome.exitCode}` };\n\t}\n\n\tprivate async notifyCompletion(task: BgTask): Promise<void> {\n\t\tif (this.shuttingDown || task.notified) return;\n\t\ttask.notified = true;\n\t\tconst { slice, error } = await readTail(task.outputPath, this.notifyTailBytes);\n\t\tthis.emit(\"completion\", task, slice, error);\n\t}\n}\n"]}
@@ -39,6 +39,12 @@ export declare function taskLabelWithin(task: {
39
39
  export declare function commandLabel(command: string, width: number): string;
40
40
  export declare function statusGlyph(status: BgTaskStatus, stalled?: boolean): string;
41
41
  export declare function statusColor(status: BgTaskStatus, stalled?: boolean): "success" | "error" | "warning" | "accent";
42
+ /** Shared running/waiting/finished count vocabulary for tools, menus, and footer. */
43
+ export declare function formatTaskCounts(counts: {
44
+ running: number;
45
+ total: number;
46
+ stalled: number;
47
+ }): string | undefined;
42
48
  /** The footer segment, or nothing when this session has no tasks at all. */
43
49
  export declare function formatStatusline(counts: {
44
50
  running: number;
@@ -1 +1 @@
1
- {"version":3,"file":"task-view.d.ts","sourceRoot":"","sources":["../../../src/extensions/background/task-view.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,iGAAiG;AACjG,wBAAgB,SAAS,CAAC,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,SAAa,GAAG,MAAM,CAEjG;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,SAAa,GAAG,MAAM,CAEpG;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,QAAQ,IAAI,MAAM,CAEnF;AAED,0FAA0F;AAC1F,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzF;AAED,sFAAsF;AACtF,wBAAgB,SAAS,CAAC,IAAI,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAGjF;AAED,gEAAgE;AAChE,wBAAgB,eAAe,CAAC,IAAI,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEtG;AAED,2FAA2F;AAC3F,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAa3E;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAa/G;AAED,4EAA4E;AAC5E,wBAAgB,gBAAgB,CAAC,MAAM,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,GAAG,SAAS,CAUhH"}
1
+ {"version":3,"file":"task-view.d.ts","sourceRoot":"","sources":["../../../src/extensions/background/task-view.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,iGAAiG;AACjG,wBAAgB,SAAS,CAAC,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,SAAa,GAAG,MAAM,CAEjG;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,SAAa,GAAG,MAAM,CAEpG;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,QAAQ,IAAI,MAAM,CAEnF;AAED,0FAA0F;AAC1F,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzF;AAED,sFAAsF;AACtF,wBAAgB,SAAS,CAAC,IAAI,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAGjF;AAED,gEAAgE;AAChE,wBAAgB,eAAe,CAAC,IAAI,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEtG;AAED,2FAA2F;AAC3F,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAa3E;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAa/G;AAED,qFAAqF;AACrF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,GAAG,SAAS,CAUhH;AAED,4EAA4E;AAC5E,wBAAgB,gBAAgB,CAAC,MAAM,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,GAAG,SAAS,CAGhH"}
@@ -71,20 +71,25 @@ export function statusColor(status, stalled) {
71
71
  return "accent";
72
72
  }
73
73
  }
74
- /** The footer segment, or nothing when this session has no tasks at all. */
75
- export function formatStatusline(counts) {
74
+ /** Shared running/waiting/finished count vocabulary for tools, menus, and footer. */
75
+ export function formatTaskCounts(counts) {
76
76
  if (counts.total === 0)
77
77
  return undefined;
78
78
  // Stalled tasks are running tasks: report them separately so the counts add up.
79
79
  const running = counts.running - counts.stalled;
80
- const ended = counts.total - counts.running;
80
+ const finished = counts.total - counts.running;
81
81
  const parts = [];
82
82
  if (running > 0)
83
83
  parts.push(`${running} running`);
84
84
  if (counts.stalled > 0)
85
85
  parts.push(`${counts.stalled} waiting for input`);
86
- if (ended > 0)
87
- parts.push(`${ended} done`);
88
- return `bg ${parts.join(" · ")}`;
86
+ if (finished > 0)
87
+ parts.push(`${finished} finished`);
88
+ return parts.join(" · ");
89
+ }
90
+ /** The footer segment, or nothing when this session has no tasks at all. */
91
+ export function formatStatusline(counts) {
92
+ const summary = formatTaskCounts(counts);
93
+ return summary ? `bg ${summary}` : undefined;
89
94
  }
90
95
  //# sourceMappingURL=task-view.js.map