@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
|
@@ -368,7 +368,7 @@ describe("native subagent fleet", () => {
|
|
|
368
368
|
currentIndex: 1,
|
|
369
369
|
description: "Review the active task",
|
|
370
370
|
activeChildren: new Map([
|
|
371
|
-
[0, { index: 0, agent: "worker", description: "Implement the active task", startedAt: now - 900, updatedAt: now - 100, tokens: 120 }],
|
|
371
|
+
[0, { index: 0, agent: "worker", description: "Implement the active task", startedAt: now - 900, updatedAt: now - 100, tokens: 120, model: "provider/live-model", thinking: "high" }],
|
|
372
372
|
[1, { index: 1, agent: "reviewer", description: "Review the active task", startedAt: now - 800, updatedAt: now, tokens: 240 }],
|
|
373
373
|
]),
|
|
374
374
|
});
|
|
@@ -388,6 +388,7 @@ describe("native subagent fleet", () => {
|
|
|
388
388
|
assert.ok(lines.some((line) => line.includes("worker")));
|
|
389
389
|
assert.ok(lines.some((line) => line.includes("reviewer")));
|
|
390
390
|
assert.ok(lines.some((line) => line.includes("foreground · live")));
|
|
391
|
+
assert.ok(lines.some((line) => line.includes("live-model · thinking high")));
|
|
391
392
|
assert.ok(lines.some((line) => line.includes("Task") && line.includes("Implement the active task")));
|
|
392
393
|
assert.ok(lines.some((line) => line.includes("Conversation") && line.includes("assistant response")));
|
|
393
394
|
assert.ok(lines.some((line) => line.includes("Worker live result")));
|
|
@@ -442,7 +443,7 @@ describe("native subagent fleet", () => {
|
|
|
442
443
|
cwd: baseCwd,
|
|
443
444
|
sessionId: "session-current",
|
|
444
445
|
updatedAt: 200,
|
|
445
|
-
children: [{ agent: "reviewer", index: 0, status: "completed", transcriptPath: recentTranscript }],
|
|
446
|
+
children: [{ agent: "reviewer", index: 0, status: "completed", transcriptPath: recentTranscript, model: "provider/recent-model", thinking: "xhigh" }],
|
|
446
447
|
});
|
|
447
448
|
state.asyncJobs.set(asyncId, {
|
|
448
449
|
asyncId,
|
|
@@ -469,7 +470,11 @@ describe("native subagent fleet", () => {
|
|
|
469
470
|
{ initialKey, refreshMs: 60_000, markdownTheme },
|
|
470
471
|
);
|
|
471
472
|
try {
|
|
472
|
-
|
|
473
|
+
const lines = component.render(100);
|
|
474
|
+
assert.ok(lines.some((line) => line.includes(expected)), `missing ${expected}`);
|
|
475
|
+
if (initialKey.startsWith("foreground-recent:")) {
|
|
476
|
+
assert.ok(lines.some((line) => line.includes("recent-model · thinking xhigh")));
|
|
477
|
+
}
|
|
473
478
|
} finally {
|
|
474
479
|
component.dispose();
|
|
475
480
|
}
|
|
@@ -506,7 +511,7 @@ describe("native subagent fleet", () => {
|
|
|
506
511
|
assert.equal(state.fleetInspectorOpen, false);
|
|
507
512
|
});
|
|
508
513
|
|
|
509
|
-
it("
|
|
514
|
+
it("focuses the selected child and renders raw foreground model details", () => {
|
|
510
515
|
const state = stateForTest();
|
|
511
516
|
state.foregroundControls.set("run-worker", {
|
|
512
517
|
runId: "run-worker",
|
|
@@ -515,6 +520,8 @@ describe("native subagent fleet", () => {
|
|
|
515
520
|
updatedAt: 20,
|
|
516
521
|
currentAgent: "worker",
|
|
517
522
|
currentIndex: 0,
|
|
523
|
+
model: "provider/raw-model",
|
|
524
|
+
thinking: "medium",
|
|
518
525
|
});
|
|
519
526
|
state.foregroundControls.set("run-reviewer", {
|
|
520
527
|
runId: "run-reviewer",
|
|
@@ -524,6 +531,14 @@ describe("native subagent fleet", () => {
|
|
|
524
531
|
currentAgent: "reviewer",
|
|
525
532
|
currentIndex: 0,
|
|
526
533
|
});
|
|
534
|
+
state.foregroundRuns!.set("run-recent", {
|
|
535
|
+
runId: "run-recent",
|
|
536
|
+
mode: "single",
|
|
537
|
+
cwd: process.cwd(),
|
|
538
|
+
sessionId: "session-current",
|
|
539
|
+
updatedAt: 19,
|
|
540
|
+
children: [{ agent: "reviewer", index: 0, status: "completed", model: "provider/recent-raw-model", thinking: "xhigh" }],
|
|
541
|
+
});
|
|
527
542
|
const component = new SubagentFleetComponent(
|
|
528
543
|
{ terminal: { rows: 28, columns: 90 }, requestRender() {} } as never,
|
|
529
544
|
theme as never,
|
|
@@ -532,11 +547,148 @@ describe("native subagent fleet", () => {
|
|
|
532
547
|
{ initialKey: "foreground-active:run-worker:0", refreshMs: 60_000 },
|
|
533
548
|
);
|
|
534
549
|
try {
|
|
535
|
-
const
|
|
550
|
+
const lines = component.render(90);
|
|
551
|
+
const selectedLine = lines.find((line) => line.includes("›"));
|
|
536
552
|
assert.ok(selectedLine?.includes("run-work"), `unexpected selected row: ${selectedLine}`);
|
|
553
|
+
assert.ok(lines.some((line) => line.includes("Model: raw-model · thinking medium")));
|
|
537
554
|
} finally {
|
|
538
555
|
component.dispose();
|
|
539
556
|
}
|
|
557
|
+
|
|
558
|
+
const recentComponent = new SubagentFleetComponent(
|
|
559
|
+
{ terminal: { rows: 28, columns: 90 }, requestRender() {} } as never,
|
|
560
|
+
theme as never,
|
|
561
|
+
state,
|
|
562
|
+
() => {},
|
|
563
|
+
{ initialKey: "foreground-recent:run-recent:0", refreshMs: 60_000 },
|
|
564
|
+
);
|
|
565
|
+
try {
|
|
566
|
+
assert.ok(recentComponent.render(90).some((line) => line.includes("Model: recent-raw-model · thinking xhigh")));
|
|
567
|
+
} finally {
|
|
568
|
+
recentComponent.dispose();
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
it("steers the selected async child with an inline message", async () => {
|
|
573
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-fleet-steer-"));
|
|
574
|
+
try {
|
|
575
|
+
const asyncDir = writeAsyncRun(root, { id: "async-steer", agents: ["worker", "reviewer"] });
|
|
576
|
+
const state = stateForTest();
|
|
577
|
+
const calls: Array<{ runId: string; asyncDir: string; index?: number; message: string }> = [];
|
|
578
|
+
const component = new SubagentFleetComponent(
|
|
579
|
+
{ terminal: { rows: 28, columns: 100 }, requestRender() {} } as never,
|
|
580
|
+
theme as never,
|
|
581
|
+
state,
|
|
582
|
+
() => {},
|
|
583
|
+
{
|
|
584
|
+
asyncDirRoot: root,
|
|
585
|
+
resultsDir: path.join(root, "results"),
|
|
586
|
+
initialKey: "async:async-steer:0",
|
|
587
|
+
refreshMs: 60_000,
|
|
588
|
+
actions: {
|
|
589
|
+
async steer(input) {
|
|
590
|
+
calls.push(input);
|
|
591
|
+
return { text: "Steering queued." };
|
|
592
|
+
},
|
|
593
|
+
stop() {
|
|
594
|
+
return { text: "unused" };
|
|
595
|
+
},
|
|
596
|
+
},
|
|
597
|
+
},
|
|
598
|
+
);
|
|
599
|
+
try {
|
|
600
|
+
component.handleInput("s");
|
|
601
|
+
assert.ok(component.render(100).some((line) => line.includes("Steer message:")));
|
|
602
|
+
for (const char of "please continue") component.handleInput(char);
|
|
603
|
+
component.handleInput("\r");
|
|
604
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
605
|
+
assert.deepEqual(calls, [{ runId: "async-steer", asyncDir, index: 0, message: "please continue" }]);
|
|
606
|
+
assert.ok(component.render(100).some((line) => line.includes("Steering queued.")));
|
|
607
|
+
} finally {
|
|
608
|
+
component.dispose();
|
|
609
|
+
}
|
|
610
|
+
} finally {
|
|
611
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
612
|
+
}
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
it("confirms stop for the selected async child before calling the action", async () => {
|
|
616
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-fleet-stop-"));
|
|
617
|
+
try {
|
|
618
|
+
const asyncDir = writeAsyncRun(root, { id: "async-stop" });
|
|
619
|
+
const state = stateForTest();
|
|
620
|
+
const calls: Array<{ runId: string; asyncDir: string; index?: number }> = [];
|
|
621
|
+
const component = new SubagentFleetComponent(
|
|
622
|
+
{ terminal: { rows: 28, columns: 100 }, requestRender() {} } as never,
|
|
623
|
+
theme as never,
|
|
624
|
+
state,
|
|
625
|
+
() => {},
|
|
626
|
+
{
|
|
627
|
+
asyncDirRoot: root,
|
|
628
|
+
resultsDir: path.join(root, "results"),
|
|
629
|
+
refreshMs: 60_000,
|
|
630
|
+
actions: {
|
|
631
|
+
async steer() {
|
|
632
|
+
return { text: "unused" };
|
|
633
|
+
},
|
|
634
|
+
stop(input) {
|
|
635
|
+
calls.push(input);
|
|
636
|
+
return { text: "Stop requested." };
|
|
637
|
+
},
|
|
638
|
+
},
|
|
639
|
+
},
|
|
640
|
+
);
|
|
641
|
+
try {
|
|
642
|
+
component.handleInput("D");
|
|
643
|
+
assert.ok(component.render(100).some((line) => line.includes("Confirm stop for async run async-stop")));
|
|
644
|
+
component.handleInput("n");
|
|
645
|
+
assert.deepEqual(calls, []);
|
|
646
|
+
component.handleInput("D");
|
|
647
|
+
component.handleInput("y");
|
|
648
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
649
|
+
assert.deepEqual(calls, [{ runId: "async-stop", asyncDir, index: 0 }]);
|
|
650
|
+
assert.ok(component.render(100).some((line) => line.includes("Stop requested.")));
|
|
651
|
+
} finally {
|
|
652
|
+
component.dispose();
|
|
653
|
+
}
|
|
654
|
+
} finally {
|
|
655
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
656
|
+
}
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
it("explains unavailable controls for completed async children", () => {
|
|
660
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-fleet-unavailable-"));
|
|
661
|
+
try {
|
|
662
|
+
writeAsyncRun(root, { id: "async-complete", state: "complete" });
|
|
663
|
+
const state = stateForTest();
|
|
664
|
+
const component = new SubagentFleetComponent(
|
|
665
|
+
{ terminal: { rows: 28, columns: 100 }, requestRender() {} } as never,
|
|
666
|
+
theme as never,
|
|
667
|
+
state,
|
|
668
|
+
() => {},
|
|
669
|
+
{
|
|
670
|
+
asyncDirRoot: root,
|
|
671
|
+
resultsDir: path.join(root, "results"),
|
|
672
|
+
refreshMs: 60_000,
|
|
673
|
+
actions: {
|
|
674
|
+
async steer() {
|
|
675
|
+
return { text: "unused" };
|
|
676
|
+
},
|
|
677
|
+
stop() {
|
|
678
|
+
return { text: "unused" };
|
|
679
|
+
},
|
|
680
|
+
},
|
|
681
|
+
},
|
|
682
|
+
);
|
|
683
|
+
try {
|
|
684
|
+
component.handleInput("s");
|
|
685
|
+
assert.ok(component.render(100).some((line) => line.includes("Selected child is complete")));
|
|
686
|
+
} finally {
|
|
687
|
+
component.dispose();
|
|
688
|
+
}
|
|
689
|
+
} finally {
|
|
690
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
691
|
+
}
|
|
540
692
|
});
|
|
541
693
|
|
|
542
694
|
it("refreshes the roster while the inspector remains open", async () => {
|
|
@@ -552,6 +704,12 @@ describe("native subagent fleet", () => {
|
|
|
552
704
|
() => {},
|
|
553
705
|
{ asyncDirRoot: root, resultsDir: path.join(root, "results"), refreshMs: 10 },
|
|
554
706
|
);
|
|
707
|
+
let invalidations = 0;
|
|
708
|
+
const originalInvalidate = component.invalidate.bind(component);
|
|
709
|
+
component.invalidate = () => {
|
|
710
|
+
invalidations++;
|
|
711
|
+
originalInvalidate();
|
|
712
|
+
};
|
|
555
713
|
try {
|
|
556
714
|
assert.ok(component.render(90).some((line) => line.includes("No tracked children")));
|
|
557
715
|
const initialOutput = Array.from({ length: 40 }, (_, index) => `output line ${index}`).join("\n");
|
|
@@ -565,6 +723,7 @@ describe("native subagent fleet", () => {
|
|
|
565
723
|
lines = component.render(90);
|
|
566
724
|
assert.ok(lines.some((line) => line.includes("LATEST LIVE OUTPUT")), "live transcript should keep following new output");
|
|
567
725
|
assert.ok(renderRequests > 0);
|
|
726
|
+
assert.ok(invalidations > 0, "live refresh must invalidate cached TUI frames before rendering");
|
|
568
727
|
} finally {
|
|
569
728
|
component.dispose();
|
|
570
729
|
}
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import { describe, it } from "node:test";
|
|
3
3
|
import type { AgentProgress, ForegroundRunControl } from "../../src/shared/types.ts";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
beginForegroundChild,
|
|
6
|
+
finishForegroundChild,
|
|
7
|
+
foregroundSchedulingSettled,
|
|
8
|
+
retainForegroundSchedulingOwner,
|
|
9
|
+
settleForegroundSchedulingOwner,
|
|
10
|
+
updateForegroundChild,
|
|
11
|
+
} from "../../src/runs/foreground/foreground-control.ts";
|
|
5
12
|
|
|
6
13
|
function progress(index: number, agent: string, tokens: number): AgentProgress {
|
|
7
14
|
return {
|
|
@@ -13,6 +20,10 @@ function progress(index: number, agent: string, tokens: number): AgentProgress {
|
|
|
13
20
|
recentOutput: [],
|
|
14
21
|
toolCount: index + 1,
|
|
15
22
|
tokens,
|
|
23
|
+
model: "openai/gpt-5.6-terra:high",
|
|
24
|
+
thinking: "high",
|
|
25
|
+
inputTokens: tokens - 20,
|
|
26
|
+
outputTokens: 20,
|
|
16
27
|
durationMs: 10,
|
|
17
28
|
};
|
|
18
29
|
}
|
|
@@ -28,11 +39,13 @@ describe("foreground child control", () => {
|
|
|
28
39
|
};
|
|
29
40
|
let firstInterrupts = 0;
|
|
30
41
|
let secondInterrupts = 0;
|
|
42
|
+
let firstDetaches = 0;
|
|
31
43
|
beginForegroundChild(control, {
|
|
32
44
|
index: 0,
|
|
33
45
|
agent: "reviewer",
|
|
34
46
|
description: "Review correctness",
|
|
35
47
|
interrupt: () => { firstInterrupts++; return true; },
|
|
48
|
+
detach: () => { firstDetaches++; return true; },
|
|
36
49
|
});
|
|
37
50
|
beginForegroundChild(control, {
|
|
38
51
|
index: 1,
|
|
@@ -46,10 +59,16 @@ describe("foreground child control", () => {
|
|
|
46
59
|
updateForegroundChild(control, 0, progress(0, "reviewer", 120));
|
|
47
60
|
assert.equal(control.currentIndex, 0);
|
|
48
61
|
assert.equal(control.tokens, 120);
|
|
62
|
+
assert.equal(control.inputTokens, 100);
|
|
63
|
+
assert.equal(control.outputTokens, 20);
|
|
64
|
+
assert.equal(control.model, "openai/gpt-5.6-terra:high");
|
|
65
|
+
assert.equal(control.thinking, "high");
|
|
49
66
|
assert.equal(control.activeChildren?.get(1)?.tokens, undefined);
|
|
50
67
|
assert.equal(control.interrupt?.(), true);
|
|
51
68
|
assert.equal(firstInterrupts, 1);
|
|
52
69
|
assert.equal(secondInterrupts, 0);
|
|
70
|
+
assert.equal(control.detach?.(), true);
|
|
71
|
+
assert.equal(firstDetaches, 1);
|
|
53
72
|
|
|
54
73
|
updateForegroundChild(control, 1, progress(1, "reviewer", 240));
|
|
55
74
|
finishForegroundChild(control, 1);
|
|
@@ -60,6 +79,27 @@ describe("foreground child control", () => {
|
|
|
60
79
|
finishForegroundChild(control, 0);
|
|
61
80
|
assert.equal(control.activeChildren?.size, 0);
|
|
62
81
|
assert.equal(control.currentIndex, undefined);
|
|
82
|
+
assert.equal(control.model, undefined);
|
|
83
|
+
assert.equal(control.inputTokens, undefined);
|
|
84
|
+
assert.equal(control.outputTokens, undefined);
|
|
63
85
|
assert.equal(control.interrupt, undefined);
|
|
86
|
+
assert.equal(control.detach, undefined);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("settles scheduling only after every owner releases", () => {
|
|
90
|
+
const control: ForegroundRunControl = {
|
|
91
|
+
runId: "owned-run",
|
|
92
|
+
mode: "parallel",
|
|
93
|
+
startedAt: 1,
|
|
94
|
+
updatedAt: 1,
|
|
95
|
+
schedulingOwners: 1,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
retainForegroundSchedulingOwner(control);
|
|
99
|
+
settleForegroundSchedulingOwner(control);
|
|
100
|
+
assert.equal(foregroundSchedulingSettled(control), false);
|
|
101
|
+
settleForegroundSchedulingOwner(control);
|
|
102
|
+
assert.equal(foregroundSchedulingSettled(control), true);
|
|
103
|
+
assert.equal(control.schedulingOwners, 0);
|
|
64
104
|
});
|
|
65
105
|
});
|
|
@@ -60,7 +60,7 @@ describe("subagent extension child mode", () => {
|
|
|
60
60
|
execFileSync(
|
|
61
61
|
process.execPath,
|
|
62
62
|
[
|
|
63
|
-
"--experimental-
|
|
63
|
+
"--experimental-strip-types",
|
|
64
64
|
"--import",
|
|
65
65
|
"./test/support/register-loader.mjs",
|
|
66
66
|
"--input-type=module",
|
|
@@ -104,7 +104,7 @@ describe("subagent extension child mode", () => {
|
|
|
104
104
|
execFileSync(
|
|
105
105
|
process.execPath,
|
|
106
106
|
[
|
|
107
|
-
"--experimental-
|
|
107
|
+
"--experimental-strip-types",
|
|
108
108
|
"--import",
|
|
109
109
|
"./test/support/register-loader.mjs",
|
|
110
110
|
"--input-type=module",
|
|
@@ -155,7 +155,7 @@ describe("subagent extension child mode", () => {
|
|
|
155
155
|
execFileSync(
|
|
156
156
|
process.execPath,
|
|
157
157
|
[
|
|
158
|
-
"--experimental-
|
|
158
|
+
"--experimental-strip-types",
|
|
159
159
|
"--import",
|
|
160
160
|
"./test/support/register-loader.mjs",
|
|
161
161
|
"--input-type=module",
|
|
@@ -207,7 +207,7 @@ describe("subagent extension child mode", () => {
|
|
|
207
207
|
const output = execFileSync(
|
|
208
208
|
process.execPath,
|
|
209
209
|
[
|
|
210
|
-
"--experimental-
|
|
210
|
+
"--experimental-strip-types",
|
|
211
211
|
"--import",
|
|
212
212
|
"./test/support/register-loader.mjs",
|
|
213
213
|
"--input-type=module",
|
|
@@ -328,7 +328,7 @@ describe("subagent extension child mode", () => {
|
|
|
328
328
|
env.SELESAI_CODING_AGENT_DIR = agentDir;
|
|
329
329
|
execFileSync(
|
|
330
330
|
process.execPath,
|
|
331
|
-
["--experimental-
|
|
331
|
+
["--experimental-strip-types", "--import", "./test/support/register-loader.mjs", "--input-type=module", "--eval", script],
|
|
332
332
|
{ cwd: projectRoot, env, stdio: "pipe" },
|
|
333
333
|
);
|
|
334
334
|
} finally {
|
|
@@ -422,7 +422,7 @@ describe("subagent extension child mode", () => {
|
|
|
422
422
|
env.SELESAI_CODING_AGENT_DIR = agentDir;
|
|
423
423
|
execFileSync(
|
|
424
424
|
process.execPath,
|
|
425
|
-
["--experimental-
|
|
425
|
+
["--experimental-strip-types", "--import", "./test/support/register-loader.mjs", "--input-type=module", "--eval", script],
|
|
426
426
|
{ cwd: projectRoot, env, stdio: "pipe" },
|
|
427
427
|
);
|
|
428
428
|
} finally {
|
|
@@ -458,7 +458,7 @@ describe("subagent extension child mode", () => {
|
|
|
458
458
|
execFileSync(
|
|
459
459
|
process.execPath,
|
|
460
460
|
[
|
|
461
|
-
"--experimental-
|
|
461
|
+
"--experimental-strip-types",
|
|
462
462
|
"--import",
|
|
463
463
|
"./test/support/register-loader.mjs",
|
|
464
464
|
"--input-type=module",
|
|
@@ -493,7 +493,7 @@ describe("subagent extension child mode", () => {
|
|
|
493
493
|
execFileSync(
|
|
494
494
|
process.execPath,
|
|
495
495
|
[
|
|
496
|
-
"--experimental-
|
|
496
|
+
"--experimental-strip-types",
|
|
497
497
|
"--import",
|
|
498
498
|
"./test/support/register-loader.mjs",
|
|
499
499
|
"--input-type=module",
|
|
@@ -529,7 +529,7 @@ describe("subagent extension child mode", () => {
|
|
|
529
529
|
execFileSync(
|
|
530
530
|
process.execPath,
|
|
531
531
|
[
|
|
532
|
-
"--experimental-
|
|
532
|
+
"--experimental-strip-types",
|
|
533
533
|
"--import",
|
|
534
534
|
"./test/support/register-loader.mjs",
|
|
535
535
|
"--input-type=module",
|
|
@@ -574,7 +574,7 @@ describe("subagent extension child mode", () => {
|
|
|
574
574
|
execFileSync(
|
|
575
575
|
process.execPath,
|
|
576
576
|
[
|
|
577
|
-
"--experimental-
|
|
577
|
+
"--experimental-strip-types",
|
|
578
578
|
"--import",
|
|
579
579
|
"./test/support/register-loader.mjs",
|
|
580
580
|
"--input-type=module",
|
|
@@ -599,14 +599,19 @@ describe("subagent extension child mode", () => {
|
|
|
599
599
|
};
|
|
600
600
|
registerFanoutChildSubagentExtension(fakePi);
|
|
601
601
|
if (!registeredTool) throw new Error("tool not registered");
|
|
602
|
+
if (registeredTool.promptGuidelines !== undefined) {
|
|
603
|
+
throw new Error("child-safe fanout tool must not carry parent-only routing promptGuidelines");
|
|
604
|
+
}
|
|
602
605
|
const ctx = {
|
|
603
606
|
cwd: process.cwd(),
|
|
604
607
|
hasUI: false,
|
|
605
608
|
sessionManager: { getSessionId() { return "session-test"; }, getSessionFile() { return null; } },
|
|
606
609
|
modelRegistry: { getAvailable() { return []; } },
|
|
607
610
|
};
|
|
608
|
-
const list = await registeredTool.execute("list-check", { action: "list" }, new AbortController().signal, undefined, ctx);
|
|
611
|
+
const list = await registeredTool.execute("list-check", { action: "list", task: "Review only; do not edit files" }, new AbortController().signal, undefined, ctx);
|
|
609
612
|
if (list.isError) throw new Error("list should be allowed: " + JSON.stringify(list.content));
|
|
613
|
+
const listText = list.content?.[0]?.text ?? "";
|
|
614
|
+
if (!listText.includes("Task-aware advisory routing:")) throw new Error("list task advice missing in child mode: " + listText.slice(0, 200));
|
|
610
615
|
const create = await registeredTool.execute("create-check", { action: "create", config: { name: "x" } }, new AbortController().signal, undefined, ctx);
|
|
611
616
|
if (!create.isError) throw new Error("create should be blocked");
|
|
612
617
|
const text = create.content?.[0]?.text ?? "";
|
|
@@ -620,7 +625,7 @@ describe("subagent extension child mode", () => {
|
|
|
620
625
|
execFileSync(
|
|
621
626
|
process.execPath,
|
|
622
627
|
[
|
|
623
|
-
"--experimental-
|
|
628
|
+
"--experimental-strip-types",
|
|
624
629
|
"--import",
|
|
625
630
|
"./test/support/register-loader.mjs",
|
|
626
631
|
"--input-type=module",
|
|
@@ -44,11 +44,15 @@ describe("resolveIntercomBridgeMode", () => {
|
|
|
44
44
|
|
|
45
45
|
describe("resolveIntercomSessionTarget", () => {
|
|
46
46
|
it("prefers an explicit session name", () => {
|
|
47
|
-
assert.equal(resolveIntercomSessionTarget("planner", "session-12345678"), "planner");
|
|
47
|
+
assert.equal(resolveIntercomSessionTarget("planner", "session-12345678", "session-stableabcdef"), "planner");
|
|
48
48
|
});
|
|
49
49
|
|
|
50
50
|
it("uses a runtime-only subagent chat alias when unnamed", () => {
|
|
51
|
-
assert.equal(resolveIntercomSessionTarget(undefined, "session-12345678"), "subagent-chat-12345678");
|
|
51
|
+
assert.equal(resolveIntercomSessionTarget(undefined, "session-12345678", ""), "subagent-chat-12345678");
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("uses the current pi-intercom runtime id for unnamed fallback when present", () => {
|
|
55
|
+
assert.equal(resolveIntercomSessionTarget(undefined, "session-12345678", "session-stableabcdef"), "subagent-chat-stableab");
|
|
52
56
|
});
|
|
53
57
|
});
|
|
54
58
|
|
|
@@ -94,10 +98,21 @@ describe("resolveIntercomBridge", () => {
|
|
|
94
98
|
});
|
|
95
99
|
|
|
96
100
|
assert.equal(bridge.active, true);
|
|
101
|
+
assert.equal(bridge.resultDelivery, true);
|
|
97
102
|
assert.equal(bridge.orchestratorTarget, "main");
|
|
98
103
|
assert.equal(bridge.extensionDir, NATIVE_INTERCOM_EXTENSION_DIR);
|
|
99
104
|
});
|
|
100
105
|
|
|
106
|
+
it("can disable external grouped-result delivery without disabling supervisor coordination", () => {
|
|
107
|
+
const bridge = resolveIntercomBridge({
|
|
108
|
+
config: { mode: "always", resultDelivery: false },
|
|
109
|
+
context: "fresh",
|
|
110
|
+
orchestratorTarget: "main",
|
|
111
|
+
});
|
|
112
|
+
assert.equal(bridge.active, true);
|
|
113
|
+
assert.equal(bridge.resultDelivery, false);
|
|
114
|
+
});
|
|
115
|
+
|
|
101
116
|
it("stays inactive for fresh context when mode is fork-only", () => {
|
|
102
117
|
const bridge = resolveIntercomBridge({
|
|
103
118
|
config: { mode: "fork-only" },
|
|
@@ -144,6 +159,7 @@ describe("applyIntercomBridgeToAgent", () => {
|
|
|
144
159
|
const activeBridge: IntercomBridgeState = {
|
|
145
160
|
active: true,
|
|
146
161
|
mode: "always",
|
|
162
|
+
resultDelivery: true,
|
|
147
163
|
orchestratorTarget: "main",
|
|
148
164
|
extensionDir: NATIVE_INTERCOM_EXTENSION_DIR,
|
|
149
165
|
instruction: "Intercom orchestration channel:\n- Need a decision or blocked: contact_supervisor({ reason: \"need_decision\", message: \"<question>\" })\n- Blocked/update: contact_supervisor({ reason: \"progress_update\", message: \"UPDATE: <summary>\" })",
|
|
@@ -5,7 +5,7 @@ import * as path from "node:path";
|
|
|
5
5
|
import { afterEach, describe, it } from "node:test";
|
|
6
6
|
import registerFanoutChildSubagentExtension from "../../src/extension/fanout-child.ts";
|
|
7
7
|
import { createSubagentExecutor } from "../../src/runs/foreground/subagent-executor.ts";
|
|
8
|
-
import { createNestedRoute, projectNestedEvents, readNestedControlRequests, readNestedControlResults, writeNestedControlRequest, writeNestedControlResult, writeNestedEvent } from "../../src/runs/shared/nested-events.ts";
|
|
8
|
+
import { createNestedRoute, findNestedControlResult, projectNestedEvents, readNestedControlRequests, readNestedControlResults, snapshotNestedEventFiles, writeNestedControlRequest, writeNestedControlResult, writeNestedEvent } from "../../src/runs/shared/nested-events.ts";
|
|
9
9
|
import {
|
|
10
10
|
SUBAGENT_CHILD_ENV,
|
|
11
11
|
SUBAGENT_FANOUT_CHILD_ENV,
|
|
@@ -129,6 +129,25 @@ async function waitFor(predicate: () => boolean, timeoutMs = 1_000): Promise<voi
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
describe("nested control routing", () => {
|
|
132
|
+
it("finds a control result without considering files present before its request", () => {
|
|
133
|
+
const route = createNestedRoute("root-targeted-result");
|
|
134
|
+
routeRoots.push(path.dirname(route.eventSink));
|
|
135
|
+
const requestedAt = Date.now();
|
|
136
|
+
writeNestedControlResult(route, { ts: requestedAt, requestId: "older", targetRunId: "child", ok: true, message: "older result" });
|
|
137
|
+
writeNestedEvent(route, {
|
|
138
|
+
type: "subagent.nested.updated",
|
|
139
|
+
ts: requestedAt + 1,
|
|
140
|
+
parentRunId: route.rootRunId,
|
|
141
|
+
child: { id: "child", parentRunId: route.rootRunId, depth: 1, path: [], state: "running" },
|
|
142
|
+
});
|
|
143
|
+
const ignoredFiles = snapshotNestedEventFiles(route);
|
|
144
|
+
writeNestedControlResult(route, { ts: requestedAt - 1, requestId: "target", targetRunId: "child", ok: true, message: "target result" });
|
|
145
|
+
|
|
146
|
+
assert.equal(findNestedControlResult(route, "target", "child", ignoredFiles)?.message, "target result");
|
|
147
|
+
assert.equal(findNestedControlResult(route, "older", "child", ignoredFiles), undefined);
|
|
148
|
+
assert.equal(readNestedControlResults(route).length, 2);
|
|
149
|
+
});
|
|
150
|
+
|
|
132
151
|
it("routes interrupt to an explicit nested id through the control inbox", async () => {
|
|
133
152
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-nested-control-"));
|
|
134
153
|
try {
|
|
@@ -157,14 +157,18 @@ describe("nested event parsing and projection", () => {
|
|
|
157
157
|
ts: 200,
|
|
158
158
|
parentRunId: "root-run",
|
|
159
159
|
parentStepIndex: 1,
|
|
160
|
-
child: {
|
|
160
|
+
child: {
|
|
161
|
+
...child("nested-a", "running", 200),
|
|
162
|
+
currentTool: "read",
|
|
163
|
+
runtimeAcknowledgedExtensions: { version: 1, source: "child-runtime", ids: ["ext.ok", "bad/path", "ext.ok"], omitted: 1 },
|
|
164
|
+
},
|
|
161
165
|
});
|
|
162
166
|
writeNestedEvent(route, {
|
|
163
167
|
type: "subagent.nested.completed",
|
|
164
168
|
ts: 300,
|
|
165
169
|
parentRunId: "root-run",
|
|
166
170
|
parentStepIndex: 1,
|
|
167
|
-
child: child("nested-a", "complete", 300),
|
|
171
|
+
child: { ...child("nested-a", "complete", 300), runtimeAcknowledgedExtensions: { version: 1, source: "child-runtime", ids: ["ext.ok", "bad/path", "ext.ok"], omitted: 1 } },
|
|
168
172
|
});
|
|
169
173
|
|
|
170
174
|
const registry = projectNestedEvents(route);
|
|
@@ -172,6 +176,12 @@ describe("nested event parsing and projection", () => {
|
|
|
172
176
|
assert.equal(registry.children[0]?.id, "nested-a");
|
|
173
177
|
assert.equal(registry.children[0]?.state, "complete");
|
|
174
178
|
assert.equal(registry.children[0]?.steps?.[0]?.agent, "leaf");
|
|
179
|
+
assert.deepEqual(registry.children[0]?.runtimeAcknowledgedExtensions, {
|
|
180
|
+
version: 1,
|
|
181
|
+
source: "child-runtime",
|
|
182
|
+
ids: ["ext.ok"],
|
|
183
|
+
omitted: 1,
|
|
184
|
+
});
|
|
175
185
|
|
|
176
186
|
const job: AsyncJobState = {
|
|
177
187
|
asyncId: "root-run",
|
|
@@ -349,6 +359,24 @@ describe("nested event parsing and projection", () => {
|
|
|
349
359
|
assert.equal(summary.steps?.[0]?.processTerminal?.reason, "proof-write-failed");
|
|
350
360
|
});
|
|
351
361
|
|
|
362
|
+
it("sanitizes runtime acknowledged extensions in nested status summaries", () => {
|
|
363
|
+
const summary = nestedSummaryFromAsyncStatus({
|
|
364
|
+
runId: "child-run",
|
|
365
|
+
mode: "single",
|
|
366
|
+
state: "complete",
|
|
367
|
+
startedAt: 1,
|
|
368
|
+
runtimeAcknowledgedExtensions: { version: 1, source: "child-runtime", ids: ["/Users/alice/.secret-extension", "ok-ext", "x".repeat(5000)], omitted: 0 } as never,
|
|
369
|
+
steps: [{
|
|
370
|
+
agent: "worker",
|
|
371
|
+
status: "complete",
|
|
372
|
+
runtimeAcknowledgedExtensions: { version: 1, source: "child-runtime", ids: ["C:/Users/alice/secret"], omitted: 0 } as never,
|
|
373
|
+
}],
|
|
374
|
+
}, "/tmp/child-run", { id: "child-run", parentRunId: "parent-run", depth: 1, mode: "single", ts: 2 });
|
|
375
|
+
|
|
376
|
+
assert.deepEqual(summary.runtimeAcknowledgedExtensions?.ids, ["ok-ext"]);
|
|
377
|
+
assert.equal(summary.steps?.[0]?.runtimeAcknowledgedExtensions, undefined);
|
|
378
|
+
});
|
|
379
|
+
|
|
352
380
|
it("removes evicted status files without replaying completed children", () => {
|
|
353
381
|
const route = trackRoute();
|
|
354
382
|
for (let index = 0; index < 1000; index++) {
|
|
@@ -140,6 +140,12 @@ describe("registerSubagentNotify", () => {
|
|
|
140
140
|
assert.equal(sent.length, 1);
|
|
141
141
|
});
|
|
142
142
|
|
|
143
|
+
it("suppresses local delivery after an acknowledged grouped intercom relay", async () => {
|
|
144
|
+
const { notifier, sent } = createPi("session-a");
|
|
145
|
+
assert.equal(await notifier.deliver(completionResult({ id: "intercom-delivered", intercomDelivered: true })), true);
|
|
146
|
+
assert.equal(sent.length, 0);
|
|
147
|
+
});
|
|
148
|
+
|
|
143
149
|
it("rejects a pending batch when the notifier is disposed", async () => {
|
|
144
150
|
const clock = createFakeClock();
|
|
145
151
|
const { notifier, sent } = createBatchingPi(clock);
|
|
@@ -466,10 +472,12 @@ describe("completion formatting helpers", () => {
|
|
|
466
472
|
notifier.dispose();
|
|
467
473
|
});
|
|
468
474
|
|
|
469
|
-
it("buildCompletionDetails derives paused
|
|
475
|
+
it("buildCompletionDetails derives paused and stopped statuses", () => {
|
|
470
476
|
assert.equal(buildCompletionDetails({ id: "x", agent: "w", success: false, state: "paused", summary: "Paused after interrupt.", timestamp: 1 }).status, "paused");
|
|
471
477
|
assert.equal(buildCompletionDetails({ id: "x", agent: "w", success: false, summary: "boom", exitCode: 1, timestamp: 1 }).status, "failed");
|
|
472
|
-
assert.equal(buildCompletionDetails({ id: "x", agent: "w", success:
|
|
478
|
+
assert.equal(buildCompletionDetails({ id: "x", agent: "w", success: false, summary: "terminated", exitCode: 1, processSignal: "SIGTERM", timestamp: 1 }).status, "stopped");
|
|
479
|
+
assert.equal(buildCompletionDetails({ id: "x", agent: "w", success: false, summary: "terminated", results: [{ success: false, exitCode: 1, processSignal: "SIGTERM" }], timestamp: 1 }).status, "stopped");
|
|
480
|
+
assert.equal(buildCompletionDetails({ id: "x", agent: "w", success: true, summary: "ok", exitCode: 0, processSignal: "SIGTERM", timestamp: 1 }).status, "completed");
|
|
473
481
|
});
|
|
474
482
|
|
|
475
483
|
it("buildCompletionDetails falls back to the unknown agent label", () => {
|
|
@@ -477,4 +485,33 @@ describe("completion formatting helpers", () => {
|
|
|
477
485
|
assert.equal(details.agent, "unknown");
|
|
478
486
|
assert.equal(details.status, "completed");
|
|
479
487
|
});
|
|
488
|
+
|
|
489
|
+
it("buildCompletionDetails prefers compact child summaries over the run summary", () => {
|
|
490
|
+
const details = buildCompletionDetails({
|
|
491
|
+
id: "x",
|
|
492
|
+
agent: "worker",
|
|
493
|
+
success: true,
|
|
494
|
+
summary: "alpha:\nfull child prose that must not leak",
|
|
495
|
+
timestamp: 1,
|
|
496
|
+
results: [
|
|
497
|
+
{ agent: "alpha", status: "completed", summary: "Output saved to: /tmp/alpha.md (12 B, 1 line). Read this file if needed." },
|
|
498
|
+
{ agent: "beta", status: "failed", summary: "boom\n\nOutput saved to: /tmp/beta.md (5 B, 1 line). Read this file if needed." },
|
|
499
|
+
],
|
|
500
|
+
});
|
|
501
|
+
assert.match(details.resultPreview, /1\. alpha\nOutput saved to: \/tmp\/alpha\.md/);
|
|
502
|
+
assert.match(details.resultPreview, /2\. beta\nboom\n\nOutput saved to: \/tmp\/beta\.md/);
|
|
503
|
+
assert.doesNotMatch(details.resultPreview, /full child prose that must not leak/);
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
it("buildCompletionDetails uses the single child summary without an index prefix", () => {
|
|
507
|
+
const details = buildCompletionDetails({
|
|
508
|
+
id: "x",
|
|
509
|
+
agent: "worker",
|
|
510
|
+
success: true,
|
|
511
|
+
summary: "ignored run summary",
|
|
512
|
+
timestamp: 1,
|
|
513
|
+
results: [{ agent: "worker", status: "completed", summary: "Output saved to: /tmp/out.md (8 B, 1 line). Read this file if needed." }],
|
|
514
|
+
});
|
|
515
|
+
assert.equal(details.resultPreview, "Output saved to: /tmp/out.md (8 B, 1 line). Read this file if needed.");
|
|
516
|
+
});
|
|
480
517
|
});
|
|
@@ -153,6 +153,28 @@ describe("mapConcurrent", () => {
|
|
|
153
153
|
assert.ok(d2 < 20, `worker 2 should start immediately, got ${d2}ms delay`);
|
|
154
154
|
});
|
|
155
155
|
|
|
156
|
+
it("notifies scheduling settlement only after workers outliving an early rejection stop", async () => {
|
|
157
|
+
let release!: () => void;
|
|
158
|
+
const gate = new Promise<void>((resolve) => { release = resolve; });
|
|
159
|
+
const started: number[] = [];
|
|
160
|
+
let schedulingSettled = false;
|
|
161
|
+
const run = mapConcurrent([0, 1, 2], 2, async (item) => {
|
|
162
|
+
started.push(item);
|
|
163
|
+
if (item === 0) throw new Error("early rejection");
|
|
164
|
+
await gate;
|
|
165
|
+
return item;
|
|
166
|
+
}, undefined, () => { schedulingSettled = true; });
|
|
167
|
+
|
|
168
|
+
await assert.rejects(run, /early rejection/);
|
|
169
|
+
assert.equal(schedulingSettled, false);
|
|
170
|
+
release();
|
|
171
|
+
for (let attempt = 0; attempt < 20 && !schedulingSettled; attempt++) {
|
|
172
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
173
|
+
}
|
|
174
|
+
assert.equal(schedulingSettled, true);
|
|
175
|
+
assert.deepEqual(started, [0, 1, 2]);
|
|
176
|
+
});
|
|
177
|
+
|
|
156
178
|
it("respects a shared global semaphore across simultaneous calls", async () => {
|
|
157
179
|
const globalSemaphore = new Semaphore(2);
|
|
158
180
|
let running = 0;
|