pi-subagents 0.66.0 → 0.68.0
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.
- package/CHANGELOG.md +138 -0
- package/README.md +5 -4
- package/agents/evidence-auditor.md +34 -0
- package/agents/reviewer.md +3 -2
- package/docs/agents.md +43 -15
- package/docs/configuration.md +67 -23
- package/docs/extension-api.md +38 -19
- package/docs/missions.md +10 -2
- package/docs/models.md +11 -79
- package/docs/observability.md +22 -12
- package/docs/standalone-background.md +59 -0
- package/docs/tool-reference.md +33 -20
- package/docs/watchdog.md +39 -10
- package/docs/workflows.md +37 -13
- package/index.ts +5 -2
- package/inspector-runner.mjs +2 -2
- package/package.json +4 -2
- package/prompts/parallel-review.md +1 -1
- package/runner-peer-loader.mjs +24 -0
- package/runner-peer-preload.mjs +32 -0
- package/skills/pi-subagents/SKILL.md +32 -21
- package/skills/pi-subagents/references/constraints-and-recipes.md +3 -2
- package/skills/pi-subagents/references/execution-controls.md +11 -9
- package/skills/pi-subagents/references/management-authoring-rpc.md +0 -1
- package/skills/pi-subagents/references/multi-lane-orchestration.md +1 -1
- package/skills/pi-subagents/references/prompting-and-roles.md +17 -13
- package/skills/pi-subagents/references/review-and-validation.md +3 -3
- package/src/agents/advertised-agent-prompt.ts +34 -3
- package/src/agents/agent-management.ts +57 -58
- package/src/agents/agent-serializer.ts +4 -3
- package/src/agents/agents.ts +190 -71
- package/src/agents/builtin-names.ts +1 -0
- package/src/agents/chain-serializer.ts +5 -0
- package/src/agents/runtime-agent-registry.ts +7 -6
- package/src/api/delegation.ts +4 -0
- package/src/api/preflight.ts +94 -59
- package/src/api/required-child-extensions.ts +6 -0
- package/src/api/shared-types.ts +2 -0
- package/src/extension/config.ts +10 -37
- package/src/extension/fanout-child.ts +66 -4
- package/src/extension/herdr-pi-bridge.ts +160 -0
- package/src/extension/index.ts +62 -39
- package/src/extension/public-execution.ts +7 -5
- package/src/extension/rpc.ts +4 -0
- package/src/extension/schemas.ts +81 -81
- package/src/extension/tool-description.ts +30 -82
- package/src/inspectors/actions.ts +148 -0
- package/src/inspectors/ghostty/actions.ts +74 -0
- package/src/inspectors/ghostty/plugin.ts +17 -0
- package/src/inspectors/herdr/actions.ts +99 -179
- package/src/inspectors/herdr/plugin.ts +20 -0
- package/src/inspectors/herdr/project-panes.ts +1 -1
- package/src/inspectors/{herdr/inspector-runner.ts → inspector-runner.ts} +12 -12
- package/src/inspectors/plugins.ts +8 -0
- package/src/inspectors/{herdr/session-roots-codec.ts → session-roots-codec.ts} +3 -14
- package/src/inspectors/types.ts +51 -0
- package/src/intercom/intercom-bridge.ts +50 -8
- package/src/intercom/native-supervisor-channel.ts +44 -31
- package/src/policy/authority.ts +4 -0
- package/src/profiles/profiles.ts +12 -6
- package/src/runs/background/active-async-capacity.ts +4 -0
- package/src/runs/background/active-run-index.ts +17 -1
- package/src/runs/background/async-execution.ts +348 -176
- package/src/runs/background/async-job-tracker.ts +8 -6
- package/src/runs/background/async-resume.ts +17 -12
- package/src/runs/background/async-status.ts +15 -4
- package/src/runs/background/auto-drain.ts +23 -10
- package/src/runs/background/binary-bootstrap.ts +38 -0
- package/src/runs/background/chain-append.ts +1 -1
- package/src/runs/background/chain-root-attachment.ts +14 -33
- package/src/runs/background/fleet-view.ts +30 -2
- package/src/runs/background/notify.ts +105 -7
- package/src/runs/background/owned-process-tree.ts +29 -2
- package/src/runs/background/result-files.ts +8 -4
- package/src/runs/background/result-watcher.ts +19 -2
- package/src/runs/background/run-child-session.ts +81 -33
- package/src/runs/background/run-status.ts +3 -0
- package/src/runs/background/runner-aliases.ts +12 -33
- package/src/runs/background/runner-child-launch.ts +6 -1
- package/src/runs/background/runner-child-sessions.ts +5 -4
- package/src/runs/background/runner-http-dispatcher.ts +119 -0
- package/src/runs/background/scheduled-runs.ts +51 -18
- package/src/runs/background/stale-run-reconciler.ts +35 -11
- package/src/runs/background/steering.ts +20 -2
- package/src/runs/background/subagent-runner.ts +441 -304
- package/src/runs/background/subagent-wait.ts +176 -28
- package/src/runs/background/wait-completions.ts +75 -27
- package/src/runs/background/wait-subscriptions.ts +9 -3
- package/src/runs/background/wait-tool.ts +5 -3
- package/src/runs/foreground/async-steering-action.ts +18 -7
- package/src/runs/foreground/async-stop-action.ts +93 -3
- package/src/runs/foreground/execution.ts +134 -248
- package/src/runs/foreground/foreground-history.ts +2 -1
- package/src/runs/foreground/prompt-audit.ts +3 -1
- package/src/runs/foreground/subagent-executor.ts +374 -178
- package/src/runs/foreground/workflow-detach-reconcile.ts +2 -0
- package/src/runs/foreground/workflow-foreground-steering.ts +2 -1
- package/src/runs/shared/acceptance.ts +38 -11
- package/src/runs/shared/async-status-projection.ts +127 -33
- package/src/runs/shared/capability-ceiling.ts +2 -0
- package/src/runs/shared/child-hooks.ts +25 -10
- package/src/runs/shared/child-launch-plan.ts +15 -3
- package/src/runs/shared/child-launch.ts +28 -5
- package/src/runs/shared/child-lifecycle.ts +6 -3
- package/src/runs/shared/child-runtime-config.ts +8 -1
- package/src/runs/shared/child-session.ts +127 -52
- package/src/runs/shared/child-tool-plan.ts +142 -11
- package/src/runs/shared/completion-guard.ts +5 -3
- package/src/runs/shared/dynamic-fanout.ts +2 -2
- package/src/runs/shared/effective-system-prompt.ts +33 -0
- package/src/runs/shared/external-cli-contract.ts +11 -1
- package/src/runs/shared/external-cli-preflight.ts +6 -2
- package/src/runs/shared/external-cli-runner.ts +9 -7
- package/src/runs/shared/herdr-connection.ts +134 -0
- package/src/runs/shared/herdr-external-adapters.ts +169 -0
- package/src/runs/shared/herdr-machine.ts +279 -0
- package/src/runs/shared/herdr-pi-protocol.ts +59 -0
- package/src/runs/shared/herdr-placed-run.ts +263 -0
- package/src/runs/shared/llm-intent-arbiter.ts +12 -3
- package/src/runs/shared/model-resolution-diagnostic.ts +76 -0
- package/src/runs/shared/{model-fallback.ts → model-resolution.ts} +22 -235
- package/src/runs/shared/model-scope.ts +1 -1
- package/src/runs/shared/nested-events.ts +11 -2
- package/src/runs/shared/orca-progress-tabs.ts +1 -1
- package/src/runs/shared/parallel-utils.ts +7 -2
- package/src/runs/shared/pi-spawn.ts +10 -0
- package/src/runs/shared/subagent-prompt-runtime.ts +12 -4
- package/src/runs/shared/task-intent.ts +46 -13
- package/src/runs/shared/workflow-async-child-guidance.ts +18 -0
- package/src/runs/shared/worktree-setup-command.ts +27 -4
- package/src/runs/shared/worktree.ts +45 -15
- package/src/shared/child-cache-retention.ts +43 -0
- package/src/shared/fork-context.ts +15 -72
- package/src/shared/launch-contract.ts +68 -8
- package/src/shared/opencode-session-headers.ts +30 -0
- package/src/shared/pruned-fork.ts +1 -1
- package/src/shared/required-child-extensions.ts +81 -0
- package/src/shared/settings.ts +5 -2
- package/src/shared/shortcuts.ts +0 -4
- package/src/shared/types.ts +74 -30
- package/src/slash/delegation-adapters.ts +3 -1
- package/src/slash/delegation-request.ts +14 -0
- package/src/slash/slash-commands.ts +2 -7
- package/src/slash/subagents-admin.ts +24 -13
- package/src/tui/fleet-status.ts +164 -19
- package/src/tui/fleet.ts +16 -14
- package/src/tui/render.ts +168 -37
- package/src/watchdog/child-status.ts +28 -28
- package/src/watchdog/lsp-diagnostics.ts +1 -1
- package/src/watchdog/model-selection.ts +21 -1
- package/src/watchdog/permission-arbiter.ts +3 -1
- package/src/watchdog/register-child.ts +10 -2
- package/src/watchdog/register-main.ts +39 -35
- package/src/watchdog/render.ts +1 -1
- package/src/watchdog/review.ts +123 -74
- package/src/watchdog/rules.ts +1 -1
- package/src/watchdog/runtime.ts +100 -27
- package/src/watchdog/scope.ts +1 -1
- package/src/watchdog/settings.ts +3 -0
- package/src/watchdog/tool-actions.ts +13 -12
- package/src/watchdog/turn-delta.ts +23 -0
- package/src/watchdog/types.ts +5 -3
- package/src/watchdog/warning-format.ts +1 -1
- package/src/workflows/scripted-workflow.ts +279 -10
- package/src/workflows/workflow-checklist.ts +2 -2
- package/src/workflows/workflow-receipt.ts +21 -3
- package/src/workflows/workflow-resources.ts +13 -2
- package/runner-server-preload.mjs +0 -13
- package/src/runs/shared/model-exclusions.ts +0 -374
- package/src/runs/shared/readonly-model-continuation.ts +0 -69
- package/src/runs/shared/readonly-session-evidence.ts +0 -307
- /package/src/inspectors/{herdr/shell-command.ts → shell-command.ts} +0 -0
package/src/tui/fleet-status.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { contextModeLabel } from "../runs/shared/context-mode.ts";
|
|
|
8
8
|
import { formatWorkflowJsonPreview } from "../workflows/scripted-workflow.ts";
|
|
9
9
|
import { hostStepReportName, hostStepVerdictLabel } from "../runs/shared/host-step-status.ts";
|
|
10
10
|
import { isStaleExtensionContextError } from "../shared/extension-context.ts";
|
|
11
|
+
import { inlineWorkflowRenderKey } from "./render.ts";
|
|
11
12
|
import { formatWorkflowChecklistBottleneck, formatWorkflowChecklistPhase, formatWorkflowChecklistSummary, projectWorkflowChecklist, type WorkflowChecklistPhase, type WorkflowChecklistProjection } from "../workflows/workflow-checklist.ts";
|
|
12
13
|
|
|
13
14
|
export const FLEET_STATUS_WIDGET_KEY = "subagent-fleet-status";
|
|
@@ -17,6 +18,35 @@ const MAX_AGENT_ROWS = 6;
|
|
|
17
18
|
const REFRESH_MS = 500;
|
|
18
19
|
|
|
19
20
|
type Theme = ExtensionContext["ui"]["theme"];
|
|
21
|
+
|
|
22
|
+
const FLEET_AGENT_IDENTITY_COLORS = [
|
|
23
|
+
"mdLink",
|
|
24
|
+
"mdHeading",
|
|
25
|
+
"syntaxFunction",
|
|
26
|
+
"syntaxKeyword",
|
|
27
|
+
"syntaxNumber",
|
|
28
|
+
"syntaxType",
|
|
29
|
+
"syntaxVariable",
|
|
30
|
+
"customMessageLabel",
|
|
31
|
+
"toolTitle",
|
|
32
|
+
"thinkingMedium",
|
|
33
|
+
"thinkingHigh",
|
|
34
|
+
"mdQuote",
|
|
35
|
+
"bashMode",
|
|
36
|
+
"userMessageText",
|
|
37
|
+
"mdCode",
|
|
38
|
+
"syntaxOperator",
|
|
39
|
+
] as const satisfies readonly Exclude<Parameters<Theme["fg"]>[0], "accent" | "success" | "error" | "warning" | "muted" | "dim">[];
|
|
40
|
+
|
|
41
|
+
export function fleetAgentIdentityColor(identity: string): (typeof FLEET_AGENT_IDENTITY_COLORS)[number] {
|
|
42
|
+
let hash = 2166136261;
|
|
43
|
+
for (let i = 0; i < identity.length; i++) {
|
|
44
|
+
hash ^= identity.charCodeAt(i);
|
|
45
|
+
hash = Math.imul(hash, 16777619);
|
|
46
|
+
}
|
|
47
|
+
return FLEET_AGENT_IDENTITY_COLORS[(hash >>> 0) % FLEET_AGENT_IDENTITY_COLORS.length]!;
|
|
48
|
+
}
|
|
49
|
+
|
|
20
50
|
type FleetStatusTui = {
|
|
21
51
|
requestRender(): void;
|
|
22
52
|
};
|
|
@@ -26,6 +56,7 @@ type FleetStatusEntry = {
|
|
|
26
56
|
parentKey?: string;
|
|
27
57
|
workflowWrapper?: boolean;
|
|
28
58
|
agent: string;
|
|
59
|
+
displayLabel?: string;
|
|
29
60
|
modelThinking?: string;
|
|
30
61
|
description?: string;
|
|
31
62
|
startedAt: number;
|
|
@@ -41,10 +72,12 @@ type FleetStatusEntry = {
|
|
|
41
72
|
|
|
42
73
|
type FleetNestedRow = {
|
|
43
74
|
name: string;
|
|
75
|
+
agentIdentity?: string;
|
|
44
76
|
state: NestedRunSummary["state"] | NestedStepSummary["status"];
|
|
45
77
|
modelThinking?: string;
|
|
46
78
|
activity?: string;
|
|
47
79
|
startedAt?: number;
|
|
80
|
+
endedAt?: number;
|
|
48
81
|
depth: number;
|
|
49
82
|
overflow?: number;
|
|
50
83
|
};
|
|
@@ -60,6 +93,7 @@ export interface FleetStatusOptions {
|
|
|
60
93
|
refreshMs?: number;
|
|
61
94
|
maxAgentRows?: number;
|
|
62
95
|
placement?: FleetViewPlacement;
|
|
96
|
+
onWorkflowCoverageChange?: (ui: ExtensionContext["ui"], coverage: ReadonlyMap<string, string>) => void;
|
|
63
97
|
}
|
|
64
98
|
|
|
65
99
|
export function resolveFleetViewPlacement(value: unknown): FleetViewPlacement {
|
|
@@ -70,14 +104,21 @@ export function formatFleetElapsed(ms: number): string {
|
|
|
70
104
|
return `${Math.max(0, Math.round(ms / 1000))}s`;
|
|
71
105
|
}
|
|
72
106
|
|
|
73
|
-
|
|
107
|
+
function detailElapsed(row: Pick<AsyncStatusWorkflowRow, "startedAt" | "endedAt" | "durationMs"> & { state: string }): string | undefined {
|
|
108
|
+
const duration = row.state === "running" && row.startedAt !== undefined
|
|
109
|
+
? Date.now() - row.startedAt
|
|
110
|
+
: row.durationMs ?? (row.startedAt !== undefined && row.endedAt !== undefined ? row.endedAt - row.startedAt : undefined);
|
|
111
|
+
return duration !== undefined ? formatFleetElapsed(duration) : undefined;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function formatFleetTokens(count: number, window?: number, windowCount = 1): string {
|
|
74
115
|
const compact = (value: number): string => value >= 1_000_000
|
|
75
116
|
? `${(value / 1_000_000).toFixed(1)}M`
|
|
76
117
|
: value >= 1_000
|
|
77
118
|
? `${(value / 1_000).toFixed(1)}k`
|
|
78
119
|
: `${Math.max(0, Math.round(value))}`;
|
|
79
120
|
return window !== undefined
|
|
80
|
-
? `↓ ${compact(window)} window · ${compact(count)} spent`
|
|
121
|
+
? `↓ ${compact(window)} ${windowCount > 1 ? "Σ windows" : "window"} · ${compact(count)} spent`
|
|
81
122
|
: `↓ ${compact(count)} tokens`;
|
|
82
123
|
}
|
|
83
124
|
|
|
@@ -184,11 +225,13 @@ function nestedFleetRows(children: NestedRunSummary[] | undefined, visibleLimit:
|
|
|
184
225
|
const activity = nestedActivity(step);
|
|
185
226
|
rows.push({
|
|
186
227
|
name: step.agent,
|
|
228
|
+
agentIdentity: step.agent,
|
|
187
229
|
state: step.status,
|
|
188
230
|
depth,
|
|
189
231
|
...(modelThinking ? { modelThinking } : {}),
|
|
190
232
|
...(activity ? { activity } : {}),
|
|
191
233
|
...(step.startedAt !== undefined ? { startedAt: step.startedAt } : {}),
|
|
234
|
+
...(step.endedAt !== undefined ? { endedAt: step.endedAt } : {}),
|
|
192
235
|
});
|
|
193
236
|
if (!appendRuns(step.children, depth + 1)) {
|
|
194
237
|
omitted += nestedStepDisplayCount(steps, stepIndex + 1);
|
|
@@ -206,11 +249,13 @@ function nestedFleetRows(children: NestedRunSummary[] | undefined, visibleLimit:
|
|
|
206
249
|
const activity = nestedActivity(child);
|
|
207
250
|
rows.push({
|
|
208
251
|
name: nestedRunLabel(child),
|
|
252
|
+
agentIdentity: child.agent ?? child.agents?.join("\0") ?? child.id,
|
|
209
253
|
state: child.state,
|
|
210
254
|
depth,
|
|
211
255
|
...(modelThinking ? { modelThinking } : {}),
|
|
212
256
|
...(activity ? { activity } : {}),
|
|
213
257
|
...(child.startedAt !== undefined ? { startedAt: child.startedAt } : {}),
|
|
258
|
+
...(child.endedAt !== undefined ? { endedAt: child.endedAt } : {}),
|
|
214
259
|
});
|
|
215
260
|
}
|
|
216
261
|
if (!appendRuns(child.children, depth + 1)) {
|
|
@@ -320,6 +365,7 @@ function projectPaneEntries(state: SubagentState): FleetStatusEntry[] {
|
|
|
320
365
|
}
|
|
321
366
|
|
|
322
367
|
export function collectFleetStatusEntries(state: SubagentState): FleetStatusEntry[] {
|
|
368
|
+
const now = Date.now();
|
|
323
369
|
const entries: FleetStatusEntry[] = [];
|
|
324
370
|
const activeWorkflowKeys = new Set([...state.asyncJobs.values()]
|
|
325
371
|
.filter((job) => job.mode === "workflow" && isActiveState(job.status))
|
|
@@ -380,7 +426,7 @@ export function collectFleetStatusEntries(state: SubagentState): FleetStatusEntr
|
|
|
380
426
|
|
|
381
427
|
for (const job of state.asyncJobs.values()) {
|
|
382
428
|
if (!isActiveState(job.status)) continue;
|
|
383
|
-
const startedAt = job.startedAt ?? job.updatedAt ??
|
|
429
|
+
const startedAt = job.startedAt ?? job.updatedAt ?? now;
|
|
384
430
|
const linkedParentKey = linkedWorkflowParentKey(job.parentWorkflowRunId, activeWorkflowKeys);
|
|
385
431
|
if (job.mode === "workflow") {
|
|
386
432
|
const latestEmit = job.workflow?.emits?.length ? formatWorkflowJsonPreview(job.workflow.emits.at(-1), 120) : undefined;
|
|
@@ -392,7 +438,7 @@ export function collectFleetStatusEntries(state: SubagentState): FleetStatusEntr
|
|
|
392
438
|
hostSteps: job.hostSteps,
|
|
393
439
|
preflight: job.preflight,
|
|
394
440
|
trace: job.workflow?.trace,
|
|
395
|
-
now
|
|
441
|
+
now,
|
|
396
442
|
});
|
|
397
443
|
entries.push({
|
|
398
444
|
key: `async:${job.asyncId}`,
|
|
@@ -439,7 +485,8 @@ export function collectFleetStatusEntries(state: SubagentState): FleetStatusEntr
|
|
|
439
485
|
entries.push({
|
|
440
486
|
key: `async:${job.asyncId}:${index}`,
|
|
441
487
|
...(linkedParentKey ? { parentKey: linkedParentKey } : {}),
|
|
442
|
-
agent: step.
|
|
488
|
+
agent: step.agent,
|
|
489
|
+
...(step.label ? { displayLabel: `${step.label} (${step.agent})` } : {}),
|
|
443
490
|
...(modelThinking ? { modelThinking } : {}),
|
|
444
491
|
description: step.description ?? job.description,
|
|
445
492
|
startedAt: step.startedAt ?? startedAt,
|
|
@@ -492,6 +539,8 @@ export class SubagentFleetStatus {
|
|
|
492
539
|
private inspectorOpen = false;
|
|
493
540
|
private lastRenderKey = "";
|
|
494
541
|
private entries: FleetStatusEntry[] = [];
|
|
542
|
+
private workflowSnapshots = new Map<string, { snapshot: string; childRows: Set<string> }>();
|
|
543
|
+
private readonly onWorkflowCoverageChange: FleetStatusOptions["onWorkflowCoverageChange"];
|
|
495
544
|
private readonly state: SubagentState;
|
|
496
545
|
private readonly openInspector: (itemKey: string) => Promise<void> | void;
|
|
497
546
|
private readonly refreshMs: number;
|
|
@@ -508,10 +557,14 @@ export class SubagentFleetStatus {
|
|
|
508
557
|
this.refreshMs = options.refreshMs ?? REFRESH_MS;
|
|
509
558
|
this.maxAgentRows = options.maxAgentRows ?? MAX_AGENT_ROWS;
|
|
510
559
|
this.placement = options.placement ?? "belowEditor";
|
|
560
|
+
this.onWorkflowCoverageChange = options.onWorkflowCoverageChange;
|
|
511
561
|
}
|
|
512
562
|
|
|
513
563
|
setContext(ctx: ExtensionContext): void {
|
|
514
|
-
if (!ctx.hasUI)
|
|
564
|
+
if (!ctx.hasUI) {
|
|
565
|
+
this.clearUiRegistration();
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
515
568
|
const ui = ctx.ui;
|
|
516
569
|
if (this.ui === ui) {
|
|
517
570
|
this.ctx = ctx;
|
|
@@ -548,6 +601,52 @@ export class SubagentFleetStatus {
|
|
|
548
601
|
return;
|
|
549
602
|
}
|
|
550
603
|
this.entries = collectFleetStatusEntries(this.state);
|
|
604
|
+
this.workflowSnapshots.clear();
|
|
605
|
+
if (this.active && !this.inspectorOpen && !this.state.fleetInspectorOpen && this.onWorkflowCoverageChange) {
|
|
606
|
+
const childrenByParent = new Map<string, AsyncJobState[]>();
|
|
607
|
+
for (const child of this.state.asyncJobs.values()) {
|
|
608
|
+
if (!child.parentWorkflowRunId) continue;
|
|
609
|
+
const children = childrenByParent.get(child.parentWorkflowRunId) ?? [];
|
|
610
|
+
children.push(child);
|
|
611
|
+
childrenByParent.set(child.parentWorkflowRunId, children);
|
|
612
|
+
}
|
|
613
|
+
const attachedByParent = new Map<string, FleetStatusEntry[]>();
|
|
614
|
+
for (const entry of this.entries) {
|
|
615
|
+
if (!entry.parentKey) continue;
|
|
616
|
+
const attached = attachedByParent.get(entry.parentKey) ?? [];
|
|
617
|
+
attached.push(entry);
|
|
618
|
+
attachedByParent.set(entry.parentKey, attached);
|
|
619
|
+
}
|
|
620
|
+
for (const job of this.state.asyncJobs.values()) {
|
|
621
|
+
// Fleet does not expand attached workflow wrappers or step descendants.
|
|
622
|
+
// Unknown/unsupported coverage deliberately retains the async tree.
|
|
623
|
+
if (job.mode !== "workflow" || !isActiveState(job.status) || job.parentWorkflowRunId
|
|
624
|
+
|| job.nestedChildren?.length || job.steps?.some((step) => step.children?.length)) continue;
|
|
625
|
+
const key = `async:${job.asyncId}`;
|
|
626
|
+
const children = childrenByParent.get(job.asyncId) ?? [];
|
|
627
|
+
const attached = attachedByParent.get(key) ?? [];
|
|
628
|
+
if (children.length && job.status !== "running") continue;
|
|
629
|
+
// Even without workflow rows, these children plus their owner cannot fit.
|
|
630
|
+
if (attached.length >= this.maxAgentRows) continue;
|
|
631
|
+
const rowKeys = new Set<string>();
|
|
632
|
+
let unsupported = false;
|
|
633
|
+
for (const child of children) {
|
|
634
|
+
if (!isActiveState(child.status) || (child.mode !== "single" && child.mode !== "parallel" && child.mode !== "chain")
|
|
635
|
+
|| child.hostSteps?.length || child.workflowGraph
|
|
636
|
+
|| childrenByParent.has(child.asyncId) || child.nestedChildren?.length
|
|
637
|
+
|| child.steps?.some((step) => step.children?.length || step.runner || !isActiveState(step.status))) {
|
|
638
|
+
unsupported = true; break;
|
|
639
|
+
}
|
|
640
|
+
const count = child.steps?.length || child.agents?.length || 0;
|
|
641
|
+
if (!count || (child.stepsTotal ?? 0) > count || (child.chainStepCount ?? 0) > count) {
|
|
642
|
+
unsupported = true; break;
|
|
643
|
+
}
|
|
644
|
+
for (let index = 0; index < count; index++) rowKeys.add(`async:${child.asyncId}:${child.steps?.[index]?.index ?? index}`);
|
|
645
|
+
}
|
|
646
|
+
if (unsupported || attached.length !== rowKeys.size || attached.some((entry) => !rowKeys.has(entry.key))) continue;
|
|
647
|
+
this.workflowSnapshots.set(key, { snapshot: inlineWorkflowRenderKey(job, children), childRows: rowKeys });
|
|
648
|
+
}
|
|
649
|
+
}
|
|
551
650
|
this.clampSelection();
|
|
552
651
|
if (this.inspectorOpen || this.state.fleetInspectorOpen) {
|
|
553
652
|
this.lastRenderKey = "";
|
|
@@ -563,6 +662,7 @@ export class SubagentFleetStatus {
|
|
|
563
662
|
}
|
|
564
663
|
|
|
565
664
|
const renderKey = this.getRenderKey();
|
|
665
|
+
if (!this.active || renderKey !== this.lastRenderKey) this.clearWorkflowCoverage();
|
|
566
666
|
if (!this.widgetRegistered) {
|
|
567
667
|
ctx.ui.setWidget(FLEET_STATUS_WIDGET_KEY, (tui, theme) => {
|
|
568
668
|
this.tui = tui;
|
|
@@ -573,6 +673,7 @@ export class SubagentFleetStatus {
|
|
|
573
673
|
},
|
|
574
674
|
dispose: () => {
|
|
575
675
|
if (this.tui !== tui) return;
|
|
676
|
+
this.clearWorkflowCoverage();
|
|
576
677
|
this.widgetRegistered = false;
|
|
577
678
|
this.tui = undefined;
|
|
578
679
|
},
|
|
@@ -654,17 +755,24 @@ export class SubagentFleetStatus {
|
|
|
654
755
|
}
|
|
655
756
|
|
|
656
757
|
render(width: number, theme: Theme): string[] {
|
|
657
|
-
if (!this.hasInlineSurface())
|
|
758
|
+
if (!this.hasInlineSurface() || this.state.widgetsSuspended || this.inspectorOpen || this.state.fleetInspectorOpen) {
|
|
759
|
+
this.clearWorkflowCoverage();
|
|
760
|
+
return [];
|
|
761
|
+
}
|
|
658
762
|
if (!this.active) {
|
|
763
|
+
this.clearWorkflowCoverage();
|
|
659
764
|
const workEntries = this.entries.filter((entry) => !entry.surface);
|
|
660
765
|
const projectEntries = this.entries.filter((entry) => entry.surface === "project-pane");
|
|
661
|
-
|
|
662
|
-
|
|
766
|
+
// Workflow totals can overlap child usage and omit live lanes. Do not
|
|
767
|
+
// present either wrapper totals or an active-only sum as workflow spend.
|
|
768
|
+
const hasWorkflow = workEntries.some((entry) => entry.workflowWrapper);
|
|
769
|
+
const nativeEntries = workEntries.filter((entry) => !entry.external && !entry.workflowWrapper && !entry.parentKey);
|
|
770
|
+
const tokens = nativeEntries.reduce((total, entry) => total + entry.tokens, 0);
|
|
663
771
|
const window = nativeEntries.length > 0 && nativeEntries.every((entry) => entry.window !== undefined)
|
|
664
772
|
? nativeEntries.reduce((total, entry) => total + entry.window!, 0)
|
|
665
773
|
: undefined;
|
|
666
774
|
const capacity = this.state.activeAsyncCapacity;
|
|
667
|
-
const hasNativeRows =
|
|
775
|
+
const hasNativeRows = nativeEntries.length > 0 || hasWorkflow;
|
|
668
776
|
const showNativeSummary = hasNativeRows || Boolean(capacity?.used);
|
|
669
777
|
const asyncRuns = capacity && showNativeSummary && (capacity.used > 0 || capacity.limit > 0) ? `Async runs ${capacity.used}/${capacity.limit || "∞"}` : "";
|
|
670
778
|
const activeEntries = activeLeafAgentCount(workEntries);
|
|
@@ -673,7 +781,11 @@ export class SubagentFleetStatus {
|
|
|
673
781
|
const paneAttention = projectEntries.filter((entry) => entry.projectPane && projectPaneNeedsAttention(entry.projectPane)).length;
|
|
674
782
|
const panes = projectEntries.length > 0 ? `${projectEntries.length} pane${projectEntries.length === 1 ? "" : "s"}${paneAttention ? ` (${paneAttention} ⚠)` : ""}` : "";
|
|
675
783
|
const label = [agents, asyncRuns, panes].filter(Boolean).join(" · ");
|
|
676
|
-
const
|
|
784
|
+
const nativeUsage = formatFleetTokens(tokens, window, nativeEntries.length);
|
|
785
|
+
const usage = hasWorkflow
|
|
786
|
+
? nativeEntries.length > 0 ? `standalone: ${nativeUsage} · workflow usage on child rows` : "usage on child rows"
|
|
787
|
+
: nativeUsage;
|
|
788
|
+
const detail = [showNativeSummary ? usage : undefined, "↓/← to inspect"].filter(Boolean).join(" · ");
|
|
677
789
|
return [truncateToWidth(` ${theme.fg("muted", label)}${label && detail ? " · " : ""}${theme.fg("dim", detail)}`, width)];
|
|
678
790
|
}
|
|
679
791
|
const roster = this.rosterKeys();
|
|
@@ -706,6 +818,26 @@ export class SubagentFleetStatus {
|
|
|
706
818
|
}
|
|
707
819
|
}
|
|
708
820
|
if (hiddenBelow > 0) lines.push(rightAlign("", theme.fg("dim", `↓ ${hiddenBelow} more`), width));
|
|
821
|
+
if (this.ui && this.widgetRegistered && this.onWorkflowCoverageChange) {
|
|
822
|
+
const coverage = new Map<string, string>();
|
|
823
|
+
for (const [key, { snapshot, childRows }] of this.workflowSnapshots) {
|
|
824
|
+
const ownerIndex = tree.findIndex((row) => row.kind === "owner" && row.entry.key === key);
|
|
825
|
+
const owner = tree[ownerIndex];
|
|
826
|
+
if (owner?.kind !== "owner" || ownerIndex < start) continue;
|
|
827
|
+
const count = childRows.size + (owner.entry.workflowRows?.length ?? 0) + (owner.entry.workflowChecklist?.phases.length ?? 0);
|
|
828
|
+
if (!count || ownerIndex + count >= start + visibleCount) continue;
|
|
829
|
+
const descendants = tree.slice(ownerIndex + 1, ownerIndex + count + 1);
|
|
830
|
+
if (!descendants.every((row) => (row.kind === "workflow" && row.ownerKey === key && !row.row.overflow
|
|
831
|
+
&& visibleWidth(this.renderWorkflowRow(row.row, row.last, Infinity, theme)) <= width)
|
|
832
|
+
|| (row.kind === "workflow-phase" && row.ownerKey === key
|
|
833
|
+
&& visibleWidth(this.renderWorkflowPhaseRow(row.phase, row.last, Infinity, theme)) <= width)
|
|
834
|
+
|| (row.kind === "child" && childRows.has(row.entry.key)
|
|
835
|
+
&& visibleWidth(this.renderEntry(rosterIndexByKey.get(row.entry.key) ?? 0, selectedIndex, row.entry, 0, theme, row.last ? "└─" : "├─", true)) <= width))) continue;
|
|
836
|
+
if (childRows.size && visibleWidth(this.renderEntry(rosterIndexByKey.get(key) ?? 0, selectedIndex, owner.entry, 0, theme, undefined, true)) > width) continue;
|
|
837
|
+
coverage.set(key.slice("async:".length), snapshot);
|
|
838
|
+
}
|
|
839
|
+
this.onWorkflowCoverageChange(this.ui, coverage);
|
|
840
|
+
}
|
|
709
841
|
this.renderProjectPaneSection(lines, selectedIndex, width, theme, rosterIndexByKey);
|
|
710
842
|
return lines;
|
|
711
843
|
}
|
|
@@ -721,18 +853,20 @@ export class SubagentFleetStatus {
|
|
|
721
853
|
}
|
|
722
854
|
|
|
723
855
|
|
|
724
|
-
private renderEntry(rosterIndex: number, selectedIndex: number, entry: FleetStatusEntry, width: number, theme: Theme, branch?: string): string {
|
|
725
|
-
const
|
|
856
|
+
private renderEntry(rosterIndex: number, selectedIndex: number, entry: FleetStatusEntry, width: number, theme: Theme, branch?: string, unclipped = false): string {
|
|
857
|
+
const label = entry.displayLabel ?? entry.agent;
|
|
858
|
+
const agent = entry.modelThinking ? `${label} (${entry.modelThinking})` : label;
|
|
726
859
|
const prefix = branch ? ` ${branch}` : " ";
|
|
727
860
|
const checklist = entry.workflowWrapper && entry.workflowChecklist
|
|
728
861
|
? ` · checklist ${formatWorkflowChecklistSummary(entry.workflowChecklist)}${entry.workflowChecklist.bottleneck ? ` · bottleneck ${formatWorkflowChecklistBottleneck(entry.workflowChecklist.bottleneck)}` : ""}`
|
|
729
862
|
: "";
|
|
730
|
-
const left = `${prefix} ${this.bullet(rosterIndex, selectedIndex, theme)} ${theme.fg(
|
|
863
|
+
const left = `${prefix} ${this.bullet(rosterIndex, selectedIndex, theme)} ${theme.fg(fleetAgentIdentityColor(entry.agent), agent)} · ${entry.state}${checklist}`;
|
|
731
864
|
const elapsed = Date.now() - entry.startedAt;
|
|
732
865
|
const rightText = entry.projectPane
|
|
733
866
|
? `${entry.projectPane.summary ?? "—"} · ${formatFleetElapsed(Date.now() - entry.projectPane.refreshedAt)} ago`
|
|
734
|
-
: entry.external ? formatFleetElapsed(elapsed) : `${formatFleetElapsed(elapsed)} · ${formatFleetTokens(entry.tokens, entry.window)}`;
|
|
867
|
+
: entry.external ? formatFleetElapsed(elapsed) : `${formatFleetElapsed(elapsed)} · ${entry.workflowWrapper ? "usage on child rows" : formatFleetTokens(entry.tokens, entry.window)}`;
|
|
735
868
|
const right = theme.fg("dim", rightText);
|
|
869
|
+
if (unclipped) return `${left} ${right}`;
|
|
736
870
|
return rightAlign(left, right, width);
|
|
737
871
|
}
|
|
738
872
|
|
|
@@ -742,9 +876,9 @@ export class SubagentFleetStatus {
|
|
|
742
876
|
if (row.overflow !== undefined) return truncateToWidth(`${indent}${marker} ${theme.fg("dim", `+${row.overflow} nested leaves`)}`, width);
|
|
743
877
|
const modelThinking = row.modelThinking ? ` (${row.modelThinking})` : "";
|
|
744
878
|
const activity = row.activity ? ` · ${row.activity}` : "";
|
|
745
|
-
const left = `${indent}${marker} ${nestedStatusGlyph(row.state, theme)} ${theme.fg(
|
|
746
|
-
const elapsed =
|
|
747
|
-
return truncateToWidth(`${left}${theme.fg("dim", elapsed)}`, width);
|
|
879
|
+
const left = `${indent}${marker} ${nestedStatusGlyph(row.state, theme)} ${theme.fg(fleetAgentIdentityColor(row.agentIdentity ?? row.name), `${row.name}${modelThinking}`)} · ${row.state}${activity}`;
|
|
880
|
+
const elapsed = detailElapsed(row);
|
|
881
|
+
return truncateToWidth(`${left}${elapsed !== undefined ? theme.fg("dim", ` · ${elapsed}`) : ""}`, width);
|
|
748
882
|
}
|
|
749
883
|
|
|
750
884
|
private workflowRowGlyph(row: AsyncStatusWorkflowRow, theme: Theme): string {
|
|
@@ -797,7 +931,7 @@ export class SubagentFleetStatus {
|
|
|
797
931
|
].filter((value): value is string => Boolean(value)).join(" · ") : "";
|
|
798
932
|
const left = `${indent}${marker} ${this.workflowRowGlyph(row, theme)} ${theme.fg("muted", `${kind}${row.name}${context ? ` ${context}` : ""}${modelThinking}`)} · ${this.workflowRowStateLabel(row, theme)}${activity}${hints ? ` · ${hints}` : ""}`;
|
|
799
933
|
const details = [
|
|
800
|
-
|
|
934
|
+
detailElapsed(row),
|
|
801
935
|
row.tokens !== undefined ? formatFleetTokens(row.tokens, row.window) : undefined,
|
|
802
936
|
row.provider ? `provider:${row.provider}` : undefined,
|
|
803
937
|
row.role ? `role:${row.role}` : undefined,
|
|
@@ -853,6 +987,7 @@ export class SubagentFleetStatus {
|
|
|
853
987
|
entry.surface,
|
|
854
988
|
entry.parentKey,
|
|
855
989
|
entry.agent,
|
|
990
|
+
entry.displayLabel,
|
|
856
991
|
entry.state,
|
|
857
992
|
entry.modelThinking,
|
|
858
993
|
entry.description,
|
|
@@ -876,6 +1011,8 @@ export class SubagentFleetStatus {
|
|
|
876
1011
|
row.modelThinking,
|
|
877
1012
|
row.activity,
|
|
878
1013
|
row.startedAt,
|
|
1014
|
+
row.endedAt,
|
|
1015
|
+
row.durationMs,
|
|
879
1016
|
row.tokens,
|
|
880
1017
|
row.provider,
|
|
881
1018
|
row.role,
|
|
@@ -889,10 +1026,12 @@ export class SubagentFleetStatus {
|
|
|
889
1026
|
]),
|
|
890
1027
|
nestedFleetRows(entry.nestedChildren, entry.parentKey ? 3 : 4).map((row) => [
|
|
891
1028
|
row.name,
|
|
1029
|
+
row.agentIdentity,
|
|
892
1030
|
row.state,
|
|
893
1031
|
row.modelThinking,
|
|
894
1032
|
row.activity,
|
|
895
1033
|
row.startedAt,
|
|
1034
|
+
row.endedAt,
|
|
896
1035
|
row.depth,
|
|
897
1036
|
row.overflow,
|
|
898
1037
|
]),
|
|
@@ -918,6 +1057,7 @@ export class SubagentFleetStatus {
|
|
|
918
1057
|
}
|
|
919
1058
|
|
|
920
1059
|
private clearWidget(): void {
|
|
1060
|
+
this.clearWorkflowCoverage();
|
|
921
1061
|
if (!this.widgetRegistered) return;
|
|
922
1062
|
try {
|
|
923
1063
|
this.ui?.setWidget(FLEET_STATUS_WIDGET_KEY, undefined);
|
|
@@ -931,6 +1071,7 @@ export class SubagentFleetStatus {
|
|
|
931
1071
|
}
|
|
932
1072
|
|
|
933
1073
|
private clearUiRegistration(): void {
|
|
1074
|
+
this.clearWorkflowCoverage();
|
|
934
1075
|
if (this.timer) clearInterval(this.timer);
|
|
935
1076
|
this.timer = undefined;
|
|
936
1077
|
|
|
@@ -961,4 +1102,8 @@ export class SubagentFleetStatus {
|
|
|
961
1102
|
throw new AggregateError(cleanupErrors, "Failed to clean up FleetView UI registration");
|
|
962
1103
|
}
|
|
963
1104
|
}
|
|
1105
|
+
|
|
1106
|
+
private clearWorkflowCoverage(): void {
|
|
1107
|
+
if (this.ui) this.onWorkflowCoverageChange?.(this.ui, new Map());
|
|
1108
|
+
}
|
|
964
1109
|
}
|
package/src/tui/fleet.ts
CHANGED
|
@@ -18,8 +18,8 @@ import { resolveWorkflowForegroundSteeringTarget, steerWorkflowForegroundTarget
|
|
|
18
18
|
import { contextModeBadge, contextModeLabel } from "../runs/shared/context-mode.ts";
|
|
19
19
|
import { FLEET_STATUS_WIDGET_KEY } from "./fleet-status.ts";
|
|
20
20
|
import { readFleetTranscript, renderFleetTranscript, type FleetTranscript } from "./fleet-transcript.ts";
|
|
21
|
-
import {
|
|
22
|
-
import type {
|
|
21
|
+
import { handleInspectorAction } from "../inspectors/actions.ts";
|
|
22
|
+
import type { InspectorPlugin } from "../inspectors/types.ts";
|
|
23
23
|
import { getLivePromptAudit, type LivePromptAudit, type PromptAuditView } from "../runs/foreground/prompt-audit.ts";
|
|
24
24
|
|
|
25
25
|
const REFRESH_MS = 750;
|
|
@@ -110,7 +110,8 @@ export interface FleetViewOptions {
|
|
|
110
110
|
fleetKeybindings?: FleetKeybindingsConfig;
|
|
111
111
|
actions?: FleetActionHandlers;
|
|
112
112
|
copyText?: (text: string) => Promise<void> | void;
|
|
113
|
-
|
|
113
|
+
inspectorPlugins?: readonly InspectorPlugin[];
|
|
114
|
+
inspectorEnv?: NodeJS.ProcessEnv;
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
function belongsToCurrentSession(sessionId: string | undefined, currentSessionId: string | null): boolean {
|
|
@@ -943,23 +944,23 @@ export class SubagentFleetComponent implements Component {
|
|
|
943
944
|
return { runId: target.item.runId, asyncDir: target.item.run.asyncDir, ...(target.item.index !== undefined ? { index: target.item.index } : {}) };
|
|
944
945
|
}
|
|
945
946
|
|
|
946
|
-
private
|
|
947
|
+
private selectedInspectAction(): { runId: string; asyncDir: string; index?: number } | { reason: string } {
|
|
947
948
|
const item = this.snapshot.items[this.selected];
|
|
948
949
|
if (!item) return { reason: "No child is selected." };
|
|
949
|
-
if (item.kind === "external") return { reason: "External jobs are display-only and have no
|
|
950
|
+
if (item.kind === "external") return { reason: "External jobs are display-only and have no inspector controls." };
|
|
950
951
|
if (item.kind === "async") {
|
|
951
952
|
if (!isActionableAsyncState(item.run.state) || !isActionableAsyncState(item.state)) return { reason: `Selected child is ${item.state}; controls require a running or queued async child.` };
|
|
952
953
|
return { runId: item.runId, asyncDir: item.run.asyncDir, ...(item.index !== undefined ? { index: item.index } : {}) };
|
|
953
954
|
}
|
|
954
955
|
if (item.kind !== "foreground-active" || !item.control.parentWorkflowRunId) return { reason: "Fleet controls are available for current-session top-level async runs only." };
|
|
955
956
|
const parent = this.state.asyncJobs.get(item.control.parentWorkflowRunId) ?? this.state.fleetJobs?.get(item.control.parentWorkflowRunId);
|
|
956
|
-
if (!parent || !isActionableAsyncState(parent.status)) return { reason: "The parent workflow is no longer available for
|
|
957
|
+
if (!parent || !isActionableAsyncState(parent.status)) return { reason: "The parent workflow is no longer available for inspection." };
|
|
957
958
|
return { runId: parent.asyncId, asyncDir: parent.asyncDir };
|
|
958
959
|
}
|
|
959
960
|
|
|
960
|
-
private
|
|
961
|
-
const target = this.
|
|
962
|
-
if ("reason" in target || !this.options.actions?.inspect) this.setActionNotice({ text: "reason" in target ? target.reason : "
|
|
961
|
+
private inspectSelected(): void {
|
|
962
|
+
const target = this.selectedInspectAction();
|
|
963
|
+
if ("reason" in target || !this.options.actions?.inspect) this.setActionNotice({ text: "reason" in target ? target.reason : "Inspector controls are unavailable in this context.", isError: true });
|
|
963
964
|
else this.runAction(() => this.options.actions!.inspect!(target));
|
|
964
965
|
}
|
|
965
966
|
|
|
@@ -1209,7 +1210,7 @@ export class SubagentFleetComponent implements Component {
|
|
|
1209
1210
|
return;
|
|
1210
1211
|
}
|
|
1211
1212
|
if (matchesFleetAction(data, this.keybindings, "inspect")) {
|
|
1212
|
-
this.
|
|
1213
|
+
this.inspectSelected();
|
|
1213
1214
|
return;
|
|
1214
1215
|
}
|
|
1215
1216
|
}
|
|
@@ -1364,7 +1365,7 @@ export class SubagentFleetComponent implements Component {
|
|
|
1364
1365
|
? ` j/k child · 1/2/3 view · g redo with guidance · c copy · Esc close Prompt Audit · ${position}`
|
|
1365
1366
|
: selected?.kind === "external"
|
|
1366
1367
|
? ` ${bindingLabel(this.keybindings, "selectUp")}/${bindingLabel(this.keybindings, "selectDown")} job · display-only · ${bindingLabel(this.keybindings, "refresh")} refresh · ${bindingLabel(this.keybindings, "close")} close · ${position}`
|
|
1367
|
-
: ` ${bindingLabel(this.keybindings, "selectUp")}/${bindingLabel(this.keybindings, "selectDown")} agent · p Prompt Audit · ${bindingLabel(this.keybindings, "inspect")}
|
|
1368
|
+
: ` ${bindingLabel(this.keybindings, "selectUp")}/${bindingLabel(this.keybindings, "selectDown")} agent · p Prompt Audit · ${bindingLabel(this.keybindings, "inspect")} Inspect · ${bindingLabel(this.keybindings, "steer")} steer · ${bindingLabel(this.keybindings, "stop")} stop · ${bindingLabel(this.keybindings, "toggleTools")} tools · ${bindingLabel(this.keybindings, "refresh")} refresh · ${bindingLabel(this.keybindings, "close")} close · ${position}`;
|
|
1368
1369
|
lines.push(this.theme.fg("border", "│") + fit(this.theme.fg("dim", footer), innerWidth) + this.theme.fg("border", "│"));
|
|
1369
1370
|
lines.push(this.theme.fg("border", `╰${"─".repeat(innerWidth)}╯`));
|
|
1370
1371
|
return lines.map((line) => truncateToWidth(line, width));
|
|
@@ -1413,7 +1414,7 @@ export async function openSubagentFleet(ctx: ExtensionContext, state: SubagentSt
|
|
|
1413
1414
|
}), `Failed to steer async run ${input.runId}.`);
|
|
1414
1415
|
},
|
|
1415
1416
|
stop: (input: { runId: string; asyncDir: string; index?: number }) => firstToolResultText(stopAsyncRun(state, input.runId, undefined, { asyncDir: input.asyncDir, resolvedId: input.runId }), `Failed to stop async run ${input.runId}.`),
|
|
1416
|
-
inspect: async (input: { runId: string; asyncDir: string; index?: number }) => firstToolResultText(await
|
|
1417
|
+
inspect: async (input: { runId: string; asyncDir: string; index?: number }) => firstToolResultText(await handleInspectorAction("inspector.open", {
|
|
1417
1418
|
id: input.runId,
|
|
1418
1419
|
dir: input.asyncDir,
|
|
1419
1420
|
focus: true,
|
|
@@ -1422,10 +1423,11 @@ export async function openSubagentFleet(ctx: ExtensionContext, state: SubagentSt
|
|
|
1422
1423
|
state,
|
|
1423
1424
|
sessionRoots: state.trustedSessionRoots,
|
|
1424
1425
|
cwd: state.baseCwd,
|
|
1425
|
-
...(options.herdrClient ? { client: options.herdrClient } : {}),
|
|
1426
1426
|
...(state.authorityPolicy ? { authorityPolicy: state.authorityPolicy } : {}),
|
|
1427
1427
|
...(state.missionStoreConfig ? { missions: state.missionStoreConfig } : {}),
|
|
1428
|
-
|
|
1428
|
+
...(options.inspectorPlugins ? { plugins: options.inspectorPlugins } : {}),
|
|
1429
|
+
...(options.inspectorEnv ? { env: options.inspectorEnv } : {}),
|
|
1430
|
+
}), `Failed to open inspector for async run ${input.runId}.`),
|
|
1429
1431
|
redoPrompt: async (input: { runId: string; index: number; guidance: string; control?: ForegroundRunControl }) => {
|
|
1430
1432
|
const control = input.control ?? state.foregroundControls.get(input.runId);
|
|
1431
1433
|
if (!control?.promptAuditRedo) return { text: "Redo is not available for this live child.", isError: true };
|