@marcoscale98/pi-extensible-workflows 5.14.1-fork.1 → 5.19.1-fork.1

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 (94) hide show
  1. package/CHANGELOG.md +135 -0
  2. package/dist/src/agent-execution.js +114 -87
  3. package/dist/src/background-widget.d.ts +61 -0
  4. package/dist/src/background-widget.js +23 -16
  5. package/dist/src/decoders.js +28 -1
  6. package/dist/src/execution.d.ts +4 -2
  7. package/dist/src/execution.js +43 -2
  8. package/dist/src/host-delivery.js +1 -0
  9. package/dist/src/host-navigator.d.ts +18 -0
  10. package/dist/src/host-navigator.js +71 -13
  11. package/dist/src/host-recovery.d.ts +5 -2
  12. package/dist/src/host-recovery.js +3 -3
  13. package/dist/src/host-view.d.ts +21 -1
  14. package/dist/src/host-view.js +138 -47
  15. package/dist/src/host.d.ts +2 -2
  16. package/dist/src/host.js +246 -60
  17. package/dist/src/index.d.ts +3 -1
  18. package/dist/src/index.js +1346 -622
  19. package/dist/src/index.js.map +3 -3
  20. package/dist/src/paths.d.ts +2 -0
  21. package/dist/src/paths.js +2 -0
  22. package/dist/src/registry.js +3 -2
  23. package/dist/src/roles.d.ts +70 -0
  24. package/dist/src/roles.js +326 -0
  25. package/dist/src/script-tools.d.ts +27 -0
  26. package/dist/src/script-tools.js +87 -0
  27. package/dist/src/settings.d.ts +26 -0
  28. package/dist/src/settings.js +277 -0
  29. package/dist/src/trajectory.d.ts +39 -4
  30. package/dist/src/trajectory.js +82 -5
  31. package/dist/src/types.d.ts +30 -3
  32. package/dist/src/types.js +1 -1
  33. package/dist/src/utils.d.ts +21 -1
  34. package/dist/src/utils.js +40 -0
  35. package/dist/src/validation.d.ts +10 -17
  36. package/dist/src/validation.js +29 -458
  37. package/dist/starter/index.js +0 -2
  38. package/dist/starter/index.js.map +1 -1
  39. package/dist/starter/review-loop.d.ts +0 -13
  40. package/dist/starter/review-loop.js +0 -2
  41. package/dist/subagents/index.js +1344 -798
  42. package/dist/subagents/index.js.map +3 -3
  43. package/dist/subagents/src/contracts.d.ts +49 -29
  44. package/dist/subagents/src/contracts.js +18 -7
  45. package/dist/subagents/src/index.d.ts +1 -1
  46. package/dist/subagents/src/index.js +15 -7
  47. package/dist/subagents/src/manager.js +32 -13
  48. package/dist/subagents/src/navigator.js +396 -247
  49. package/dist/subagents/src/view.d.ts +24 -2
  50. package/dist/subagents/src/view.js +107 -80
  51. package/dist/trajectory/assets/index.html +370 -232
  52. package/dist/trajectory/assets/prism.min.js +13 -0
  53. package/dist/trajectory/index.js +445 -277
  54. package/dist/trajectory/index.js.map +3 -3
  55. package/dist/trajectory/src/assets/index.html +370 -232
  56. package/dist/trajectory/src/assets/prism.min.js +13 -0
  57. package/dist/trajectory/src/export.js +4 -2
  58. package/dist/trajectory/src/index.d.ts +2 -0
  59. package/dist/trajectory/src/index.js +151 -60
  60. package/dist/trajectory/src/server.js +138 -11
  61. package/dist/trajectory/src/server.js.map +2 -2
  62. package/package.json +7 -6
  63. package/skills/pi-extensible-workflows/SKILL.md +2 -0
  64. package/src/agent-execution.ts +110 -80
  65. package/src/background-widget.ts +26 -19
  66. package/src/decoders.ts +22 -1
  67. package/src/execution.ts +41 -4
  68. package/src/host-delivery.ts +1 -0
  69. package/src/host-navigator.ts +58 -14
  70. package/src/host-recovery.ts +8 -7
  71. package/src/host-view.ts +116 -42
  72. package/src/host.ts +223 -55
  73. package/src/index.ts +3 -1
  74. package/src/paths.ts +3 -0
  75. package/src/registry.ts +3 -2
  76. package/src/roles.ts +327 -0
  77. package/src/script-tools.ts +76 -0
  78. package/src/settings.ts +224 -0
  79. package/src/trajectory.ts +97 -9
  80. package/src/types.ts +12 -5
  81. package/src/utils.ts +36 -1
  82. package/src/validation.ts +30 -356
  83. package/starter/review-loop.ts +0 -2
  84. package/subagents/README.md +3 -3
  85. package/subagents/src/contracts.ts +22 -7
  86. package/subagents/src/index.ts +18 -7
  87. package/subagents/src/manager.ts +31 -13
  88. package/subagents/src/navigator.ts +336 -180
  89. package/subagents/src/view.ts +108 -76
  90. package/trajectory/src/assets/index.html +370 -232
  91. package/trajectory/src/assets/prism.min.js +13 -0
  92. package/trajectory/src/export.ts +4 -2
  93. package/trajectory/src/index.ts +124 -47
  94. package/trajectory/src/server.ts +114 -14
@@ -1,6 +1,8 @@
1
- import type { AgentToolResult, ExtensionContext, Theme } from "@earendil-works/pi-coding-agent";
1
+ import type { AgentToolResult, ExtensionAPI, ExtensionContext, Theme } from "@earendil-works/pi-coding-agent";
2
2
  import { truncateToWidth } from "@earendil-works/pi-tui";
3
- import { formatCost, formatStalledDuration, sanitizeDisplayText, WORKFLOW_AGENT_STALL_THRESHOLD_MS } from "../../src/index.js";
3
+ import { formatCost, formatStalledDuration, formatWorkflowRuntime, sanitizeDisplayText, WORKFLOW_AGENT_STALL_THRESHOLD_MS } from "../../src/index.js";
4
+ import { agentActivityLabel, stalledDuration, textBlock } from "../../src/host-view.js";
5
+ import { drawFrame, formatElapsed, formatTokens, mark, QUIET_MS, REPAINT_MS, type Paint } from "../../src/background-widget.js";
4
6
  import type { SubagentRunRequest, SubagentStatus } from "./contracts.js";
5
7
 
6
8
  const SPINNER = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"] as const;
@@ -18,13 +20,6 @@ export type SubagentRenderState = {
18
20
  subagentProgressFrozenAt?: number;
19
21
  };
20
22
 
21
- function textBlock(text: string) {
22
- return {
23
- render(width: number): string[] { return text.split("\n").map((line) => truncateToWidth(line, Math.max(1, width), "…")); },
24
- invalidate() {},
25
- };
26
- }
27
-
28
23
  function roleName(value: unknown): string | undefined {
29
24
  if (typeof value === "string") return value.trim() || undefined;
30
25
  if (typeof value !== "object" || value === null || Array.isArray(value)) return undefined;
@@ -72,18 +67,6 @@ function statusValue(value: unknown): SubagentStatus | undefined {
72
67
  return value as SubagentStatus;
73
68
  }
74
69
 
75
- function runtime(startedAt: number | undefined, finishedAt: number | undefined, now: number): string {
76
- if (startedAt === undefined) return "";
77
- const seconds = Math.max(0, Math.floor(((finishedAt ?? now) - startedAt) / 1000));
78
- if (seconds < 60) return `${String(seconds)}s`;
79
- const minutes = Math.floor(seconds / 60);
80
- const remainingSeconds = seconds % 60;
81
- if (minutes < 60) return `${String(minutes)}m${remainingSeconds ? ` ${String(remainingSeconds)}s` : ""}`;
82
- const hours = Math.floor(minutes / 60);
83
- const remainingMinutes = minutes % 60;
84
- return `${String(hours)}h${remainingMinutes ? ` ${String(remainingMinutes)}m` : ""}`;
85
- }
86
-
87
70
  function stateGlyph(state: SubagentStatus["state"], spinner: string): string {
88
71
  if (state === "running") return spinner;
89
72
  return state === "completed" ? "✓" : "✗";
@@ -94,30 +77,14 @@ function stateColor(state: SubagentStatus["state"]): "accent" | "success" | "err
94
77
  return state === "completed" ? "success" : "error";
95
78
  }
96
79
 
97
- function activity(status: SubagentStatus): string | undefined {
98
- if (status.state !== "running") return undefined;
99
- const current = status.progress?.activity;
100
- if (current?.kind === "reasoning" || current?.kind === "text") {
101
- const name = current.kind === "reasoning" ? "reasoning" : "responding";
102
- const text = sanitizeDisplayText(current.text);
103
- return text && text !== name ? `${name} · ${text}` : name;
104
- }
105
- if (current?.kind === "tool") return sanitizeDisplayText(current.text);
106
- return sanitizeDisplayText([...(status.progress?.toolCalls ?? [])].reverse().find(({ state }) => state === "running")?.name ?? "");
107
- }
108
-
109
- function stalledDuration(status: SubagentStatus, now: number): number | undefined {
110
- const lastEventAt = status.progress?.lastEventAt;
111
- if (status.state !== "running" || lastEventAt === undefined || !Number.isFinite(lastEventAt)) return undefined;
112
- const duration = now - lastEventAt;
113
- return duration >= WORKFLOW_AGENT_STALL_THRESHOLD_MS ? duration : undefined;
114
- }
115
-
116
- function accounting(status: SubagentStatus): string | undefined {
80
+ /** Tokens and cost as the workflow header shows them. */
81
+ function usageStats(status: SubagentStatus): string {
117
82
  const value = status.progress?.accounting;
118
- if (!value) return undefined;
119
- const total = value.input + value.output + value.cacheRead + value.cacheWrite;
120
- return `tokens=${String(total)} cost=${formatCost(value.cost) || "$0.00"}`;
83
+ return value ? [formatTokens(value.input + value.output), formatCost(value.cost)].filter(Boolean).join(" · ") : "";
84
+ }
85
+ function modelName(status: SubagentStatus): string {
86
+ const model = status.progress?.state?.model ?? status.attemptDetails?.at(-1)?.setup.model;
87
+ return model ? `${model.model}${model.thinking ? `:${model.thinking}` : ""}` : "";
121
88
  }
122
89
 
123
90
  function timestamp(value: number | undefined): string | undefined {
@@ -139,22 +106,21 @@ function boundedValue(value: unknown): string {
139
106
 
140
107
  function formatSubagentProgress(status: SubagentStatus, args: SubagentRenderArgs, theme: Theme, spinner: string, now: number, expanded: boolean): string {
141
108
  const color = stateColor(status.state);
142
- const elapsed = runtime(status.startedAt, status.finishedAt, now);
109
+ const elapsed = status.startedAt === undefined ? "" : formatWorkflowRuntime((status.finishedAt ?? now) - status.startedAt);
143
110
  const metadata = requestMetadata(args, args.id === undefined);
111
+ const stats = usageStats(status);
144
112
  const lines = [
145
- `${theme.fg(color, stateGlyph(status.state, spinner))} ${theme.bold(theme.fg("accent", `Subagent: ${label({ ...args, id: status.id })}`))} ${theme.fg(color, `[${status.state}]`)}${metadata ? ` ${theme.fg("dim", metadata)}` : ""}${elapsed ? ` runtime=${elapsed}` : ""}`,
113
+ `${theme.fg(color, stateGlyph(status.state, "●"))} ${theme.bold(theme.fg("accent", `Subagent: ${label({ ...args, id: status.id })}`))} ${theme.fg(color, `[${status.state}]`)}${metadata ? ` ${theme.fg("dim", metadata)}` : ""}${stats ? ` ${stats}` : ""}${elapsed ? ` runtime=${elapsed}` : ""}`,
146
114
  ];
147
- const current = activity(status);
148
- const stalled = stalledDuration(status, now);
149
- if (current) lines.push(` ${theme.fg("accent", spinner)} ${theme.fg("dim", current)}${stalled === undefined ? "" : ` ${theme.fg("warning", `- stalled? ${formatStalledDuration(stalled)}`)}`}`);
115
+ const current = status.state === "running" ? agentActivityLabel(status.progress ?? {}) : undefined;
116
+ const stalled = stalledDuration({ ...status.progress, state: status.state }, now);
117
+ if (current || status.state === "running") lines.push(` ${theme.fg("accent", spinner)}${current ? ` ${theme.fg("dim", current)}` : ""}${stalled === undefined ? "" : ` ${theme.fg("warning", `- stalled? ${formatStalledDuration(stalled)}`)}`}`);
150
118
  else if (stalled !== undefined) lines.push(` ${theme.fg("warning", `stalled? ${formatStalledDuration(stalled)}`)}`);
151
119
  if (status.error) lines.push(` ${theme.fg("error", `${status.error.code}: ${status.error.message}`)}`);
152
120
  if (expanded) {
153
121
  lines.push(` ${theme.fg("dim", `id=${status.id}`)}`);
154
122
  const model = status.progress?.state?.model;
155
123
  if (model) lines.push(` ${theme.fg("dim", `model=${model.provider}/${model.model}${model.thinking ? `:${model.thinking}` : ""}`)}`);
156
- const usage = accounting(status);
157
- if (usage) lines.push(` ${theme.fg("dim", usage)}`);
158
124
  if (status.worktree) lines.push(` ${theme.fg("dim", `worktree=${status.worktree.path} branch=${status.worktree.branch}`)}`);
159
125
  }
160
126
  return lines.join("\n");
@@ -215,7 +181,7 @@ export function subagentProgressBlock(status: SubagentStatus, args: SubagentRend
215
181
  render(width: number): string[] {
216
182
  const now = TERMINAL_STATES.has(current.state) ? frozenAt : Date.now();
217
183
  if (!TERMINAL_STATES.has(current.state)) frozenAt = now;
218
- const frame = SPINNER[Math.floor(now / 80) % SPINNER.length] ?? "◇";
184
+ const frame = SPINNER[Math.floor(now / REPAINT_MS) % SPINNER.length] ?? "◇";
219
185
  return formatSubagentProgress(current, args, currentTheme, frame, now, expanded).split("\n").map((line) => truncateToWidth(line, Math.max(1, width), "…"));
220
186
  },
221
187
  invalidate() {},
@@ -233,7 +199,7 @@ export function renderSubagentResult(result: AgentToolResult<unknown>, options:
233
199
  const status = state.subagentStatus;
234
200
 
235
201
  if (status?.state === "running" && options.isPartial && !state.subagentSpinner) {
236
- state.subagentSpinner = setInterval(() => { context.invalidate(); }, 80);
202
+ state.subagentSpinner = setInterval(() => { context.invalidate(); }, REPAINT_MS);
237
203
  state.subagentSpinner.unref();
238
204
  } else if ((!options.isPartial || status?.state !== "running") && state.subagentSpinner) {
239
205
  clearInterval(state.subagentSpinner);
@@ -257,9 +223,77 @@ export function renderSubagentResult(result: AgentToolResult<unknown>, options:
257
223
 
258
224
  type WidgetRun = { status: Readonly<SubagentStatus>; request: Readonly<SubagentRunRequest> };
259
225
 
260
- export function createSubagentBackgroundWidget() {
226
+ /** One run as a workflow agent row: a quiet or stalled warning on the left, model and figures against the right rule. */
227
+ function widgetRow({ status, request }: WidgetRun, now: number, paint: Paint): { text: string; right: string } {
228
+ const lastEventAt = status.progress?.lastEventAt;
229
+ const silent = lastEventAt === undefined || !Number.isFinite(lastEventAt) || now - lastEventAt < QUIET_MS ? undefined : now - lastEventAt;
230
+ const role = silent !== undefined && silent >= WORKFLOW_AGENT_STALL_THRESHOLD_MS ? "error" : "warning";
231
+ const icon = silent === undefined ? mark(status.state, now, paint) : paint(role, "⚠");
232
+ const warning = silent === undefined ? "" : ` ${paint(role, `${role === "error" ? "stalled" : "quiet"} ${formatElapsed(silent)}`)}`;
233
+ const accounting = status.progress?.accounting;
234
+ const attempts = status.attempts ?? 1;
235
+ const right = [
236
+ modelName(status),
237
+ formatTokens(accounting === undefined ? undefined : accounting.input + accounting.output),
238
+ formatCost(accounting?.cost),
239
+ status.startedAt === undefined ? "" : formatElapsed(now - status.startedAt),
240
+ attempts > 1 ? `attempt ${String(attempts)}` : "",
241
+ ].filter(Boolean).join(" · ");
242
+ return { text: `${icon} ${sanitizeDisplayText(label({ ...request, id: status.id }))}${warning}`, right };
243
+ }
244
+
245
+ const RECEIPT_ENTRY_TYPE = "piewf-subagent-receipt";
246
+ type SubagentReceipt = { readonly id: string; readonly label: string; readonly state: string; readonly model?: string; readonly role?: string; readonly tools?: readonly string[]; readonly input: number; readonly output: number; readonly cacheRead: number; readonly costUsd: number; readonly durationMs: number; readonly attempts: number; readonly error?: string };
247
+
248
+ function receiptFor(status: Readonly<SubagentStatus>, request: Readonly<SubagentRunRequest>): SubagentReceipt {
249
+ const accounting = status.progress?.accounting;
250
+ const model = modelName(status);
251
+ const role = roleName(request.role);
252
+ const tools = status.progress?.state?.tools ?? status.attemptDetails?.at(-1)?.setup.tools;
253
+ return {
254
+ id: status.id,
255
+ label: label({ ...request, id: status.id }),
256
+ state: status.state,
257
+ ...(model ? { model } : {}),
258
+ ...(role === undefined ? {} : { role }),
259
+ ...(tools === undefined ? {} : { tools: [...tools] }),
260
+ input: accounting?.input ?? 0,
261
+ output: accounting?.output ?? 0,
262
+ cacheRead: accounting?.cacheRead ?? 0,
263
+ costUsd: accounting?.cost ?? 0,
264
+ durationMs: status.startedAt === undefined ? 0 : Math.max(0, (status.finishedAt ?? Date.now()) - status.startedAt),
265
+ attempts: status.attempts ?? 1,
266
+ ...(status.error === undefined ? {} : { error: `${status.error.code}: ${status.error.message}` }),
267
+ };
268
+ }
269
+
270
+ /** The transcript line a finished background run leaves behind, in the shape of the workflow receipt. */
271
+ export function renderSubagentReceipt(data: SubagentReceipt, expanded: boolean, theme: Theme): string[] {
272
+ const glyph = data.state === "completed" ? theme.fg("success", "✓") : data.state === "failed" ? theme.fg("error", "✗") : theme.fg("muted", "·");
273
+ const headline = [formatTokens(data.input + data.output), formatCost(data.costUsd) || "$0.00", formatElapsed(data.durationMs), data.state].filter(Boolean).join(" · ");
274
+ const lines = [`${glyph} ${theme.bold(sanitizeDisplayText(data.label))} ${theme.fg("muted", headline)}`];
275
+ if (!expanded) return lines;
276
+ const meta = [data.model ?? "", data.role ? `role ${data.role}` : "", data.attempts > 1 ? `${String(data.attempts)} attempts` : "", data.tools?.join(" ") ?? ""].filter(Boolean);
277
+ if (meta.length > 0) lines.push(theme.fg("muted", ` ${meta.join(" · ")}`));
278
+ const split = [data.input ? `in ${formatTokens(data.input)}` : "", data.output ? `out ${formatTokens(data.output)}` : "", data.cacheRead ? `cache ${formatTokens(data.cacheRead)}` : ""].filter(Boolean);
279
+ if (split.length > 0) lines.push(theme.fg("muted", ` ${split.join(" · ")}`));
280
+ if (data.error !== undefined) lines.push(theme.fg("error", ` ${sanitizeDisplayText(data.error)}`));
281
+ lines.push(theme.fg("muted", ` run ${data.id}`));
282
+ return lines;
283
+ }
284
+
285
+ type ReceiptHost = { appendEntry?: (customType: string, data: SubagentReceipt) => void; registerEntryRenderer?: ExtensionAPI["registerEntryRenderer"] };
286
+
287
+ export function createSubagentBackgroundWidget(host: ReceiptHost = {}) {
261
288
  const key = "piewf-subagents-background";
262
289
  const runs = new Map<string, WidgetRun>();
290
+ const receipted = new Set<string>();
291
+ host.registerEntryRenderer?.<SubagentReceipt>(RECEIPT_ENTRY_TYPE, (entry, options, theme) => {
292
+ if (!entry.data) return undefined;
293
+ const lines = renderSubagentReceipt(entry.data, options.expanded, theme);
294
+ // Pi treats an over-wide line as fatal, and an error message has no bound.
295
+ return { render: (width: number): string[] => lines.map((line) => truncateToWidth(line, Math.max(1, width), "…")), invalidate() {} };
296
+ });
263
297
  let context: ExtensionContext | undefined;
264
298
  let requestRender: (() => void) | undefined;
265
299
  let timer: ReturnType<typeof setInterval> | undefined;
@@ -289,29 +323,20 @@ export function createSubagentBackgroundWidget() {
289
323
  return {
290
324
  render(width: number): string[] {
291
325
  const now = Date.now();
292
- const frame = SPINNER[Math.floor(now / 80) % SPINNER.length] ?? "◇";
293
- const title = theme.bold(theme.fg("accent", `Subagents (${String(runs.size)} running)`));
294
- const blocks = [...runs.values()].map(({ status, request }) => formatSubagentProgress(status, request, theme, frame, now, false).split("\n"));
295
- const allRunsFit = blocks.reduce((rows, block) => rows + block.length, 1) <= MAX_BACKGROUND_WIDGET_ROWS;
296
- const runRowBudget = allRunsFit ? MAX_BACKGROUND_WIDGET_ROWS - 1 : MAX_BACKGROUND_WIDGET_ROWS - 2;
297
- const lines = [title];
298
- let runRows = 0;
299
- let displayedRuns = 0;
300
- for (const block of blocks) {
301
- if (runRows + block.length > runRowBudget) break;
302
- lines.push(...block);
303
- runRows += block.length;
304
- displayedRuns += 1;
305
- }
306
- const hiddenRuns = blocks.length - displayedRuns;
307
- if (hiddenRuns > 0) lines.push(`… ${String(hiddenRuns)} more`);
308
- return lines.map((line) => truncateToWidth(line, Math.max(1, width), "…"));
326
+ const paintRole: Paint = (role, text) => theme.fg(role, text);
327
+ // One row per run, so the default concurrency of eight fills the frame exactly.
328
+ // ponytail: no Alt+O scrolling as in the workflow widget; add it if runs routinely exceed the frame.
329
+ const budget = MAX_BACKGROUND_WIDGET_ROWS - 2;
330
+ const rows = [...runs.values()].map((run) => widgetRow(run, now, paintRole));
331
+ const body = rows.length <= budget ? rows : [...rows.slice(0, budget - 1), { text: theme.fg("muted", `… ${String(rows.length - budget + 1)} more`) }];
332
+ const title = runs.size === 1 ? "Subagent" : `Subagents · ${String(runs.size)} runs`;
333
+ return drawFrame(title, "", body, width, paintRole, (text) => theme.fg("accent", text)).map((line) => truncateToWidth(line, Math.max(1, width), ""));
309
334
  },
310
335
  invalidate() {},
311
336
  };
312
337
  }, { placement: "belowEditor" });
313
338
  showing = true;
314
- timer = setInterval(() => { requestRender?.(); }, 80);
339
+ timer = setInterval(() => { requestRender?.(); }, REPAINT_MS);
315
340
  timer.unref();
316
341
  } catch {
317
342
  hide();
@@ -322,12 +347,19 @@ export function createSubagentBackgroundWidget() {
322
347
  start(next: ExtensionContext): void {
323
348
  hide();
324
349
  runs.clear();
350
+ receipted.clear();
325
351
  context = next.mode === "tui" ? next : undefined;
326
352
  },
327
353
  update(status: Readonly<SubagentStatus>, request: Readonly<SubagentRunRequest>): void {
328
354
  if (request.mode !== "background" || context === undefined) return;
329
- if (TERMINAL_STATES.has(status.state)) runs.delete(status.id);
330
- else runs.set(status.id, { status, request });
355
+ if (TERMINAL_STATES.has(status.state)) {
356
+ runs.delete(status.id);
357
+ // A foreground run already has its tool block; a background one leaves a receipt, once, like a workflow run.
358
+ if (!receipted.has(status.id)) {
359
+ receipted.add(status.id);
360
+ try { host.appendEntry?.(RECEIPT_ENTRY_TYPE, receiptFor(status, request)); } catch { /* A receipt is display-only. */ }
361
+ }
362
+ } else runs.set(status.id, { status, request });
331
363
  paint();
332
364
  },
333
365
  dispose(): void {
@@ -339,9 +371,9 @@ export function createSubagentBackgroundWidget() {
339
371
  }
340
372
 
341
373
 
342
- export function renderSubagentInspectCall(args: { id?: string }, theme: Theme) {
374
+ export function renderSubagentInspectCall(args: { id?: string; scope?: string }, theme: Theme) {
343
375
  const title = theme.fg("toolTitle", theme.bold("subagents_inspect"));
344
- return textBlock(args.id ? `${title} ${theme.fg("accent", args.id)}` : `${title} ${theme.fg("muted", "all")}`);
376
+ return textBlock(args.id ? `${title} ${theme.fg("accent", args.id)}` : `${title} ${theme.fg("muted", args.scope === "all" ? "all" : "session")}`);
345
377
  }
346
378
 
347
379
  export function renderSubagentInspectResult(result: AgentToolResult<unknown>, options: { expanded: boolean }, theme: Theme, args: { id?: string }) {