@selesai/code 0.8.6 → 0.8.7
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 +16 -0
- package/dist/core/agent-session.js +13 -1
- package/dist/core/extensions/types.d.ts +2 -0
- package/dist/core/provider-composer.js +17 -4
- package/dist/core/settings-manager.d.ts +2 -0
- package/dist/core/settings-manager.js +3 -0
- package/dist/core/system-prompt.js +2 -8
- package/dist/core/system-prompt.test.js +6 -0
- package/dist/core/tools/index.d.ts +1 -0
- package/dist/core/tools/index.js +1 -0
- package/dist/core/tools/schema-prune.d.ts +16 -0
- package/dist/core/tools/schema-prune.js +39 -0
- package/dist/core/tools/schema-prune.test.d.ts +1 -0
- package/dist/core/tools/schema-prune.test.js +111 -0
- package/dist/defaults/settings.json +1 -0
- package/dist/extensions/model-prompt-injector/config.json +10 -0
- package/dist/extensions/model-prompt-injector/index.test.ts +112 -0
- package/dist/extensions/model-prompt-injector/index.ts +151 -0
- package/dist/extensions/package.json +1 -0
- package/dist/extensions/pi-subagents/CHANGELOG.md +158 -90
- package/dist/extensions/pi-subagents/UPSTREAM-V0.50-MAPPING.md +172 -0
- package/dist/extensions/pi-subagents/agents/oracle.md +7 -5
- package/dist/extensions/pi-subagents/agents/reviewer.md +2 -2
- package/dist/extensions/pi-subagents/agents/scout.md +1 -1
- package/dist/extensions/pi-subagents/agents/worker.md +1 -1
- package/dist/extensions/pi-subagents/docs/configuration.md +78 -19
- package/dist/extensions/pi-subagents/docs/extension-api.md +36 -0
- package/dist/extensions/pi-subagents/docs/missions.md +5 -3
- package/dist/extensions/pi-subagents/docs/models.md +1 -1
- package/dist/extensions/pi-subagents/docs/observability.md +42 -2
- package/dist/extensions/pi-subagents/docs/tool-reference.md +20 -3
- package/dist/extensions/pi-subagents/docs/workflows.md +5 -5
- package/dist/extensions/pi-subagents/install.mjs +2 -2
- package/dist/extensions/pi-subagents/package-lock.json +1470 -1472
- package/dist/extensions/pi-subagents/package.json +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +5 -4
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +15 -14
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +5 -5
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +46 -26
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +2 -0
- package/dist/extensions/pi-subagents/src/agents/agents.ts +37 -12
- package/dist/extensions/pi-subagents/src/api/external-runs.ts +174 -84
- package/dist/extensions/pi-subagents/src/api/preflight.ts +13 -7
- package/dist/extensions/pi-subagents/src/extension/config.ts +53 -0
- package/dist/extensions/pi-subagents/src/extension/index.ts +67 -13
- package/dist/extensions/pi-subagents/src/extension/public-execution.ts +34 -6
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +5 -1
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +31 -30
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +10 -9
- package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +13 -8
- package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +16 -3
- package/dist/extensions/pi-subagents/src/inspectors/herdr/project-panes.ts +2 -6
- package/dist/extensions/pi-subagents/src/inspectors/herdr/shell-command.ts +16 -0
- package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +5 -4
- package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +19 -42
- package/dist/extensions/pi-subagents/src/missions/goal-driver.ts +3 -1
- package/dist/extensions/pi-subagents/src/missions/store.ts +8 -3
- package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +82 -25
- package/dist/extensions/pi-subagents/src/runs/background/active-run-index.ts +71 -1
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +73 -43
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +5 -0
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +14 -6
- package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +277 -0
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +8 -3
- package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +2 -2
- package/dist/extensions/pi-subagents/src/runs/background/completion-replay.ts +11 -1
- package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +21 -6
- package/dist/extensions/pi-subagents/src/runs/background/result-files.ts +437 -0
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +205 -41
- package/dist/extensions/pi-subagents/src/runs/background/resume-guidance.ts +27 -7
- package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +76 -19
- package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +30 -24
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +101 -4
- package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +54 -28
- package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +27 -13
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +298 -33
- package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +2 -0
- package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +5 -2
- package/dist/extensions/pi-subagents/src/runs/foreground/async-dismiss-action.ts +2 -1
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +16 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +219 -15
- package/dist/extensions/pi-subagents/src/runs/foreground/prompt-audit.ts +4 -3
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +333 -45
- package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +107 -1
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +4 -0
- package/dist/extensions/pi-subagents/src/runs/shared/llm-intent-arbiter.ts +39 -23
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +16 -2
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +66 -62
- package/dist/extensions/pi-subagents/src/runs/shared/orca-progress-tabs.ts +376 -0
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +2 -0
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +15 -0
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +1 -9
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +12 -0
- package/dist/extensions/pi-subagents/src/runs/shared/tool-timeout.ts +95 -0
- package/dist/extensions/pi-subagents/src/shared/agent-stream-options.ts +5 -0
- package/dist/extensions/pi-subagents/src/shared/artifacts.ts +0 -4
- package/dist/extensions/pi-subagents/src/shared/display-text.ts +50 -0
- package/dist/extensions/pi-subagents/src/shared/node-executable.ts +21 -0
- package/dist/extensions/pi-subagents/src/shared/types.ts +50 -4
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +34 -25
- package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +4 -0
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +160 -45
- package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +1 -48
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +128 -16
- package/dist/extensions/pi-subagents/src/tui/render.ts +122 -44
- package/dist/extensions/pi-subagents/src/watchdog/permission-arbiter.ts +2 -1
- package/dist/extensions/pi-subagents/src/watchdog/review.ts +4 -3
- package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +10 -2
- package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +272 -76
- package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/types.d.ts +2 -0
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +68 -9
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +27 -1
- package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +49 -0
- package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +26 -1
- package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +144 -0
- package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +26 -0
- package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +369 -98
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +111 -78
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +49 -1
- package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +12 -0
- package/dist/extensions/pi-subagents/test/support/node-command.ts +15 -0
- package/dist/extensions/pi-subagents/test/unit/active-async-capacity.test.ts +50 -0
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +28 -0
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +61 -0
- package/dist/extensions/pi-subagents/test/unit/agent-stream-options.test.ts +14 -0
- package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +76 -0
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +2 -0
- package/dist/extensions/pi-subagents/test/unit/async-status-snapshot.test.ts +162 -0
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +209 -10
- package/dist/extensions/pi-subagents/test/unit/completion-replay.test.ts +41 -1
- package/dist/extensions/pi-subagents/test/unit/external-runs.test.ts +135 -42
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +252 -1
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +192 -6
- package/dist/extensions/pi-subagents/test/unit/herdr-inspector-bootstrap.test.ts +32 -0
- package/dist/extensions/pi-subagents/test/unit/herdr-shell-command.test.ts +59 -0
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +69 -0
- package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +23 -4
- package/dist/extensions/pi-subagents/test/unit/llm-intent-arbiter.test.ts +56 -1
- package/dist/extensions/pi-subagents/test/unit/mission-goal-driver.test.ts +67 -3
- package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +14 -0
- package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +18 -0
- package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +25 -2
- package/dist/extensions/pi-subagents/test/unit/node-executable.test.ts +26 -0
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +8 -0
- package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +348 -0
- package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +5 -2
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +34 -0
- package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +6 -1
- package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +92 -0
- package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +175 -0
- package/dist/extensions/pi-subagents/test/unit/retained-children.test.ts +127 -17
- package/dist/extensions/pi-subagents/test/unit/run-id-resolver.test.ts +44 -0
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +247 -0
- package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +107 -2
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +5 -8
- package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +456 -4
- package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +128 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +28 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +16 -7
- package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +15 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +79 -15
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +12 -12
- package/dist/extensions/pi-subagents/test/unit/tool-timeout.test.ts +109 -0
- package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +34 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +94 -1
- package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +42 -2
- package/dist/extensions/question/index.ts +21 -6
- package/dist/extensions/question/question-list.ts +7 -1
- package/dist/extensions/question/row-layout.ts +3 -0
- package/dist/extensions/question/tests/exp.test.ts +70 -0
- package/dist/extensions/question/tests/exp2.test.ts +59 -0
- package/dist/extensions/question/tests/exp3.test.ts +47 -0
- package/dist/extensions/question/tests/helpers.test.ts +7 -0
- package/dist/extensions/question/tests/question-list.test.ts +140 -0
- package/dist/extensions/question/tests/row-layout.test.ts +13 -0
- package/dist/extensions/question/tests/selection-mode.test.ts +54 -0
- package/dist/extensions/question/tests/zz-ig3.test.ts +20 -0
- package/dist/extensions/question/tests/zz-probe.test.ts +29 -0
- package/dist/skills/pi-subagents/SKILL.md +1 -1
- package/dist/skills/pi-subagents/references/constraints-and-recipes.md +5 -4
- package/dist/skills/pi-subagents/references/execution-controls.md +15 -14
- package/dist/skills/pi-subagents/references/management-authoring-rpc.md +5 -5
- package/dist/skills/pi-subagents/references/prompting-and-roles.md +46 -26
- package/docs/settings.md +6 -0
- package/package.json +3 -3
|
@@ -215,7 +215,7 @@ export interface ControlEvent {
|
|
|
215
215
|
nestedRunId?: string;
|
|
216
216
|
nestingPath?: NestedRunAddress["path"];
|
|
217
217
|
message: string;
|
|
218
|
-
reason?: "idle" | "completion_guard" | "active_long_running" | "tool_failures" | "supervisor_request" | "time_threshold" | "turn_threshold" | "token_threshold";
|
|
218
|
+
reason?: "idle" | "completion_guard" | "active_long_running" | "tool_failures" | "supervisor_request" | "time_threshold" | "turn_threshold" | "token_threshold" | "tool_open_threshold";
|
|
219
219
|
turns?: number;
|
|
220
220
|
tokens?: number;
|
|
221
221
|
toolCount?: number;
|
|
@@ -528,6 +528,8 @@ export interface SteeringRecoveryDescriptor {
|
|
|
528
528
|
structuredOutputSchema?: JsonSchemaObject;
|
|
529
529
|
acceptance?: AcceptanceInput;
|
|
530
530
|
controlConfig?: ResolvedControlConfig;
|
|
531
|
+
/** Raw per-run bridge override. Omitted descriptors continue to use global config. */
|
|
532
|
+
intercomBridge?: IntercomBridgeConfig;
|
|
531
533
|
absoluteDeadlineAt?: number;
|
|
532
534
|
initialTurnBudget?: ResolvedTurnBudget;
|
|
533
535
|
initialToolBudget?: ResolvedToolBudget;
|
|
@@ -1029,6 +1031,7 @@ export interface Details {
|
|
|
1029
1031
|
controlEvents?: ControlEvent[];
|
|
1030
1032
|
steering?: SteerActionResult;
|
|
1031
1033
|
asyncId?: string;
|
|
1034
|
+
background?: boolean;
|
|
1032
1035
|
asyncDir?: string;
|
|
1033
1036
|
timeoutMs?: number;
|
|
1034
1037
|
deadlineAt?: number;
|
|
@@ -1086,7 +1089,7 @@ export interface Details {
|
|
|
1086
1089
|
trace: Array<{
|
|
1087
1090
|
operation: "run" | "status";
|
|
1088
1091
|
key: string;
|
|
1089
|
-
state: "started" | "completed" | "failed" | "reused";
|
|
1092
|
+
state: "started" | "completed" | "failed" | "detached" | "stopped" | "reused";
|
|
1090
1093
|
agent?: string;
|
|
1091
1094
|
runId?: string;
|
|
1092
1095
|
phase?: string;
|
|
@@ -1259,6 +1262,8 @@ export interface AsyncStartedEvent {
|
|
|
1259
1262
|
asyncDir?: string;
|
|
1260
1263
|
/** Parent-resolved launch directory, used as a trusted artifact root while this session is live. */
|
|
1261
1264
|
cwd?: string;
|
|
1265
|
+
/** Parent-resolved child session root, used only while this session owns the live run. */
|
|
1266
|
+
sessionRoot?: string;
|
|
1262
1267
|
pid?: number;
|
|
1263
1268
|
sessionId?: string;
|
|
1264
1269
|
mode?: SubagentRunMode;
|
|
@@ -1464,8 +1469,12 @@ export interface AsyncJobState {
|
|
|
1464
1469
|
asyncDir: string;
|
|
1465
1470
|
/** True when the job was adopted from a previous session via lineage carry-over. */
|
|
1466
1471
|
adopted?: boolean;
|
|
1472
|
+
/** Host tool-call id retained when it differs from the internal run id. */
|
|
1473
|
+
toolCallId?: string;
|
|
1467
1474
|
/** Parent-resolved launch directory retained for trusted live artifact lookup. */
|
|
1468
1475
|
cwd?: string;
|
|
1476
|
+
/** Parent-resolved child session root retained for trusted live transcript lookup. */
|
|
1477
|
+
sessionRoot?: string;
|
|
1469
1478
|
status: "queued" | "running" | "complete" | "failed" | "paused" | "stopped" | "rejected";
|
|
1470
1479
|
/** Short caller-facing task/goal shown in fleet surfaces when available. */
|
|
1471
1480
|
description?: string;
|
|
@@ -1671,6 +1680,10 @@ export interface SubagentState {
|
|
|
1671
1680
|
/** Runtime mission-store snapshot used by optional inspector context. */
|
|
1672
1681
|
missionStoreConfig?: MissionStoreConfig;
|
|
1673
1682
|
parentSessionFile?: string | null;
|
|
1683
|
+
/** Extension-owned roots trusted for child session transcript reads. */
|
|
1684
|
+
trustedSessionRoots?: string[];
|
|
1685
|
+
/** Live async session roots created by this parent executor, keyed by run id. */
|
|
1686
|
+
liveAsyncSessionRoots?: Map<string, string>;
|
|
1674
1687
|
/** Last valid parent session model observed for this session; used when continuation contexts omit ctx.model. */
|
|
1675
1688
|
lastParentModel?: { provider: string; id: string };
|
|
1676
1689
|
subagentInProgress?: boolean;
|
|
@@ -1767,6 +1780,10 @@ export interface RunSyncOptions {
|
|
|
1767
1780
|
interruptSignal?: AbortSignal;
|
|
1768
1781
|
timeoutMs?: number;
|
|
1769
1782
|
deadlineAt?: number;
|
|
1783
|
+
/** Per-call per-tool timeout (ms), resolved with the agent/config/environment ladder at execution. */
|
|
1784
|
+
toolTimeoutMs?: number;
|
|
1785
|
+
/** Raw global config.toolTimeoutMs, used by the per-child resolver. */
|
|
1786
|
+
configToolTimeoutMs?: number;
|
|
1770
1787
|
turnBudget?: ResolvedTurnBudget;
|
|
1771
1788
|
usageBudget?: UsageBudgetConfig;
|
|
1772
1789
|
/** Enforce maxTurns + graceTurns as a hard model-turn boundary. */
|
|
@@ -1831,6 +1848,8 @@ export interface RunSyncOptions {
|
|
|
1831
1848
|
};
|
|
1832
1849
|
/** Private live callback for the exact child prompt after runtime acceptance injection. */
|
|
1833
1850
|
onEffectivePrompt?: (prompt: string) => void;
|
|
1851
|
+
/** Internal lifecycle hook for the observer shared across retries of one logical child. */
|
|
1852
|
+
onOrcaProgressTabCreated?: (tab: import("../runs/shared/orca-progress-tabs.ts").OrcaProgressTab) => void;
|
|
1834
1853
|
}
|
|
1835
1854
|
|
|
1836
1855
|
export type IntercomBridgeMode = "off" | "fork-only" | "always";
|
|
@@ -1892,8 +1911,22 @@ export const FLEET_KEYBINDING_ACTIONS = [
|
|
|
1892
1911
|
export type FleetKeybindingAction = typeof FLEET_KEYBINDING_ACTIONS[number];
|
|
1893
1912
|
export type FleetKeybindingsConfig = Partial<Record<FleetKeybindingAction, string[]>>;
|
|
1894
1913
|
|
|
1914
|
+
export interface OrcaProgressTabsConfig {
|
|
1915
|
+
/** Create one Orca terminal tab per running subagent. Experimental and opt-in. */
|
|
1916
|
+
enabled?: boolean;
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
export interface MainWindowRendererConfig {
|
|
1920
|
+
/** Unit of horizontal space in main chat subagent call/result rows. Omit to preserve current spacing. Set 0 for no extra padding. */
|
|
1921
|
+
horizontalSpacing?: number;
|
|
1922
|
+
/** Maximum collapsed rich-result rows. Expanded output is not capped. */
|
|
1923
|
+
compactResultMaxLines?: number;
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1895
1926
|
export interface ExtensionConfig {
|
|
1896
1927
|
asyncByDefault?: boolean;
|
|
1928
|
+
/** Optional shortcut that detaches the active foreground single-subagent run. */
|
|
1929
|
+
foregroundDetachShortcut?: string;
|
|
1897
1930
|
/** Show the Claude Code-style navigable fleet. Defaults to true. */
|
|
1898
1931
|
fleetView?: boolean;
|
|
1899
1932
|
/** Place the persistent FleetView above or below the editor. Defaults to belowEditor. */
|
|
@@ -1902,12 +1935,16 @@ export interface ExtensionConfig {
|
|
|
1902
1935
|
fleetKeybindings?: FleetKeybindingsConfig;
|
|
1903
1936
|
/** Show the under-editor async runs widget. Defaults to true, including when FleetView is enabled. */
|
|
1904
1937
|
asyncWidget?: boolean;
|
|
1905
|
-
/** Tool description variant registered for the parent-facing subagent tool. Defaults to
|
|
1938
|
+
/** Tool description variant registered for the parent-facing subagent tool. Defaults to compact. */
|
|
1906
1939
|
toolDescriptionMode?: ToolDescriptionMode;
|
|
1907
1940
|
/** Include legacy append-step and checkpoint controls in the registered tool schema. Defaults to false. */
|
|
1908
1941
|
legacyChainControls?: boolean;
|
|
1909
1942
|
/** Inline chat rendering for the subagent tool. Defaults to rich. */
|
|
1910
1943
|
inlineToolDisplay?: InlineToolDisplay;
|
|
1944
|
+
/** Density controls for the main chat subagent call/result renderer. */
|
|
1945
|
+
mainWindowRenderer?: MainWindowRendererConfig;
|
|
1946
|
+
/** Experimental observer: mirror each native subagent's progress into a new Orca tab. */
|
|
1947
|
+
orcaProgressTabs?: OrcaProgressTabsConfig;
|
|
1911
1948
|
forceTopLevelAsync?: boolean;
|
|
1912
1949
|
waitTool?: WaitToolConfig;
|
|
1913
1950
|
defaultSessionDir?: string;
|
|
@@ -1937,6 +1974,15 @@ export interface ExtensionConfig {
|
|
|
1937
1974
|
* Must be a positive integer; invalid values are ignored.
|
|
1938
1975
|
*/
|
|
1939
1976
|
timeoutMs?: number;
|
|
1977
|
+
/**
|
|
1978
|
+
* Optional hard per-tool-call timeout in milliseconds. Bounds a single
|
|
1979
|
+
* subagent tool call inside the child; the run-level timeout remains
|
|
1980
|
+
* authoritative. Known-fast built-in tools have a five-minute default when
|
|
1981
|
+
* this is undefined. Precedence: call param > agent frontmatter > this config >
|
|
1982
|
+
* SELESAI_SUBAGENT_TOOL_TIMEOUT_MS. Must be a positive integer; invalid values
|
|
1983
|
+
* are rejected with an error.
|
|
1984
|
+
*/
|
|
1985
|
+
toolTimeoutMs?: number;
|
|
1940
1986
|
control?: ControlConfig;
|
|
1941
1987
|
completionBatch?: CompletionBatchConfig;
|
|
1942
1988
|
turnBudget?: TurnBudgetConfig;
|
|
@@ -2060,7 +2106,7 @@ export const SLASH_SUBAGENT_CANCEL_EVENT = "subagent:slash:cancel";
|
|
|
2060
2106
|
export const POLL_INTERVAL_MS = 250;
|
|
2061
2107
|
export const MAX_WIDGET_JOBS = 4;
|
|
2062
2108
|
export const DEFAULT_SUBAGENT_MAX_DEPTH = 2;
|
|
2063
|
-
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", "grant-spawn-budget", "interrupt", "resume", "steer", "stop", "dismiss", "append-step", "approve-checkpoint", "reject-checkpoint", "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;
|
|
2109
|
+
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", "append-step", "approve-checkpoint", "reject-checkpoint", "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;
|
|
2064
2110
|
|
|
2065
2111
|
export const DEFAULT_FORK_PREAMBLE =
|
|
2066
2112
|
"You are a delegated subagent running from a fork of the parent session. " +
|
|
@@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { keyText, type ExtensionAPI, type ExtensionContext } from "@selesai/code";
|
|
5
|
-
import { Key, matchesKey, truncateToWidth, type Component, type TUI } from "@earendil-works/pi-tui";
|
|
5
|
+
import { Key, matchesKey, truncateToWidth, type Component, type KeyId, type TUI } from "@earendil-works/pi-tui";
|
|
6
6
|
import { BUILTIN_AGENT_NAMES, discoverAgents } from "../agents/agents.ts";
|
|
7
7
|
import { registerInlineSubagentInvocation } from "./inline-subagents.ts";
|
|
8
8
|
import { resolveExistingReadPaths } from "../shared/settings.ts";
|
|
@@ -632,7 +632,7 @@ function slashRunWorkflowScript(key: string, child: Record<string, unknown>): st
|
|
|
632
632
|
export function registerSlashCommands(
|
|
633
633
|
pi: ExtensionAPI,
|
|
634
634
|
state: SubagentState,
|
|
635
|
-
options: { fleetKeybindings?: FleetKeybindingsConfig } = {},
|
|
635
|
+
options: { fleetKeybindings?: FleetKeybindingsConfig; foregroundDetachShortcut?: string } = {},
|
|
636
636
|
): void {
|
|
637
637
|
registerInlineSubagentInvocation(pi, state);
|
|
638
638
|
let fleetOpen = false;
|
|
@@ -743,33 +743,42 @@ export function registerSlashCommands(
|
|
|
743
743
|
handler: async (ctx) => showFleet(ctx),
|
|
744
744
|
});
|
|
745
745
|
|
|
746
|
+
const detachForegroundRun = (args: string, ctx: ExtensionContext): void => {
|
|
747
|
+
const id = args.trim();
|
|
748
|
+
let control: ReturnType<typeof selectForegroundDetachControl>;
|
|
749
|
+
try {
|
|
750
|
+
control = selectForegroundDetachControl(state, id);
|
|
751
|
+
} catch (error) {
|
|
752
|
+
ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
if (!control) {
|
|
756
|
+
ctx.ui.notify(id ? `No active foreground run found for '${id}'.` : "No active foreground single-subagent run to detach.", "info");
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
if (control.mode !== "single") {
|
|
760
|
+
ctx.ui.notify("/subagents-detach currently supports single-subagent runs only.", "error");
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
if (!control.detach?.()) {
|
|
764
|
+
ctx.ui.notify(`Foreground run ${control.runId} is not currently detachable.`, "info");
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
sendSlashText(pi, `Detached foreground run ${control.runId} without terminating its child. Use subagent({ action: "status", id: ${JSON.stringify(control.runId)} }) or subagent_wait({ id: ${JSON.stringify(control.runId)} }) to recover the eventual result. This does not daemonize the process or guarantee survival across Pi reload/restart.`);
|
|
768
|
+
};
|
|
769
|
+
|
|
746
770
|
pi.registerCommand("subagents-detach", {
|
|
747
771
|
description: "Detach the active foreground single-subagent run without terminating it",
|
|
748
|
-
handler: async (args, ctx) =>
|
|
749
|
-
const id = args.trim();
|
|
750
|
-
let control: ReturnType<typeof selectForegroundDetachControl>;
|
|
751
|
-
try {
|
|
752
|
-
control = selectForegroundDetachControl(state, id);
|
|
753
|
-
} catch (error) {
|
|
754
|
-
ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
|
|
755
|
-
return;
|
|
756
|
-
}
|
|
757
|
-
if (!control) {
|
|
758
|
-
ctx.ui.notify(id ? `No active foreground run found for '${id}'.` : "No active foreground single-subagent run to detach.", "info");
|
|
759
|
-
return;
|
|
760
|
-
}
|
|
761
|
-
if (control.mode !== "single") {
|
|
762
|
-
ctx.ui.notify("/subagents-detach currently supports single-subagent runs only.", "error");
|
|
763
|
-
return;
|
|
764
|
-
}
|
|
765
|
-
if (!control.detach?.()) {
|
|
766
|
-
ctx.ui.notify(`Foreground run ${control.runId} is not currently detachable.`, "info");
|
|
767
|
-
return;
|
|
768
|
-
}
|
|
769
|
-
sendSlashText(pi, `Detached foreground run ${control.runId} without terminating its child. Use subagent({ action: "status", id: ${JSON.stringify(control.runId)} }) or subagent_wait({ id: ${JSON.stringify(control.runId)} }) to recover the eventual result. This does not daemonize the process or guarantee survival across Pi reload/restart.`);
|
|
770
|
-
},
|
|
772
|
+
handler: async (args, ctx) => detachForegroundRun(args, ctx),
|
|
771
773
|
});
|
|
772
774
|
|
|
775
|
+
if (options.foregroundDetachShortcut) {
|
|
776
|
+
pi.registerShortcut(options.foregroundDetachShortcut as KeyId, {
|
|
777
|
+
description: "Detach the active foreground subagent and keep it running in the background",
|
|
778
|
+
handler: async (ctx) => detachForegroundRun("", ctx),
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
|
|
773
782
|
pi.registerCommand("subagents-stop", {
|
|
774
783
|
description: "Stop a current-session async subagent run",
|
|
775
784
|
handler: async (args, ctx) => {
|
|
@@ -81,6 +81,7 @@ function buildParallelInitialResult(params: SubagentParamsLike): AgentToolResult
|
|
|
81
81
|
content: [{ type: "text", text: tasks.map((task) => `${task.agent}: ${task.task}`).join("\n\n") }],
|
|
82
82
|
details: {
|
|
83
83
|
mode: "parallel",
|
|
84
|
+
...(params.async ? { background: true } : {}),
|
|
84
85
|
...(params.context ? { context: params.context } : {}),
|
|
85
86
|
results: tasks.map((task, index) => createPlaceholderResult(task.agent, task.task, "running", index)),
|
|
86
87
|
progress: tasks.map((task, index) => ({
|
|
@@ -136,6 +137,7 @@ function buildChainInitialResult(params: SubagentParamsLike): AgentToolResult<De
|
|
|
136
137
|
}],
|
|
137
138
|
details: {
|
|
138
139
|
mode: "chain",
|
|
140
|
+
...(params.async ? { background: true } : {}),
|
|
139
141
|
...(params.context ? { context: params.context } : {}),
|
|
140
142
|
results,
|
|
141
143
|
progress: results.map((result, index) => ({
|
|
@@ -164,6 +166,7 @@ function buildSingleInitialResult(params: SubagentParamsLike): AgentToolResult<D
|
|
|
164
166
|
content: [{ type: "text", text: task }],
|
|
165
167
|
details: {
|
|
166
168
|
mode: "single",
|
|
169
|
+
...(params.async ? { background: true } : {}),
|
|
167
170
|
...(params.context ? { context: params.context } : {}),
|
|
168
171
|
results: [createPlaceholderResult(agent, task, "running", 0)],
|
|
169
172
|
progress: [{
|
|
@@ -189,6 +192,7 @@ function buildWorkflowInitialResult(params: SubagentParamsLike): AgentToolResult
|
|
|
189
192
|
details: {
|
|
190
193
|
mode: "workflow",
|
|
191
194
|
...(params.context ? { context: params.context } : {}),
|
|
195
|
+
...(params.async ? { background: true } : {}),
|
|
192
196
|
results: [],
|
|
193
197
|
workflow: { trace: [], emits: [], console: [] },
|
|
194
198
|
},
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { ExtensionContext } from "@selesai/code";
|
|
2
2
|
import { type EditorComponent, isKeyRelease, Key, matchesKey, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
3
|
+
import { snapshotExternalRuns } from "../api/external-runs.ts";
|
|
3
4
|
import { formatModelThinking } from "../shared/formatters.ts";
|
|
4
5
|
import type { AsyncJobStep, FleetViewPlacement, NestedRunSummary, NestedStepSummary, SubagentState } from "../shared/types.ts";
|
|
5
6
|
import { formatWorkflowJsonPreview } from "../workflows/scripted-workflow.ts";
|
|
6
7
|
|
|
7
8
|
export const FLEET_STATUS_WIDGET_KEY = "subagent-fleet-status";
|
|
8
9
|
|
|
9
|
-
// Six rows fit the accepted collapsed hierarchy: one owner, four
|
|
10
|
+
// Six rows fit the accepted collapsed hierarchy: one owner, four visible descendants, and overflow.
|
|
10
11
|
const MAX_AGENT_ROWS = 6;
|
|
11
12
|
const REFRESH_MS = 500;
|
|
12
13
|
|
|
@@ -16,12 +17,15 @@ type FleetStatusTui = {
|
|
|
16
17
|
};
|
|
17
18
|
type FleetStatusEntry = {
|
|
18
19
|
key: string;
|
|
20
|
+
parentKey?: string;
|
|
21
|
+
workflowWrapper?: boolean;
|
|
19
22
|
agent: string;
|
|
20
23
|
modelThinking?: string;
|
|
21
24
|
description?: string;
|
|
22
25
|
startedAt: number;
|
|
23
26
|
tokens: number;
|
|
24
27
|
state: string;
|
|
28
|
+
external?: true;
|
|
25
29
|
nestedChildren?: NestedRunSummary[];
|
|
26
30
|
};
|
|
27
31
|
|
|
@@ -31,11 +35,13 @@ type FleetNestedRow = {
|
|
|
31
35
|
modelThinking?: string;
|
|
32
36
|
activity?: string;
|
|
33
37
|
startedAt?: number;
|
|
38
|
+
depth: number;
|
|
34
39
|
overflow?: number;
|
|
35
40
|
};
|
|
36
41
|
|
|
37
42
|
type FleetTreeRow =
|
|
38
43
|
| { kind: "owner"; entry: FleetStatusEntry }
|
|
44
|
+
| { kind: "child"; entry: FleetStatusEntry; last: boolean }
|
|
39
45
|
| { kind: "nested"; ownerKey: string; row: FleetNestedRow; last: boolean };
|
|
40
46
|
|
|
41
47
|
export interface FleetStatusOptions {
|
|
@@ -94,44 +100,112 @@ function nestedStatusGlyph(state: FleetNestedRow["state"], theme: Theme): string
|
|
|
94
100
|
return theme.fg("warning", "■");
|
|
95
101
|
}
|
|
96
102
|
|
|
97
|
-
function
|
|
98
|
-
|
|
99
|
-
for (
|
|
103
|
+
function nestedStepDisplayCount(steps: NestedStepSummary[] | undefined, start = 0): number {
|
|
104
|
+
let count = 0;
|
|
105
|
+
for (let index = start; index < (steps?.length ?? 0); index++) {
|
|
106
|
+
count += 1 + nestedDisplayCount(steps![index]!.children);
|
|
107
|
+
}
|
|
108
|
+
return count;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function nestedDisplayCount(children: NestedRunSummary[] | undefined, start = 0): number {
|
|
112
|
+
let count = 0;
|
|
113
|
+
for (let index = start; index < (children?.length ?? 0); index++) {
|
|
114
|
+
const child = children![index]!;
|
|
100
115
|
const steps = (child.mode === "parallel" || child.mode === "chain") ? child.steps ?? [] : [];
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
116
|
+
count += steps.length > 0 ? nestedStepDisplayCount(steps) : 1;
|
|
117
|
+
count += nestedDisplayCount(child.children);
|
|
118
|
+
}
|
|
119
|
+
return count;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function nestedFleetRows(children: NestedRunSummary[] | undefined, visibleLimit: number): FleetNestedRow[] {
|
|
123
|
+
const rows: FleetNestedRow[] = [];
|
|
124
|
+
let omitted = 0;
|
|
125
|
+
const appendRuns = (runs: NestedRunSummary[] | undefined, depth: number): boolean => {
|
|
126
|
+
for (let runIndex = 0; runIndex < (runs?.length ?? 0); runIndex++) {
|
|
127
|
+
const child = runs![runIndex]!;
|
|
128
|
+
const steps = (child.mode === "parallel" || child.mode === "chain") ? child.steps ?? [] : [];
|
|
129
|
+
if (steps.length > 0) {
|
|
130
|
+
for (let stepIndex = 0; stepIndex < steps.length; stepIndex++) {
|
|
131
|
+
if (rows.length >= visibleLimit) {
|
|
132
|
+
omitted += nestedStepDisplayCount(steps, stepIndex);
|
|
133
|
+
omitted += nestedDisplayCount(child.children);
|
|
134
|
+
omitted += nestedDisplayCount(runs, runIndex + 1);
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
const step = steps[stepIndex]!;
|
|
138
|
+
const modelThinking = formatModelThinking(step.model, step.thinking) || undefined;
|
|
139
|
+
const activity = nestedActivity(step);
|
|
140
|
+
rows.push({
|
|
141
|
+
name: step.agent,
|
|
142
|
+
state: step.status,
|
|
143
|
+
depth,
|
|
144
|
+
...(modelThinking ? { modelThinking } : {}),
|
|
145
|
+
...(activity ? { activity } : {}),
|
|
146
|
+
...(step.startedAt !== undefined ? { startedAt: step.startedAt } : {}),
|
|
147
|
+
});
|
|
148
|
+
if (!appendRuns(step.children, depth + 1)) {
|
|
149
|
+
omitted += nestedStepDisplayCount(steps, stepIndex + 1);
|
|
150
|
+
omitted += nestedDisplayCount(child.children);
|
|
151
|
+
omitted += nestedDisplayCount(runs, runIndex + 1);
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
if (rows.length >= visibleLimit) {
|
|
157
|
+
omitted += nestedDisplayCount(runs, runIndex);
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
const modelThinking = formatModelThinking(child.model, child.thinking) || undefined;
|
|
161
|
+
const activity = nestedActivity(child);
|
|
105
162
|
rows.push({
|
|
106
|
-
name:
|
|
107
|
-
state:
|
|
163
|
+
name: nestedRunLabel(child),
|
|
164
|
+
state: child.state,
|
|
165
|
+
depth,
|
|
108
166
|
...(modelThinking ? { modelThinking } : {}),
|
|
109
167
|
...(activity ? { activity } : {}),
|
|
110
|
-
...(
|
|
168
|
+
...(child.startedAt !== undefined ? { startedAt: child.startedAt } : {}),
|
|
111
169
|
});
|
|
112
170
|
}
|
|
113
|
-
|
|
171
|
+
if (!appendRuns(child.children, depth + 1)) {
|
|
172
|
+
omitted += nestedDisplayCount(runs, runIndex + 1);
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
114
175
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
...(modelThinking ? { modelThinking } : {}),
|
|
121
|
-
...(activity ? { activity } : {}),
|
|
122
|
-
...(child.startedAt !== undefined ? { startedAt: child.startedAt } : {}),
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
const visible = rows.slice(0, 4);
|
|
126
|
-
if (rows.length > visible.length) visible.push({ name: `… +${rows.length - visible.length} more nested leaves`, state: "complete", overflow: rows.length - visible.length });
|
|
127
|
-
return visible;
|
|
176
|
+
return true;
|
|
177
|
+
};
|
|
178
|
+
appendRuns(children, 0);
|
|
179
|
+
if (omitted > 0) rows.push({ name: `… +${omitted} more nested leaves`, state: "complete", depth: 0, overflow: omitted });
|
|
180
|
+
return rows;
|
|
128
181
|
}
|
|
129
182
|
|
|
130
183
|
function fleetTreeRows(entries: FleetStatusEntry[]): FleetTreeRow[] {
|
|
131
184
|
const rows: FleetTreeRow[] = [];
|
|
185
|
+
const entryKeys = new Set(entries.map((entry) => entry.key));
|
|
186
|
+
const childrenByParent = new Map<string, FleetStatusEntry[]>();
|
|
187
|
+
for (const entry of entries) {
|
|
188
|
+
if (!entry.parentKey || !entryKeys.has(entry.parentKey)) continue;
|
|
189
|
+
const children = childrenByParent.get(entry.parentKey) ?? [];
|
|
190
|
+
children.push(entry);
|
|
191
|
+
childrenByParent.set(entry.parentKey, children);
|
|
192
|
+
}
|
|
132
193
|
for (const entry of entries) {
|
|
194
|
+
if (entry.parentKey && entryKeys.has(entry.parentKey)) continue;
|
|
133
195
|
rows.push({ kind: "owner", entry });
|
|
134
|
-
const
|
|
196
|
+
const attached = childrenByParent.get(entry.key) ?? [];
|
|
197
|
+
for (const [index, child] of attached.entries()) {
|
|
198
|
+
const nested = nestedFleetRows(child.nestedChildren, 3);
|
|
199
|
+
const laterRows = index < attached.length - 1 || Boolean(entry.nestedChildren?.length);
|
|
200
|
+
rows.push({ kind: "child", entry: child, last: !laterRows && nested.length === 0 });
|
|
201
|
+
for (const [nestedIndex, row] of nested.entries()) rows.push({
|
|
202
|
+
kind: "nested",
|
|
203
|
+
ownerKey: child.key,
|
|
204
|
+
row: { ...row, depth: row.depth + 1 },
|
|
205
|
+
last: nestedIndex === nested.length - 1 && !laterRows,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
const nested = nestedFleetRows(entry.nestedChildren, attached.length > 0 ? 3 : 4);
|
|
135
209
|
for (const [index, row] of nested.entries()) rows.push({ kind: "nested", ownerKey: entry.key, row, last: index === nested.length - 1 });
|
|
136
210
|
}
|
|
137
211
|
return rows;
|
|
@@ -150,14 +224,24 @@ function foregroundDescription(control: { parentWorkflowRunId?: string; workflow
|
|
|
150
224
|
return description ? `${workflow} · ${description}` : workflow;
|
|
151
225
|
}
|
|
152
226
|
|
|
227
|
+
function activeLeafAgentCount(entries: FleetStatusEntry[]): number {
|
|
228
|
+
return entries.filter((entry) => !entry.workflowWrapper).length;
|
|
229
|
+
}
|
|
230
|
+
|
|
153
231
|
export function collectFleetStatusEntries(state: SubagentState): FleetStatusEntry[] {
|
|
154
232
|
const entries: FleetStatusEntry[] = [];
|
|
233
|
+
const activeWorkflowKeys = new Set([...state.asyncJobs.values()]
|
|
234
|
+
.filter((job) => job.mode === "workflow" && isActiveState(job.status))
|
|
235
|
+
.map((job) => `async:${job.asyncId}`));
|
|
155
236
|
for (const control of state.foregroundControls.values()) {
|
|
237
|
+
const parentKey = control.parentWorkflowRunId ? `async:${control.parentWorkflowRunId}` : undefined;
|
|
238
|
+
const linkedParentKey = parentKey && activeWorkflowKeys.has(parentKey) ? parentKey : undefined;
|
|
156
239
|
if (control.activeChildren) {
|
|
157
240
|
for (const child of [...control.activeChildren.values()].sort((left, right) => left.index - right.index)) {
|
|
158
241
|
const modelThinking = formatModelThinking(child.model, child.thinking) || undefined;
|
|
159
242
|
entries.push({
|
|
160
243
|
key: `foreground-active:${control.runId}:${child.index}`,
|
|
244
|
+
...(linkedParentKey ? { parentKey: linkedParentKey } : {}),
|
|
161
245
|
agent: child.agent,
|
|
162
246
|
...(modelThinking ? { modelThinking } : {}),
|
|
163
247
|
description: foregroundDescription(control, child.description),
|
|
@@ -174,6 +258,7 @@ export function collectFleetStatusEntries(state: SubagentState): FleetStatusEntr
|
|
|
174
258
|
const modelThinking = formatModelThinking(control.model, control.thinking) || undefined;
|
|
175
259
|
entries.push({
|
|
176
260
|
key: `foreground-active:${control.runId}:${control.currentIndex ?? 0}`,
|
|
261
|
+
...(linkedParentKey ? { parentKey: linkedParentKey } : {}),
|
|
177
262
|
agent: control.currentAgent ?? control.mode,
|
|
178
263
|
...(modelThinking ? { modelThinking } : {}),
|
|
179
264
|
description: foregroundDescription(control, control.description),
|
|
@@ -191,6 +276,7 @@ export function collectFleetStatusEntries(state: SubagentState): FleetStatusEntr
|
|
|
191
276
|
const latestEmit = job.workflow?.emits?.length ? formatWorkflowJsonPreview(job.workflow.emits.at(-1), 120) : undefined;
|
|
192
277
|
entries.push({
|
|
193
278
|
key: `async:${job.asyncId}`,
|
|
279
|
+
workflowWrapper: true,
|
|
194
280
|
agent: "workflow",
|
|
195
281
|
description: latestEmit !== undefined ? `latest emit: ${latestEmit}` : job.description,
|
|
196
282
|
startedAt,
|
|
@@ -241,6 +327,25 @@ export function collectFleetStatusEntries(state: SubagentState): FleetStatusEntr
|
|
|
241
327
|
}
|
|
242
328
|
}
|
|
243
329
|
|
|
330
|
+
if (state.currentSessionId) {
|
|
331
|
+
try {
|
|
332
|
+
for (const run of snapshotExternalRuns(state.currentSessionId, { ignoreMalformed: true, onMalformedRecord: (message) => console.warn(`[pi-subagents] Removed ${message}`) })) {
|
|
333
|
+
if (!isActiveState(run.state)) continue;
|
|
334
|
+
entries.push({
|
|
335
|
+
key: `external:${run.id}`,
|
|
336
|
+
agent: `external · ${run.label}`,
|
|
337
|
+
description: run.currentAction ?? `source: ${run.source}`,
|
|
338
|
+
startedAt: run.startedAt,
|
|
339
|
+
tokens: 0,
|
|
340
|
+
state: run.state,
|
|
341
|
+
external: true,
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
} catch (cause) {
|
|
345
|
+
console.warn(`[pi-subagents] Failed to inspect external jobs: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
244
349
|
return entries.sort((left, right) => left.startedAt - right.startedAt || left.key.localeCompare(right.key));
|
|
245
350
|
}
|
|
246
351
|
|
|
@@ -417,10 +522,15 @@ export class SubagentFleetStatus {
|
|
|
417
522
|
if (!this.active) {
|
|
418
523
|
const tokens = this.entries.reduce((total, entry) => total + entry.tokens, 0);
|
|
419
524
|
const capacity = this.state.activeAsyncCapacity;
|
|
420
|
-
const
|
|
421
|
-
const
|
|
525
|
+
const hasNativeRows = this.entries.some((entry) => !entry.external);
|
|
526
|
+
const showNativeSummary = hasNativeRows || Boolean(capacity?.used);
|
|
527
|
+
const asyncRuns = capacity && showNativeSummary ? `Async runs ${capacity.used}/${capacity.limit || "∞"}` : "";
|
|
528
|
+
const activeEntries = activeLeafAgentCount(this.entries);
|
|
529
|
+
const noun = this.entries.some((entry) => entry.external) ? "job" : "agent";
|
|
530
|
+
const agents = activeEntries > 0 ? `${activeEntries} active ${noun}${activeEntries === 1 ? "" : "s"}` : "";
|
|
422
531
|
const label = [agents, asyncRuns].filter(Boolean).join(" · ");
|
|
423
|
-
|
|
532
|
+
const detail = [showNativeSummary ? formatFleetTokens(tokens) : undefined, "↓/← to inspect"].filter(Boolean).join(" · ");
|
|
533
|
+
return [truncateToWidth(` ${theme.fg("muted", label)} · ${theme.fg("dim", detail)}`, width)];
|
|
424
534
|
}
|
|
425
535
|
const roster = this.rosterKeys();
|
|
426
536
|
const selectedIndex = Math.max(0, roster.indexOf(this.selectedKey));
|
|
@@ -428,16 +538,16 @@ export class SubagentFleetStatus {
|
|
|
428
538
|
lines.push(truncateToWidth(` ${this.bullet(0, selectedIndex, theme)} main`, width));
|
|
429
539
|
|
|
430
540
|
const tree = fleetTreeRows(this.entries);
|
|
431
|
-
const selectedTreeIndex = Math.max(0, tree.findIndex((row) => row.kind === "owner" && row.entry.key === this.selectedKey));
|
|
541
|
+
const selectedTreeIndex = Math.max(0, tree.findIndex((row) => (row.kind === "owner" || row.kind === "child") && row.entry.key === this.selectedKey));
|
|
432
542
|
const visibleCount = Math.min(this.maxAgentRows, tree.length);
|
|
433
543
|
const start = selectedTreeIndex < visibleCount ? 0 : selectedTreeIndex - visibleCount + 1;
|
|
434
544
|
const hiddenBelow = tree.length - (start + visibleCount);
|
|
435
545
|
if (start > 0) lines.push(rightAlign("", theme.fg("dim", `↑ ${start} more`), width));
|
|
436
546
|
for (let index = start; index < start + visibleCount; index++) {
|
|
437
547
|
const row = tree[index]!;
|
|
438
|
-
if (row.kind === "owner") {
|
|
548
|
+
if (row.kind === "owner" || row.kind === "child") {
|
|
439
549
|
const ownerIndex = this.entries.findIndex((entry) => entry.key === row.entry.key);
|
|
440
|
-
lines.push(this.renderEntry(ownerIndex + 1, selectedIndex, row.entry, width, theme));
|
|
550
|
+
lines.push(this.renderEntry(ownerIndex + 1, selectedIndex, row.entry, width, theme, row.kind === "child" ? (row.last ? "└─" : "├─") : undefined));
|
|
441
551
|
} else {
|
|
442
552
|
lines.push(this.renderNestedRow(row.row, row.last, width, theme));
|
|
443
553
|
}
|
|
@@ -446,20 +556,22 @@ export class SubagentFleetStatus {
|
|
|
446
556
|
return lines;
|
|
447
557
|
}
|
|
448
558
|
|
|
449
|
-
private renderEntry(rosterIndex: number, selectedIndex: number, entry: FleetStatusEntry, width: number, theme: Theme): string {
|
|
559
|
+
private renderEntry(rosterIndex: number, selectedIndex: number, entry: FleetStatusEntry, width: number, theme: Theme, branch?: string): string {
|
|
450
560
|
const agent = entry.modelThinking ? `${entry.agent} (${entry.modelThinking})` : entry.agent;
|
|
451
|
-
const
|
|
561
|
+
const prefix = branch ? ` ${branch}` : " ";
|
|
562
|
+
const left = `${prefix} ${this.bullet(rosterIndex, selectedIndex, theme)} ${theme.fg("muted", agent)} · ${entry.state}`;
|
|
452
563
|
const elapsed = Date.now() - entry.startedAt;
|
|
453
|
-
const right = theme.fg("dim", `${formatFleetElapsed(elapsed)} · ${formatFleetTokens(entry.tokens)}`);
|
|
564
|
+
const right = theme.fg("dim", entry.external ? formatFleetElapsed(elapsed) : `${formatFleetElapsed(elapsed)} · ${formatFleetTokens(entry.tokens)}`);
|
|
454
565
|
return rightAlign(left, right, width);
|
|
455
566
|
}
|
|
456
567
|
|
|
457
568
|
private renderNestedRow(row: FleetNestedRow, last: boolean, width: number, theme: Theme): string {
|
|
458
569
|
const marker = last ? "└─" : "├─";
|
|
459
|
-
|
|
570
|
+
const indent = " ".repeat(row.depth + 1);
|
|
571
|
+
if (row.overflow !== undefined) return truncateToWidth(`${indent}${marker} ${theme.fg("dim", `+${row.overflow} nested leaves`)}`, width);
|
|
460
572
|
const modelThinking = row.modelThinking ? ` (${row.modelThinking})` : "";
|
|
461
573
|
const activity = row.activity ? ` · ${row.activity}` : "";
|
|
462
|
-
const left =
|
|
574
|
+
const left = `${indent}${marker} ${nestedStatusGlyph(row.state, theme)} ${theme.fg("muted", `${row.name}${modelThinking}`)} · ${row.state}${activity}`;
|
|
463
575
|
const elapsed = row.startedAt !== undefined ? ` · ${formatFleetElapsed(Date.now() - row.startedAt)}` : "";
|
|
464
576
|
return truncateToWidth(`${left}${theme.fg("dim", elapsed)}`, width);
|
|
465
577
|
}
|
|
@@ -504,22 +616,25 @@ export class SubagentFleetStatus {
|
|
|
504
616
|
entries: this.entries.map((entry) => this.active
|
|
505
617
|
? [
|
|
506
618
|
entry.key,
|
|
619
|
+
entry.parentKey,
|
|
507
620
|
entry.agent,
|
|
508
621
|
entry.state,
|
|
509
622
|
entry.modelThinking,
|
|
510
623
|
entry.description,
|
|
624
|
+
entry.external,
|
|
511
625
|
Math.round((now - entry.startedAt) / 1000),
|
|
512
626
|
entry.tokens,
|
|
513
|
-
entry.nestedChildren
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
627
|
+
nestedFleetRows(entry.nestedChildren, entry.parentKey ? 3 : 4).map((row) => [
|
|
628
|
+
row.name,
|
|
629
|
+
row.state,
|
|
630
|
+
row.modelThinking,
|
|
631
|
+
row.activity,
|
|
632
|
+
row.startedAt,
|
|
633
|
+
row.depth,
|
|
634
|
+
row.overflow,
|
|
520
635
|
]),
|
|
521
636
|
]
|
|
522
|
-
: [entry.key, entry.state, entry.tokens]),
|
|
637
|
+
: [entry.key, entry.state, entry.external, entry.tokens]),
|
|
523
638
|
});
|
|
524
639
|
}
|
|
525
640
|
|