pi-subagents 0.56.0 → 0.57.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 +53 -0
- package/agents/claude-code-writer.md +15 -0
- package/agents/claude-code.md +15 -0
- package/agents/codex-exec-writer.md +15 -0
- package/agents/codex-exec.md +15 -0
- package/agents/cursor-agent-writer.md +14 -0
- package/agents/cursor-agent.md +14 -0
- package/docs/agents.md +111 -15
- package/docs/configuration.md +37 -0
- package/docs/extension-api.md +2 -2
- package/docs/observability.md +8 -7
- package/docs/tool-reference.md +11 -1
- package/docs/workflows.md +20 -0
- package/package.json +1 -1
- package/skills/pi-subagents/references/execution-controls.md +1 -1
- package/src/agents/agent-management.ts +13 -5
- package/src/agents/agent-refinements.ts +4 -4
- package/src/agents/agents.ts +219 -48
- package/src/agents/builtin-names.ts +6 -0
- package/src/agents/runtime-agent-registry.ts +8 -2
- package/src/api/preflight.ts +2 -2
- package/src/extension/config.ts +70 -0
- package/src/extension/doctor.ts +3 -3
- package/src/extension/index.ts +18 -4
- package/src/extension/public-execution.ts +29 -13
- package/src/extension/rpc.ts +20 -5
- package/src/extension/schemas.ts +4 -3
- package/src/extension/tool-description.ts +11 -9
- package/src/inspectors/herdr/actions.ts +2 -1
- package/src/inspectors/herdr/inspector-runner.ts +2 -10
- package/src/inspectors/herdr/session-roots-codec.ts +42 -0
- package/src/integrations/herdr-status.ts +46 -3
- package/src/runs/background/active-async-capacity.ts +77 -10
- package/src/runs/background/async-execution.ts +100 -9
- package/src/runs/background/async-job-tracker.ts +5 -0
- package/src/runs/background/async-retention.ts +20 -3
- package/src/runs/background/async-status.ts +5 -0
- package/src/runs/background/chain-root-attachment.ts +15 -1
- package/src/runs/background/fleet-view.ts +16 -10
- package/src/runs/background/inspect-rpc.ts +8 -8
- package/src/runs/background/result-files.ts +27 -14
- package/src/runs/background/result-watcher.ts +9 -5
- package/src/runs/background/run-status.ts +33 -6
- package/src/runs/background/scheduled-runs.ts +7 -1
- package/src/runs/background/subagent-runner.ts +177 -44
- package/src/runs/background/wait-completions.ts +4 -0
- package/src/runs/foreground/execution.ts +72 -10
- package/src/runs/foreground/foreground-control.ts +6 -0
- package/src/runs/foreground/foreground-history.ts +22 -1
- package/src/runs/foreground/subagent-executor.ts +270 -81
- package/src/runs/foreground/workflow-detach-reconcile.ts +16 -1
- package/src/runs/shared/child-protocol.ts +21 -7
- package/src/runs/shared/claude-code-adapter.ts +129 -0
- package/src/runs/shared/codex-exec-adapter.ts +129 -0
- package/src/runs/shared/cursor-agent-adapter.ts +114 -0
- package/src/runs/shared/external-cli-contract.ts +167 -0
- package/src/runs/shared/external-cli-preflight.ts +122 -0
- package/src/runs/shared/external-cli-runner.ts +348 -55
- package/src/runs/shared/model-exclusions.ts +57 -7
- package/src/runs/shared/model-fallback.ts +23 -1
- package/src/runs/shared/mutation-evidence.ts +7 -2
- package/src/runs/shared/nested-events.ts +3 -1
- package/src/runs/shared/nested-render.ts +2 -2
- package/src/runs/shared/process-signal.ts +13 -0
- package/src/runs/shared/run-history.ts +21 -1
- package/src/shared/fork-context.ts +21 -0
- package/src/shared/formatters.ts +7 -1
- package/src/shared/pruned-fork.ts +450 -0
- package/src/shared/session-file-trust.ts +19 -0
- package/src/shared/session-tokens.ts +14 -3
- package/src/shared/settings.ts +10 -2
- package/src/shared/shortcuts.ts +17 -0
- package/src/shared/types.ts +118 -9
- package/src/shared/workflow-child-permit.ts +116 -0
- package/src/slash/delegation-adapters.ts +0 -1
- package/src/slash/slash-commands.ts +8 -6
- package/src/tui/fleet-status.ts +27 -10
- package/src/tui/fleet-transcript.ts +11 -5
- package/src/tui/fleet.ts +28 -13
- package/src/tui/render.ts +47 -21
- package/src/workflows/scripted-workflow.ts +248 -27
- package/src/workflows/workflow-child-summary.ts +117 -0
- package/src/workflows/workflow-receipt.ts +119 -4
package/src/shared/types.ts
CHANGED
|
@@ -14,6 +14,7 @@ import type { AuthorityPolicyConfig } from "../policy/authority.ts";
|
|
|
14
14
|
import type { ThinkingLevel } from "./model-info.ts";
|
|
15
15
|
import type { GlobalMissionIndexRecord, MissionRecord, MissionStoreConfig } from "../missions/types.ts";
|
|
16
16
|
import type { ExtensionBindings } from "../runs/shared/extension-bindings.ts";
|
|
17
|
+
import type { WorkflowChildPermitContext } from "./workflow-child-permit.ts";
|
|
17
18
|
|
|
18
19
|
// ============================================================================
|
|
19
20
|
// Basic Types
|
|
@@ -75,6 +76,22 @@ export interface WorkflowGraphSnapshot {
|
|
|
75
76
|
|
|
76
77
|
export type WorkflowReceiptState = "complete" | "failed" | "paused" | "stopped";
|
|
77
78
|
|
|
79
|
+
export interface WorkflowChildSummaryV1 {
|
|
80
|
+
version: 1;
|
|
81
|
+
parentToolCallId: string;
|
|
82
|
+
workflowRunId: string;
|
|
83
|
+
inventoryComplete: boolean;
|
|
84
|
+
workflowState: "queued" | "running" | "completed" | "failed" | "paused" | "stopped";
|
|
85
|
+
children: Array<{
|
|
86
|
+
childId: string;
|
|
87
|
+
runId?: string;
|
|
88
|
+
agent?: string;
|
|
89
|
+
model?: string;
|
|
90
|
+
thinking?: string;
|
|
91
|
+
state: "pending" | "running" | "completed" | "failed" | "paused" | "stopped" | "rejected" | "detached";
|
|
92
|
+
}>;
|
|
93
|
+
}
|
|
94
|
+
|
|
78
95
|
type WorkflowReceiptEntryResumability =
|
|
79
96
|
| { latestRunId: string; resumability: { state: "resumable" } }
|
|
80
97
|
| { latestRunId?: string; resumability: { state: "not-resumable"; reason: string } };
|
|
@@ -85,6 +102,7 @@ export type WorkflowReceiptEntry = WorkflowReceiptEntryResumability & {
|
|
|
85
102
|
requestedContext?: "fresh" | "fork";
|
|
86
103
|
resolvedContext?: "fresh" | "fork" | "mixed";
|
|
87
104
|
outputReference?: string;
|
|
105
|
+
externalAdapter?: ExternalCliReceiptMetadata;
|
|
88
106
|
continuation: { runIds: string[] };
|
|
89
107
|
};
|
|
90
108
|
|
|
@@ -94,6 +112,7 @@ export interface WorkflowReceipt {
|
|
|
94
112
|
state: WorkflowReceiptState;
|
|
95
113
|
createdAt: number;
|
|
96
114
|
entries: Record<string, WorkflowReceiptEntry>;
|
|
115
|
+
workflowChildren?: WorkflowChildSummaryV1;
|
|
97
116
|
}
|
|
98
117
|
|
|
99
118
|
export interface SavedOutputReference {
|
|
@@ -166,6 +185,10 @@ export interface TokenUsage {
|
|
|
166
185
|
input: number;
|
|
167
186
|
output: number;
|
|
168
187
|
total: number;
|
|
188
|
+
/** Input plus cache-read tokens for the latest assistant turn. */
|
|
189
|
+
window?: number;
|
|
190
|
+
/** Largest window observed in this usage scope. */
|
|
191
|
+
windowPeak?: number;
|
|
169
192
|
}
|
|
170
193
|
|
|
171
194
|
export type ActivityState = "active_long_running" | "needs_attention";
|
|
@@ -703,6 +726,8 @@ export interface AgentProgress {
|
|
|
703
726
|
thinking?: string;
|
|
704
727
|
inputTokens?: number;
|
|
705
728
|
outputTokens?: number;
|
|
729
|
+
window?: number;
|
|
730
|
+
windowPeak?: number;
|
|
706
731
|
durationMs: number;
|
|
707
732
|
error?: string;
|
|
708
733
|
failedTool?: string;
|
|
@@ -1044,6 +1069,8 @@ export interface SingleResult {
|
|
|
1044
1069
|
watchdog?: ChildWatchdogProgress;
|
|
1045
1070
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
1046
1071
|
capabilityAudit?: SubagentCapabilityAudit;
|
|
1072
|
+
runner?: ExternalCliRunnerStatus | ExternalJobRunnerStatus;
|
|
1073
|
+
externalProcess?: ExternalProcessStatus;
|
|
1047
1074
|
}
|
|
1048
1075
|
|
|
1049
1076
|
export interface SpawnBudgetGrant {
|
|
@@ -1090,6 +1117,7 @@ export interface WaitCompletion {
|
|
|
1090
1117
|
/** Versioned bounded output archive retained with the durable completion replay. */
|
|
1091
1118
|
archivePath?: string;
|
|
1092
1119
|
results?: WaitCompletionChild[];
|
|
1120
|
+
workflowChildren?: WorkflowChildSummaryV1;
|
|
1093
1121
|
}
|
|
1094
1122
|
|
|
1095
1123
|
export interface Details {
|
|
@@ -1100,6 +1128,7 @@ export interface Details {
|
|
|
1100
1128
|
/** Run-level context summary. "mixed" when children resolved to different modes. */
|
|
1101
1129
|
context?: "fresh" | "fork" | "mixed";
|
|
1102
1130
|
results: SingleResult[];
|
|
1131
|
+
workflowChildren?: WorkflowChildSummaryV1;
|
|
1103
1132
|
/**
|
|
1104
1133
|
* Terminal completion payloads for runs this subagent_wait call observed
|
|
1105
1134
|
* finishing. Async completions travel as result files that are consumed and
|
|
@@ -1375,9 +1404,11 @@ export type AgentRunnerConfig =
|
|
|
1375
1404
|
| { type: "pi" }
|
|
1376
1405
|
| {
|
|
1377
1406
|
type: "external-cli";
|
|
1407
|
+
adapter?: "codex-exec" | "codex-exec-writer" | "claude-code" | "claude-code-writer" | "cursor-agent" | "cursor-agent-writer";
|
|
1378
1408
|
command: string;
|
|
1379
1409
|
args?: string[];
|
|
1380
1410
|
promptDelivery?: "stdin";
|
|
1411
|
+
capabilities?: ExternalCliCapabilityNarrowing;
|
|
1381
1412
|
}
|
|
1382
1413
|
| {
|
|
1383
1414
|
type: "external-job";
|
|
@@ -1385,18 +1416,46 @@ export type AgentRunnerConfig =
|
|
|
1385
1416
|
options?: Record<string, unknown>;
|
|
1386
1417
|
};
|
|
1387
1418
|
|
|
1419
|
+
export type ExternalCliCapabilityNarrowing = Partial<Record<"steer" | "resume" | "structuredOutput" | "toolEvents" | "supervisor" | "forkContext" | "extensionBindings", false>>;
|
|
1420
|
+
|
|
1421
|
+
export interface ExternalCliCapabilities {
|
|
1422
|
+
stop: true;
|
|
1423
|
+
steer: false;
|
|
1424
|
+
resume: false;
|
|
1425
|
+
structuredOutput: false;
|
|
1426
|
+
toolEvents: false;
|
|
1427
|
+
supervisor: "unsupported";
|
|
1428
|
+
forkContext: false;
|
|
1429
|
+
extensionBindings: false;
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
export interface ExternalCliReceiptMetadata {
|
|
1433
|
+
adapter: { id: "external-cli" | "codex-exec" | "codex-exec-writer" | "claude-code" | "claude-code-writer" | "cursor-agent" | "cursor-agent-writer" | "grok-build"; version: 1; executionMode: "one-shot-stdin" | "one-shot-prompt-file" };
|
|
1434
|
+
capabilities: ExternalCliCapabilities;
|
|
1435
|
+
safety?:
|
|
1436
|
+
| { sandbox: "read-only"; approvalPolicy: "never"; ephemeral: true }
|
|
1437
|
+
| { access: "workspace-write"; sandbox: "workspace-write"; approvalPolicy: "never"; ephemeral: true }
|
|
1438
|
+
| { permissionMode: "plan"; tools: "none"; mcp: "empty-strict"; settingSources: "none"; sessionPersistence: false }
|
|
1439
|
+
| { access: "read-only"; authentication: "existing-cli-required"; permissionMode: "plan"; tools: "none"; mcp: "empty-strict"; settingSources: "user"; userSettingsTrust: "required"; sessionPersistence: false }
|
|
1440
|
+
| { access: "workspace-write"; authentication: "existing-cli-required"; permissionMode: "acceptEdits"; tools: "Read,Write,Edit,Glob,Grep"; mcp: "empty-strict"; settingSources: "user"; userSettingsTrust: "required"; sessionPersistence: false }
|
|
1441
|
+
| { access: "read-only"; authentication: "cursor-api-key-or-existing-login"; mode: "ask"; sandbox: "enabled"; workspaceTrust: "existing-required"; sessionReuse: false }
|
|
1442
|
+
| { access: "workspace-write"; authentication: "cursor-api-key-or-existing-login"; mode: "print"; sandbox: "enabled"; workspaceTrust: "existing-required"; sessionReuse: false };
|
|
1443
|
+
outputArtifacts?: { stdoutPath?: string; stderrPath?: string; finalOutputPath?: string };
|
|
1444
|
+
handoff: { mode: "fresh" };
|
|
1445
|
+
supervisor: { mode: "unsupported"; reason: string };
|
|
1446
|
+
nonResumableReason: string;
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1388
1449
|
export interface ExternalCliRunnerStatus {
|
|
1389
1450
|
type: "external-cli";
|
|
1390
1451
|
command: string;
|
|
1391
1452
|
args: string[];
|
|
1392
|
-
promptDelivery: "stdin";
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
toolEvents: false;
|
|
1399
|
-
};
|
|
1453
|
+
promptDelivery: "stdin" | "prompt-file";
|
|
1454
|
+
adapter: ExternalCliReceiptMetadata["adapter"];
|
|
1455
|
+
safety?: ExternalCliReceiptMetadata["safety"];
|
|
1456
|
+
capabilities: ExternalCliCapabilities;
|
|
1457
|
+
unsupportedReasons: Record<Exclude<keyof ExternalCliCapabilities, "stop">, string>;
|
|
1458
|
+
nonResumableReason: string;
|
|
1400
1459
|
}
|
|
1401
1460
|
|
|
1402
1461
|
export interface ExternalJobRunnerStatus {
|
|
@@ -1443,6 +1502,11 @@ export interface ExternalProcessStatus {
|
|
|
1443
1502
|
processSignal?: string | null;
|
|
1444
1503
|
stdoutPath: string;
|
|
1445
1504
|
stderrPath: string;
|
|
1505
|
+
finalOutputPath?: string;
|
|
1506
|
+
stdoutBytes?: number;
|
|
1507
|
+
stderrBytes?: number;
|
|
1508
|
+
stdoutTruncated?: boolean;
|
|
1509
|
+
stderrTruncated?: boolean;
|
|
1446
1510
|
}
|
|
1447
1511
|
|
|
1448
1512
|
export interface AsyncStatus {
|
|
@@ -1499,6 +1563,7 @@ export interface AsyncStatus {
|
|
|
1499
1563
|
capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
|
|
1500
1564
|
capabilityAudit?: SubagentCapabilityAudit;
|
|
1501
1565
|
workflow?: Details["workflow"];
|
|
1566
|
+
workflowChildren?: WorkflowChildSummaryV1;
|
|
1502
1567
|
parentWorkflowRunId?: string;
|
|
1503
1568
|
workflowKey?: string;
|
|
1504
1569
|
/** Set when a durable schedule launched this run, so completions can name their origin. */
|
|
@@ -1654,6 +1719,7 @@ export interface AsyncJobState {
|
|
|
1654
1719
|
parentWorkflowRunId?: string;
|
|
1655
1720
|
workflowKey?: string;
|
|
1656
1721
|
workflow?: Details["workflow"];
|
|
1722
|
+
workflowChildren?: WorkflowChildSummaryV1;
|
|
1657
1723
|
}
|
|
1658
1724
|
|
|
1659
1725
|
export interface ForegroundResumeChild {
|
|
@@ -1671,6 +1737,8 @@ export interface ForegroundResumeChild {
|
|
|
1671
1737
|
currentPath?: string;
|
|
1672
1738
|
turnCount?: number;
|
|
1673
1739
|
tokens?: number;
|
|
1740
|
+
window?: number;
|
|
1741
|
+
windowPeak?: number;
|
|
1674
1742
|
toolCount?: number;
|
|
1675
1743
|
exitCode?: number;
|
|
1676
1744
|
error?: string;
|
|
@@ -1685,6 +1753,14 @@ export interface ForegroundResumeChild {
|
|
|
1685
1753
|
detachedReason?: string;
|
|
1686
1754
|
acceptance?: AcceptanceLedger;
|
|
1687
1755
|
agentContract?: AgentContract;
|
|
1756
|
+
/** Private bounded launch fields needed to preserve the child contract on resume. */
|
|
1757
|
+
resumeContract?: {
|
|
1758
|
+
outputSchema?: JsonSchemaObject;
|
|
1759
|
+
agentContract?: AgentContract;
|
|
1760
|
+
acceptance?: AcceptanceInput;
|
|
1761
|
+
output?: string | boolean;
|
|
1762
|
+
outputMode?: OutputMode;
|
|
1763
|
+
};
|
|
1688
1764
|
launchContractDigest?: string;
|
|
1689
1765
|
/** Private retained launch authority. Never project into status or result output. */
|
|
1690
1766
|
extensionBindings?: ExtensionBindings;
|
|
@@ -1723,6 +1799,8 @@ export interface ForegroundChildControl {
|
|
|
1723
1799
|
tokens?: number;
|
|
1724
1800
|
inputTokens?: number;
|
|
1725
1801
|
outputTokens?: number;
|
|
1802
|
+
window?: number;
|
|
1803
|
+
windowPeak?: number;
|
|
1726
1804
|
model?: string;
|
|
1727
1805
|
thinking?: string;
|
|
1728
1806
|
toolCount?: number;
|
|
@@ -1758,6 +1836,8 @@ export interface ForegroundRunControl {
|
|
|
1758
1836
|
tokens?: number;
|
|
1759
1837
|
inputTokens?: number;
|
|
1760
1838
|
outputTokens?: number;
|
|
1839
|
+
window?: number;
|
|
1840
|
+
windowPeak?: number;
|
|
1761
1841
|
model?: string;
|
|
1762
1842
|
thinking?: string;
|
|
1763
1843
|
toolCount?: number;
|
|
@@ -1808,6 +1888,8 @@ export interface SubagentState {
|
|
|
1808
1888
|
parentSessionFile?: string | null;
|
|
1809
1889
|
/** Extension-owned roots trusted for child session transcript reads. */
|
|
1810
1890
|
trustedSessionRoots?: string[];
|
|
1891
|
+
/** Pi sessions base that caps exact runtime-recorded session file trust. */
|
|
1892
|
+
trustedSessionFileRoot?: string;
|
|
1811
1893
|
/** Live async session roots created by this parent executor, keyed by run id. */
|
|
1812
1894
|
liveAsyncSessionRoots?: Map<string, string>;
|
|
1813
1895
|
/** Last valid parent session model observed for this session; used when continuation contexts omit ctx.model. */
|
|
@@ -1932,6 +2014,8 @@ export interface SubagentChildStatusEvent {
|
|
|
1932
2014
|
// ============================================================================
|
|
1933
2015
|
|
|
1934
2016
|
export interface RunSyncOptions {
|
|
2017
|
+
/** Exact discovery provenance for an unknown-agent error; omission uses defensive fallback discovery. */
|
|
2018
|
+
unknownAgentDiagnosticContext?: import("../agents/agents.ts").UnknownAgentDiagnosticContext;
|
|
1935
2019
|
/** Opt-in global permission rules; missing tools remain allowed. */
|
|
1936
2020
|
permissions?: import("../runs/shared/permissions.ts").PermissionConfig;
|
|
1937
2021
|
/** Session id of the direct parent session for permission-system ask forwarding. */
|
|
@@ -1998,6 +2082,8 @@ export interface RunSyncOptions {
|
|
|
1998
2082
|
thinkingOverride?: AgentConfig["thinking"];
|
|
1999
2083
|
thinkingCeiling?: ThinkingLevel;
|
|
2000
2084
|
extensionBindings?: ExtensionBindings;
|
|
2085
|
+
/** Package-internal one-use authorization for one foreground workflow child. */
|
|
2086
|
+
workflowChildPermitLaunch?: WorkflowChildPermitContext;
|
|
2001
2087
|
/** Registry models available for heuristic bare-model resolution */
|
|
2002
2088
|
availableModels?: Array<{ provider: string; id: string; fullId: string }>;
|
|
2003
2089
|
/** Current parent-session provider to prefer for ambiguous bare model ids */
|
|
@@ -2063,6 +2149,11 @@ export interface ScheduledRunsConfig {
|
|
|
2063
2149
|
storeRoot?: string;
|
|
2064
2150
|
}
|
|
2065
2151
|
|
|
2152
|
+
export interface ModelExclusionsConfig {
|
|
2153
|
+
/** Default duration in milliseconds. A lower configured value also shortens active cached exclusions. */
|
|
2154
|
+
defaultTtlMs?: number;
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2066
2157
|
export type FleetViewPlacement = "aboveEditor" | "belowEditor";
|
|
2067
2158
|
|
|
2068
2159
|
export const FLEET_KEYBINDING_ACTIONS = [
|
|
@@ -2097,10 +2188,24 @@ export interface MainWindowRendererConfig {
|
|
|
2097
2188
|
compactResultMaxLines?: number;
|
|
2098
2189
|
}
|
|
2099
2190
|
|
|
2191
|
+
export interface ForkContextConfig {
|
|
2192
|
+
/** Keep the complete fork by default, or summarize large text-only tool results before launch. */
|
|
2193
|
+
mode?: "full" | "pruned";
|
|
2194
|
+
/** Required pruning model when mode is "pruned". */
|
|
2195
|
+
model?: string;
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2198
|
+
export interface ActiveAsyncCapacityConfig {
|
|
2199
|
+
/** Reclaim failed runner slots after this age when process proof is unknown; false keeps strict retention. */
|
|
2200
|
+
abandonedSlotReleaseAfterMs?: number | false;
|
|
2201
|
+
}
|
|
2202
|
+
|
|
2100
2203
|
export interface ExtensionConfig {
|
|
2101
2204
|
asyncByDefault?: boolean;
|
|
2102
2205
|
/** Set the context for launches that omit an explicit context. */
|
|
2103
2206
|
defaultSubagentContext?: "fresh" | "fork";
|
|
2207
|
+
/** Configure how every resolved fork session is prepared before child spawn. */
|
|
2208
|
+
forkContext?: ForkContextConfig;
|
|
2104
2209
|
/** Optional shortcut that detaches the active foreground single-subagent run. */
|
|
2105
2210
|
foregroundDetachShortcut?: string;
|
|
2106
2211
|
/** Show the Claude Code-style navigable fleet. Defaults to true. */
|
|
@@ -2111,6 +2216,8 @@ export interface ExtensionConfig {
|
|
|
2111
2216
|
fleetKeybindings?: FleetKeybindingsConfig;
|
|
2112
2217
|
/** Show the under-editor async runs widget. Defaults to true, including when FleetView is enabled. */
|
|
2113
2218
|
asyncWidget?: boolean;
|
|
2219
|
+
/** Configure the process-wide TTL policy for persisted model exclusions. */
|
|
2220
|
+
modelExclusions?: ModelExclusionsConfig;
|
|
2114
2221
|
/** Tool description variant registered for the parent-facing subagent tool. Defaults to split metadata. */
|
|
2115
2222
|
toolDescriptionMode?: ToolDescriptionMode;
|
|
2116
2223
|
/** Inline chat rendering for the subagent tool. Defaults to rich. */
|
|
@@ -2130,6 +2237,8 @@ export interface ExtensionConfig {
|
|
|
2130
2237
|
maxSubagentSpawnsPerRun?: number;
|
|
2131
2238
|
/** Optional active top-level async run cap per parent session. Unset or 0 means unlimited. */
|
|
2132
2239
|
maxActiveAsyncRunsPerSession?: number;
|
|
2240
|
+
/** Active-capacity cleanup policy. */
|
|
2241
|
+
capacity?: ActiveAsyncCapacityConfig;
|
|
2133
2242
|
/** Global cap on simultaneously-running subagent tasks within a single run. Defaults to 20. */
|
|
2134
2243
|
globalConcurrencyLimit?: number;
|
|
2135
2244
|
/**
|
|
@@ -2285,7 +2394,7 @@ export const POLL_INTERVAL_MS = 250;
|
|
|
2285
2394
|
export const WIDGET_ANIMATION_INTERVAL_MS = 1000;
|
|
2286
2395
|
export const MAX_WIDGET_JOBS = 4;
|
|
2287
2396
|
export const DEFAULT_SUBAGENT_MAX_DEPTH = 2;
|
|
2288
|
-
export const SUBAGENT_ACTIONS = ["list", "get", "models", "children.list", "guide", "create", "update", "delete", "eject", "disable", "enable", "reset", "mission.create", "mission.list", "mission.show", "mission.update", "mission.resolve-decision", "mission.attach-run", "mission.close", "worktree.discard", "refine", "refine.show", "refine.rollback", "inspector.open", "inspector.status", "inspector.close", "project.open", "project.status", "project.close", "status", "debug.run", "grant-spawn-budget", "interrupt", "resume", "steer", "stop", "dismiss", "doctor", "watchdog.status", "watchdog.check", "watchdog.configure", "watchdog.recommend-model", "schedule.create", "schedule.list", "schedule.show", "schedule.history", "schedule.pause", "schedule.resume", "schedule.run", "schedule.run-due", "schedule.delete"] as const;
|
|
2397
|
+
export const SUBAGENT_ACTIONS = ["list", "get", "models", "children.list", "guide", "validate", "create", "update", "delete", "eject", "disable", "enable", "reset", "mission.create", "mission.list", "mission.show", "mission.update", "mission.resolve-decision", "mission.attach-run", "mission.close", "worktree.discard", "refine", "refine.show", "refine.rollback", "inspector.open", "inspector.status", "inspector.close", "project.open", "project.status", "project.close", "status", "debug.run", "grant-spawn-budget", "interrupt", "resume", "steer", "stop", "dismiss", "doctor", "watchdog.status", "watchdog.check", "watchdog.configure", "watchdog.recommend-model", "schedule.create", "schedule.list", "schedule.show", "schedule.history", "schedule.pause", "schedule.resume", "schedule.run", "schedule.run-due", "schedule.delete"] as const;
|
|
2289
2398
|
|
|
2290
2399
|
export const DEFAULT_FORK_PREAMBLE =
|
|
2291
2400
|
"You are a delegated subagent running from a fork of the parent session. " +
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { stableJsonDigest } from "./launch-contract.ts";
|
|
2
|
+
|
|
3
|
+
export interface WorkflowChildPermitInput {
|
|
4
|
+
issuerPackage: string;
|
|
5
|
+
workflowRunId: string;
|
|
6
|
+
childKey: string;
|
|
7
|
+
agent: string;
|
|
8
|
+
launchContractDigest: string;
|
|
9
|
+
context: "fresh" | "fork";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface WorkflowChildPermitLaunch {
|
|
13
|
+
workflowRunId: string;
|
|
14
|
+
childKey: string;
|
|
15
|
+
agent: string;
|
|
16
|
+
launchContractDigest: string;
|
|
17
|
+
context: "fresh" | "fork";
|
|
18
|
+
runner: "pi";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface WorkflowChildPermitContext {
|
|
22
|
+
permit: WorkflowChildPermit;
|
|
23
|
+
workflowRunId: string;
|
|
24
|
+
childKey: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface WorkflowChildPermit {
|
|
28
|
+
readonly __workflowChildPermit: unique symbol;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface WorkflowChildPermitRecord {
|
|
32
|
+
issuerPackage: string;
|
|
33
|
+
workflowRunId: string;
|
|
34
|
+
childKey: string;
|
|
35
|
+
agent: string;
|
|
36
|
+
expectedProjectionDigest: string;
|
|
37
|
+
state: "available" | "claimed" | "consumed";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const records = new WeakMap<object, WorkflowChildPermitRecord>();
|
|
41
|
+
|
|
42
|
+
function projectionDigest(input: Omit<WorkflowChildPermitLaunch, "workflowRunId">): string {
|
|
43
|
+
return stableJsonDigest({
|
|
44
|
+
version: 1,
|
|
45
|
+
childKey: input.childKey,
|
|
46
|
+
agent: input.agent,
|
|
47
|
+
launchContractDigest: input.launchContractDigest,
|
|
48
|
+
context: input.context,
|
|
49
|
+
runner: input.runner,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function required(value: string, label: string): string {
|
|
54
|
+
if (!value.trim() || value !== value.trim()) throw new Error(`${label} must be a non-empty trimmed string.`);
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Package-internal first-slice permit. It is opaque, in-memory, and not serializable. */
|
|
59
|
+
export function createWorkflowChildPermit(input: WorkflowChildPermitInput): WorkflowChildPermit {
|
|
60
|
+
const permit = Object.freeze(Object.create(null)) as WorkflowChildPermit;
|
|
61
|
+
const record: WorkflowChildPermitRecord = {
|
|
62
|
+
issuerPackage: required(input.issuerPackage, "issuerPackage"),
|
|
63
|
+
workflowRunId: required(input.workflowRunId, "workflowRunId"),
|
|
64
|
+
childKey: required(input.childKey, "childKey"),
|
|
65
|
+
agent: required(input.agent, "agent"),
|
|
66
|
+
expectedProjectionDigest: projectionDigest({
|
|
67
|
+
childKey: input.childKey,
|
|
68
|
+
agent: input.agent,
|
|
69
|
+
launchContractDigest: required(input.launchContractDigest, "launchContractDigest"),
|
|
70
|
+
context: input.context,
|
|
71
|
+
runner: "pi",
|
|
72
|
+
}),
|
|
73
|
+
state: "available",
|
|
74
|
+
};
|
|
75
|
+
records.set(permit as object, record);
|
|
76
|
+
return permit;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function validateWorkflowChildPermitRoot(permit: WorkflowChildPermit, workflowRunId: string): string | undefined {
|
|
80
|
+
const record = records.get(permit as object);
|
|
81
|
+
if (!record) return "Workflow child permit is invalid.";
|
|
82
|
+
if (record.state !== "available") return "Workflow child permit is already consumed.";
|
|
83
|
+
if (record.workflowRunId !== workflowRunId) return "Workflow child permit does not match this workflow root.";
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Claim the first distinct launch attempt before validating its model-authored shape. */
|
|
88
|
+
export function claimWorkflowChildPermit(permit: WorkflowChildPermit, workflowRunId: string, childKey: string): string | undefined {
|
|
89
|
+
const record = records.get(permit as object);
|
|
90
|
+
if (!record) return "Workflow child permit is invalid.";
|
|
91
|
+
if (record.state !== "available") return "Workflow child permit is already consumed.";
|
|
92
|
+
if (record.workflowRunId !== workflowRunId) return "Workflow child permit does not match this workflow root.";
|
|
93
|
+
record.state = record.childKey === childKey ? "claimed" : "consumed";
|
|
94
|
+
if (record.childKey !== childKey) return "Workflow child permit child key mismatch.";
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Verify and permanently consume the permit before the one native process spawn. */
|
|
99
|
+
export function consumeWorkflowChildPermit(permit: WorkflowChildPermit, launch: WorkflowChildPermitLaunch): string | undefined {
|
|
100
|
+
const record = records.get(permit as object);
|
|
101
|
+
if (!record) return "Workflow child permit is invalid.";
|
|
102
|
+
if (record.state === "available") return "Workflow child permit launch was not claimed.";
|
|
103
|
+
if (record.state === "consumed") return "Workflow child permit is already consumed.";
|
|
104
|
+
if (record.workflowRunId !== launch.workflowRunId) return "Workflow child permit does not match this workflow root.";
|
|
105
|
+
record.state = "consumed";
|
|
106
|
+
if (record.childKey !== launch.childKey) return "Workflow child permit child key mismatch.";
|
|
107
|
+
if (record.agent !== launch.agent) return "Workflow child permit agent mismatch.";
|
|
108
|
+
if (launch.runner !== "pi") return "Workflow child permit supports native Pi children only.";
|
|
109
|
+
if (record.expectedProjectionDigest !== projectionDigest(launch)) return "Workflow child permit does not match the final launch projection.";
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function workflowChildPermitConsumed(permit: WorkflowChildPermit): boolean {
|
|
114
|
+
const state = records.get(permit as object)?.state;
|
|
115
|
+
return state === "claimed" || state === "consumed";
|
|
116
|
+
}
|
|
@@ -298,7 +298,6 @@ export function toSubagentDelegationExecutionParams(request: SubagentDelegationR
|
|
|
298
298
|
enforceHardTurnLimit: true,
|
|
299
299
|
toolBudget: request.toolBudget,
|
|
300
300
|
skill: request.skill,
|
|
301
|
-
output: false,
|
|
302
301
|
...(request.result.kind === "structured" ? { outputSchema: request.result.schema } : {}),
|
|
303
302
|
acceptance: false,
|
|
304
303
|
artifacts: request.artifacts,
|
|
@@ -3,7 +3,7 @@ import * as fs from "node:fs";
|
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { keyText, type ExtensionAPI, type ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
5
5
|
import { Key, matchesKey, truncateToWidth, type Component, type KeyId, type TUI } from "@earendil-works/pi-tui";
|
|
6
|
-
import { BUILTIN_AGENT_NAMES, discoverAgents, discoverAgentsAll, findBlockingAgentDiagnostic, resolveAgentName, type AgentConfig, type AgentDiscoveryDiagnostic, type AgentScope } from "../agents/agents.ts";
|
|
6
|
+
import { BUILTIN_AGENT_NAMES, discoverAgents, discoverAgentsAll, findBlockingAgentDiagnostic, formatUnknownAgentError, resolveAgentName, unknownAgentDiagnosticContext, type AgentConfig, type AgentDiscoveryDiagnostic, type AgentScope, type UnknownAgentDiagnosticContext } from "../agents/agents.ts";
|
|
7
7
|
import { listRuntimeAgentConfigs, mergeRuntimeAgents } from "../agents/runtime-agent-registry.ts";
|
|
8
8
|
import { resolveExistingReadPaths } from "../shared/settings.ts";
|
|
9
9
|
import {
|
|
@@ -22,6 +22,7 @@ import { listAsyncRuns, formatAsyncRunProgressLabel, type AsyncRunSummary } from
|
|
|
22
22
|
import { encodeInspectReply, handleInspectRpcArgs, INSPECT_WIDGET_KEY } from "../runs/background/inspect-rpc.ts";
|
|
23
23
|
import { listScheduledRunSummaries } from "../runs/background/scheduled-runs.ts";
|
|
24
24
|
import { SUBAGENT_FANOUT_CHILD_ENV } from "../runs/shared/pi-args.ts";
|
|
25
|
+
import { FLEET_OPEN_SHORTCUT } from "../shared/shortcuts.ts";
|
|
25
26
|
import type { SlashSubagentResponse, SlashSubagentUpdate } from "./slash-bridge.ts";
|
|
26
27
|
import { registerPromptWorkflowCommands } from "./prompt-workflows.ts";
|
|
27
28
|
import { openSubagentsAdmin } from "./subagents-admin.ts";
|
|
@@ -108,9 +109,9 @@ const extractExecutionFlags = (rawArgs: string): { args: string; bg: boolean; fo
|
|
|
108
109
|
return { args, bg, fork };
|
|
109
110
|
};
|
|
110
111
|
|
|
111
|
-
function discoverSlashAgents(pi: ExtensionAPI, cwd: string, scope: AgentScope): { agents: AgentConfig[]; agentDiagnostics?: AgentDiscoveryDiagnostic[] } {
|
|
112
|
+
function discoverSlashAgents(pi: ExtensionAPI, cwd: string, scope: AgentScope): { agents: AgentConfig[]; agentDiagnostics?: AgentDiscoveryDiagnostic[]; unknownAgentDiagnosticContext: UnknownAgentDiagnosticContext } {
|
|
112
113
|
const discovered = discoverAgents(cwd, scope);
|
|
113
|
-
if (listRuntimeAgentConfigs(pi).length === 0) return discovered;
|
|
114
|
+
if (listRuntimeAgentConfigs(pi).length === 0) return { ...discovered, unknownAgentDiagnosticContext: unknownAgentDiagnosticContext(discovered) };
|
|
114
115
|
const all = discoverAgentsAll(cwd);
|
|
115
116
|
const configuredAgents: AgentConfig[] = [
|
|
116
117
|
...all.builtin,
|
|
@@ -118,7 +119,8 @@ function discoverSlashAgents(pi: ExtensionAPI, cwd: string, scope: AgentScope):
|
|
|
118
119
|
...(scope !== "project" ? all.user : []),
|
|
119
120
|
...(scope !== "user" ? all.project : []),
|
|
120
121
|
];
|
|
121
|
-
|
|
122
|
+
const merged = mergeRuntimeAgents(pi, discovered, configuredAgents);
|
|
123
|
+
return { ...merged, unknownAgentDiagnosticContext: { ...unknownAgentDiagnosticContext(discovered), agents: merged.agents } };
|
|
122
124
|
}
|
|
123
125
|
|
|
124
126
|
const makeAgentCompletions = (pi: ExtensionAPI, state: SubagentState) => (prefix: string) => {
|
|
@@ -693,7 +695,7 @@ export function registerSlashCommands(
|
|
|
693
695
|
: resolvedAgent.agent;
|
|
694
696
|
const diagnostic = findBlockingAgentDiagnostic(agentName, candidates, discovered.agentDiagnostics);
|
|
695
697
|
if (diagnostic || resolvedAgent.error || !resolvedAgent.agent) {
|
|
696
|
-
ctx.ui.notify(diagnostic ? `Agent '${agentName}' has invalid configuration: ${diagnostic.error}` : resolvedAgent.error ??
|
|
698
|
+
ctx.ui.notify(diagnostic ? `Agent '${agentName}' has invalid configuration: ${diagnostic.error}` : resolvedAgent.error ?? formatUnknownAgentError(agentName, discovered.unknownAgentDiagnosticContext), "error");
|
|
697
699
|
return;
|
|
698
700
|
}
|
|
699
701
|
|
|
@@ -776,7 +778,7 @@ export function registerSlashCommands(
|
|
|
776
778
|
handler: async (_args, ctx) => showFleet(ctx),
|
|
777
779
|
});
|
|
778
780
|
|
|
779
|
-
pi.registerShortcut(
|
|
781
|
+
pi.registerShortcut(FLEET_OPEN_SHORTCUT, {
|
|
780
782
|
description: "Open subagent fleet inspector",
|
|
781
783
|
handler: async (ctx) => showFleet(ctx),
|
|
782
784
|
});
|
package/src/tui/fleet-status.ts
CHANGED
|
@@ -25,6 +25,7 @@ type FleetStatusEntry = {
|
|
|
25
25
|
description?: string;
|
|
26
26
|
startedAt: number;
|
|
27
27
|
tokens: number;
|
|
28
|
+
window?: number;
|
|
28
29
|
state: string;
|
|
29
30
|
external?: true;
|
|
30
31
|
projectPane?: HerdrProjectPaneSnapshot;
|
|
@@ -39,6 +40,7 @@ type FleetWorkflowRow = {
|
|
|
39
40
|
activity?: string;
|
|
40
41
|
startedAt?: number;
|
|
41
42
|
tokens?: number;
|
|
43
|
+
window?: number;
|
|
42
44
|
overflow?: number;
|
|
43
45
|
};
|
|
44
46
|
|
|
@@ -72,12 +74,15 @@ export function formatFleetElapsed(ms: number): string {
|
|
|
72
74
|
return `${Math.max(0, Math.round(ms / 1000))}s`;
|
|
73
75
|
}
|
|
74
76
|
|
|
75
|
-
export function formatFleetTokens(count: number): string {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
export function formatFleetTokens(count: number, window?: number): string {
|
|
78
|
+
const compact = (value: number): string => value >= 1_000_000
|
|
79
|
+
? `${(value / 1_000_000).toFixed(1)}M`
|
|
80
|
+
: value >= 1_000
|
|
81
|
+
? `${(value / 1_000).toFixed(1)}k`
|
|
82
|
+
: `${Math.max(0, Math.round(value))}`;
|
|
83
|
+
return window !== undefined
|
|
84
|
+
? `↓ ${compact(window)} window · ${compact(count)} spent`
|
|
85
|
+
: `↓ ${compact(count)} tokens`;
|
|
81
86
|
}
|
|
82
87
|
|
|
83
88
|
function rightAlign(left: string, right: string, width: number): string {
|
|
@@ -134,6 +139,7 @@ function workflowFleetRows(steps: AsyncJobStep[] | undefined): FleetWorkflowRow[
|
|
|
134
139
|
...(activity ? { activity } : {}),
|
|
135
140
|
...(step.startedAt !== undefined ? { startedAt: step.startedAt } : {}),
|
|
136
141
|
...(step.tokens?.total !== undefined ? { tokens: step.tokens.total } : {}),
|
|
142
|
+
...(step.tokens?.window !== undefined ? { window: step.tokens.window } : {}),
|
|
137
143
|
};
|
|
138
144
|
});
|
|
139
145
|
}
|
|
@@ -332,7 +338,8 @@ export function collectFleetStatusEntries(state: SubagentState): FleetStatusEntr
|
|
|
332
338
|
...(modelThinking ? { modelThinking } : {}),
|
|
333
339
|
description: foregroundDescription(control, child.description),
|
|
334
340
|
startedAt: child.startedAt,
|
|
335
|
-
|
|
341
|
+
tokens: child.tokens ?? 0,
|
|
342
|
+
...(child.window !== undefined ? { window: child.window } : {}),
|
|
336
343
|
state: "running",
|
|
337
344
|
...((control.nestedChildren?.filter((nested) => nested.parentStepIndex === child.index).length ?? 0) > 0
|
|
338
345
|
? { nestedChildren: control.nestedChildren!.filter((nested) => nested.parentStepIndex === child.index) }
|
|
@@ -350,6 +357,7 @@ export function collectFleetStatusEntries(state: SubagentState): FleetStatusEntr
|
|
|
350
357
|
description: foregroundDescription(control, control.description),
|
|
351
358
|
startedAt: control.startedAt,
|
|
352
359
|
tokens: control.tokens ?? 0,
|
|
360
|
+
...(control.window !== undefined ? { window: control.window } : {}),
|
|
353
361
|
state: "running",
|
|
354
362
|
...(control.nestedChildren?.length ? { nestedChildren: control.nestedChildren } : {}),
|
|
355
363
|
});
|
|
@@ -367,6 +375,7 @@ export function collectFleetStatusEntries(state: SubagentState): FleetStatusEntr
|
|
|
367
375
|
description: latestEmit !== undefined ? `latest emit: ${latestEmit}` : job.description,
|
|
368
376
|
startedAt,
|
|
369
377
|
tokens: job.totalTokens?.total ?? 0,
|
|
378
|
+
...(job.totalTokens?.window !== undefined ? { window: job.totalTokens.window } : {}),
|
|
370
379
|
state: job.status,
|
|
371
380
|
...(job.steps?.length ? { workflowRows: workflowFleetRows(job.steps) } : {}),
|
|
372
381
|
...(job.nestedChildren?.length ? { nestedChildren: job.nestedChildren } : {}),
|
|
@@ -387,6 +396,7 @@ export function collectFleetStatusEntries(state: SubagentState): FleetStatusEntr
|
|
|
387
396
|
description: job.description,
|
|
388
397
|
startedAt,
|
|
389
398
|
tokens: job.totalTokens?.total ?? 0,
|
|
399
|
+
...(job.totalTokens?.window !== undefined ? { window: job.totalTokens.window } : {}),
|
|
390
400
|
state: job.status,
|
|
391
401
|
...(job.nestedChildren?.length ? { nestedChildren: job.nestedChildren } : {}),
|
|
392
402
|
});
|
|
@@ -404,6 +414,9 @@ export function collectFleetStatusEntries(state: SubagentState): FleetStatusEntr
|
|
|
404
414
|
description: step.description ?? job.description,
|
|
405
415
|
startedAt: step.startedAt ?? startedAt,
|
|
406
416
|
tokens: step.tokens?.total ?? (steps.length === 1 ? job.totalTokens?.total ?? 0 : 0),
|
|
417
|
+
...((step.tokens?.window ?? (steps.length === 1 ? job.totalTokens?.window : undefined)) !== undefined
|
|
418
|
+
? { window: step.tokens?.window ?? job.totalTokens?.window }
|
|
419
|
+
: {}),
|
|
407
420
|
state: step.status,
|
|
408
421
|
...((step.children?.length ?? 0) > 0
|
|
409
422
|
? { nestedChildren: step.children }
|
|
@@ -611,6 +624,10 @@ export class SubagentFleetStatus {
|
|
|
611
624
|
const workEntries = this.entries.filter((entry) => !entry.surface);
|
|
612
625
|
const projectEntries = this.entries.filter((entry) => entry.surface === "project-pane");
|
|
613
626
|
const tokens = workEntries.reduce((total, entry) => total + entry.tokens, 0);
|
|
627
|
+
const nativeEntries = workEntries.filter((entry) => !entry.external);
|
|
628
|
+
const window = nativeEntries.length > 0 && nativeEntries.every((entry) => entry.window !== undefined)
|
|
629
|
+
? nativeEntries.reduce((total, entry) => total + entry.window!, 0)
|
|
630
|
+
: undefined;
|
|
614
631
|
const capacity = this.state.activeAsyncCapacity;
|
|
615
632
|
const hasNativeRows = workEntries.some((entry) => !entry.external);
|
|
616
633
|
const showNativeSummary = hasNativeRows || Boolean(capacity?.used);
|
|
@@ -621,7 +638,7 @@ export class SubagentFleetStatus {
|
|
|
621
638
|
const paneAttention = projectEntries.filter((entry) => entry.projectPane && projectPaneNeedsAttention(entry.projectPane)).length;
|
|
622
639
|
const panes = projectEntries.length > 0 ? `${projectEntries.length} pane${projectEntries.length === 1 ? "" : "s"}${paneAttention ? ` (${paneAttention} ⚠)` : ""}` : "";
|
|
623
640
|
const label = [agents, asyncRuns, panes].filter(Boolean).join(" · ");
|
|
624
|
-
const detail = [showNativeSummary ? formatFleetTokens(tokens) : undefined, "↓/← to inspect"].filter(Boolean).join(" · ");
|
|
641
|
+
const detail = [showNativeSummary ? formatFleetTokens(tokens, window) : undefined, "↓/← to inspect"].filter(Boolean).join(" · ");
|
|
625
642
|
return [truncateToWidth(` ${theme.fg("muted", label)}${label && detail ? " · " : ""}${theme.fg("dim", detail)}`, width)];
|
|
626
643
|
}
|
|
627
644
|
const roster = this.rosterKeys();
|
|
@@ -670,7 +687,7 @@ export class SubagentFleetStatus {
|
|
|
670
687
|
const elapsed = Date.now() - entry.startedAt;
|
|
671
688
|
const rightText = entry.projectPane
|
|
672
689
|
? `${entry.projectPane.summary ?? "—"} · ${formatFleetElapsed(Date.now() - entry.projectPane.refreshedAt)} ago`
|
|
673
|
-
: entry.external ? formatFleetElapsed(elapsed) : `${formatFleetElapsed(elapsed)} · ${formatFleetTokens(entry.tokens)}`;
|
|
690
|
+
: entry.external ? formatFleetElapsed(elapsed) : `${formatFleetElapsed(elapsed)} · ${formatFleetTokens(entry.tokens, entry.window)}`;
|
|
674
691
|
const right = theme.fg("dim", rightText);
|
|
675
692
|
return rightAlign(left, right, width);
|
|
676
693
|
}
|
|
@@ -695,7 +712,7 @@ export class SubagentFleetStatus {
|
|
|
695
712
|
const left = `${indent}${marker} ${nestedStatusGlyph(row.state, theme)} ${theme.fg("muted", `${row.name}${modelThinking}`)} · ${row.state}${activity}`;
|
|
696
713
|
const details = [
|
|
697
714
|
row.startedAt !== undefined ? formatFleetElapsed(Date.now() - row.startedAt) : undefined,
|
|
698
|
-
row.tokens !== undefined ? formatFleetTokens(row.tokens) : undefined,
|
|
715
|
+
row.tokens !== undefined ? formatFleetTokens(row.tokens, row.window) : undefined,
|
|
699
716
|
].filter(Boolean).join(" · ");
|
|
700
717
|
return truncateToWidth(`${left}${details ? theme.fg("dim", ` · ${details}`) : ""}`, width);
|
|
701
718
|
}
|