@selesai/code 0.8.5 → 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 +28 -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/models.json +5 -0
- package/dist/defaults/settings.json +1 -0
- package/dist/extensions/agent-browser.test.ts +178 -2
- package/dist/extensions/agent-browser.ts +2 -0
- package/dist/extensions/copy-turn.test.ts +229 -0
- package/dist/extensions/copy-turn.ts +11 -0
- package/dist/extensions/grep-app/index.test.ts +356 -1
- package/dist/extensions/grep-app/index.ts +6 -1
- package/dist/extensions/handoff-new.test.ts +351 -161
- package/dist/extensions/handoff-new.ts +3 -0
- package/dist/extensions/inline-skills.test.ts +93 -0
- package/dist/extensions/inline-skills.ts +3 -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/builder.md +5 -2
- package/dist/extensions/pi-subagents/agents/commentator.md +1 -1
- 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 -11
- 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 +4 -4
- 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 +16 -15
- 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 +59 -0
- package/dist/extensions/pi-subagents/src/extension/index.ts +146 -23
- 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 +17 -6
- 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 +11 -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/notify.ts +5 -2
- package/dist/extensions/pi-subagents/src/runs/background/result-files.ts +437 -0
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +224 -42
- 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 +35 -26
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +108 -9
- 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/background/wait-subscriptions.ts +2 -1
- 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/foreground-history.ts +7 -4
- package/dist/extensions/pi-subagents/src/runs/foreground/prompt-audit.ts +4 -3
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +368 -50
- 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/session-lineage.ts +71 -0
- package/dist/extensions/pi-subagents/src/shared/types.ts +66 -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 +129 -17
- 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/src/workflows/workflow-auto-relaunch.ts +28 -0
- 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/handoff-adoption.test.ts +103 -0
- 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 +91 -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/session-lineage.test.ts +73 -0
- 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-auto-relaunch.test.ts +45 -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/ponytail/index.js +11 -0
- package/dist/extensions/ponytail/ponytail-config.cjs +2 -0
- package/dist/extensions/ponytail/ponytail-instructions.cjs +6 -0
- package/dist/extensions/ponytail/test/extension.test.js +274 -140
- package/dist/extensions/ponytail/test/helpers.test.js +280 -92
- package/dist/extensions/question/index.ts +33 -0
- package/dist/extensions/question/question-list.ts +28 -0
- package/dist/extensions/question/row-layout.ts +3 -0
- package/dist/extensions/question/tests/batch.test.ts +103 -65
- 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 +75 -35
- package/dist/extensions/question/tests/question-list.test.ts +640 -198
- package/dist/extensions/question/tests/row-layout.test.ts +193 -114
- package/dist/extensions/question/tests/schemas.test.ts +42 -19
- package/dist/extensions/question/tests/selection-mode.test.ts +54 -0
- package/dist/extensions/question/tests/shortcuts.test.ts +106 -84
- package/dist/extensions/question/tests/wizard.test.ts +771 -50
- package/dist/extensions/question/tests/zz-ig3.test.ts +20 -0
- package/dist/extensions/question/tests/zz-probe.test.ts +29 -0
- package/dist/extensions/rtk.test.ts +180 -1
- package/dist/extensions/tokenin-onboarding.ts +3 -0
- package/dist/extensions/undo.test.ts +720 -0
- package/dist/extensions/undo.ts +6 -0
- package/dist/extensions/web-agent-onboarding.test.ts +415 -0
- package/dist/extensions/workflow/extension.ts +3 -3
- package/dist/extensions/workflow/modes.ts +41 -19
- 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 +16 -15
- 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/plans/workflow-autoloop-reference.md +1 -2
- package/docs/plans/workflow-handoff-carryover.md +108 -0
- package/docs/settings.md +6 -0
- package/package.json +4 -1
|
@@ -16,6 +16,7 @@ import { randomUUID } from "node:crypto";
|
|
|
16
16
|
import * as fs from "node:fs";
|
|
17
17
|
import * as os from "node:os";
|
|
18
18
|
import * as path from "node:path";
|
|
19
|
+
import { fileURLToPath } from "node:url";
|
|
19
20
|
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
20
21
|
import { keyText, type ExtensionAPI, type ExtensionContext, type ToolDefinition } from "@selesai/code";
|
|
21
22
|
import { Box, Container, Spacer, Text, truncateToWidth, visibleWidth, wrapTextWithAnsi, type Component } from "@earendil-works/pi-tui";
|
|
@@ -23,6 +24,7 @@ import { discoverAgents } from "../agents/agents.ts";
|
|
|
23
24
|
import { ensureAccessibleDir } from "../shared/accessible-dir.ts";
|
|
24
25
|
import { cleanupAllArtifactDirs, cleanupOldArtifacts, getArtifactsDir } from "../shared/artifacts.ts";
|
|
25
26
|
import { resolveCurrentSessionId } from "../shared/session-identity.ts";
|
|
27
|
+
import { resolveSessionLineage } from "../shared/session-lineage.ts";
|
|
26
28
|
import { cleanupOldChainDirs } from "../shared/settings.ts";
|
|
27
29
|
import { clearLegacyResultAnimationTimer, renderSubagentResult, renderSubagentSummary } from "../tui/render.ts";
|
|
28
30
|
import { openSubagentFleet } from "../tui/fleet.ts";
|
|
@@ -32,6 +34,7 @@ import { validateChainInput } from "./chain-validation.ts";
|
|
|
32
34
|
import { createSubagentExecutor, type SubagentParamsLike } from "../runs/foreground/subagent-executor.ts";
|
|
33
35
|
import { createAsyncJobTracker } from "../runs/background/async-job-tracker.ts";
|
|
34
36
|
import { getActiveAsyncCapacitySnapshot, resolveMaxActiveAsyncRunsPerSession } from "../runs/background/active-async-capacity.ts";
|
|
37
|
+
import { cleanupResultIndexes } from "../runs/background/result-files.ts";
|
|
35
38
|
import { createResultWatcher } from "../runs/background/result-watcher.ts";
|
|
36
39
|
import { createScheduledRunManager } from "../runs/background/scheduled-runs.ts";
|
|
37
40
|
import { registerSlashCommands } from "../slash/slash-commands.ts";
|
|
@@ -60,6 +63,7 @@ import { resolveMissionStoreLocation } from "../missions/store.ts";
|
|
|
60
63
|
import { listRetainedChildren } from "../runs/background/retained-children.ts";
|
|
61
64
|
import {
|
|
62
65
|
type Details,
|
|
66
|
+
type MainWindowRendererConfig,
|
|
63
67
|
type SubagentState,
|
|
64
68
|
DIRS,
|
|
65
69
|
DEFAULT_ARTIFACT_CONFIG,
|
|
@@ -82,6 +86,13 @@ import {
|
|
|
82
86
|
|
|
83
87
|
export { loadConfig, resolveAsyncByDefault } from "./config.ts";
|
|
84
88
|
|
|
89
|
+
const SLOW_RELOAD_PHASE_MS = 250;
|
|
90
|
+
|
|
91
|
+
function logSlowPhase(label: string, startedAt: number): void {
|
|
92
|
+
const elapsed = Date.now() - startedAt;
|
|
93
|
+
if (elapsed >= SLOW_RELOAD_PHASE_MS) console.error(`Subagent reload phase '${label}' took ${elapsed}ms.`);
|
|
94
|
+
}
|
|
95
|
+
|
|
85
96
|
function workflowLaneKeys(script: string): string[] {
|
|
86
97
|
const keys: string[] = [];
|
|
87
98
|
const seen = new Set<string>();
|
|
@@ -258,12 +269,14 @@ function rebuildSlashResultContainer(
|
|
|
258
269
|
result: AgentToolResult<Details>,
|
|
259
270
|
options: { expanded: boolean },
|
|
260
271
|
theme: ExtensionContext["ui"]["theme"],
|
|
272
|
+
rendererConfig?: MainWindowRendererConfig,
|
|
273
|
+
foregroundDetachShortcut?: string,
|
|
261
274
|
): void {
|
|
262
275
|
container.clear();
|
|
263
276
|
container.addChild(new Spacer(1));
|
|
264
277
|
const boxTheme = isSlashResultRunning(result) ? "toolPendingBg" : isSlashResultError(result) ? "toolErrorBg" : "toolSuccessBg";
|
|
265
278
|
const box = new Box(1, 1, (text: string) => theme.bg(boxTheme, text));
|
|
266
|
-
box.addChild(renderSubagentResult(result, options, theme));
|
|
279
|
+
box.addChild(renderSubagentResult(result, options, theme, undefined, rendererConfig, foregroundDetachShortcut));
|
|
267
280
|
container.addChild(box);
|
|
268
281
|
}
|
|
269
282
|
|
|
@@ -271,6 +284,8 @@ function createSlashResultComponent(
|
|
|
271
284
|
details: SlashMessageDetails,
|
|
272
285
|
options: { expanded: boolean },
|
|
273
286
|
theme: ExtensionContext["ui"]["theme"],
|
|
287
|
+
rendererConfig?: MainWindowRendererConfig,
|
|
288
|
+
foregroundDetachShortcut?: string,
|
|
274
289
|
): Container {
|
|
275
290
|
const container = new Container();
|
|
276
291
|
let lastVersion = -1;
|
|
@@ -278,7 +293,7 @@ function createSlashResultComponent(
|
|
|
278
293
|
const snapshot = getSlashRenderableSnapshot(details);
|
|
279
294
|
if (snapshot.version !== lastVersion || isSlashResultRunning(snapshot.result)) {
|
|
280
295
|
lastVersion = snapshot.version;
|
|
281
|
-
rebuildSlashResultContainer(container, snapshot.result, options, theme);
|
|
296
|
+
rebuildSlashResultContainer(container, snapshot.result, options, theme, rendererConfig, foregroundDetachShortcut);
|
|
282
297
|
}
|
|
283
298
|
return Container.prototype.render.call(container, width);
|
|
284
299
|
};
|
|
@@ -375,6 +390,20 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
375
390
|
const tempArtifactsDir = getArtifactsDir(null);
|
|
376
391
|
const artifactCleanupDays = config.artifactConfig?.cleanupDays ?? DEFAULT_ARTIFACT_CONFIG.cleanupDays;
|
|
377
392
|
cleanupAllArtifactDirs(artifactCleanupDays);
|
|
393
|
+
const resultIndexCleanupTimer = setTimeout(() => {
|
|
394
|
+
try {
|
|
395
|
+
cleanupResultIndexes(DIRS.results);
|
|
396
|
+
} catch (error) {
|
|
397
|
+
console.error("Failed to clean stale subagent result indexes:", error);
|
|
398
|
+
}
|
|
399
|
+
}, 30_000);
|
|
400
|
+
resultIndexCleanupTimer.unref?.();
|
|
401
|
+
|
|
402
|
+
// Replay guard for lineage result adoption: accept result files written at
|
|
403
|
+
// most this long before the adoption window opened (covers completions that
|
|
404
|
+
// raced the session switch). Older files were left behind by a dead watcher
|
|
405
|
+
// and are ignored until their owning session is resumed.
|
|
406
|
+
const ADOPTED_RESULT_SLACK_MS = 60_000;
|
|
378
407
|
|
|
379
408
|
const state: SubagentState = {
|
|
380
409
|
baseCwd: "",
|
|
@@ -383,6 +412,7 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
383
412
|
...(config.authorityPolicy ? { authorityPolicy: config.authorityPolicy } : {}),
|
|
384
413
|
...(config.missions ? { missionStoreConfig: config.missions } : {}),
|
|
385
414
|
parentSessionFile: null,
|
|
415
|
+
trustedSessionRoots: [],
|
|
386
416
|
subagentInProgress: false,
|
|
387
417
|
subagentSpawns: {
|
|
388
418
|
sessionId: null,
|
|
@@ -456,6 +486,7 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
456
486
|
);
|
|
457
487
|
|
|
458
488
|
const runtimeCleanup = () => {
|
|
489
|
+
clearTimeout(resultIndexCleanupTimer);
|
|
459
490
|
stopResultWatcher();
|
|
460
491
|
state.currentSessionId = null;
|
|
461
492
|
completionNotifier.dispose();
|
|
@@ -486,7 +517,7 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
486
517
|
pi.registerMessageRenderer<SlashMessageDetails>(SLASH_RESULT_TYPE, (message, options, theme) => {
|
|
487
518
|
const details = resolveSlashMessageDetails(message.details);
|
|
488
519
|
if (!details) return undefined;
|
|
489
|
-
return createSlashResultComponent(details, options, theme);
|
|
520
|
+
return createSlashResultComponent(details, options, theme, config.mainWindowRenderer, config.foregroundDetachShortcut);
|
|
490
521
|
});
|
|
491
522
|
|
|
492
523
|
pi.registerMessageRenderer<undefined>(SLASH_TEXT_RESULT_TYPE, (message, _options, _theme) => {
|
|
@@ -580,28 +611,31 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
580
611
|
label: "Subagent",
|
|
581
612
|
description: buildSubagentToolDescription(config),
|
|
582
613
|
parameters,
|
|
614
|
+
keepParameterDescriptions: true,
|
|
583
615
|
|
|
584
616
|
execute(id, params, signal, onUpdate, ctx) {
|
|
585
617
|
return executeSubagentCollapsed(id, params as SubagentParamsLike, signal ?? new AbortController().signal, onUpdate, ctx);
|
|
586
618
|
},
|
|
587
619
|
|
|
588
620
|
renderCall(args, theme) {
|
|
621
|
+
const gap = " ".repeat(config.mainWindowRenderer?.horizontalSpacing ?? 1);
|
|
622
|
+
const title = theme.fg("toolTitle", theme.bold("subagent"));
|
|
589
623
|
if (args.action) {
|
|
590
624
|
const target = args.agent || args.chainName || "";
|
|
591
625
|
return new Text(
|
|
592
|
-
`${
|
|
626
|
+
`${title}${gap}${args.action}${target ? `${gap}${theme.fg("accent", target)}` : ""}`,
|
|
593
627
|
0, 0,
|
|
594
628
|
);
|
|
595
629
|
}
|
|
596
630
|
if (args.workflowScript)
|
|
597
631
|
return new Text(
|
|
598
|
-
`${
|
|
632
|
+
`${title}${gap}${formatWorkflowManifest(args.workflowScript, args.async, false)}`,
|
|
599
633
|
0,
|
|
600
634
|
0,
|
|
601
635
|
);
|
|
602
|
-
const asyncLabel = args.async === true ? theme.fg("warning", "
|
|
636
|
+
const asyncLabel = args.async === true ? `${gap}${theme.fg("warning", "[async]")}` : "";
|
|
603
637
|
return new Text(
|
|
604
|
-
`${
|
|
638
|
+
`${title}${gap}${theme.fg("accent", args.agent || "?")}${asyncLabel}`,
|
|
605
639
|
0,
|
|
606
640
|
0,
|
|
607
641
|
);
|
|
@@ -612,7 +646,7 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
612
646
|
const renderedResult = { ...result, isError: context.isError };
|
|
613
647
|
return summaryInlineToolDisplay
|
|
614
648
|
? renderSubagentSummary(renderedResult, options, theme)
|
|
615
|
-
: renderSubagentResult(renderedResult, options, theme);
|
|
649
|
+
: renderSubagentResult(renderedResult, options, theme, undefined, config.mainWindowRenderer, config.foregroundDetachShortcut);
|
|
616
650
|
},
|
|
617
651
|
|
|
618
652
|
};
|
|
@@ -630,26 +664,41 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
630
664
|
|
|
631
665
|
pi.on("agent_end", async (_event, ctx) => {
|
|
632
666
|
if (!ctx.hasUI) await drainOutstandingWork({ state, events: pi.events });
|
|
633
|
-
const
|
|
634
|
-
|
|
667
|
+
const ownerSessionIds = state.sessionLineage?.length
|
|
668
|
+
? state.sessionLineage
|
|
669
|
+
: state.currentSessionId ? [state.currentSessionId] : [];
|
|
670
|
+
if (ownerSessionIds.length === 0) return;
|
|
635
671
|
goalTurnId += 1;
|
|
636
672
|
try {
|
|
637
673
|
const location = resolveMissionStoreLocation({ projectRoot: state.baseCwd, ...(config.missions ? { config: config.missions } : {}) });
|
|
638
|
-
const retainedChildren = listRetainedChildren(DIRS.async,
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
674
|
+
const retainedChildren = listRetainedChildren(DIRS.async, ownerSessionIds);
|
|
675
|
+
const emittedMissions = new Set<string>();
|
|
676
|
+
for (const ownerSessionId of ownerSessionIds) {
|
|
677
|
+
for (const notice of collectGoalContinuationNotices({ location, ownerSessionId, retainedChildren, turnId: goalTurnId })) {
|
|
678
|
+
if (emittedMissions.has(notice.missionId)) continue;
|
|
679
|
+
emittedMissions.add(notice.missionId);
|
|
680
|
+
handleSubagentControlNotice({
|
|
681
|
+
pi,
|
|
682
|
+
state,
|
|
683
|
+
visibleControlNotices: new Set(),
|
|
684
|
+
details: { source: "goal", event: notice.event, noticeText: notice.message },
|
|
685
|
+
});
|
|
686
|
+
}
|
|
646
687
|
}
|
|
647
688
|
} catch (error) {
|
|
648
689
|
console.error("Failed to evaluate goal missions:", error);
|
|
649
690
|
}
|
|
650
691
|
});
|
|
651
692
|
|
|
652
|
-
registerSlashCommands(pi, state, {
|
|
693
|
+
registerSlashCommands(pi, state, {
|
|
694
|
+
fleetKeybindings: config.fleetKeybindings,
|
|
695
|
+
foregroundDetachShortcut: config.foregroundDetachShortcut,
|
|
696
|
+
});
|
|
697
|
+
pi.on("resources_discover", () => {
|
|
698
|
+
return {
|
|
699
|
+
promptPaths: [fileURLToPath(new URL("../../prompts", import.meta.url))],
|
|
700
|
+
};
|
|
701
|
+
});
|
|
653
702
|
|
|
654
703
|
const eventUnsubscribeStoreKey = "__piSubagentEventUnsubscribes";
|
|
655
704
|
const controlNoticeSeenStoreKey = "__piSubagentVisibleControlNotices";
|
|
@@ -758,14 +807,51 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
758
807
|
resolveMaxActiveAsyncRunsPerSession(config.maxActiveAsyncRunsPerSession),
|
|
759
808
|
{ liveWorkflowRunIds: new Set(state.workflowControllers?.keys() ?? []) },
|
|
760
809
|
);
|
|
810
|
+
const adoptedActive = [...state.asyncJobs.values()].filter((job) => job.adopted && (job.status === "queued" || job.status === "running")).length;
|
|
811
|
+
if (adoptedActive > 0) {
|
|
812
|
+
state.activeAsyncCapacity = {
|
|
813
|
+
...state.activeAsyncCapacity,
|
|
814
|
+
used: state.activeAsyncCapacity.used + adoptedActive,
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
|
|
819
|
+
const formatActiveWorkflowSummary = (target: SubagentState, intro: string): string => {
|
|
820
|
+
const active = [...target.asyncJobs.values()]
|
|
821
|
+
.filter((job) => job.status === "queued" || job.status === "running")
|
|
822
|
+
.sort((left, right) => (left.startedAt ?? 0) - (right.startedAt ?? 0));
|
|
823
|
+
const lines = active.map((job) => {
|
|
824
|
+
const label = job.mode === "workflow"
|
|
825
|
+
? `workflow[${job.workflowKey ?? "script"}]`
|
|
826
|
+
: `${job.mode ?? "run"}${job.agents?.length ? ` ${job.agents.join(", ")}` : ""}`;
|
|
827
|
+
const step = job.currentStep !== undefined
|
|
828
|
+
? ` · step ${job.currentStep + 1}/${job.chainStepCount ?? job.stepsTotal ?? "?"}`
|
|
829
|
+
: "";
|
|
830
|
+
const activity = job.currentTool ? ` · last: ${job.currentTool}` : "";
|
|
831
|
+
const adopted = job.adopted ? " (carried over from a previous session)" : "";
|
|
832
|
+
return `- ${job.asyncId} ${label}${step}${activity}${adopted}`;
|
|
833
|
+
});
|
|
834
|
+
return [
|
|
835
|
+
intro,
|
|
836
|
+
...lines,
|
|
837
|
+
"Monitor with subagent status <id>; interrupt/resume/steer by run id; children.list lists completed steps. Results arrive automatically.",
|
|
838
|
+
].join("\n");
|
|
761
839
|
};
|
|
762
840
|
|
|
763
|
-
const resetSessionState = (ctx: ExtensionContext, recovering: boolean) => {
|
|
841
|
+
const resetSessionState = (ctx: ExtensionContext, recovering: boolean, previousSessionFile?: string | null) => {
|
|
842
|
+
state.sessionLineage = resolveSessionLineage({ sessionManager: ctx.sessionManager }, { parentHint: previousSessionFile ?? null });
|
|
843
|
+
state.handoffResumePending = false;
|
|
844
|
+
if (state.sessionLineage.length > 1) state.adoptedResultWindowStart = Date.now() - ADOPTED_RESULT_SLACK_MS;
|
|
845
|
+
else state.adoptedResultWindowStart = undefined;
|
|
764
846
|
state.widgetsSuspended = false;
|
|
765
847
|
state.baseCwd = ctx.cwd;
|
|
766
848
|
goalTurnId = 0;
|
|
767
849
|
state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
768
850
|
state.parentSessionFile = ctx.sessionManager.getSessionFile();
|
|
851
|
+
state.trustedSessionRoots = [...new Set([
|
|
852
|
+
...(config.defaultSessionDir ? [path.resolve(expandTilde(config.defaultSessionDir))] : []),
|
|
853
|
+
...(state.parentSessionFile ? [getSubagentSessionRoot(state.parentSessionFile)] : []),
|
|
854
|
+
])];
|
|
769
855
|
state.subagentSpawns = {
|
|
770
856
|
sessionId: state.currentSessionId,
|
|
771
857
|
count: 0,
|
|
@@ -785,18 +871,39 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
785
871
|
}
|
|
786
872
|
}
|
|
787
873
|
state.lastUiContext = ctx;
|
|
874
|
+
let phaseStartedAt = Date.now();
|
|
788
875
|
refreshActiveAsyncCapacity();
|
|
876
|
+
logSlowPhase("active-capacity", phaseStartedAt);
|
|
877
|
+
phaseStartedAt = Date.now();
|
|
789
878
|
cleanupSessionArtifacts(ctx);
|
|
879
|
+
logSlowPhase("session-artifact-cleanup", phaseStartedAt);
|
|
790
880
|
state.foregroundControls.clear();
|
|
791
881
|
state.lastForegroundControlId = null;
|
|
882
|
+
phaseStartedAt = Date.now();
|
|
792
883
|
resetJobs(ctx);
|
|
884
|
+
logSlowPhase("reset-jobs", phaseStartedAt);
|
|
885
|
+
phaseStartedAt = Date.now();
|
|
793
886
|
restoreForegroundRunHistory(state, { resultsDir: DIRS.results });
|
|
794
|
-
|
|
887
|
+
logSlowPhase("foreground-history", phaseStartedAt);
|
|
888
|
+
phaseStartedAt = Date.now();
|
|
889
|
+
const adoptedJobs = restoreActiveJobs(ctx);
|
|
890
|
+
logSlowPhase("active-job-restore", phaseStartedAt);
|
|
891
|
+
state.handoffResumePending = adoptedJobs > 0 && state.lastUiContext?.hasUI === true;
|
|
892
|
+
phaseStartedAt = Date.now();
|
|
795
893
|
scheduledRunManager.bindSession(ctx);
|
|
894
|
+
logSlowPhase("scheduled-runs", phaseStartedAt);
|
|
895
|
+
phaseStartedAt = Date.now();
|
|
796
896
|
restoreSlashFinalSnapshots(ctx.sessionManager.getEntries());
|
|
897
|
+
logSlowPhase("slash-snapshots", phaseStartedAt);
|
|
898
|
+
phaseStartedAt = Date.now();
|
|
797
899
|
waitSubscriptionManager.restore();
|
|
900
|
+
logSlowPhase("wait-subscriptions", phaseStartedAt);
|
|
901
|
+
phaseStartedAt = Date.now();
|
|
798
902
|
startResultWatcher();
|
|
903
|
+
logSlowPhase("result-watcher-start", phaseStartedAt);
|
|
904
|
+
phaseStartedAt = Date.now();
|
|
799
905
|
primeExistingResults({ triggerTurn: !recovering });
|
|
906
|
+
logSlowPhase("result-prime", phaseStartedAt);
|
|
800
907
|
fleetStatus?.setContext(ctx);
|
|
801
908
|
};
|
|
802
909
|
|
|
@@ -807,6 +914,17 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
807
914
|
|
|
808
915
|
pi.on("agent_settled", () => {
|
|
809
916
|
resumeWidgetsAfterCompaction();
|
|
917
|
+
if (state.handoffResumePending && state.lastUiContext?.hasUI === true) {
|
|
918
|
+
state.handoffResumePending = false;
|
|
919
|
+
pi.sendMessage(
|
|
920
|
+
{
|
|
921
|
+
customType: "subagent-handoff-resume",
|
|
922
|
+
content: formatActiveWorkflowSummary(state, "Session handoff detected. The previous session's background workflows were carried over:"),
|
|
923
|
+
display: false,
|
|
924
|
+
},
|
|
925
|
+
{ triggerTurn: true },
|
|
926
|
+
);
|
|
927
|
+
}
|
|
810
928
|
});
|
|
811
929
|
|
|
812
930
|
pi.on("session_before_compact", (event) => {
|
|
@@ -819,7 +937,7 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
819
937
|
pi.sendMessage(
|
|
820
938
|
{
|
|
821
939
|
customType: "subagent-compaction-resume",
|
|
822
|
-
content: "Compaction is complete. Resume the parent task now;
|
|
940
|
+
content: formatActiveWorkflowSummary(state, "Compaction is complete. Resume the parent task now; results for the runs below arrive separately when ready:"),
|
|
823
941
|
display: false,
|
|
824
942
|
},
|
|
825
943
|
{ triggerTurn: true },
|
|
@@ -828,7 +946,8 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
828
946
|
|
|
829
947
|
pi.on("session_start", (event, ctx) => {
|
|
830
948
|
const recovering = event.reason === "startup" || event.reason === "reload" || event.reason === "resume";
|
|
831
|
-
|
|
949
|
+
const previousSessionFile = event.reason === "new" || event.reason === "fork" ? event.previousSessionFile : null;
|
|
950
|
+
resetSessionState(ctx, recovering, previousSessionFile);
|
|
832
951
|
herdrStatusBridge.sessionStarted({
|
|
833
952
|
hasUI: ctx.hasUI === true,
|
|
834
953
|
runs: activeHerdrRuns(),
|
|
@@ -839,9 +958,13 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
839
958
|
|
|
840
959
|
pi.on("session_shutdown", async () => {
|
|
841
960
|
state.widgetsSuspended = false;
|
|
961
|
+
clearTimeout(resultIndexCleanupTimer);
|
|
842
962
|
stopResultWatcher();
|
|
843
963
|
state.currentSessionId = null;
|
|
844
964
|
state.parentSessionFile = null;
|
|
965
|
+
state.sessionLineage = undefined;
|
|
966
|
+
state.adoptedResultWindowStart = undefined;
|
|
967
|
+
state.handoffResumePending = false;
|
|
845
968
|
completionNotifier.dispose();
|
|
846
969
|
delete process.env[SUBAGENT_PARENT_SESSION_ENV];
|
|
847
970
|
for (const unsubscribe of eventUnsubscribes) {
|
|
@@ -9,6 +9,7 @@ export interface PublicSubagentExecutionParams {
|
|
|
9
9
|
concurrency?: unknown;
|
|
10
10
|
chainDir?: unknown;
|
|
11
11
|
workflowScript?: unknown;
|
|
12
|
+
output?: unknown;
|
|
12
13
|
resume?: unknown;
|
|
13
14
|
clarify?: unknown;
|
|
14
15
|
runFanoutBudget?: unknown;
|
|
@@ -33,7 +34,7 @@ export function normalizePublicSubagentExecution<T extends PublicSubagentExecuti
|
|
|
33
34
|
}
|
|
34
35
|
const action = params.action;
|
|
35
36
|
if (action !== undefined && (typeof action !== "string" || !action.trim())) {
|
|
36
|
-
return { ok: false, error: "action must be a non-empty management/control action, or omit action and
|
|
37
|
+
return { ok: false, error: "action must be a non-empty management/control action, or omit action and use workflowScript.", mode: "management" };
|
|
37
38
|
}
|
|
38
39
|
const normalizedAction = typeof action === "string" ? action.trim() : undefined;
|
|
39
40
|
if (params.clarify === true && params.workflowScript !== undefined) {
|
|
@@ -59,10 +60,16 @@ export function normalizePublicSubagentExecution<T extends PublicSubagentExecuti
|
|
|
59
60
|
if (params.workflowScript !== undefined) {
|
|
60
61
|
return { ok: false, error: "workflowScript execution must omit action; only schedule.create accepts action with workflowScript.", mode: "management" };
|
|
61
62
|
}
|
|
63
|
+
if (params.task !== undefined) {
|
|
64
|
+
return { ok: false, error: "Structured single-child task cannot be combined with a management/control action.", mode: "management" };
|
|
65
|
+
}
|
|
62
66
|
return { ok: true, params: { ...params, action: normalizedAction } };
|
|
63
67
|
}
|
|
64
|
-
if (
|
|
65
|
-
return { ok:
|
|
68
|
+
if (params.step !== undefined) {
|
|
69
|
+
return { ok: false, error: "step is only available with action='append-step'; it is not an execution mode.", mode: "workflow" };
|
|
70
|
+
}
|
|
71
|
+
if (params.workflowScript !== undefined && (params.agent !== undefined || params.task !== undefined)) {
|
|
72
|
+
return { ok: false, error: "Structured single-child execution cannot be combined with workflowScript.", mode: "workflow" };
|
|
66
73
|
}
|
|
67
74
|
if (params.chain !== undefined) {
|
|
68
75
|
return { ok: true, params };
|
|
@@ -70,8 +77,29 @@ export function normalizePublicSubagentExecution<T extends PublicSubagentExecuti
|
|
|
70
77
|
if (params.tasks !== undefined) {
|
|
71
78
|
return { ok: true, params };
|
|
72
79
|
}
|
|
73
|
-
if (params.agent !== undefined || params.task !== undefined
|
|
74
|
-
|
|
80
|
+
if (params.agent !== undefined || params.task !== undefined) {
|
|
81
|
+
if (typeof params.agent !== "string" || !params.agent.trim()) {
|
|
82
|
+
return { ok: false, error: "Structured single-child execution requires agent to be a non-empty string.", mode: "workflow" };
|
|
83
|
+
}
|
|
84
|
+
if (params.task !== undefined && typeof params.task !== "string") {
|
|
85
|
+
return { ok: false, error: "Structured single-child task must be a string when provided.", mode: "workflow" };
|
|
86
|
+
}
|
|
87
|
+
const { agent: _agent, task: _task, output, ...workflowDefaults } = params;
|
|
88
|
+
const child = {
|
|
89
|
+
agent: params.agent.trim(),
|
|
90
|
+
...(params.task !== undefined ? { task: params.task } : {}),
|
|
91
|
+
output: output === undefined ? true : output,
|
|
92
|
+
};
|
|
93
|
+
return {
|
|
94
|
+
ok: true,
|
|
95
|
+
params: {
|
|
96
|
+
...workflowDefaults,
|
|
97
|
+
workflowScript: `console.info("Converted structured single-child request to workflow runs.run('main', ...)."); return runs.run("main", ${JSON.stringify(child)})`,
|
|
98
|
+
} as T,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (typeof params.workflowScript !== "string" || !params.workflowScript.trim()) {
|
|
102
|
+
return { ok: false, error: "Execution requires one mode: { agent, task? }, { chain: [...] }, { tasks: [...] }, or { workflowScript }.", mode: "workflow" };
|
|
75
103
|
}
|
|
76
|
-
return { ok:
|
|
104
|
+
return { ok: true, params };
|
|
77
105
|
}
|
|
@@ -21,6 +21,7 @@ import { sanitizeDisplayText, truncateDisplayText } from "../shared/display-text
|
|
|
21
21
|
import { readStatus } from "../shared/utils.ts";
|
|
22
22
|
import { SubagentParams } from "./schemas.ts";
|
|
23
23
|
import { normalizePublicSubagentExecution } from "./public-execution.ts";
|
|
24
|
+
import { ASYNC_STATUS_SNAPSHOT_KIND, ASYNC_STATUS_SNAPSHOT_VERSION, buildAsyncStatusSnapshotForState } from "../runs/background/async-status-snapshot.ts";
|
|
24
25
|
|
|
25
26
|
export const SUBAGENT_RPC_PROTOCOL_VERSION = 1;
|
|
26
27
|
export const SUBAGENT_RPC_REQUEST_EVENT = "subagents:rpc:v1:request";
|
|
@@ -381,6 +382,7 @@ function pingData(ctx: ExtensionContext | null) {
|
|
|
381
382
|
capabilities: {
|
|
382
383
|
status: true,
|
|
383
384
|
fleetStatus: { version: 1 },
|
|
385
|
+
asyncStatusSnapshot: { kind: ASYNC_STATUS_SNAPSHOT_KIND, version: ASYNC_STATUS_SNAPSHOT_VERSION },
|
|
384
386
|
asyncSpawn: true,
|
|
385
387
|
steer: true,
|
|
386
388
|
nonRecoveringSteer: true,
|
|
@@ -550,13 +552,15 @@ async function handleRequest(
|
|
|
550
552
|
request.method,
|
|
551
553
|
{ action: "status", ...normalizeTargetParams(request.params, "status") },
|
|
552
554
|
);
|
|
555
|
+
const sessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
553
556
|
return {
|
|
554
557
|
...status,
|
|
555
558
|
fleet: buildFleetStatus(
|
|
556
559
|
options.state,
|
|
557
560
|
fleetKeys,
|
|
558
|
-
|
|
561
|
+
sessionId,
|
|
559
562
|
),
|
|
563
|
+
asyncSnapshot: buildAsyncStatusSnapshotForState(options.state, sessionId),
|
|
560
564
|
};
|
|
561
565
|
}
|
|
562
566
|
if (request.method === "steer") {
|
|
@@ -89,11 +89,11 @@ const AcceptanceOverride = Type.Unsafe({
|
|
|
89
89
|
{ type: "boolean", enum: [false] },
|
|
90
90
|
{ type: "object", additionalProperties: true },
|
|
91
91
|
],
|
|
92
|
-
description: `Optional acceptance policy.
|
|
92
|
+
description: `Optional acceptance policy. Omit for read-only calls. Example: { level: "checked", evidence: ["commands-run", "changed-files"] }. Supported evidence kinds: ${AcceptanceEvidenceKinds.join(", ")}. Evidence levels end at verified; use acceptance.review.required for review.`,
|
|
93
93
|
});
|
|
94
94
|
|
|
95
95
|
const AgentContractOverride = Type.Object({
|
|
96
|
-
version: Type.Integer({
|
|
96
|
+
version: Type.Integer({ minimum: 1, maximum: 1, description: "Enable compatibility behavior for this run/child." }),
|
|
97
97
|
}, { additionalProperties: false, description: "Compatibility behavior. Omit for the default behavior." });
|
|
98
98
|
|
|
99
99
|
const ChainGateOverride = Type.String({
|
|
@@ -255,49 +255,49 @@ const ControlOverrides = Type.Object({
|
|
|
255
255
|
});
|
|
256
256
|
|
|
257
257
|
const SubagentParamProperties = {
|
|
258
|
-
agent: Type.Optional(Type.String({ description: "Agent
|
|
259
|
-
task: Type.Optional(Type.String({ description: "
|
|
258
|
+
agent: Type.Optional(Type.String({ description: "Agent for one-child execution, or target for agent management actions." })),
|
|
259
|
+
task: Type.Optional(Type.String({ description: "Optional one-child task. Requires agent; cannot combine with action or workflowScript." })),
|
|
260
260
|
resume: Type.Optional(Type.String({ description: "Retained child run id for a workflowScript runs.run/runs.all item. Mutually exclusive with agent; task supplies the follow-up." })),
|
|
261
261
|
// Management action (when present, tool operates in management mode)
|
|
262
262
|
action: Type.Optional(Type.String({ minLength: 1,
|
|
263
|
-
description: "Optional management/control action. Omit this field for workflowScript execution; use it only for management/control actions."
|
|
263
|
+
description: "Optional management/control action. Omit this field for structured single-child or workflowScript execution; use it only for management/control actions."
|
|
264
264
|
})),
|
|
265
265
|
name: Type.Optional(Type.String({ description: "Human-readable name for action='schedule.create'." })),
|
|
266
266
|
id: Type.Optional(Type.String({
|
|
267
|
-
description: "Run id
|
|
267
|
+
description: "Run id/prefix for status/debug.run, interrupt, steer, append-step, approve-checkpoint, reject-checkpoint, or mission."
|
|
268
268
|
})),
|
|
269
269
|
runId: Type.Optional(Type.String({
|
|
270
|
-
description: "Target run ID for
|
|
270
|
+
description: "Target run ID for debug.run, interrupt, steer, append-step, or mission.attach-run. Prefer id."
|
|
271
271
|
})),
|
|
272
272
|
dir: Type.Optional(Type.String({
|
|
273
|
-
description: "Async run directory for
|
|
273
|
+
description: "Async run directory for status/debug.run, stop, resume, or steer."
|
|
274
274
|
})),
|
|
275
275
|
handoffPath: Type.Optional(Type.String({ description: "worktree.discard manifest." })),
|
|
276
276
|
index: Type.Optional(Type.Integer({ minimum: 0, description: "Zero-based child index for actions that target a specific child or transcript." })),
|
|
277
277
|
view: Type.Optional(Type.String({
|
|
278
278
|
enum: ["fleet", "transcript"],
|
|
279
|
-
description: "Optional status view
|
|
279
|
+
description: "Optional status view: 'fleet' for a read-only fleet surface, or 'transcript' with id/dir (and optional index) to tail a run transcript.",
|
|
280
280
|
})),
|
|
281
281
|
lines: Type.Optional(Type.Integer({ minimum: 1, maximum: 500, description: "Maximum transcript lines for action='status', view='transcript'. Defaults to 80." })),
|
|
282
282
|
topic: Type.Optional(Type.String()),
|
|
283
283
|
message: Type.Optional(Type.String({ description: "Follow-up message for resume, live guidance for steer, or optional startup prompt for project.open." })),
|
|
284
|
-
mode: Type.Optional(Type.String({ enum: ["steer", "follow_up", "auto"], description: "Delivery mode for action='steer'
|
|
285
|
-
steeringRecovery: Type.Optional(Type.Boolean({ description: "For action='steer', allow pause-and-revive recovery after a missed acknowledgment. Defaults true for direct tool calls
|
|
286
|
-
additional: Type.Optional(Type.Integer({ minimum: 1, description: "Positive launches to add with action='grant-spawn-budget'. Root interactive parent with native user confirmation only
|
|
287
|
-
scope: Type.Optional(Type.String({ enum: ["session", "user", "project"], description: "Scope for action='watchdog.configure'. Defaults to session
|
|
284
|
+
mode: Type.Optional(Type.String({ enum: ["steer", "follow_up", "auto"], description: "Delivery mode for action='steer': steer interrupts at the next safe point (default), follow_up waits for the next turn boundary, auto follows up mid-turn." })),
|
|
285
|
+
steeringRecovery: Type.Optional(Type.Boolean({ description: "For action='steer', allow pause-and-revive recovery after a missed acknowledgment. Defaults true for direct tool calls; false for extension RPC steering." })),
|
|
286
|
+
additional: Type.Optional(Type.Integer({ minimum: 1, description: "Positive launches to add with action='grant-spawn-budget'. Root interactive parent with native user confirmation only." })),
|
|
287
|
+
scope: Type.Optional(Type.String({ enum: ["session", "user", "project"], description: "Scope for action='watchdog.configure'. Defaults to session." })),
|
|
288
288
|
target: Type.Optional(Type.String({ enum: ["main", "children", "child"], description: "Target for watchdog actions." })),
|
|
289
289
|
focus: Type.Optional(Type.Boolean({ description: "Focus the new Herdr pane for inspector.open or project.open." })),
|
|
290
290
|
thinking: Type.Optional(Type.Unsafe({ anyOf: [{ type: "string" }, { type: "boolean", enum: [false] }], description: "Thinking level for action='watchdog.configure' (off/minimal/low/medium/high/xhigh/max, inherit, or false for off)." })),
|
|
291
|
-
schedule: Type.Optional(Type.String({ deprecated: true, description: "
|
|
292
|
-
scheduleName: Type.Optional(Type.String({ deprecated: true, description: "
|
|
291
|
+
schedule: Type.Optional(Type.String({ deprecated: true, description: "Deprecated. Use action='schedule.create' with at." })),
|
|
292
|
+
scheduleName: Type.Optional(Type.String({ deprecated: true, description: "Deprecated. Use name." })),
|
|
293
293
|
at: Type.Optional(Type.String({ description: "One-shot trigger for action='schedule.create': a relative delay such as '+10m' or an ISO timestamp with timezone." })),
|
|
294
294
|
every: Type.Optional(Type.String({ description: "Fixed recurring interval for action='schedule.create', such as '30m', '6h', '2d', or '2w'." })),
|
|
295
|
-
on: Type.Optional(Type.Unsafe({ anyOf: [{ type: "string" }, { type: "integer" }], description: "
|
|
296
|
-
timezone: Type.Optional(Type.String({ description: "
|
|
295
|
+
on: Type.Optional(Type.Unsafe({ anyOf: [{ type: "string" }, { type: "integer" }], description: "Reserved for a later calendar schedule slice." })),
|
|
296
|
+
timezone: Type.Optional(Type.String({ description: "Reserved for a later calendar schedule slice." })),
|
|
297
297
|
overlap: Type.Optional(Type.String({ enum: ["skip"], description: "Overlap policy. This slice supports skip only." })),
|
|
298
298
|
catchUp: Type.Optional(Type.String({ enum: ["none", "latest"], description: "Missed occurrence policy for recurring schedules. Defaults to latest." })),
|
|
299
299
|
missionId: Type.Optional(Type.String({ description: "Mission id." })),
|
|
300
|
-
mission: Type.Optional(Type.Unsafe({ ...MissionLaunchOverride, description: "Mission object, or false for no mission.
|
|
300
|
+
mission: Type.Optional(Type.Unsafe({ ...MissionLaunchOverride, description: "Mission object, or false for no mission. Requires exactly one non-empty title or summary; goal may only be true and then requires budget.tokens." })),
|
|
301
301
|
missionUpdate: Type.Optional(Type.Unsafe({ ...MissionUpdateOverride, description: "Mission update: objective, goal false or {paused:boolean}, budget, summary, labels, decisions, artifacts, or delivery receipts." })),
|
|
302
302
|
missionStatus: Type.Optional(Type.String({ description: "Mission status." })),
|
|
303
303
|
missionScope: Type.Optional(Type.String({ description: "Mission list scope: project (default) or global pointer index." })),
|
|
@@ -316,10 +316,10 @@ const SubagentParamProperties = {
|
|
|
316
316
|
],
|
|
317
317
|
description: "Agent/chain config for create/update. Object or JSON string; presence of steps creates a chain."
|
|
318
318
|
})),
|
|
319
|
-
workflowScript: Type.Optional(Type.String({ minLength: 1, description: "Trusted inline JavaScript statement body
|
|
319
|
+
workflowScript: Type.Optional(Type.String({ minLength: 1, description: "Trusted inline JavaScript statement body; use explicit return for output. Available: runs.run(key, {agent, task, ...}) and runs.run(key, {resume, task}), runs.all([...]), runs.status(id), runs.ref(s), await prompts.render(ref, vars?), emit, console; mission workflows also have async state.get/set. Scripts start async by default. Set worktree:true at workflow or child level for a separate managed worktree; child fields override workflow defaults. Compose sequential and parallel phases dynamically. No filesystem, shell, Pi tools, or host globals." })),
|
|
320
320
|
chain: Type.Optional(Type.Unsafe({
|
|
321
321
|
anyOf: [Type.Array(ChainItem, { minItems: 1, description: "Sequential chain of steps" })],
|
|
322
|
-
description: "Sequential chain of steps. Steps support template variables {task}, {previous}, {chain_dir}, and {outputs.name}; use as: \"name\" on a step to bind {outputs.name} for later steps
|
|
322
|
+
description: "Sequential chain of steps. Steps support template variables {task}, {previous}, {chain_dir}, and {outputs.name}; use as: \"name\" on a step to bind {outputs.name} for later steps; { checkpoint: \"name\", message?: \"...\" } pauses for approve-checkpoint / reject-checkpoint; gateOn: \"acceptance\" advances on acceptance instead of execution.",
|
|
323
323
|
})),
|
|
324
324
|
tasks: Type.Optional(Type.Unsafe({
|
|
325
325
|
anyOf: [
|
|
@@ -328,27 +328,28 @@ const SubagentParamProperties = {
|
|
|
328
328
|
],
|
|
329
329
|
description: "Top-level parallel tasks array, or a single dynamic fanout child template when expand/collect are present.",
|
|
330
330
|
})),
|
|
331
|
-
chatProgress: Type.Optional(Type.String({ enum: ["auto", "off", "terminal", "milestones", "live-card"], description: "WorkflowScript chat progress projection
|
|
332
|
-
worktree: Type.Optional(Type.Boolean({ description: "Managed child isolation. true gives each workflow child a separate git worktree;
|
|
331
|
+
chatProgress: Type.Optional(Type.String({ enum: ["auto", "off", "terminal", "milestones", "live-card"], description: "WorkflowScript chat progress projection: auto shows a live in-chat card for watched foreground workflows in the same Git repository, milestones for background runs, terminal otherwise." })),
|
|
332
|
+
worktree: Type.Optional(Type.Boolean({ description: "Managed child isolation. true gives each workflow child a separate git worktree; individual runs.run/runs.all items can override with worktree:false." })),
|
|
333
333
|
step: Type.Optional(Type.Unsafe({ ...ChainItem, description: "One chain step for action='append-step' only. Not an execution mode." })),
|
|
334
334
|
context: Type.Optional(Type.String({
|
|
335
335
|
enum: ["fresh", "fork"],
|
|
336
|
-
description: "'fresh' or 'fork' to branch from parent session. Explicit context overrides every child in the invocation. If omitted, each requested agent uses its own defaultContext; agents without
|
|
336
|
+
description: "'fresh' or 'fork' to branch from parent session. Explicit context overrides every child in the invocation. If omitted, each requested agent uses its own defaultContext; agents without one run 'fork' fresh.",
|
|
337
337
|
})),
|
|
338
338
|
async: Type.Optional(Type.Boolean({ description: "Run in background (default: false, or per config)" })),
|
|
339
|
-
clarify: Type.Optional(Type.Boolean({ description: "Show TUI to preview/edit before execution
|
|
340
|
-
timeoutMs: Type.Optional(Type.Integer({ minimum: 1, description: "Timeout.
|
|
341
|
-
maxRuntimeMs: Type.Optional(Type.Integer({ minimum: 1, description: "Alias
|
|
339
|
+
clarify: Type.Optional(Type.Boolean({ description: "Show TUI to preview/edit before execution; explicit true keeps the run foreground." })),
|
|
340
|
+
timeoutMs: Type.Optional(Type.Integer({ minimum: 1, description: "Timeout. Defaults to config timeoutMs or 30m for foreground/single async runs. Alias maxRuntimeMs." })),
|
|
341
|
+
maxRuntimeMs: Type.Optional(Type.Integer({ minimum: 1, description: "Alias of timeoutMs." })),
|
|
342
|
+
toolTimeoutMs: Type.Optional(Type.Integer({ minimum: 1, description: "Optional hard per-tool-call timeout in milliseconds." })),
|
|
342
343
|
turnBudget: Type.Optional(TurnBudgetOverride),
|
|
343
344
|
toolBudget: Type.Optional(ToolBudgetOverride),
|
|
344
345
|
usageBudget: Type.Optional(UsageBudgetOverride),
|
|
345
|
-
agentScope: Type.Optional(Type.String({ description: "Agent discovery scope: 'user', 'project', or 'both' (default
|
|
346
|
+
agentScope: Type.Optional(Type.String({ description: "Agent discovery scope: 'user', 'project', or 'both' (default 'both')." })),
|
|
346
347
|
cwd: Type.Optional(Type.String({ description: "Execution cwd, or target project directory for project.open/status/close." })),
|
|
347
348
|
artifacts: Type.Optional(Type.Boolean({ description: "Write debug artifacts (default: true)" })),
|
|
348
349
|
includeProgress: Type.Optional(Type.Boolean({ description: "Include full progress in result (default: false)" })),
|
|
349
350
|
share: Type.Optional(Type.Boolean({ description: "Upload session to GitHub Gist for sharing (default: false)" })),
|
|
350
351
|
sessionDir: Type.Optional(
|
|
351
|
-
Type.String({ description: "Directory to store session logs (default: temp
|
|
352
|
+
Type.String({ description: "Directory to store session logs (default: temp)." }),
|
|
352
353
|
),
|
|
353
354
|
control: Type.Optional(ControlOverrides),
|
|
354
355
|
// Workflow defaults forwarded to each runs.run/runs.all child unless overridden there.
|
|
@@ -372,10 +373,10 @@ const { step: _legacyChainStep, ...subagentParamPropertiesWithoutStep } = Subage
|
|
|
372
373
|
const trimmedSubagentParamProperties = {
|
|
373
374
|
...subagentParamPropertiesWithoutStep,
|
|
374
375
|
id: Type.Optional(Type.String({
|
|
375
|
-
description: "Run id
|
|
376
|
+
description: "Run id/prefix for status/debug.run, interrupt, steer, or mission.attach-run."
|
|
376
377
|
})),
|
|
377
378
|
runId: Type.Optional(Type.String({
|
|
378
|
-
description: "Target run ID for
|
|
379
|
+
description: "Target run ID for debug.run, interrupt, steer, or mission.attach-run. Prefer id."
|
|
379
380
|
})),
|
|
380
381
|
};
|
|
381
382
|
const SubagentParamsSchema = Type.Object(SubagentParamProperties);
|