@selesai/code 0.5.19 → 0.5.21
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/dist/extensions/handoff-new.test.ts +8 -9
- package/dist/extensions/handoff-new.ts +6 -8
- package/dist/extensions/pi-intercom/broker/spawn.test.ts +31 -0
- package/dist/extensions/pi-intercom/broker/spawn.ts +5 -3
- package/dist/extensions/pi-subagents/CHANGELOG.md +1367 -0
- package/dist/extensions/pi-subagents/README.md +602 -220
- package/dist/extensions/pi-subagents/banner.png +0 -0
- package/dist/extensions/pi-subagents/index.ts +1 -0
- package/dist/extensions/pi-subagents/install.mjs +3 -3
- package/dist/extensions/pi-subagents/package-lock.json +3405 -0
- package/dist/extensions/pi-subagents/package.json +26 -14
- package/dist/extensions/pi-subagents/prompts/gather-context-and-clarify.md +1 -1
- package/dist/extensions/pi-subagents/prompts/parallel-cleanup.md +9 -9
- package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +3 -3
- package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +7 -7
- package/dist/extensions/pi-subagents/prompts/parallel-research.md +6 -6
- package/dist/extensions/pi-subagents/prompts/parallel-review.md +8 -8
- package/dist/extensions/pi-subagents/prompts/review-loop.md +13 -11
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +267 -176
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +89 -16
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +19 -0
- package/dist/extensions/pi-subagents/src/agents/agents.ts +218 -120
- package/dist/extensions/pi-subagents/src/agents/frontmatter.ts +67 -13
- package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +2 -2
- package/dist/extensions/pi-subagents/src/agents/skills.ts +25 -12
- package/dist/extensions/pi-subagents/src/api/background-work.ts +197 -0
- package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +17 -0
- package/dist/extensions/pi-subagents/src/api/delegation.ts +285 -0
- package/dist/extensions/pi-subagents/src/api/preflight.ts +399 -0
- package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +165 -0
- package/dist/extensions/pi-subagents/src/extension/config.ts +7 -1
- package/dist/extensions/pi-subagents/src/extension/doctor.ts +15 -0
- package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +3 -1
- package/dist/extensions/pi-subagents/src/extension/index.ts +113 -157
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +41 -4
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +45 -15
- package/dist/extensions/pi-subagents/src/extension/steering-notices.ts +35 -0
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -15
- package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +4 -3
- package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +225 -29
- package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +11 -0
- package/dist/extensions/pi-subagents/src/profiles/profiles.ts +8 -10
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +452 -62
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +60 -9
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +198 -52
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +119 -21
- package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +67 -0
- package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +2 -0
- package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +16 -8
- package/dist/extensions/pi-subagents/src/runs/background/completion-batcher.ts +6 -4
- package/dist/extensions/pi-subagents/src/runs/background/completion-dedupe.ts +2 -11
- package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +260 -13
- package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +32 -6
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +171 -90
- package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +280 -0
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +149 -88
- package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +14 -2
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +33 -17
- package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +9 -1
- package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +38 -10
- package/dist/extensions/pi-subagents/src/runs/background/steering.ts +237 -0
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +1297 -307
- package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +610 -0
- package/dist/extensions/pi-subagents/src/runs/background/top-level-async.ts +2 -1
- package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +36 -0
- package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +26 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +230 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +22 -6
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +228 -140
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +452 -138
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +90 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1001 -416
- package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +443 -132
- package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +38 -0
- package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +178 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +121 -0
- package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +41 -93
- package/dist/extensions/pi-subagents/src/runs/shared/context-mode.ts +44 -0
- package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +11 -9
- package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +4 -0
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +12 -6
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +36 -0
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +44 -7
- package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +4 -1
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +154 -0
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +18 -0
- package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +174 -54
- package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +38 -31
- package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +90 -5
- package/dist/extensions/pi-subagents/src/runs/shared/session-lease.ts +299 -0
- package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +61 -6
- package/dist/extensions/pi-subagents/src/runs/shared/spawn-budget.ts +128 -0
- package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +112 -7
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +14 -6
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +149 -36
- package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +181 -0
- package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +83 -0
- package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +11 -5
- package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +50 -4
- package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +63 -14
- package/dist/extensions/pi-subagents/src/shared/accessible-dir.ts +25 -0
- package/dist/extensions/pi-subagents/src/shared/artifacts.ts +37 -7
- package/dist/extensions/pi-subagents/src/shared/atomic-json.ts +18 -43
- package/dist/extensions/pi-subagents/src/shared/child-transcript.ts +52 -0
- package/dist/extensions/pi-subagents/src/shared/env.ts +16 -0
- package/dist/extensions/pi-subagents/src/shared/file-system-retry.ts +47 -0
- package/dist/extensions/pi-subagents/src/shared/fork-context.ts +28 -3
- package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +123 -0
- package/dist/extensions/pi-subagents/src/shared/model-info.ts +8 -5
- package/dist/extensions/pi-subagents/src/shared/settings.ts +9 -1
- package/dist/extensions/pi-subagents/src/shared/status-format.ts +7 -1
- package/dist/extensions/pi-subagents/src/shared/types.ts +522 -51
- package/dist/extensions/pi-subagents/src/shared/utils.ts +59 -53
- package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +604 -0
- package/dist/extensions/pi-subagents/src/slash/delegation-json.ts +108 -0
- package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +249 -0
- package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +353 -345
- package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +2 -2
- package/dist/extensions/pi-subagents/src/slash/selector.ts +147 -0
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +265 -23
- package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +2 -2
- package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +428 -0
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +362 -0
- package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +472 -0
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +664 -0
- package/dist/extensions/pi-subagents/src/tui/render.ts +115 -31
- package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +220 -0
- package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +205 -0
- package/dist/extensions/pi-subagents/src/watchdog/emission-guard.ts +123 -0
- package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +532 -0
- package/dist/extensions/pi-subagents/src/watchdog/model-selection.ts +167 -0
- package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +117 -0
- package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +433 -0
- package/dist/extensions/pi-subagents/src/watchdog/render.ts +54 -0
- package/dist/extensions/pi-subagents/src/watchdog/review.ts +298 -0
- package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +714 -0
- package/dist/extensions/pi-subagents/src/watchdog/settings.ts +528 -0
- package/dist/extensions/pi-subagents/src/watchdog/tool-actions.ts +155 -0
- package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +161 -0
- package/dist/extensions/pi-subagents/src/watchdog/types.ts +188 -0
- package/dist/extensions/pi-subagents/src/watchdog/warning-format.ts +73 -0
- package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +130 -2
- package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +439 -0
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1632 -61
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +54 -1
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +112 -0
- package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +98 -1
- package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +179 -9
- package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +16 -9
- package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +6 -5
- package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +589 -9
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +528 -21
- package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +227 -3
- package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +235 -7
- package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +172 -2
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1502 -18
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +993 -4
- package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +7 -1
- package/dist/extensions/pi-subagents/test/support/helpers.ts +32 -0
- package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +59 -2
- package/dist/extensions/pi-subagents/test/support/mock-pi.ts +32 -6
- package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +25 -24
- package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +59 -35
- package/dist/extensions/pi-subagents/test/support/session-lease-child.mjs +42 -0
- package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +703 -69
- package/dist/extensions/pi-subagents/test/unit/accessible-dir.test.ts +82 -0
- package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +15 -15
- package/dist/extensions/pi-subagents/test/unit/agent-eject-disable.test.ts +66 -66
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +478 -19
- package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +228 -7
- package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +198 -78
- package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +15 -1
- package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +102 -7
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +439 -6
- package/dist/extensions/pi-subagents/test/unit/atomic-json.test.ts +41 -1
- package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +79 -0
- package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +285 -0
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +84 -0
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +68 -0
- package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +326 -0
- package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +82 -0
- package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +46 -4
- package/dist/extensions/pi-subagents/test/unit/completion-batcher.test.ts +3 -1
- package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +9 -17
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +175 -3
- package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +10 -5
- package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +126 -6
- package/dist/extensions/pi-subagents/test/unit/default-extensions.test.ts +219 -0
- package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +913 -0
- package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +13 -2
- package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +3 -3
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +351 -0
- package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +280 -0
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +575 -0
- package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +65 -0
- package/dist/extensions/pi-subagents/test/unit/fork-context.test.ts +94 -1
- package/dist/extensions/pi-subagents/test/unit/get-final-output.test.ts +23 -0
- package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +157 -0
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +367 -5
- package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +11 -0
- package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +36 -0
- package/dist/extensions/pi-subagents/test/unit/model-info.test.ts +25 -3
- package/dist/extensions/pi-subagents/test/unit/model-scope.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +341 -10
- package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +16 -0
- package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +52 -0
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +168 -7
- package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +85 -7
- package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +175 -0
- package/dist/extensions/pi-subagents/test/unit/path-resolution.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +243 -16
- package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +79 -36
- package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +174 -56
- package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +322 -0
- package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +204 -0
- package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +20 -12
- package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +117 -4
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +40 -7
- package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +48 -1
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +21 -3
- package/dist/extensions/pi-subagents/test/unit/selector.test.ts +57 -0
- package/dist/extensions/pi-subagents/test/unit/session-lease.test.ts +326 -0
- package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +101 -2
- package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +111 -1
- package/dist/extensions/pi-subagents/test/unit/spawn-budget.test.ts +124 -0
- package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +6 -4
- package/dist/extensions/pi-subagents/test/unit/status-format.test.ts +7 -0
- package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +397 -0
- package/dist/extensions/pi-subagents/test/unit/steering-notices.test.ts +58 -0
- package/dist/extensions/pi-subagents/test/unit/steering.test.ts +173 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +25 -4
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +390 -25
- package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +837 -0
- package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +86 -0
- package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +15 -0
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +47 -1
- package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +56 -10
- package/dist/extensions/pi-subagents/test/unit/watchdog-change-signature.test.ts +387 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +110 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-emission-guard.test.ts +62 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-lsp-diagnostics.test.ts +144 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-model-selection.test.ts +121 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-render.test.ts +76 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-review.test.ts +327 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +863 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +290 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +91 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-turn-delta.test.ts +130 -0
- package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +32 -4
- package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +5 -1
- package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +30 -0
- package/dist/extensions/question/batch.ts +39 -0
- package/dist/extensions/question/dialog-adapter.ts +23 -1
- package/dist/extensions/question/index.ts +237 -7
- package/dist/extensions/question/schemas.ts +28 -15
- package/dist/extensions/question/tests/batch.test.ts +26 -0
- package/dist/extensions/question/tests/ui-protocol.test.ts +23 -3
- package/dist/extensions/question/tui-adapter.ts +2 -3
- package/dist/extensions/question/types.ts +37 -0
- package/dist/extensions/question/ui-protocol.ts +3 -3
- package/dist/skills/batch-grill-me/SKILL.md +3 -1
- package/package.json +2 -1
|
@@ -69,14 +69,16 @@ interface MetadataCache {
|
|
|
69
69
|
servers: Record<string, ServerCacheEntry>;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
export
|
|
72
|
+
export interface ResolvedMcpDirectToolSelection { name: string; selector: string }
|
|
73
|
+
|
|
74
|
+
export function resolveMcpDirectToolSelections(mcpDirectTools: string[] | undefined, cwd = process.cwd()): ResolvedMcpDirectToolSelection[] {
|
|
73
75
|
if (!mcpDirectTools?.length) return [];
|
|
74
76
|
|
|
75
77
|
try {
|
|
76
78
|
const config = loadMcpConfig(cwd);
|
|
77
79
|
const cache = loadMetadataCache();
|
|
78
80
|
if (!cache) return [];
|
|
79
|
-
return
|
|
81
|
+
return resolveDirectToolSelections(config, cache, getToolPrefix(config.settings?.toolPrefix), mcpDirectTools);
|
|
80
82
|
} catch {
|
|
81
83
|
return [];
|
|
82
84
|
}
|
|
@@ -195,8 +197,8 @@ function extractServers(config: unknown, kind: ImportKind): Record<string, Serve
|
|
|
195
197
|
return servers && typeof servers === "object" && !Array.isArray(servers) ? servers as Record<string, ServerEntry> : {};
|
|
196
198
|
}
|
|
197
199
|
|
|
198
|
-
function
|
|
199
|
-
const names:
|
|
200
|
+
function resolveDirectToolSelections(config: McpConfig, cache: MetadataCache, prefix: ToolPrefix, envOverride: string[]): ResolvedMcpDirectToolSelection[] {
|
|
201
|
+
const names: ResolvedMcpDirectToolSelection[] = [];
|
|
200
202
|
const seenNames = new Set<string>();
|
|
201
203
|
const { servers: selectedServers, tools: selectedTools } = parseSelections(envOverride);
|
|
202
204
|
|
|
@@ -216,7 +218,7 @@ function resolveDirectToolNames(config: McpConfig, cache: MetadataCache, prefix:
|
|
|
216
218
|
const prefixedName = formatToolName(tool.name, serverName, prefix);
|
|
217
219
|
if (BUILTIN_TOOL_NAMES.has(prefixedName) || seenNames.has(prefixedName)) continue;
|
|
218
220
|
seenNames.add(prefixedName);
|
|
219
|
-
names.push(prefixedName);
|
|
221
|
+
names.push({ name: prefixedName, selector: `${serverName}/${tool.name}` });
|
|
220
222
|
}
|
|
221
223
|
|
|
222
224
|
if (definition.exposeResources === false) continue;
|
|
@@ -228,13 +230,17 @@ function resolveDirectToolNames(config: McpConfig, cache: MetadataCache, prefix:
|
|
|
228
230
|
const prefixedName = formatToolName(baseName, serverName, prefix);
|
|
229
231
|
if (BUILTIN_TOOL_NAMES.has(prefixedName) || seenNames.has(prefixedName)) continue;
|
|
230
232
|
seenNames.add(prefixedName);
|
|
231
|
-
names.push(prefixedName);
|
|
233
|
+
names.push({ name: prefixedName, selector: `${serverName}/${baseName}` });
|
|
232
234
|
}
|
|
233
235
|
}
|
|
234
236
|
|
|
235
237
|
return names;
|
|
236
238
|
}
|
|
237
239
|
|
|
240
|
+
export function resolveMcpDirectToolNames(mcpDirectTools: string[] | undefined, cwd = process.cwd()): string[] {
|
|
241
|
+
return resolveMcpDirectToolSelections(mcpDirectTools, cwd).map((selection) => selection.name);
|
|
242
|
+
}
|
|
243
|
+
|
|
238
244
|
function parseSelections(selections: string[]): { servers: Set<string>; tools: Map<string, Set<string>> } {
|
|
239
245
|
const servers = new Set<string>();
|
|
240
246
|
const tools = new Map<string, Set<string>>();
|
|
@@ -211,6 +211,31 @@ export function resolveSubagentModelOverride(
|
|
|
211
211
|
return resolved;
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
+
export function resolveEffectiveSubagentModel(
|
|
215
|
+
explicitModel: string | boolean | undefined,
|
|
216
|
+
agentModel: string | boolean | undefined,
|
|
217
|
+
parentModel: ParentModel | undefined,
|
|
218
|
+
availableModels: AvailableModelInfo[] | undefined,
|
|
219
|
+
preferredProvider?: string,
|
|
220
|
+
options?: Omit<ResolveSubagentModelOverrideOptions, "source">,
|
|
221
|
+
): string | undefined {
|
|
222
|
+
const resolved = resolveSubagentModelOverride(
|
|
223
|
+
explicitModel ?? agentModel,
|
|
224
|
+
parentModel,
|
|
225
|
+
availableModels,
|
|
226
|
+
preferredProvider,
|
|
227
|
+
{ ...options, source: explicitModel !== undefined ? "explicit" : "inherited" },
|
|
228
|
+
);
|
|
229
|
+
if (resolved || explicitModel === undefined) return resolved;
|
|
230
|
+
return resolveSubagentModelOverride(
|
|
231
|
+
agentModel,
|
|
232
|
+
parentModel,
|
|
233
|
+
availableModels,
|
|
234
|
+
preferredProvider,
|
|
235
|
+
{ ...options, source: "inherited" },
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
214
239
|
export interface BuildModelCandidatesOptions {
|
|
215
240
|
/** Fallback models are inherited agent config and warn, rather than error, when out of scope. */
|
|
216
241
|
scope?: ModelScopeConfig;
|
|
@@ -267,6 +292,7 @@ const RETRYABLE_MODEL_FAILURE_PATTERNS = [
|
|
|
267
292
|
/fetch failed/i,
|
|
268
293
|
/network error/i,
|
|
269
294
|
/socket hang up/i,
|
|
295
|
+
/stream ended without finish_reason/i,
|
|
270
296
|
/upstream/i,
|
|
271
297
|
/timed? out/i,
|
|
272
298
|
/timeout/i,
|
|
@@ -279,8 +305,18 @@ const RETRYABLE_MODEL_FAILURE_PATTERNS = [
|
|
|
279
305
|
/model.*(?:load|fail|error)/i,
|
|
280
306
|
];
|
|
281
307
|
|
|
308
|
+
/**
|
|
309
|
+
* Failures reported as `<tool> failed (exit N): ...` or `<tool> failed with
|
|
310
|
+
* exit code N` come from a tool call inside the child's task, not from the
|
|
311
|
+
* provider/model, however network-flavored their details read. Retrying a
|
|
312
|
+
* different model cannot fix them and would rerun the whole task. Tool names
|
|
313
|
+
* include namespaced forms like `mcp.server/write`.
|
|
314
|
+
*/
|
|
315
|
+
const TOOL_FAILURE_PREFIX = /^[\w.:@/-]+ failed (?:(?:\(exit \d+\):)|(?:with exit code \d+))(?:\s|$)/i;
|
|
316
|
+
|
|
282
317
|
export function isRetryableModelFailure(error: string | undefined): boolean {
|
|
283
318
|
if (!error) return false;
|
|
319
|
+
if (TOOL_FAILURE_PREFIX.test(error.trim())) return false;
|
|
284
320
|
return RETRYABLE_MODEL_FAILURE_PATTERNS.some((pattern) => pattern.test(error));
|
|
285
321
|
}
|
|
286
322
|
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
SUBAGENT_PARENT_RUN_ID_ENV,
|
|
28
28
|
} from "./pi-args.ts";
|
|
29
29
|
import { writeAtomicJson } from "../../shared/atomic-json.ts";
|
|
30
|
+
import { sanitizeProcessTerminal } from "../background/process-terminal.ts";
|
|
30
31
|
|
|
31
32
|
export const NESTED_EVENTS_DIR = path.join(TEMP_ROOT_DIR, "nested-subagent-events");
|
|
32
33
|
const ROUTE_FILE = "route.json";
|
|
@@ -202,7 +203,7 @@ function sanitizeTurnBudget(value: unknown): TurnBudgetState | undefined {
|
|
|
202
203
|
const maxTurns = clampNumber(raw.maxTurns);
|
|
203
204
|
const graceTurns = clampNumber(raw.graceTurns);
|
|
204
205
|
const turnCount = clampNumber(raw.turnCount);
|
|
205
|
-
const outcome = raw.outcome === "within-budget" || raw.outcome === "wrap-up-requested" || raw.outcome === "exceeded" ? raw.outcome : undefined;
|
|
206
|
+
const outcome = raw.outcome === "within-budget" || raw.outcome === "wrap-up-requested" || raw.outcome === "termination-deferred" || raw.outcome === "exceeded" ? raw.outcome : undefined;
|
|
206
207
|
if (maxTurns === undefined || graceTurns === undefined || turnCount === undefined || !outcome) return undefined;
|
|
207
208
|
return {
|
|
208
209
|
maxTurns,
|
|
@@ -210,12 +211,13 @@ function sanitizeTurnBudget(value: unknown): TurnBudgetState | undefined {
|
|
|
210
211
|
turnCount,
|
|
211
212
|
outcome,
|
|
212
213
|
...(clampNumber(raw.wrapUpRequestedAtTurn) !== undefined ? { wrapUpRequestedAtTurn: clampNumber(raw.wrapUpRequestedAtTurn) } : {}),
|
|
214
|
+
...(clampNumber(raw.terminationDeferredAtTurn) !== undefined ? { terminationDeferredAtTurn: clampNumber(raw.terminationDeferredAtTurn) } : {}),
|
|
213
215
|
...(clampNumber(raw.exceededAtTurn) !== undefined ? { exceededAtTurn: clampNumber(raw.exceededAtTurn) } : {}),
|
|
214
216
|
};
|
|
215
217
|
}
|
|
216
218
|
|
|
217
219
|
function sanitizeState(value: unknown, fallback: NestedRunState): NestedRunState {
|
|
218
|
-
return value === "queued" || value === "running" || value === "complete" || value === "failed" || value === "paused"
|
|
220
|
+
return value === "queued" || value === "running" || value === "complete" || value === "failed" || value === "paused" || value === "stopped"
|
|
219
221
|
? value
|
|
220
222
|
: fallback;
|
|
221
223
|
}
|
|
@@ -225,7 +227,7 @@ function sanitizeStep(input: unknown, depth: number): NestedStepSummary | undefi
|
|
|
225
227
|
const raw = input as Record<string, unknown>;
|
|
226
228
|
const agent = stringValue(raw.agent, 128);
|
|
227
229
|
if (!agent) return undefined;
|
|
228
|
-
const status = raw.status === "pending" || raw.status === "running" || raw.status === "complete" || raw.status === "completed" || raw.status === "failed" || raw.status === "paused"
|
|
230
|
+
const status = raw.status === "pending" || raw.status === "running" || raw.status === "complete" || raw.status === "completed" || raw.status === "failed" || raw.status === "paused" || raw.status === "stopped"
|
|
229
231
|
? raw.status
|
|
230
232
|
: "pending";
|
|
231
233
|
return {
|
|
@@ -243,6 +245,7 @@ function sanitizeStep(input: unknown, depth: number): NestedStepSummary | undefi
|
|
|
243
245
|
...(clampNumber(raw.endedAt) !== undefined ? { endedAt: clampNumber(raw.endedAt) } : {}),
|
|
244
246
|
...(stringValue(raw.error, 1024) ? { error: stringValue(raw.error, 1024) } : {}),
|
|
245
247
|
...(raw.timedOut === true ? { timedOut: true } : {}),
|
|
248
|
+
...(raw.stopped === true ? { stopped: true } : {}),
|
|
246
249
|
...(sanitizeTurnBudget(raw.turnBudget) ? { turnBudget: sanitizeTurnBudget(raw.turnBudget) } : {}),
|
|
247
250
|
...(raw.turnBudgetExceeded === true ? { turnBudgetExceeded: true } : {}),
|
|
248
251
|
...(raw.wrapUpRequested === true ? { wrapUpRequested: true } : {}),
|
|
@@ -298,6 +301,7 @@ export function sanitizeSummary(input: unknown, depth = 0): NestedRunSummary | u
|
|
|
298
301
|
...(clampNumber(raw.timeoutMs) !== undefined ? { timeoutMs: clampNumber(raw.timeoutMs) } : {}),
|
|
299
302
|
...(clampNumber(raw.deadlineAt) !== undefined ? { deadlineAt: clampNumber(raw.deadlineAt) } : {}),
|
|
300
303
|
...(raw.timedOut === true ? { timedOut: true } : {}),
|
|
304
|
+
...(raw.stopped === true ? { stopped: true } : {}),
|
|
301
305
|
...(sanitizeTurnBudget(raw.turnBudget) ? { turnBudget: sanitizeTurnBudget(raw.turnBudget) } : {}),
|
|
302
306
|
...(raw.turnBudgetExceeded === true ? { turnBudgetExceeded: true } : {}),
|
|
303
307
|
...(raw.wrapUpRequested === true ? { wrapUpRequested: true } : {}),
|
|
@@ -353,7 +357,7 @@ export function parseNestedEventRecords(content: string, route: NestedRoute): Ne
|
|
|
353
357
|
}
|
|
354
358
|
|
|
355
359
|
function terminal(state: NestedRunState): boolean {
|
|
356
|
-
return state === "complete" || state === "failed" || state === "paused";
|
|
360
|
+
return state === "complete" || state === "failed" || state === "paused" || state === "stopped";
|
|
357
361
|
}
|
|
358
362
|
|
|
359
363
|
function mergeSummary(existing: NestedRunSummary | undefined, event: NestedEventRecord): NestedRunSummary {
|
|
@@ -609,7 +613,9 @@ export function projectNestedEvents(route: NestedRoute): NestedRegistry {
|
|
|
609
613
|
} catch {
|
|
610
614
|
continue;
|
|
611
615
|
}
|
|
612
|
-
|
|
616
|
+
const records = parseNestedEventRecords(content, route);
|
|
617
|
+
if (records.length === 0) continue;
|
|
618
|
+
for (const event of records) {
|
|
613
619
|
registry = applyNestedEvent(registry, event);
|
|
614
620
|
changed = true;
|
|
615
621
|
}
|
|
@@ -617,11 +623,34 @@ export function projectNestedEvents(route: NestedRoute): NestedRegistry {
|
|
|
617
623
|
changed = true;
|
|
618
624
|
}
|
|
619
625
|
if (changed) {
|
|
620
|
-
|
|
626
|
+
const processedEvents = [...seen];
|
|
627
|
+
const retainedEvents = processedEvents.slice(-1000);
|
|
628
|
+
const evictedEvents = processedEvents.slice(0, -1000);
|
|
629
|
+
registry = { ...registry, processedEvents: retainedEvents };
|
|
621
630
|
// Parent projection is the only writer to this sidecar registry. Child and
|
|
622
631
|
// runner processes only create immutable event files, so parent status.json
|
|
623
632
|
// remains owned by the existing runner writer and is never rewritten here.
|
|
624
633
|
writeAtomicJson(registryPath(route), registry);
|
|
634
|
+
|
|
635
|
+
// The registry retains only a bounded filename cursor. Remove the old
|
|
636
|
+
// immutable status records after the cursor is durable; otherwise an evicted
|
|
637
|
+
// filename is rediscovered on the next projection and replayed forever.
|
|
638
|
+
for (const entry of evictedEvents) {
|
|
639
|
+
const eventPath = path.join(route.eventSink, entry);
|
|
640
|
+
if (!containedPath(route.eventSink, eventPath)) continue;
|
|
641
|
+
try {
|
|
642
|
+
const stat = fs.statSync(eventPath);
|
|
643
|
+
if (!stat.isFile() || stat.size > MAX_EVENT_BYTES) continue;
|
|
644
|
+
const content = fs.readFileSync(eventPath, "utf-8");
|
|
645
|
+
const hasStatusRecord = parseNestedEventRecords(content, route).length > 0;
|
|
646
|
+
const hasControlResult = content
|
|
647
|
+
.split("\n")
|
|
648
|
+
.some((line) => line.trim() && parseControlResult(line.trim(), route));
|
|
649
|
+
if (hasStatusRecord && !hasControlResult) fs.unlinkSync(eventPath);
|
|
650
|
+
} catch {
|
|
651
|
+
// A cleanup failure must not make a successfully projected status fail.
|
|
652
|
+
}
|
|
653
|
+
}
|
|
625
654
|
}
|
|
626
655
|
return registry;
|
|
627
656
|
}
|
|
@@ -845,6 +874,9 @@ export function nestedSummaryFromAsyncStatus(status: AsyncStatus, asyncDir: stri
|
|
|
845
874
|
...(status.pid ? { pid: status.pid } : {}),
|
|
846
875
|
...(status.sessionId ? { sessionId: status.sessionId } : {}),
|
|
847
876
|
mode: status.mode ?? fallback.mode,
|
|
877
|
+
...(status.processTerminal ? { processTerminal: sanitizeProcessTerminal(status.processTerminal, { runId: status.runId || fallback.id, runnerProcessInstanceId: status.processTerminal.runnerProcessInstanceId }, `${asyncDir}/status.json`) } : {}),
|
|
878
|
+
...(status.capabilityCeiling ? { capabilityCeiling: status.capabilityCeiling } : {}),
|
|
879
|
+
...(status.capabilityAudit ? { capabilityAudit: status.capabilityAudit } : {}),
|
|
848
880
|
state: status.state,
|
|
849
881
|
...(status.currentStep !== undefined ? { currentStep: status.currentStep } : {}),
|
|
850
882
|
...(status.chainStepCount !== undefined ? { chainStepCount: status.chainStepCount } : {}),
|
|
@@ -859,6 +891,7 @@ export function nestedSummaryFromAsyncStatus(status: AsyncStatus, asyncDir: stri
|
|
|
859
891
|
...(status.timeoutMs !== undefined ? { timeoutMs: status.timeoutMs } : {}),
|
|
860
892
|
...(status.deadlineAt !== undefined ? { deadlineAt: status.deadlineAt } : {}),
|
|
861
893
|
...(status.timedOut !== undefined ? { timedOut: status.timedOut } : {}),
|
|
894
|
+
...(status.stopped !== undefined ? { stopped: status.stopped } : {}),
|
|
862
895
|
...(status.turnBudget ? { turnBudget: status.turnBudget } : {}),
|
|
863
896
|
...(status.turnBudgetExceeded !== undefined ? { turnBudgetExceeded: status.turnBudgetExceeded } : {}),
|
|
864
897
|
...(status.wrapUpRequested !== undefined ? { wrapUpRequested: status.wrapUpRequested } : {}),
|
|
@@ -867,7 +900,7 @@ export function nestedSummaryFromAsyncStatus(status: AsyncStatus, asyncDir: stri
|
|
|
867
900
|
...(status.endedAt !== undefined ? { endedAt: status.endedAt } : {}),
|
|
868
901
|
lastUpdate: status.lastUpdate ?? fallback.ts,
|
|
869
902
|
...(status.sessionFile ? { sessionFile: status.sessionFile } : {}),
|
|
870
|
-
...(status.steps?.length ? { steps: status.steps.map((step) => ({
|
|
903
|
+
...(status.steps?.length ? { steps: status.steps.map((step, index) => ({
|
|
871
904
|
agent: step.agent,
|
|
872
905
|
status: step.status,
|
|
873
906
|
...(step.sessionFile ? { sessionFile: step.sessionFile } : {}),
|
|
@@ -882,9 +915,13 @@ export function nestedSummaryFromAsyncStatus(status: AsyncStatus, asyncDir: stri
|
|
|
882
915
|
...(step.endedAt !== undefined ? { endedAt: step.endedAt } : {}),
|
|
883
916
|
...(step.error ? { error: step.error } : {}),
|
|
884
917
|
...(step.timedOut !== undefined ? { timedOut: step.timedOut } : {}),
|
|
918
|
+
...(step.stopped !== undefined ? { stopped: step.stopped } : {}),
|
|
885
919
|
...(step.turnBudget ? { turnBudget: step.turnBudget } : {}),
|
|
886
920
|
...(step.turnBudgetExceeded !== undefined ? { turnBudgetExceeded: step.turnBudgetExceeded } : {}),
|
|
887
921
|
...(step.wrapUpRequested !== undefined ? { wrapUpRequested: step.wrapUpRequested } : {}),
|
|
922
|
+
...(step.processTerminal ? { processTerminal: sanitizeProcessTerminal(step.processTerminal, { runId: status.runId || fallback.id, runnerProcessInstanceId: step.processTerminal.runnerProcessInstanceId }, `${asyncDir}/status.json step ${index}`) } : {}),
|
|
923
|
+
...(step.capabilityCeiling ? { capabilityCeiling: step.capabilityCeiling } : {}),
|
|
924
|
+
...(step.capabilityAudit ? { capabilityAudit: step.capabilityAudit } : {}),
|
|
888
925
|
})).slice(0, MAX_STEPS) } : {}),
|
|
889
926
|
};
|
|
890
927
|
}
|
|
@@ -8,11 +8,12 @@ export interface NestedRunCounts {
|
|
|
8
8
|
paused: number;
|
|
9
9
|
complete: number;
|
|
10
10
|
failed: number;
|
|
11
|
+
stopped: number;
|
|
11
12
|
queued: number;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
export function countNestedRuns(children: NestedRunSummary[] | undefined): NestedRunCounts {
|
|
15
|
-
const counts: NestedRunCounts = { total: 0, running: 0, paused: 0, complete: 0, failed: 0, queued: 0 };
|
|
16
|
+
const counts: NestedRunCounts = { total: 0, running: 0, paused: 0, complete: 0, failed: 0, stopped: 0, queued: 0 };
|
|
16
17
|
for (const child of children ?? []) {
|
|
17
18
|
counts.total++;
|
|
18
19
|
counts[child.state]++;
|
|
@@ -22,6 +23,7 @@ export function countNestedRuns(children: NestedRunSummary[] | undefined): Neste
|
|
|
22
23
|
counts.paused += nested.paused;
|
|
23
24
|
counts.complete += nested.complete;
|
|
24
25
|
counts.failed += nested.failed;
|
|
26
|
+
counts.stopped += nested.stopped;
|
|
25
27
|
counts.queued += nested.queued;
|
|
26
28
|
}
|
|
27
29
|
return counts;
|
|
@@ -34,6 +36,7 @@ export function formatNestedAggregate(children: NestedRunSummary[] | undefined):
|
|
|
34
36
|
counts.running > 0 ? `${counts.running} running` : "",
|
|
35
37
|
counts.paused > 0 ? `${counts.paused} paused` : "",
|
|
36
38
|
counts.failed > 0 ? `${counts.failed} failed` : "",
|
|
39
|
+
counts.stopped > 0 ? `${counts.stopped} stopped` : "",
|
|
37
40
|
counts.complete > 0 ? `${counts.complete} complete` : "",
|
|
38
41
|
counts.queued > 0 ? `${counts.queued} queued` : "",
|
|
39
42
|
].filter(Boolean);
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { writeAtomicJson } from "../../shared/atomic-json.ts";
|
|
4
|
+
import type {
|
|
5
|
+
ParallelHandoffGroup,
|
|
6
|
+
ParallelHandoffManifest,
|
|
7
|
+
ParallelHandoffReference,
|
|
8
|
+
SubagentResultStatus,
|
|
9
|
+
} from "../../shared/types.ts";
|
|
10
|
+
import type {
|
|
11
|
+
WorktreeCleanupReport,
|
|
12
|
+
WorktreeDiff,
|
|
13
|
+
WorktreeSetup,
|
|
14
|
+
} from "./worktree.ts";
|
|
15
|
+
|
|
16
|
+
export interface ParallelHandoffResult {
|
|
17
|
+
agent: string;
|
|
18
|
+
status: SubagentResultStatus;
|
|
19
|
+
summary: string;
|
|
20
|
+
outputPath?: string;
|
|
21
|
+
structuredOutput?: unknown;
|
|
22
|
+
structuredOutputPath?: string;
|
|
23
|
+
sessionPath?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function readManifest(manifestPath: string): ParallelHandoffManifest | undefined {
|
|
27
|
+
if (!fs.existsSync(manifestPath)) return undefined;
|
|
28
|
+
const parsed = JSON.parse(fs.readFileSync(manifestPath, "utf-8")) as ParallelHandoffManifest;
|
|
29
|
+
if (parsed.version !== 1 || !Array.isArray(parsed.groups)) {
|
|
30
|
+
throw new Error(`Invalid parallel handoff manifest: ${manifestPath}`);
|
|
31
|
+
}
|
|
32
|
+
return parsed;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function referenceFor(manifestPath: string, manifest: ParallelHandoffManifest): ParallelHandoffReference {
|
|
36
|
+
const children = manifest.groups.flatMap((group) => group.children);
|
|
37
|
+
return {
|
|
38
|
+
version: 1,
|
|
39
|
+
path: manifestPath,
|
|
40
|
+
groupCount: manifest.groups.length,
|
|
41
|
+
childCount: children.length,
|
|
42
|
+
changedPatches: children.filter((child) => child.patch.changed).length,
|
|
43
|
+
cleanupState: manifest.groups.every((group) => group.cleanup.state === "complete") ? "complete" : "partial",
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function safeHandoffAgentName(agent: string): string {
|
|
48
|
+
return agent.replace(/[^\w.-]/g, "_");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function missingDiff(input: { manifestPath: string; stepIndex: number; taskIndex: number; agent: string; branch?: string }): WorktreeDiff {
|
|
52
|
+
const patchPath = path.join(path.dirname(input.manifestPath), `missing-diff-step-${input.stepIndex}-task-${input.taskIndex}-${safeHandoffAgentName(input.agent)}.patch`);
|
|
53
|
+
try {
|
|
54
|
+
fs.mkdirSync(path.dirname(patchPath), { recursive: true });
|
|
55
|
+
fs.writeFileSync(patchPath, "", "utf-8");
|
|
56
|
+
} catch {
|
|
57
|
+
// Handoff records the artifact failure below; patch creation remains best-effort.
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
index: input.taskIndex,
|
|
61
|
+
agent: input.agent,
|
|
62
|
+
branch: input.branch ?? "",
|
|
63
|
+
diffStat: "",
|
|
64
|
+
filesChanged: 0,
|
|
65
|
+
insertions: 0,
|
|
66
|
+
deletions: 0,
|
|
67
|
+
patchPath,
|
|
68
|
+
error: "diff artifact unavailable; no patch was captured",
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function writeParallelHandoffGroup(input: {
|
|
73
|
+
manifestPath: string;
|
|
74
|
+
runId: string;
|
|
75
|
+
mode: "parallel" | "chain";
|
|
76
|
+
source: "foreground" | "async";
|
|
77
|
+
cwd: string;
|
|
78
|
+
stepIndex: number;
|
|
79
|
+
flatStartIndex: number;
|
|
80
|
+
setup: WorktreeSetup;
|
|
81
|
+
diffs: WorktreeDiff[];
|
|
82
|
+
cleanup: WorktreeCleanupReport;
|
|
83
|
+
results: ParallelHandoffResult[];
|
|
84
|
+
now?: number;
|
|
85
|
+
}): ParallelHandoffReference {
|
|
86
|
+
const now = input.now ?? Date.now();
|
|
87
|
+
const existing = readManifest(input.manifestPath);
|
|
88
|
+
if (existing && (existing.runId !== input.runId || existing.mode !== input.mode || existing.source !== input.source)) {
|
|
89
|
+
throw new Error(`Parallel handoff manifest belongs to a different run: ${input.manifestPath}`);
|
|
90
|
+
}
|
|
91
|
+
const group: ParallelHandoffGroup = {
|
|
92
|
+
stepIndex: input.stepIndex,
|
|
93
|
+
baseCommit: input.setup.baseCommit,
|
|
94
|
+
repoRoot: input.setup.cwd,
|
|
95
|
+
children: input.results.map((result, taskIndex) => {
|
|
96
|
+
const diff = input.diffs[taskIndex] ?? missingDiff({
|
|
97
|
+
manifestPath: input.manifestPath,
|
|
98
|
+
stepIndex: input.stepIndex,
|
|
99
|
+
taskIndex,
|
|
100
|
+
agent: result.agent,
|
|
101
|
+
branch: input.setup.worktrees[taskIndex]?.branch,
|
|
102
|
+
});
|
|
103
|
+
return {
|
|
104
|
+
index: input.flatStartIndex + taskIndex,
|
|
105
|
+
taskIndex,
|
|
106
|
+
agent: result.agent,
|
|
107
|
+
status: result.status,
|
|
108
|
+
summary: result.summary,
|
|
109
|
+
...(result.outputPath ? { outputPath: result.outputPath } : {}),
|
|
110
|
+
...(result.structuredOutput !== undefined ? { structuredOutput: result.structuredOutput } : {}),
|
|
111
|
+
...(result.structuredOutputPath ? { structuredOutputPath: result.structuredOutputPath } : {}),
|
|
112
|
+
...(result.sessionPath ? { sessionPath: result.sessionPath } : {}),
|
|
113
|
+
patch: {
|
|
114
|
+
path: diff.patchPath,
|
|
115
|
+
branch: diff.branch,
|
|
116
|
+
changed: diff.filesChanged > 0 || diff.insertions > 0 || diff.deletions > 0 || diff.diffStat.trim().length > 0,
|
|
117
|
+
diffStat: diff.diffStat,
|
|
118
|
+
filesChanged: diff.filesChanged,
|
|
119
|
+
insertions: diff.insertions,
|
|
120
|
+
deletions: diff.deletions,
|
|
121
|
+
...(diff.error ? { error: diff.error } : {}),
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}),
|
|
125
|
+
cleanup: input.cleanup,
|
|
126
|
+
};
|
|
127
|
+
const groups = existing?.groups.filter((candidate) => candidate.stepIndex !== input.stepIndex) ?? [];
|
|
128
|
+
groups.push(group);
|
|
129
|
+
groups.sort((left, right) => left.stepIndex - right.stepIndex);
|
|
130
|
+
const manifest: ParallelHandoffManifest = {
|
|
131
|
+
version: 1,
|
|
132
|
+
runId: input.runId,
|
|
133
|
+
mode: input.mode,
|
|
134
|
+
source: input.source,
|
|
135
|
+
cwd: input.cwd,
|
|
136
|
+
createdAt: existing?.createdAt ?? now,
|
|
137
|
+
updatedAt: now,
|
|
138
|
+
groups,
|
|
139
|
+
};
|
|
140
|
+
writeAtomicJson(input.manifestPath, manifest);
|
|
141
|
+
return referenceFor(input.manifestPath, manifest);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function parallelHandoffPath(baseDir: string, runId?: string): string {
|
|
145
|
+
return runId ? path.join(baseDir, "handoffs", `${runId}.json`) : path.join(baseDir, "handoff.json");
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function formatParallelHandoffReference(reference: ParallelHandoffReference): string {
|
|
149
|
+
return `Parallel handoff: ${reference.path} (${reference.childCount} children, ${reference.changedPatches} changed patches, cleanup ${reference.cleanupState})`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function formatParallelHandoffError(error: unknown): string {
|
|
153
|
+
return `Parallel handoff unavailable: ${error instanceof Error ? error.message : String(error)}`;
|
|
154
|
+
}
|
|
@@ -3,6 +3,8 @@ export interface RunnerSubagentStep {
|
|
|
3
3
|
parentSessionId?: string;
|
|
4
4
|
agent: string;
|
|
5
5
|
task: string;
|
|
6
|
+
/** Resolved launch context for this child. */
|
|
7
|
+
context?: "fresh" | "fork";
|
|
6
8
|
importAsyncRoot?: {
|
|
7
9
|
runId: string;
|
|
8
10
|
asyncDir: string;
|
|
@@ -28,17 +30,29 @@ export interface RunnerSubagentStep {
|
|
|
28
30
|
inheritSkills: boolean;
|
|
29
31
|
skills?: string[];
|
|
30
32
|
outputPath?: string;
|
|
33
|
+
/** Defer the authoritative output instruction until a dynamic fanout item is materialized. */
|
|
34
|
+
namespaceOutputPath?: boolean;
|
|
31
35
|
outputMode?: "inline" | "file-only";
|
|
32
36
|
sessionFile?: string;
|
|
33
37
|
maxSubagentDepth?: number;
|
|
38
|
+
waitToolEnabled?: boolean;
|
|
34
39
|
structuredOutput?: {
|
|
35
40
|
schema: import("../../shared/types.ts").JsonSchemaObject;
|
|
36
41
|
schemaPath: string;
|
|
37
42
|
outputPath: string;
|
|
38
43
|
};
|
|
39
44
|
structuredOutputSchema?: import("../../shared/types.ts").JsonSchemaObject;
|
|
45
|
+
agentContract?: import("../../shared/types.ts").AgentContract;
|
|
46
|
+
definitionDigest?: string;
|
|
47
|
+
launchBindingTask?: string;
|
|
48
|
+
launchContractDigest?: string;
|
|
40
49
|
effectiveAcceptance?: import("../../shared/types.ts").ResolvedAcceptanceConfig;
|
|
50
|
+
acceptanceInput?: import("../../shared/types.ts").AcceptanceInput;
|
|
51
|
+
acceptanceRole?: import("../../shared/types.ts").AcceptanceRole;
|
|
52
|
+
gateOn?: import("../../shared/types.ts").ChainGateLayer;
|
|
41
53
|
toolBudget?: import("../../shared/types.ts").ResolvedToolBudget;
|
|
54
|
+
capabilityCeiling?: import("./capability-ceiling.ts").ResolvedSubagentCapabilityCeiling;
|
|
55
|
+
capabilityAudit?: import("./capability-ceiling.ts").SubagentCapabilityAudit;
|
|
42
56
|
}
|
|
43
57
|
|
|
44
58
|
export interface ParallelStepGroup {
|
|
@@ -59,6 +73,10 @@ export interface DynamicRunnerGroup {
|
|
|
59
73
|
sessionFiles?: (string | undefined)[];
|
|
60
74
|
thinkingOverrides?: (string | undefined)[];
|
|
61
75
|
effectiveAcceptance?: import("../../shared/types.ts").ResolvedAcceptanceConfig;
|
|
76
|
+
acceptanceInput?: import("../../shared/types.ts").AcceptanceInput;
|
|
77
|
+
acceptanceRole?: import("../../shared/types.ts").AcceptanceRole;
|
|
78
|
+
agentContract?: import("../../shared/types.ts").AgentContract;
|
|
79
|
+
gateOn?: import("../../shared/types.ts").ChainGateLayer;
|
|
62
80
|
}
|
|
63
81
|
|
|
64
82
|
export type RunnerStep = RunnerSubagentStep | ParallelStepGroup | DynamicRunnerGroup;
|