@selesai/code 0.5.28 → 0.6.1
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 +24 -0
- package/README.md +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +9 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +1 -1
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/credential-print.d.ts +23 -0
- package/dist/cli/credential-print.d.ts.map +1 -0
- package/dist/cli/credential-print.js +117 -0
- package/dist/cli/credential-print.js.map +1 -0
- package/dist/cli/startup-ui.d.ts.map +1 -1
- package/dist/cli/startup-ui.js +1 -1
- package/dist/cli/startup-ui.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +3 -0
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session.d.ts +12 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +20 -14
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +11 -3
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +1 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +11 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +14 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +10 -0
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +1 -1
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/llama/provider.d.ts.map +1 -1
- package/dist/core/llama/provider.js +8 -3
- package/dist/core/llama/provider.js.map +1 -1
- package/dist/core/model-config.d.ts +30 -0
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +6 -0
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +2 -2
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +1 -0
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +20 -3
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-runtime.d.ts +2 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +5 -4
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +13 -6
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts +1 -1
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +24 -11
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/resource-loader.d.ts +15 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +66 -9
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/settings-manager.d.ts +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +19 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/system-prompt.test.d.ts +2 -0
- package/dist/core/system-prompt.test.d.ts.map +1 -0
- package/dist/core/system-prompt.test.js +89 -0
- package/dist/core/system-prompt.test.js.map +1 -0
- package/dist/core/tools/bash.d.ts +2 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +34 -5
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js +3 -1
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/defaults/models.json +13 -45
- package/dist/defaults/settings.json +1 -2
- package/dist/extensions/copy-turn.test.ts +131 -0
- package/dist/extensions/copy-turn.ts +6 -1
- package/dist/extensions/package.json +0 -1
- package/dist/extensions/pi-intercom/CHANGELOG.md +249 -0
- package/dist/extensions/pi-intercom/README.md +102 -39
- package/dist/extensions/pi-intercom/broker/broker.ts +1233 -36
- package/dist/extensions/pi-intercom/broker/client.test.ts +83 -0
- package/dist/extensions/pi-intercom/broker/client.ts +315 -12
- package/dist/extensions/pi-intercom/broker/extension-state.ts +186 -0
- package/dist/extensions/pi-intercom/broker/extension.test.ts +387 -0
- package/dist/extensions/pi-intercom/broker/framing.test.ts +114 -0
- package/dist/extensions/pi-intercom/broker/framing.ts +82 -24
- package/dist/extensions/pi-intercom/broker/paths.test.ts +153 -0
- package/dist/extensions/pi-intercom/broker/paths.ts +117 -8
- package/dist/extensions/pi-intercom/broker/runtime-claim.test.ts +34 -0
- package/dist/extensions/pi-intercom/broker/runtime-claim.ts +21 -0
- package/dist/extensions/pi-intercom/broker/spawn.test.ts +160 -23
- package/dist/extensions/pi-intercom/broker/spawn.ts +113 -27
- package/dist/extensions/pi-intercom/config.test.ts +93 -0
- package/dist/extensions/pi-intercom/config.ts +55 -6
- package/dist/extensions/pi-intercom/cwd.test.ts +40 -0
- package/dist/extensions/pi-intercom/cwd.ts +31 -0
- package/dist/extensions/pi-intercom/extension-api.ts +44 -0
- package/dist/extensions/pi-intercom/format-context.test.ts +31 -0
- package/dist/extensions/pi-intercom/format-context.ts +32 -0
- package/dist/extensions/pi-intercom/index.ts +742 -145
- package/dist/extensions/pi-intercom/intercom.integration.test.ts +2646 -0
- package/dist/extensions/pi-intercom/package.json +15 -5
- package/dist/extensions/pi-intercom/reply-tracker.test.ts +134 -0
- package/dist/extensions/pi-intercom/reply-tracker.ts +31 -13
- package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +13 -11
- package/dist/extensions/pi-intercom/test/inline-message.test.ts +184 -0
- package/dist/extensions/pi-intercom/test/overlay-width.test.ts +66 -0
- package/dist/extensions/pi-intercom/types.ts +94 -4
- package/dist/extensions/pi-intercom/ui/compose.ts +8 -4
- package/dist/extensions/pi-intercom/ui/inline-message.ts +61 -25
- package/dist/extensions/pi-intercom/ui/session-list.ts +7 -3
- package/dist/extensions/pi-subagents/CHANGELOG.md +88 -0
- package/dist/extensions/pi-subagents/LICENSE +21 -0
- package/dist/extensions/pi-subagents/README.md +158 -69
- package/dist/extensions/pi-subagents/agents/architect.md +5 -4
- package/dist/extensions/pi-subagents/agents/builder.md +6 -4
- package/dist/extensions/pi-subagents/agents/commentator.md +3 -2
- package/dist/extensions/pi-subagents/agents/explorer.md +3 -2
- package/dist/extensions/pi-subagents/agents/recapper.md +3 -2
- package/dist/extensions/pi-subagents/agents/researcher.md +4 -3
- package/dist/extensions/pi-subagents/package-lock.json +2 -2
- package/dist/extensions/pi-subagents/package.json +3 -3
- package/dist/extensions/pi-subagents/prompts/review-loop.md +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +22 -988
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +257 -0
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +431 -0
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +144 -0
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +281 -0
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +125 -37
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +4 -0
- package/dist/extensions/pi-subagents/src/agents/agents.ts +118 -9
- package/dist/extensions/pi-subagents/src/agents/skills.ts +14 -12
- package/dist/extensions/pi-subagents/src/agents/task-aware-routing.ts +125 -0
- package/dist/extensions/pi-subagents/src/api/delegation.ts +3 -0
- package/dist/extensions/pi-subagents/src/api/preflight.ts +17 -13
- package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +17 -1
- package/dist/extensions/pi-subagents/src/extension/index.ts +22 -8
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +248 -6
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +33 -8
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +32 -14
- package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +9 -4
- package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +33 -4
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +86 -21
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +24 -13
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +7 -5
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +18 -2
- package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +48 -5
- package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +68 -1
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +56 -5
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +92 -11
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +29 -3
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +388 -29
- package/dist/extensions/pi-subagents/src/runs/foreground/async-stop-action.ts +65 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +3 -3
- package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +214 -60
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +546 -252
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +42 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +553 -154
- package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +19 -13
- package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +51 -19
- package/dist/extensions/pi-subagents/src/runs/shared/chain-outputs.ts +3 -1
- package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +44 -11
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +8 -0
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +97 -20
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +43 -12
- package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +52 -4
- package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +19 -0
- package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +45 -9
- package/dist/extensions/pi-subagents/src/runs/shared/runtime-acknowledged-extensions.ts +71 -0
- package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +63 -9
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +31 -1
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +101 -0
- package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +22 -1
- package/dist/extensions/pi-subagents/src/runs/shared/usage-budget.ts +65 -0
- package/dist/extensions/pi-subagents/src/runs/shared/workflow-graph.ts +26 -1
- package/dist/extensions/pi-subagents/src/shared/settings.ts +17 -1
- package/dist/extensions/pi-subagents/src/shared/types.ts +196 -12
- package/dist/extensions/pi-subagents/src/shared/utils.ts +102 -5
- package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +10 -1
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +46 -4
- package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +5 -3
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +87 -24
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +182 -9
- package/dist/extensions/pi-subagents/src/tui/render.ts +55 -34
- package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +14 -7
- package/dist/extensions/pi-subagents/src/watchdog/review.ts +5 -4
- package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +170 -17
- package/dist/extensions/pi-subagents/src/watchdog/scope.ts +62 -0
- package/dist/extensions/pi-subagents/src/watchdog/settings.ts +41 -1
- package/dist/extensions/pi-subagents/src/watchdog/types.ts +10 -0
- package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +113 -8
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +419 -47
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +84 -0
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +4 -2
- package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +51 -2
- package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +62 -22
- package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +48 -0
- package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +8 -6
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +231 -19
- package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +48 -7
- package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +44 -0
- package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +199 -17
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +898 -16
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +112 -23
- package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +17 -5
- package/dist/extensions/pi-subagents/test/support/mock-pi.ts +2 -0
- package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +18 -2
- package/dist/extensions/pi-subagents/test/support/register-loader.mjs +3 -3
- package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +3 -1
- package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +198 -6
- package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +161 -1
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +47 -2
- package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +60 -0
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +8 -0
- package/dist/extensions/pi-subagents/test/unit/builtin-agent-documentation.test.ts +63 -0
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +136 -0
- package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/chain-append.test.ts +6 -0
- package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +48 -48
- package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +23 -0
- package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +28 -2
- package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +176 -8
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +164 -5
- package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +41 -1
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +17 -12
- package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +18 -2
- package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +20 -1
- package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +30 -2
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +39 -2
- package/dist/extensions/pi-subagents/test/unit/parallel-utils.test.ts +22 -0
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +103 -0
- package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +18 -0
- package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +48 -0
- package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +13 -1
- package/dist/extensions/pi-subagents/test/unit/result-intercom.test.ts +29 -4
- package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +223 -4
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +30 -0
- package/dist/extensions/pi-subagents/test/unit/runtime-acknowledged-extensions.test.ts +52 -0
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +46 -2
- package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +91 -1
- package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/streamed-progress-bounds.test.ts +78 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +41 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +77 -0
- package/dist/extensions/pi-subagents/test/unit/task-aware-routing.test.ts +213 -0
- package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +26 -1
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +61 -10
- package/dist/extensions/pi-subagents/test/unit/total-cost.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +210 -1
- package/dist/extensions/pi-subagents/test/unit/watchdog-scope.test.ts +33 -0
- package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +32 -0
- package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +43 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts +3 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +10 -2
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts +1 -2
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +16 -46
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +4 -1
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +22 -13
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/external-editor.d.ts +12 -0
- package/dist/modes/interactive/external-editor.d.ts.map +1 -0
- package/dist/modes/interactive/external-editor.js +37 -0
- package/dist/modes/interactive/external-editor.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +72 -64
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +14 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/skills/ponytail/SKILL.md +1 -3
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +19 -8
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +1 -1
- package/dist/utils/version-check.js.map +1 -1
- package/docs/compaction.md +1 -1
- package/docs/custom-provider.md +14 -5
- package/docs/environment-variables.md +86 -0
- package/docs/extensions.md +15 -5
- package/docs/index.md +1 -0
- package/docs/models.md +9 -2
- package/docs/plans/subagent-delegation/phase-0-correctness.md +265 -0
- package/docs/plans/subagent-delegation/phase-1-behavioral-contract.md +486 -0
- package/docs/plans/subagent-delegation/phase-2-context-controls.md +282 -0
- package/docs/plans/subagent-delegation/phase-3-advisory-routing.md +362 -0
- package/docs/plans/subagent-delegation/phase-4-optional-enforcement.md +381 -0
- package/docs/providers.md +21 -2
- package/docs/rpc.md +23 -6
- package/docs/session-format.md +2 -0
- package/docs/settings.md +1 -1
- package/docs/usage.md +0 -13
- package/examples/extensions/custom-compaction.ts +5 -2
- package/examples/extensions/custom-provider-anthropic/index.ts +9 -3
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/handoff.ts +11 -3
- package/examples/extensions/message-renderer.ts +3 -3
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/summarize.ts +5 -2
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/12-full-control.ts +3 -1
- package/package.json +16 -7
- package/dist/extensions/caveman/caveman-instructions.cjs +0 -11
- package/dist/extensions/caveman/index.js +0 -118
- package/dist/extensions/caveman/package.json +0 -8
- package/dist/extensions/caveman/test/extension.test.js +0 -203
- package/dist/extensions/caveman/test/helpers.test.js +0 -58
- package/dist/skills/caveman/SKILL.md +0 -50
|
@@ -114,6 +114,27 @@ function createUiContext() {
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
describe("async job tracker", { skip: !available ? "pi packages not available" : undefined }, () => {
|
|
117
|
+
it("drops stale captured extension contexts instead of crashing background timers", () => {
|
|
118
|
+
const asyncRoot = createTempDir("pi-async-job-tracker-stale-context-");
|
|
119
|
+
try {
|
|
120
|
+
const state = createState();
|
|
121
|
+
const recorder = createEventRecorder();
|
|
122
|
+
const tracker = trackerMod!.createAsyncJobTracker(recorder.pi, state as never, asyncRoot);
|
|
123
|
+
(state as { lastUiContext: unknown }).lastUiContext = {
|
|
124
|
+
get hasUI() {
|
|
125
|
+
throw new Error("This extension ctx is stale after session replacement or reload.");
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
tracker.handleStarted({ id: "run-stale-context", asyncDir: path.join(asyncRoot, "run-stale-context"), agent: "worker" });
|
|
130
|
+
|
|
131
|
+
assert.equal(state.lastUiContext, null);
|
|
132
|
+
if (state.poller) clearInterval(state.poller);
|
|
133
|
+
} finally {
|
|
134
|
+
removeTempDir(asyncRoot);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
117
138
|
it("removes completed jobs after retention and requests a rerender", async () => {
|
|
118
139
|
const asyncRoot = createTempDir("pi-async-job-tracker-");
|
|
119
140
|
try {
|
|
@@ -856,6 +877,69 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
|
|
|
856
877
|
}
|
|
857
878
|
});
|
|
858
879
|
|
|
880
|
+
it("resynchronizes when a saved cursor resumes inside an oversized JSONL record", async () => {
|
|
881
|
+
const asyncRoot = createTempDir("pi-async-job-tracker-");
|
|
882
|
+
const originalError = console.error;
|
|
883
|
+
const errors: unknown[][] = [];
|
|
884
|
+
console.error = (...args: unknown[]) => {
|
|
885
|
+
errors.push(args);
|
|
886
|
+
};
|
|
887
|
+
try {
|
|
888
|
+
const runDir = path.join(asyncRoot, "run-midline-oversized-control");
|
|
889
|
+
fs.mkdirSync(runDir, { recursive: true });
|
|
890
|
+
fs.writeFileSync(path.join(runDir, "status.json"), JSON.stringify({
|
|
891
|
+
runId: "run-midline-oversized-control",
|
|
892
|
+
mode: "single",
|
|
893
|
+
state: "running",
|
|
894
|
+
startedAt: Date.now() - 1000,
|
|
895
|
+
lastUpdate: Date.now(),
|
|
896
|
+
steps: [{ agent: "worker", status: "running" }],
|
|
897
|
+
}), "utf-8");
|
|
898
|
+
const largeDiagnostic = JSON.stringify({
|
|
899
|
+
type: "message_update",
|
|
900
|
+
message: { role: "assistant", content: [{ type: "text", text: "x".repeat(2_500_000) }] },
|
|
901
|
+
});
|
|
902
|
+
const controlEvent = JSON.stringify({
|
|
903
|
+
type: "subagent.control",
|
|
904
|
+
channels: ["event"],
|
|
905
|
+
event: {
|
|
906
|
+
type: "needs_attention",
|
|
907
|
+
to: "needs_attention",
|
|
908
|
+
ts: 123,
|
|
909
|
+
runId: "run-midline-oversized-control",
|
|
910
|
+
agent: "worker",
|
|
911
|
+
message: "worker needs attention",
|
|
912
|
+
},
|
|
913
|
+
});
|
|
914
|
+
fs.writeFileSync(path.join(runDir, "events.jsonl"), `${largeDiagnostic}\n${controlEvent}\n`, "utf-8");
|
|
915
|
+
|
|
916
|
+
const state = createState();
|
|
917
|
+
state.asyncJobs.set("run-midline-oversized-control", {
|
|
918
|
+
asyncId: "run-midline-oversized-control",
|
|
919
|
+
asyncDir: runDir,
|
|
920
|
+
status: "running",
|
|
921
|
+
agents: ["worker"],
|
|
922
|
+
startedAt: Date.now() - 1000,
|
|
923
|
+
updatedAt: Date.now(),
|
|
924
|
+
controlEventCursor: 0,
|
|
925
|
+
});
|
|
926
|
+
const recorder = createEventRecorder();
|
|
927
|
+
const tracker = trackerMod!.createAsyncJobTracker(recorder.pi, state as never, asyncRoot, {
|
|
928
|
+
pollIntervalMs: 10,
|
|
929
|
+
});
|
|
930
|
+
tracker.ensurePoller();
|
|
931
|
+
|
|
932
|
+
await waitForCondition(
|
|
933
|
+
() => recorder.events.some((event) => event.channel === "subagent:control-event"),
|
|
934
|
+
"control event after oversized diagnostic",
|
|
935
|
+
);
|
|
936
|
+
assert.equal(errors.some((args) => String(args[0]).includes("Ignoring malformed async control event")), false);
|
|
937
|
+
} finally {
|
|
938
|
+
console.error = originalError;
|
|
939
|
+
removeTempDir(asyncRoot);
|
|
940
|
+
}
|
|
941
|
+
});
|
|
942
|
+
|
|
859
943
|
it("does not tail-skip control events for newly tracked large logs", async () => {
|
|
860
944
|
const asyncRoot = createTempDir("pi-async-job-tracker-");
|
|
861
945
|
try {
|
|
@@ -27,8 +27,8 @@ describe("async status helpers", () => {
|
|
|
27
27
|
currentStep: 1,
|
|
28
28
|
outputFile,
|
|
29
29
|
steps: [
|
|
30
|
-
{ agent: "scout", status: "complete", durationMs: 10 },
|
|
31
|
-
{ agent: "worker", status: "running", durationMs: 20 },
|
|
30
|
+
{ agent: "scout", status: "complete", durationMs: 10, description: "Inspect auth only" },
|
|
31
|
+
{ agent: "worker", status: "running", durationMs: 20, description: "Patch billing only" },
|
|
32
32
|
],
|
|
33
33
|
});
|
|
34
34
|
createAsyncDir(root, "run-b", {
|
|
@@ -47,6 +47,8 @@ describe("async status helpers", () => {
|
|
|
47
47
|
assert.equal(runs[0]?.steps.length, 2);
|
|
48
48
|
assert.equal(runs[0]?.steps[1]?.agent, "worker");
|
|
49
49
|
assert.equal(runs[0]?.steps[1]?.status, "running");
|
|
50
|
+
assert.equal(runs[0]?.steps[0]?.description, "Inspect auth only");
|
|
51
|
+
assert.equal(runs[0]?.steps[1]?.description, "Patch billing only");
|
|
50
52
|
assert.match(formatAsyncRunList(runs), /output: .*output-1\.log/);
|
|
51
53
|
} finally {
|
|
52
54
|
fs.rmSync(root, { recursive: true, force: true });
|
|
@@ -349,9 +349,9 @@ describe("chain clarify model display", { skip: !available ? "pi packages not av
|
|
|
349
349
|
assert.match(initial, /\[Enter\] Run • \[Esc\] Cancel/);
|
|
350
350
|
if (mode === "single") {
|
|
351
351
|
assert.match(initial, /\[w\]Output/);
|
|
352
|
-
assert.doesNotMatch(initial, /\[
|
|
352
|
+
assert.doesNotMatch(initial, /\[↑↓\/jk\] Navigate/);
|
|
353
353
|
} else {
|
|
354
|
-
assert.match(initial, /\[
|
|
354
|
+
assert.match(initial, /\[↑↓\/jk\] Navigate/);
|
|
355
355
|
}
|
|
356
356
|
if (mode === "chain") {
|
|
357
357
|
assert.match(initial, /\[w\]Output/);
|
|
@@ -368,4 +368,53 @@ describe("chain clarify model display", { skip: !available ? "pi packages not av
|
|
|
368
368
|
assert.match(component.render(84).map(stripAnsi).join("\n"), /\[b\]Background:ON/);
|
|
369
369
|
}
|
|
370
370
|
});
|
|
371
|
+
|
|
372
|
+
it("navigates non-editing chain steps with j and k", () => {
|
|
373
|
+
const agents = ["scout", "worker"].map((name) => ({
|
|
374
|
+
name,
|
|
375
|
+
description: "",
|
|
376
|
+
systemPrompt: "",
|
|
377
|
+
systemPromptMode: "replace",
|
|
378
|
+
inheritProjectContext: false,
|
|
379
|
+
inheritSkills: false,
|
|
380
|
+
source: "user",
|
|
381
|
+
filePath: `${name}.md`,
|
|
382
|
+
}));
|
|
383
|
+
const component = new ChainClarifyComponent(
|
|
384
|
+
{ requestRender() {} },
|
|
385
|
+
{ fg(_key: string, text: string) { return text; } },
|
|
386
|
+
agents,
|
|
387
|
+
["Scout", "Implement"],
|
|
388
|
+
"Task",
|
|
389
|
+
undefined,
|
|
390
|
+
agents.map(() => ({ output: false, outputMode: "inline", reads: false, progress: false, skills: [], model: undefined })),
|
|
391
|
+
[],
|
|
392
|
+
undefined,
|
|
393
|
+
[{ name: "jk-skill", source: "user" }],
|
|
394
|
+
() => {},
|
|
395
|
+
"chain",
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
component.handleInput("j");
|
|
399
|
+
assert.equal(component.selectedStep, 1);
|
|
400
|
+
component.handleInput("k");
|
|
401
|
+
assert.equal(component.selectedStep, 0);
|
|
402
|
+
|
|
403
|
+
component.handleInput("e");
|
|
404
|
+
component.handleInput("j");
|
|
405
|
+
component.handleInput("k");
|
|
406
|
+
assert.match(component.render(84).map(stripAnsi).join("\n"), /jkScout/);
|
|
407
|
+
component.handleInput("\x1b");
|
|
408
|
+
|
|
409
|
+
component.handleInput("m");
|
|
410
|
+
component.handleInput("j");
|
|
411
|
+
component.handleInput("k");
|
|
412
|
+
assert.match(component.render(84).map(stripAnsi).join("\n"), /Search: jk/);
|
|
413
|
+
component.handleInput("\x1b");
|
|
414
|
+
|
|
415
|
+
component.handleInput("s");
|
|
416
|
+
component.handleInput("j");
|
|
417
|
+
component.handleInput("k");
|
|
418
|
+
assert.match(component.render(84).map(stripAnsi).join("\n"), /Search: jk/);
|
|
419
|
+
});
|
|
371
420
|
});
|
|
@@ -64,7 +64,7 @@ interface TestParallelTask {
|
|
|
64
64
|
gateOn?: "execution" | "acceptance";
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
type TestChainStep = TestSequentialStep | {
|
|
67
|
+
type TestChainStep = { checkpoint: string; message?: string; label?: string; phase?: string } | TestSequentialStep | {
|
|
68
68
|
parallel: TestParallelTask[];
|
|
69
69
|
concurrency?: number;
|
|
70
70
|
failFast?: boolean;
|
|
@@ -91,6 +91,7 @@ type TestChainStep = TestSequentialStep | {
|
|
|
91
91
|
};
|
|
92
92
|
|
|
93
93
|
interface ChainResultItem {
|
|
94
|
+
index: number;
|
|
94
95
|
agent: string;
|
|
95
96
|
exitCode: number;
|
|
96
97
|
finalOutput?: string;
|
|
@@ -118,6 +119,7 @@ interface ChainExecutionResult {
|
|
|
118
119
|
currentStepIndex?: number;
|
|
119
120
|
outputs?: Record<string, { text: string; structured?: unknown }>;
|
|
120
121
|
parallelHandoff?: { version: number; path: string; groupCount: number; childCount: number; cleanupState: string };
|
|
122
|
+
checkpoint?: { name?: string; status?: string; message?: string };
|
|
121
123
|
};
|
|
122
124
|
}
|
|
123
125
|
|
|
@@ -215,6 +217,27 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
|
|
|
215
217
|
);
|
|
216
218
|
}
|
|
217
219
|
|
|
220
|
+
it("pauses foreground chains at approval checkpoints without launching the next child", async () => {
|
|
221
|
+
mockPi.onCall({ output: "analysis done" });
|
|
222
|
+
mockPi.onCall({ output: "should not run" });
|
|
223
|
+
const agents = [makeAgent("analyst"), makeAgent("worker")];
|
|
224
|
+
|
|
225
|
+
const result = await executeChain!(makeChainParams([
|
|
226
|
+
{ agent: "analyst", task: "Analyze" },
|
|
227
|
+
{ checkpoint: "review", message: "Approve implementation?" },
|
|
228
|
+
{ agent: "worker", task: "Implement" },
|
|
229
|
+
], agents));
|
|
230
|
+
|
|
231
|
+
assert.equal(result.isError, undefined);
|
|
232
|
+
assert.match(result.content[0]!.text, /Chain paused at checkpoint 'review'/);
|
|
233
|
+
assert.equal(result.details.results.length, 1);
|
|
234
|
+
assert.equal(result.details.checkpoint?.name, "review");
|
|
235
|
+
assert.equal(result.details.checkpoint?.status, "pending");
|
|
236
|
+
assert.equal(result.details.workflowGraph?.nodes[1]?.kind, "checkpoint");
|
|
237
|
+
assert.equal(result.details.workflowGraph?.nodes[1]?.status, "paused");
|
|
238
|
+
assert.equal(mockPi.callCount(), 1);
|
|
239
|
+
});
|
|
240
|
+
|
|
218
241
|
it("runs a 2-step chain", async () => {
|
|
219
242
|
mockPi.onCall({ output: "Analysis complete: found 3 issues" });
|
|
220
243
|
const agents = [makeAgent("analyst"), makeAgent("reporter")];
|
|
@@ -344,8 +367,9 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
|
|
|
344
367
|
assert.doesNotMatch(firstTaskArg, /\[Write to:|Write your findings to exactly this path/);
|
|
345
368
|
assert.ok(result.details.results[0]?.savedOutputPath);
|
|
346
369
|
assert.equal(fs.readFileSync(result.details.results[0].savedOutputPath, "utf-8"), "full chain output\nwith details");
|
|
347
|
-
assert.
|
|
348
|
-
assert.
|
|
370
|
+
assert.equal(result.details.results[0]?.finalOutput, undefined);
|
|
371
|
+
assert.match(result.details.results[0]?.outputReference?.message ?? "", /Output saved to:/);
|
|
372
|
+
assert.doesNotMatch(result.details.results[0]?.outputReference?.message ?? "", /full chain output/);
|
|
349
373
|
const secondTaskArg = readCallArgs(1).at(-1) ?? "";
|
|
350
374
|
assert.match(secondTaskArg, /Output saved to:/);
|
|
351
375
|
assert.match(secondTaskArg, /2 lines/);
|
|
@@ -381,7 +405,8 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
|
|
|
381
405
|
);
|
|
382
406
|
|
|
383
407
|
assert.ok(!result.isError, `chain should succeed: ${JSON.stringify(result.content)}`);
|
|
384
|
-
assert.
|
|
408
|
+
assert.equal(result.details.results[0]?.finalOutput, undefined);
|
|
409
|
+
assert.match(result.details.results[0]?.outputReference?.message ?? "", /Output saved to:/);
|
|
385
410
|
assert.equal(result.details.results[0]?.acceptance?.status, "checked");
|
|
386
411
|
assert.ok(result.details.results[0]?.acceptance?.childReport);
|
|
387
412
|
|
|
@@ -607,10 +632,13 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
|
|
|
607
632
|
|
|
608
633
|
assert.ok(!result.isError);
|
|
609
634
|
const step2Task = result.details.results[1].task;
|
|
635
|
+
// Reference-first handoff: {previous} carries the saved-output reference and
|
|
636
|
+
// the step reads the named path instead of re-inlined prose.
|
|
610
637
|
assert.ok(
|
|
611
|
-
step2Task.includes("
|
|
612
|
-
`step 2 task should contain
|
|
638
|
+
step2Task.includes("Output saved to:"),
|
|
639
|
+
`step 2 task should contain the saved-output reference via {previous}: ${step2Task.slice(0, 200)}`,
|
|
613
640
|
);
|
|
641
|
+
assert.doesNotMatch(step2Task, /MARKER_ABC_123/);
|
|
614
642
|
});
|
|
615
643
|
|
|
616
644
|
it("passes named sequential outputs through {outputs.name}", async () => {
|
|
@@ -629,7 +657,8 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
|
|
|
629
657
|
);
|
|
630
658
|
|
|
631
659
|
assert.ok(!result.isError);
|
|
632
|
-
assert.match(readCallArgs(1).at(-1) ?? "", /
|
|
660
|
+
assert.match(readCallArgs(1).at(-1) ?? "", /Output saved to: /);
|
|
661
|
+
assert.doesNotMatch(readCallArgs(1).at(-1) ?? "", /CTX_123/);
|
|
633
662
|
assert.equal(result.details.workflowGraph?.nodes[0]?.outputName, "contextOutput");
|
|
634
663
|
});
|
|
635
664
|
|
|
@@ -669,9 +698,10 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
|
|
|
669
698
|
assert.match(readCallArgs(1).at(-1) ?? "", /Review src\/a\.ts/);
|
|
670
699
|
assert.match(readCallArgs(2).at(-1) ?? "", /Review src\/b\.ts/);
|
|
671
700
|
assert.match(readCallArgs(3).at(-1) ?? "", /"key":"src\/a\.ts"/);
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
assert.
|
|
701
|
+
// Terminal details strip chain outputs text/structured; bindings remain
|
|
702
|
+
// reference-first via {outputs.name} and the workflow graph keeps item keys.
|
|
703
|
+
assert.equal(result.details.outputs?.reviews?.text, "");
|
|
704
|
+
assert.equal(result.details.outputs?.reviews?.structured, undefined);
|
|
675
705
|
const dynamicNode = result.details.workflowGraph?.nodes[1];
|
|
676
706
|
assert.equal(dynamicNode?.kind, "dynamic-parallel-group");
|
|
677
707
|
assert.deepEqual(dynamicNode?.children?.map((child) => child.itemKey), ["src/a.ts", "src/b.ts"]);
|
|
@@ -845,7 +875,7 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
|
|
|
845
875
|
{ agent: "scout", task: "Return targets", as: "targets", outputSchema: { type: "object" } },
|
|
846
876
|
{
|
|
847
877
|
expand: { from: { output: "targets", path: "/items" }, key: "/path", maxItems: 4 },
|
|
848
|
-
parallel: { agent: "reviewer", task: "Review {item.path}", outputMode: "file-only" },
|
|
878
|
+
parallel: { agent: "reviewer", task: "Review {item.path}", output: false, outputMode: "file-only" },
|
|
849
879
|
collect: { as: "reviews" },
|
|
850
880
|
},
|
|
851
881
|
],
|
|
@@ -883,7 +913,8 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
|
|
|
883
913
|
|
|
884
914
|
assert.ok(!result.isError, `chain should succeed: ${JSON.stringify(result.content)}`);
|
|
885
915
|
assert.equal(mockPi.callCount(), 2);
|
|
886
|
-
assert.
|
|
916
|
+
assert.equal(result.details.outputs?.reviews?.text, "");
|
|
917
|
+
assert.equal(result.details.outputs?.reviews?.structured, undefined);
|
|
887
918
|
assert.equal(result.details.workflowGraph?.nodes[1]?.status, "completed");
|
|
888
919
|
assert.deepEqual(result.details.workflowGraph?.nodes[1]?.children, []);
|
|
889
920
|
});
|
|
@@ -1100,7 +1131,9 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
|
|
|
1100
1131
|
assert.equal(result.details.results.length, 2);
|
|
1101
1132
|
assert.equal(result.details.results[0]?.acceptance?.status, "rejected");
|
|
1102
1133
|
assert.equal(result.details.results[0]?.exitCode, 0);
|
|
1103
|
-
assert.
|
|
1134
|
+
assert.equal(result.details.results[1]?.finalOutput, undefined);
|
|
1135
|
+
assert.ok(result.details.results[1]?.savedOutputPath);
|
|
1136
|
+
assert.equal(fs.readFileSync(result.details.results[1]!.savedOutputPath!, "utf-8"), "Step 2 ran");
|
|
1104
1137
|
});
|
|
1105
1138
|
|
|
1106
1139
|
it("agent contract v1 chain can gate progression on acceptance", async () => {
|
|
@@ -1172,7 +1205,8 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
|
|
|
1172
1205
|
);
|
|
1173
1206
|
|
|
1174
1207
|
const finalTaskArg = readCallArgs(chainLength - 1).at(-1) ?? "";
|
|
1175
|
-
assert.match(finalTaskArg, /
|
|
1208
|
+
assert.match(finalTaskArg, /Output saved to: /);
|
|
1209
|
+
assert.doesNotMatch(finalTaskArg, /step-38-output/);
|
|
1176
1210
|
assert.doesNotMatch(finalTaskArg, /step-37-output/);
|
|
1177
1211
|
assert.match(result.content[0]?.text ?? "", /40 steps/);
|
|
1178
1212
|
});
|
|
@@ -1261,7 +1295,9 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
|
|
|
1261
1295
|
);
|
|
1262
1296
|
|
|
1263
1297
|
assert.ok(!result.isError);
|
|
1264
|
-
|
|
1298
|
+
const depthChild = result.details.results[0];
|
|
1299
|
+
assert.ok(depthChild.savedOutputPath);
|
|
1300
|
+
assert.deepEqual(JSON.parse(fs.readFileSync(depthChild.savedOutputPath, "utf-8")), {
|
|
1265
1301
|
SELESAI_SUBAGENT_DEPTH: "1",
|
|
1266
1302
|
SELESAI_SUBAGENT_MAX_DEPTH: "1",
|
|
1267
1303
|
});
|
|
@@ -1361,6 +1397,7 @@ describe("chain execution — parallel steps", { skip: !available ? "pi packages
|
|
|
1361
1397
|
|
|
1362
1398
|
assert.ok(!result.isError, `should succeed: ${JSON.stringify(result.content)}`);
|
|
1363
1399
|
assert.equal(result.details.results.length, 2);
|
|
1400
|
+
assert.deepEqual(result.details.results.map((row) => row.index), [0, 1]);
|
|
1364
1401
|
});
|
|
1365
1402
|
|
|
1366
1403
|
it("aggregates worktree handoffs across foreground chain groups", { skip: process.platform === "win32" ? "worktree paths differ on Windows" : undefined }, async () => {
|
|
@@ -1450,8 +1487,9 @@ describe("chain execution — parallel steps", { skip: !available ? "pi packages
|
|
|
1450
1487
|
|
|
1451
1488
|
assert.ok(!result.isError);
|
|
1452
1489
|
const finalTask = readCallArgs(2).at(-1) ?? "";
|
|
1453
|
-
assert.match(finalTask, /
|
|
1454
|
-
assert.
|
|
1490
|
+
assert.match(finalTask, /Output saved to: /);
|
|
1491
|
+
assert.doesNotMatch(finalTask, /Alpha named output/);
|
|
1492
|
+
assert.doesNotMatch(finalTask, /Beta named output/);
|
|
1455
1493
|
});
|
|
1456
1494
|
|
|
1457
1495
|
it("funnels an initial parallel step through one agent, then fans the funnel output back out", async () => {
|
|
@@ -1488,13 +1526,14 @@ describe("chain execution — parallel steps", { skip: !available ? "pi packages
|
|
|
1488
1526
|
assert.equal(result.details.totalSteps, 3);
|
|
1489
1527
|
const funnelTask = readCallArgsMatching("Synthesize:").at(-1) ?? "";
|
|
1490
1528
|
assert.match(funnelTask, /=== Parallel Task 1 \(scout-a\) ===/);
|
|
1491
|
-
assert.match(funnelTask, /Scout A findings/);
|
|
1492
1529
|
assert.match(funnelTask, /=== Parallel Task 2 \(scout-b\) ===/);
|
|
1493
|
-
assert.match(funnelTask, /
|
|
1530
|
+
assert.match(funnelTask, /Output saved to: /);
|
|
1531
|
+
assert.doesNotMatch(funnelTask, /Scout A findings/);
|
|
1532
|
+
assert.doesNotMatch(funnelTask, /Scout B findings/);
|
|
1494
1533
|
const fanoutTaskA = readCallArgsMatching("Review funnel A:").at(-1) ?? "";
|
|
1495
1534
|
const fanoutTaskB = readCallArgsMatching("Review funnel B:").at(-1) ?? "";
|
|
1496
|
-
assert.match(fanoutTaskA, /Review funnel A:\
|
|
1497
|
-
assert.match(fanoutTaskB, /Review funnel B:\
|
|
1535
|
+
assert.match(fanoutTaskA, /Review funnel A:\nOutput saved to: /);
|
|
1536
|
+
assert.match(fanoutTaskB, /Review funnel B:\nOutput saved to: /);
|
|
1498
1537
|
assert.equal(result.details.workflowGraph?.nodes[0]?.kind, "parallel-group");
|
|
1499
1538
|
assert.equal(result.details.workflowGraph?.nodes[1]?.kind, "step");
|
|
1500
1539
|
assert.equal(result.details.workflowGraph?.nodes[2]?.kind, "parallel-group");
|
|
@@ -1536,7 +1575,7 @@ describe("chain execution — parallel steps", { skip: !available ? "pi packages
|
|
|
1536
1575
|
makeChainParams(
|
|
1537
1576
|
[{
|
|
1538
1577
|
parallel: [
|
|
1539
|
-
{ agent: "reviewer-a", task: "Review A", outputMode: "file-only" },
|
|
1578
|
+
{ agent: "reviewer-a", task: "Review A", output: false, outputMode: "file-only" },
|
|
1540
1579
|
{ agent: "reviewer-b", task: "Review B", output: "b.md" },
|
|
1541
1580
|
],
|
|
1542
1581
|
}],
|
|
@@ -1700,6 +1739,7 @@ describe("chain execution — parallel steps", { skip: !available ? "pi packages
|
|
|
1700
1739
|
|
|
1701
1740
|
assert.ok(!result.isError);
|
|
1702
1741
|
assert.equal(result.details.results.length, 4);
|
|
1742
|
+
assert.deepEqual(result.details.results.map((row) => row.index), [0, 1, 2, 3]);
|
|
1703
1743
|
assert.equal(result.details.totalSteps, 3);
|
|
1704
1744
|
});
|
|
1705
1745
|
});
|
|
@@ -53,6 +53,18 @@ function assistantToolCall(toolName: string): Record<string, unknown> {
|
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
function emptyTerminalAssistant(): Record<string, unknown> {
|
|
57
|
+
return {
|
|
58
|
+
role: "assistant",
|
|
59
|
+
content: [],
|
|
60
|
+
api: "test",
|
|
61
|
+
provider: "test",
|
|
62
|
+
model: "test",
|
|
63
|
+
stopReason: "stop",
|
|
64
|
+
usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: { total: 0 } },
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
56
68
|
describe("detectSubagentError", { skip: !available ? "utils not importable" : undefined }, () => {
|
|
57
69
|
// ---- Basic detection (must still work) ----
|
|
58
70
|
|
|
@@ -197,6 +209,42 @@ describe("detectSubagentError", { skip: !available ? "utils not importable" : un
|
|
|
197
209
|
"tool-call assistant message without text is not a recovery");
|
|
198
210
|
});
|
|
199
211
|
|
|
212
|
+
it("accepts a successful tool recovery followed by a clean empty terminal stop", () => {
|
|
213
|
+
const messages = [
|
|
214
|
+
toolResult("bash", "error: process exited with code 1", true),
|
|
215
|
+
assistantToolCall("edit"),
|
|
216
|
+
toolResult("edit", "Updated src/file.ts"),
|
|
217
|
+
emptyTerminalAssistant(),
|
|
218
|
+
];
|
|
219
|
+
const result = detectSubagentError(messages);
|
|
220
|
+
assert.equal(result.hasError, false,
|
|
221
|
+
"later successful work plus a clean terminal stop recovers the earlier tool error");
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it("keeps the final failed tool result despite a clean empty terminal stop", () => {
|
|
225
|
+
const messages = [
|
|
226
|
+
toolResult("edit", "Updated src/file.ts"),
|
|
227
|
+
assistantToolCall("bash"),
|
|
228
|
+
toolResult("bash", "error: process exited with code 2", true),
|
|
229
|
+
emptyTerminalAssistant(),
|
|
230
|
+
];
|
|
231
|
+
const result = detectSubagentError(messages);
|
|
232
|
+
assert.equal(result.hasError, true,
|
|
233
|
+
"a clean terminal stop alone cannot recover the final failed tool result");
|
|
234
|
+
assert.equal(result.exitCode, 2);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it("does not recover an earlier tool error after an unsuccessful terminal stop", () => {
|
|
238
|
+
const messages = [
|
|
239
|
+
toolResult("bash", "error: process exited with code 1", true),
|
|
240
|
+
toolResult("edit", "Updated src/file.ts"),
|
|
241
|
+
{ ...emptyTerminalAssistant(), errorMessage: "provider transport failed" },
|
|
242
|
+
];
|
|
243
|
+
const result = detectSubagentError(messages);
|
|
244
|
+
assert.equal(result.hasError, true,
|
|
245
|
+
"the terminal assistant stop must itself be clean");
|
|
246
|
+
});
|
|
247
|
+
|
|
200
248
|
it("does not treat empty/whitespace assistant message as recovery", () => {
|
|
201
249
|
const messages = [
|
|
202
250
|
toolResult("read", "EISDIR: illegal operation on a directory", true),
|
|
@@ -310,7 +310,8 @@ describe("fork context execution wiring", { skip: !available ? "subagent executo
|
|
|
310
310
|
|
|
311
311
|
assert.equal(result.isError, undefined);
|
|
312
312
|
const args = readCallArgs();
|
|
313
|
-
assert.ok((args.at(-1) ?? "").startsWith("Task: \n\n
|
|
313
|
+
assert.ok((args.at(-1) ?? "").startsWith("Task: \n\n---\n**Output:**"));
|
|
314
|
+
assert.match(args.at(-1) ?? "", /## Acceptance Contract/);
|
|
314
315
|
});
|
|
315
316
|
|
|
316
317
|
it("does not treat top-level agent as single mode when tasks are present", async () => {
|
|
@@ -327,7 +328,8 @@ describe("fork context execution wiring", { skip: !available ? "subagent executo
|
|
|
327
328
|
|
|
328
329
|
assert.equal(result.isError, undefined);
|
|
329
330
|
const args = readCallArgs();
|
|
330
|
-
assert.ok((args.at(-1) ?? "").startsWith("Task: parallel task\n\n
|
|
331
|
+
assert.ok((args.at(-1) ?? "").startsWith("Task: parallel task\n\n---\n**Output:**"));
|
|
332
|
+
assert.match(args.at(-1) ?? "", /## Acceptance Contract/);
|
|
331
333
|
});
|
|
332
334
|
|
|
333
335
|
it("uses agent defaultContext fork when launch context is omitted", async () => {
|
|
@@ -1827,7 +1829,7 @@ describe("fork context execution wiring", { skip: !available ? "subagent executo
|
|
|
1827
1829
|
);
|
|
1828
1830
|
|
|
1829
1831
|
assert.equal(result.isError, undefined);
|
|
1830
|
-
const args = readAllCallArgs().find((callArgs) => (callArgs.at(-1) ?? "").startsWith(`Task: ${task}\n\n
|
|
1832
|
+
const args = readAllCallArgs().find((callArgs) => (callArgs.at(-1) ?? "").startsWith(`Task: ${task}\n\n---\n**Output:**`));
|
|
1831
1833
|
assert.ok(args, "expected a recorded mock pi call for this test task");
|
|
1832
1834
|
const modelIndex = args.indexOf("--model");
|
|
1833
1835
|
assert.notEqual(modelIndex, -1);
|
|
@@ -1863,14 +1865,14 @@ describe("fork context execution wiring", { skip: !available ? "subagent executo
|
|
|
1863
1865
|
process.env.USERPROFILE = tempHome;
|
|
1864
1866
|
const worktreeDir = path.join(tempDir, "worktree");
|
|
1865
1867
|
fs.mkdirSync(worktreeDir, { recursive: true });
|
|
1866
|
-
writeProjectOverride(tempDir, "
|
|
1867
|
-
writeProjectOverride(worktreeDir, "
|
|
1868
|
+
writeProjectOverride(tempDir, "commentator", "openai/gpt-5-main");
|
|
1869
|
+
writeProjectOverride(worktreeDir, "commentator", "openai/gpt-5-worktree");
|
|
1868
1870
|
const executor = makeExecutor();
|
|
1869
1871
|
|
|
1870
1872
|
try {
|
|
1871
1873
|
const result = await executor.execute(
|
|
1872
1874
|
"id",
|
|
1873
|
-
{ action: "get", agent: "
|
|
1875
|
+
{ action: "get", agent: "commentator", cwd: "worktree" },
|
|
1874
1876
|
new AbortController().signal,
|
|
1875
1877
|
undefined,
|
|
1876
1878
|
makeCtx(makeSessionManagerRecorder().manager),
|