@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
|
@@ -520,10 +520,10 @@ describe("slash command custom message delivery", { skip: !available ? "slash-co
|
|
|
520
520
|
|
|
521
521
|
const ctx = createCommandContext({ sessionManager });
|
|
522
522
|
registerSlashCommands!(pi, createState(process.cwd()));
|
|
523
|
-
await commands.get("run")!.handler("
|
|
523
|
+
await commands.get("run")!.handler("explorer", ctx);
|
|
524
524
|
await new Promise<void>((resolve) => setImmediate(resolve));
|
|
525
525
|
|
|
526
|
-
assert.deepEqual(requestedParams, { agent: "
|
|
526
|
+
assert.deepEqual(requestedParams, { agent: "explorer", task: "", clarify: false, agentScope: "both" });
|
|
527
527
|
assert.equal(requestedCtx, ctx);
|
|
528
528
|
assert.equal(sent.length, 2);
|
|
529
529
|
assert.equal((sent[0] as { display?: boolean }).display, true);
|
|
@@ -565,7 +565,7 @@ describe("slash command custom message delivery", { skip: !available ? "slash-co
|
|
|
565
565
|
};
|
|
566
566
|
|
|
567
567
|
registerSlashCommands!(pi, createState(process.cwd()));
|
|
568
|
-
await commands.get("run")!.handler("
|
|
568
|
+
await commands.get("run")!.handler("explorer inspect this", createCommandContext({
|
|
569
569
|
hasUI: true,
|
|
570
570
|
setStatus: (_key, text) => {
|
|
571
571
|
log.push(`status:${text ?? "clear"}`);
|
|
@@ -615,7 +615,7 @@ describe("slash command custom message delivery", { skip: !available ? "slash-co
|
|
|
615
615
|
};
|
|
616
616
|
|
|
617
617
|
registerSlashCommands!(pi, createState(process.cwd()));
|
|
618
|
-
await commands.get("run")!.handler("
|
|
618
|
+
await commands.get("run")!.handler("explorer inspect this", createCommandContext({
|
|
619
619
|
hasUI: true,
|
|
620
620
|
setToolsExpanded: (expanded) => log.push(`expanded:${String(expanded)}`),
|
|
621
621
|
}));
|
|
@@ -655,7 +655,7 @@ describe("slash command custom message delivery", { skip: !available ? "slash-co
|
|
|
655
655
|
};
|
|
656
656
|
|
|
657
657
|
registerSlashCommands!(pi, createState(process.cwd()));
|
|
658
|
-
await commands.get("run")!.handler("
|
|
658
|
+
await commands.get("run")!.handler("explorer inspect this", createCommandContext({
|
|
659
659
|
hasUI: true,
|
|
660
660
|
setStatus: (_key, text) => {
|
|
661
661
|
log.push(`status:${text ?? "clear"}`);
|
|
@@ -706,10 +706,10 @@ describe("slash command custom message delivery", { skip: !available ? "slash-co
|
|
|
706
706
|
};
|
|
707
707
|
|
|
708
708
|
registerSlashCommands!(pi, createState(process.cwd()));
|
|
709
|
-
await commands.get("parallel")!.handler("
|
|
709
|
+
await commands.get("parallel")!.handler("explorer[output=x.md,outputMode=file-only,reads=a.md+b.md,progress] -- Review", createCommandContext());
|
|
710
710
|
|
|
711
711
|
assert.deepEqual(requestedParams, {
|
|
712
|
-
tasks: [{ agent: "
|
|
712
|
+
tasks: [{ agent: "explorer", task: "Review", output: "x.md", outputMode: "file-only", reads: ["a.md", "b.md"], progress: true }],
|
|
713
713
|
clarify: false,
|
|
714
714
|
agentScope: "both",
|
|
715
715
|
});
|
|
@@ -746,7 +746,7 @@ describe("slash command custom message delivery", { skip: !available ? "slash-co
|
|
|
746
746
|
};
|
|
747
747
|
|
|
748
748
|
registerSlashCommands!(pi, createState(process.cwd()));
|
|
749
|
-
const args = Array.from({ length: 9 }, (_, index) => `
|
|
749
|
+
const args = Array.from({ length: 9 }, (_, index) => `explorer \"task ${index + 1}\"`).join(" -> ");
|
|
750
750
|
await commands.get("parallel")!.handler(args, createCommandContext());
|
|
751
751
|
await new Promise<void>((resolve) => setImmediate(resolve));
|
|
752
752
|
|
|
@@ -1271,8 +1271,8 @@ describe("subagents-models slash command", { skip: !available ? "slash-commands.
|
|
|
1271
1271
|
});
|
|
1272
1272
|
|
|
1273
1273
|
it("passes an optional builtin filter", async () => {
|
|
1274
|
-
const { params } = await captureSlashCommandParams("subagents-models", "
|
|
1275
|
-
assert.deepEqual(params, { action: "models", agent: "
|
|
1274
|
+
const { params } = await captureSlashCommandParams("subagents-models", "explorer", process.cwd());
|
|
1275
|
+
assert.deepEqual(params, { action: "models", agent: "explorer" });
|
|
1276
1276
|
});
|
|
1277
1277
|
|
|
1278
1278
|
it("rejects invalid builtin filters without launching", async () => {
|
|
@@ -1294,8 +1294,8 @@ describe("subagents-models slash command", { skip: !available ? "slash-commands.
|
|
|
1294
1294
|
};
|
|
1295
1295
|
|
|
1296
1296
|
registerSlashCommands!(pi, createState(process.cwd()));
|
|
1297
|
-
const completions = commands.get("subagents-models")!.getArgumentCompletions!("
|
|
1298
|
-
assert.deepEqual(completions.map((completion) => completion.value), ["
|
|
1297
|
+
const completions = commands.get("subagents-models")!.getArgumentCompletions!("ex") as Array<{ value: string; label: string }>;
|
|
1298
|
+
assert.deepEqual(completions.map((completion) => completion.value), ["explorer"]);
|
|
1299
1299
|
});
|
|
1300
1300
|
});
|
|
1301
1301
|
});
|
|
@@ -1421,7 +1421,7 @@ describe("subagent profiles slash commands", { skip: !available ? "slash-command
|
|
|
1421
1421
|
const profilesDir = path.join(process.env.HOME!, ".selesai", "agent", "profiles", "pi-subagents");
|
|
1422
1422
|
fs.mkdirSync(profilesDir, { recursive: true });
|
|
1423
1423
|
fs.writeFileSync(path.join(profilesDir, "openai-codex.quota.json"), JSON.stringify({
|
|
1424
|
-
subagents: { agentOverrides: {
|
|
1424
|
+
subagents: { agentOverrides: { builder: { model: "gpt-5.4:high" } } },
|
|
1425
1425
|
}, null, 2));
|
|
1426
1426
|
const sent: unknown[] = [];
|
|
1427
1427
|
const commands = new Map<string, RegisteredSlashCommand>();
|
|
@@ -1593,7 +1593,7 @@ describe("subagents admin slash command", { skip: !available ? "slash-commands.t
|
|
|
1593
1593
|
notify: (message) => notifications.push(message),
|
|
1594
1594
|
}));
|
|
1595
1595
|
|
|
1596
|
-
await commands.get("subagents")!.handler("
|
|
1596
|
+
await commands.get("subagents")!.handler("builder model", createCommandContext({
|
|
1597
1597
|
cwd: root,
|
|
1598
1598
|
hasUI: true,
|
|
1599
1599
|
modelRegistry: { getAvailable: () => [{ provider: "test", id: "new-model", reasoning: true }] },
|
|
@@ -1611,13 +1611,13 @@ describe("subagents admin slash command", { skip: !available ? "slash-commands.t
|
|
|
1611
1611
|
it("reports duplicate names as ambiguous without UI", async () => {
|
|
1612
1612
|
await withIsolatedHome(async () => {
|
|
1613
1613
|
await withTempProject("pi-subagents-admin-ambiguous-", async (root) => {
|
|
1614
|
-
fs.writeFileSync(path.join(root, ".selesai", "agents", "
|
|
1614
|
+
fs.writeFileSync(path.join(root, ".selesai", "agents", "builder.md"), "---\nname: builder\ndescription: Project builder\n---\n\nWork.\n", "utf-8");
|
|
1615
1615
|
const sent: unknown[] = [];
|
|
1616
1616
|
const commands = registerAdmin(sent);
|
|
1617
|
-
await commands.get("subagents")!.handler("
|
|
1617
|
+
await commands.get("subagents")!.handler("builder", createCommandContext({ cwd: root }));
|
|
1618
1618
|
assert.equal(sent.length, 1);
|
|
1619
1619
|
const content = (sent[0] as { content?: string }).content ?? "";
|
|
1620
|
-
assert.match(content, /Subagent '
|
|
1620
|
+
assert.match(content, /Subagent 'builder' is ambiguous/);
|
|
1621
1621
|
assert.match(content, /project:/);
|
|
1622
1622
|
assert.match(content, /builtin:/);
|
|
1623
1623
|
});
|
|
@@ -1729,7 +1729,7 @@ describe("subagents admin slash command", { skip: !available ? "slash-commands.t
|
|
|
1729
1729
|
fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
|
|
1730
1730
|
fs.writeFileSync(settingsPath, JSON.stringify({ subagents: { disableThinking: true } }, null, 2), "utf-8");
|
|
1731
1731
|
const commands = registerAdmin([]);
|
|
1732
|
-
await commands.get("subagents")!.handler("
|
|
1732
|
+
await commands.get("subagents")!.handler("builder model", createCommandContext({
|
|
1733
1733
|
cwd: root,
|
|
1734
1734
|
hasUI: true,
|
|
1735
1735
|
modelRegistry: { getAvailable: () => [{ provider: "test", id: "new-model", reasoning: true }] },
|
|
@@ -1738,7 +1738,7 @@ describe("subagents admin slash command", { skip: !available ? "slash-commands.t
|
|
|
1738
1738
|
|
|
1739
1739
|
assert.deepEqual(JSON.parse(fs.readFileSync(settingsPath, "utf-8")).subagents, {
|
|
1740
1740
|
disableThinking: true,
|
|
1741
|
-
agentOverrides: {
|
|
1741
|
+
agentOverrides: { builder: { model: "test/new-model" } },
|
|
1742
1742
|
});
|
|
1743
1743
|
});
|
|
1744
1744
|
});
|
|
@@ -2063,7 +2063,7 @@ describe("subagents-doctor slash command", { skip: !available ? "slash-commands.
|
|
|
2063
2063
|
|
|
2064
2064
|
assert.equal(opened, 2);
|
|
2065
2065
|
assert.match(rendered, /Subagent fleet/);
|
|
2066
|
-
assert.match(rendered, /
|
|
2066
|
+
assert.match(rendered, /live controls/);
|
|
2067
2067
|
});
|
|
2068
2068
|
|
|
2069
2069
|
it("routes subagents-stop with an id directly to the stop action", async () => {
|
|
@@ -2071,6 +2071,66 @@ describe("subagents-doctor slash command", { skip: !available ? "slash-commands.
|
|
|
2071
2071
|
assert.deepEqual(params, { action: "stop", id: "run-123" });
|
|
2072
2072
|
});
|
|
2073
2073
|
|
|
2074
|
+
it("detaches the latest active foreground single run without terminating it", async () => {
|
|
2075
|
+
const commands = new Map<string, RegisteredSlashCommand>();
|
|
2076
|
+
const sent: unknown[] = [];
|
|
2077
|
+
const state = createState(process.cwd());
|
|
2078
|
+
let detached = 0;
|
|
2079
|
+
state.foregroundControls.set("foreground-single", {
|
|
2080
|
+
runId: "foreground-single",
|
|
2081
|
+
mode: "single",
|
|
2082
|
+
startedAt: 1,
|
|
2083
|
+
updatedAt: 2,
|
|
2084
|
+
detach: () => { detached++; return true; },
|
|
2085
|
+
});
|
|
2086
|
+
state.foregroundControls.set("newer-parallel", {
|
|
2087
|
+
runId: "newer-parallel",
|
|
2088
|
+
mode: "parallel",
|
|
2089
|
+
startedAt: 2,
|
|
2090
|
+
updatedAt: 3,
|
|
2091
|
+
});
|
|
2092
|
+
state.lastForegroundControlId = "newer-parallel";
|
|
2093
|
+
registerSlashCommands!({
|
|
2094
|
+
events: createEventBus(),
|
|
2095
|
+
registerCommand(name: string, spec: RegisteredSlashCommand) { commands.set(name, spec); },
|
|
2096
|
+
registerShortcut() {},
|
|
2097
|
+
sendMessage(message: unknown) { sent.push(message); },
|
|
2098
|
+
}, state);
|
|
2099
|
+
|
|
2100
|
+
await commands.get("subagents-detach")!.handler("", createCommandContext());
|
|
2101
|
+
|
|
2102
|
+
assert.equal(detached, 1);
|
|
2103
|
+
const content = String((sent[0] as { content?: unknown }).content ?? "");
|
|
2104
|
+
assert.match(content, /Detached foreground run foreground-single without terminating its child/);
|
|
2105
|
+
assert.match(content, /does not daemonize the process or guarantee survival across Pi reload\/restart/);
|
|
2106
|
+
});
|
|
2107
|
+
|
|
2108
|
+
it("reports missing and unsupported foreground detach targets", async () => {
|
|
2109
|
+
const commands = new Map<string, RegisteredSlashCommand>();
|
|
2110
|
+
const notifications: string[] = [];
|
|
2111
|
+
const state = createState(process.cwd());
|
|
2112
|
+
state.foregroundControls.set("parallel-run", {
|
|
2113
|
+
runId: "parallel-run",
|
|
2114
|
+
mode: "parallel",
|
|
2115
|
+
startedAt: 1,
|
|
2116
|
+
updatedAt: 1,
|
|
2117
|
+
detach: () => true,
|
|
2118
|
+
});
|
|
2119
|
+
registerSlashCommands!({
|
|
2120
|
+
events: createEventBus(),
|
|
2121
|
+
registerCommand(name: string, spec: RegisteredSlashCommand) { commands.set(name, spec); },
|
|
2122
|
+
registerShortcut() {},
|
|
2123
|
+
sendMessage() {},
|
|
2124
|
+
}, state);
|
|
2125
|
+
const ctx = createCommandContext({ notify: (message) => notifications.push(message) });
|
|
2126
|
+
|
|
2127
|
+
await commands.get("subagents-detach")!.handler("missing", ctx);
|
|
2128
|
+
await commands.get("subagents-detach")!.handler("parallel", ctx);
|
|
2129
|
+
|
|
2130
|
+
assert.match(notifications[0] ?? "", /No active foreground run found for 'missing'/);
|
|
2131
|
+
assert.match(notifications[1] ?? "", /currently supports single-subagent runs only/);
|
|
2132
|
+
});
|
|
2133
|
+
|
|
2074
2134
|
it("prints exact stop commands when subagents-stop has no UI", async () => {
|
|
2075
2135
|
await withIsolatedHome(async () => {
|
|
2076
2136
|
const runId = `slash-stop-${Date.now().toString(36)}`;
|
|
@@ -2162,6 +2222,17 @@ describe("subagents-doctor slash command", { skip: !available ? "slash-commands.
|
|
|
2162
2222
|
cwd: root,
|
|
2163
2223
|
sessionId: "session-test",
|
|
2164
2224
|
jobs: [{
|
|
2225
|
+
id: "job-1",
|
|
2226
|
+
name: "early scout",
|
|
2227
|
+
schedule: "+5m",
|
|
2228
|
+
runAt: Date.now() + 300_000,
|
|
2229
|
+
state: "scheduled",
|
|
2230
|
+
createdAt: Date.now(),
|
|
2231
|
+
updatedAt: Date.now(),
|
|
2232
|
+
cwd: root,
|
|
2233
|
+
sessionId: "session-test",
|
|
2234
|
+
params: { agent: "scout", task: "soon", async: true },
|
|
2235
|
+
}, {
|
|
2165
2236
|
id: "job-2",
|
|
2166
2237
|
name: "delayed worker",
|
|
2167
2238
|
schedule: "+10m",
|
|
@@ -2200,9 +2271,27 @@ describe("subagents-doctor slash command", { skip: !available ? "slash-commands.
|
|
|
2200
2271
|
await commands.get("subagents-stop")!.handler("", createCommandContext({
|
|
2201
2272
|
cwd: root,
|
|
2202
2273
|
hasUI: true,
|
|
2203
|
-
custom: async () => ({
|
|
2204
|
-
|
|
2205
|
-
|
|
2274
|
+
custom: async (...args: unknown[]) => new Promise((resolve) => {
|
|
2275
|
+
const factory = args[0] as (
|
|
2276
|
+
tui: { requestRender(): void },
|
|
2277
|
+
theme: { fg(key: string, text: string): string; bold(text: string): string },
|
|
2278
|
+
keybindings: unknown,
|
|
2279
|
+
done: (result: unknown) => void,
|
|
2280
|
+
) => { handleInput(data: string): void; render(width: number): string[] };
|
|
2281
|
+
const component = factory(
|
|
2282
|
+
{ requestRender() {} },
|
|
2283
|
+
{ fg(_key, text) { return text; }, bold(text) { return text; } },
|
|
2284
|
+
{},
|
|
2285
|
+
resolve,
|
|
2286
|
+
);
|
|
2287
|
+
assert.match(component.render(84).join("\n"), /↑↓\/jk select/);
|
|
2288
|
+
component.handleInput("j");
|
|
2289
|
+
assert.ok(component.render(84).some((line) => line.startsWith("›") && line.includes("job-2")));
|
|
2290
|
+
component.handleInput("k");
|
|
2291
|
+
assert.ok(component.render(84).some((line) => line.startsWith("›") && line.includes("job-1")));
|
|
2292
|
+
component.handleInput("j");
|
|
2293
|
+
component.handleInput("\r");
|
|
2294
|
+
component.handleInput("y");
|
|
2206
2295
|
}),
|
|
2207
2296
|
}));
|
|
2208
2297
|
|
|
@@ -185,6 +185,14 @@ function writeStructuredOutputCapture(response) {
|
|
|
185
185
|
fs.writeFileSync(outputPath, JSON.stringify(response.structuredOutputCapture), "utf-8");
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
function writeRuntimeAcknowledgedExtensions(response) {
|
|
189
|
+
if (!Object.prototype.hasOwnProperty.call(response, "runtimeAcknowledgedExtensions")) return;
|
|
190
|
+
const outputPath = process.env.SELESAI_SUBAGENT_RUNTIME_ACKNOWLEDGED_EXTENSIONS;
|
|
191
|
+
if (!outputPath) return;
|
|
192
|
+
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
193
|
+
fs.writeFileSync(outputPath, JSON.stringify(response.runtimeAcknowledgedExtensions), "utf-8");
|
|
194
|
+
}
|
|
195
|
+
|
|
188
196
|
function writeToolDiagnostic(response) {
|
|
189
197
|
if (!Array.isArray(response.missingTools) || response.missingTools.length === 0) return;
|
|
190
198
|
const diagnosticPath = process.env.SELESAI_SUBAGENT_TOOL_DIAGNOSTIC_PATH;
|
|
@@ -327,11 +335,10 @@ async function main() {
|
|
|
327
335
|
}
|
|
328
336
|
writeSessionFile(args);
|
|
329
337
|
writeToolDiagnostic(response);
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
);
|
|
338
|
+
const callPath = path.join(queueDir, `call-${Date.now()}-${process.pid}-${Math.random().toString(16).slice(2)}.json`);
|
|
339
|
+
const callTempPath = `${callPath}.tmp-${process.pid}-${Date.now()}`;
|
|
340
|
+
fs.writeFileSync(callTempPath, JSON.stringify({ args, systemPrompts: readSystemPromptRecords(args) }), "utf-8");
|
|
341
|
+
fs.renameSync(callTempPath, callPath);
|
|
335
342
|
|
|
336
343
|
if (typeof response.delay === "number" && response.delay > 0) {
|
|
337
344
|
await new Promise((resolve) => setTimeout(resolve, response.delay));
|
|
@@ -346,6 +353,7 @@ async function main() {
|
|
|
346
353
|
|
|
347
354
|
writeDeclaredFiles(response);
|
|
348
355
|
writeStructuredOutputCapture(response);
|
|
356
|
+
writeRuntimeAcknowledgedExtensions(response);
|
|
349
357
|
|
|
350
358
|
if (Array.isArray(response.steps) && response.steps.length > 0) {
|
|
351
359
|
for (const step of response.steps) {
|
|
@@ -384,6 +392,10 @@ async function main() {
|
|
|
384
392
|
await new Promise((resolve) => setTimeout(resolve, response.keepAliveAfterFinalMessageMs));
|
|
385
393
|
}
|
|
386
394
|
|
|
395
|
+
if (typeof response.signal === "string") {
|
|
396
|
+
process.kill(process.pid, response.signal);
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
387
399
|
exitAfterFlush(typeof response.exitCode === "number" ? response.exitCode : 0);
|
|
388
400
|
}
|
|
389
401
|
|
|
@@ -7,6 +7,7 @@ interface MockPiResponse {
|
|
|
7
7
|
output?: string;
|
|
8
8
|
stderr?: string;
|
|
9
9
|
exitCode?: number;
|
|
10
|
+
signal?: NodeJS.Signals;
|
|
10
11
|
delay?: number;
|
|
11
12
|
waitForPath?: string;
|
|
12
13
|
keepAliveAfterFinalMessageMs?: number;
|
|
@@ -28,6 +29,7 @@ interface MockPiResponse {
|
|
|
28
29
|
writeFiles?: Array<{ path: string; content: string }>;
|
|
29
30
|
/** Writes the structured-output capture file without emitting a structured_output tool event. */
|
|
30
31
|
structuredOutputCapture?: unknown;
|
|
32
|
+
runtimeAcknowledgedExtensions?: unknown;
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
export interface MockPi {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import * as os from "node:os";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
@@ -47,6 +47,21 @@ export function subagentCall(args: Record<string, unknown>, id = "call-subagent-
|
|
|
47
47
|
return fauxToolCall("subagent", args, { id });
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
function resolvedSubagentResultText(resultText: string): string {
|
|
51
|
+
// Reference-first completion: the tool result carries "Output saved to:
|
|
52
|
+
// <path> (…)". Resolve the durable file so the scripted parent can relay the
|
|
53
|
+
// exact child output.
|
|
54
|
+
if (!resultText.includes("Output saved to: ")) return resultText;
|
|
55
|
+
const rest = resultText.split("Output saved to: ")[1];
|
|
56
|
+
if (!rest) return resultText;
|
|
57
|
+
const outputPath = rest.split(" (")[0];
|
|
58
|
+
try {
|
|
59
|
+
return readFileSync(outputPath, "utf-8");
|
|
60
|
+
} catch {
|
|
61
|
+
return resultText;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
50
65
|
export function routeParentThroughSubagent(input: {
|
|
51
66
|
childMarker: string;
|
|
52
67
|
subagentArgs: Record<string, unknown>;
|
|
@@ -56,7 +71,8 @@ export function routeParentThroughSubagent(input: {
|
|
|
56
71
|
if (!isParent) return "Unexpected non-parent model call.";
|
|
57
72
|
const resultText = latestSubagentToolResultText(context.messages as Array<{ role?: string; toolName?: string; content?: unknown }>);
|
|
58
73
|
if (resultText !== undefined) {
|
|
59
|
-
|
|
74
|
+
const resolved = resolvedSubagentResultText(resultText);
|
|
75
|
+
return `Parent relays: ${resolved.includes(input.childMarker) ? input.childMarker : "CHILD_MISSING"}`;
|
|
60
76
|
}
|
|
61
77
|
return subagentCall(input.subagentArgs);
|
|
62
78
|
};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Register the .js → .ts loader hook for integration tests.
|
|
3
3
|
*
|
|
4
|
-
* Usage: node --experimental-
|
|
4
|
+
* Usage: node --experimental-strip-types --import ./test/support/register-loader.mjs --test test/integration/*.test.ts
|
|
5
5
|
*
|
|
6
6
|
* Handles two issues:
|
|
7
7
|
* 1. Source files use .js import extensions (TypeScript ESM convention) but
|
|
8
8
|
* files on disk are .ts — the loader rewrites .js → .ts at resolve time.
|
|
9
|
-
* 2.
|
|
10
|
-
*
|
|
9
|
+
* 2. Source stays within Node's erasable TypeScript syntax so the supported
|
|
10
|
+
* --experimental-strip-types path is sufficient.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { register } from "node:module";
|
|
@@ -1046,7 +1046,9 @@ describe("acceptance gates", () => {
|
|
|
1046
1046
|
{ id: "release check", must: "second" },
|
|
1047
1047
|
] }).join("\n"), /acceptance\.criteria\[1\]\.id duplicates normalized criterion id 'release-check'/);
|
|
1048
1048
|
assert.match(validateAcceptanceInput({ criteria: [123] }).join("\n"), /acceptance\.criteria\[0\] must be a string or an object/);
|
|
1049
|
-
assert.match(validateAcceptanceInput({ evidence:
|
|
1049
|
+
assert.match(validateAcceptanceInput({ evidence: "commands-run" }).join("\n"), /acceptance\.evidence must be an array.*Supported evidence kinds:.*commands-run.*changed-files/s);
|
|
1050
|
+
assert.match(validateAcceptanceInput({ evidence: ["bogus"] }).join("\n"), /acceptance\.evidence\[0\] "bogus" is not a supported evidence kind.*Supported evidence kinds:.*manual-notes.*Example:/s);
|
|
1051
|
+
assert.match(validateAcceptanceInput({ criteria: [{ id: "ship", must: "ship", evidence: ["commands_run"] }] }).join("\n"), /acceptance\.criteria\[0\]\.evidence\[0\] "commands_run" is not a supported evidence kind.*Supported evidence kinds:/s);
|
|
1050
1052
|
assert.match(validateAcceptanceInput({ review: true }).join("\n"), /acceptance\.review must be false or an object/);
|
|
1051
1053
|
assert.match(validateAcceptanceInput({ review: { required: "yes" } }).join("\n"), /acceptance\.review\.required must be a boolean/);
|
|
1052
1054
|
assert.match(validateAcceptanceInput({ stopRules: [123] }).join("\n"), /acceptance\.stopRules\[0\] must be a string/);
|
|
@@ -177,7 +177,7 @@ describe("builtin agent disabling", () => {
|
|
|
177
177
|
{ cwd: tempProject, modelRegistry: { getAvailable: () => [] } },
|
|
178
178
|
));
|
|
179
179
|
|
|
180
|
-
assert.match(text, /Executable agents:\n- helper \(project\): Helper/);
|
|
180
|
+
assert.match(text, /Executable agents:\n- helper \(project, context: fresh\): Helper/);
|
|
181
181
|
assert.doesNotMatch(text, /Disabled builtins:/);
|
|
182
182
|
for (const name of disabledBuiltinNames) {
|
|
183
183
|
assert.doesNotMatch(text, new RegExp(`^- ${name} \\(builtin`, "m"));
|
|
@@ -6,7 +6,7 @@ import { afterEach, describe, it } from "node:test";
|
|
|
6
6
|
import { handleManagementAction } from "../../src/agents/agent-management.ts";
|
|
7
7
|
import { serializeAgent } from "../../src/agents/agent-serializer.ts";
|
|
8
8
|
import { parseChain, serializeChain } from "../../src/agents/chain-serializer.ts";
|
|
9
|
-
import { discoverAgents, discoverAgentsAll, type AgentConfig } from "../../src/agents/agents.ts";
|
|
9
|
+
import { BUILTIN_AGENT_NAMES, discoverAgents, discoverAgentsAll, type AgentConfig } from "../../src/agents/agents.ts";
|
|
10
10
|
import { parseFrontmatter } from "../../src/agents/frontmatter.ts";
|
|
11
11
|
import { buildPiArgs } from "../../src/runs/shared/pi-args.ts";
|
|
12
12
|
import { THINKING_LEVELS } from "../../src/shared/model-info.ts";
|
|
@@ -153,6 +153,47 @@ body`);
|
|
|
153
153
|
}));
|
|
154
154
|
});
|
|
155
155
|
|
|
156
|
+
describe("agent aliases", () => {
|
|
157
|
+
it("parses and serializes agent aliases", () => withTempHome(() => {
|
|
158
|
+
const project = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-alias-agent-"));
|
|
159
|
+
tempDirs.push(project);
|
|
160
|
+
writeAgent(path.join(project, ".selesai", "agents", "worker.md"), `---
|
|
161
|
+
name: worker
|
|
162
|
+
description: Worker
|
|
163
|
+
aliases: shipper, tester, worker
|
|
164
|
+
---
|
|
165
|
+
body`);
|
|
166
|
+
|
|
167
|
+
const worker = discoverAgents(project, "both").agents.find((agent) => agent.name === "worker")!;
|
|
168
|
+
assert.deepEqual(worker.aliases, ["shipper", "tester"]);
|
|
169
|
+
assert.match(serializeAgent(worker), /^aliases: shipper, tester$/m);
|
|
170
|
+
|
|
171
|
+
const ctx = { cwd: project, modelRegistry: { getAvailable: () => [] } };
|
|
172
|
+
assert.match(handleManagementAction("list", {}, ctx).content[0]?.text ?? "", /aliases: shipper, tester/);
|
|
173
|
+
assert.match(handleManagementAction("get", { agent: "shipper" }, ctx).content[0]?.text ?? "", /Agent: worker/);
|
|
174
|
+
}));
|
|
175
|
+
|
|
176
|
+
it("reports management alias collisions as ambiguous", () => withTempHome(() => {
|
|
177
|
+
const project = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-alias-collision-"));
|
|
178
|
+
tempDirs.push(project);
|
|
179
|
+
writeAgent(path.join(project, ".selesai", "agents", "review-agent.md"), `---
|
|
180
|
+
name: review-agent
|
|
181
|
+
description: Custom reviewer
|
|
182
|
+
aliases: developer
|
|
183
|
+
---
|
|
184
|
+
body`);
|
|
185
|
+
|
|
186
|
+
const ctx = { cwd: project, modelRegistry: { getAvailable: () => [] } };
|
|
187
|
+
const getResult = handleManagementAction("get", { agent: "developer" }, ctx);
|
|
188
|
+
assert.equal(getResult.isError, true);
|
|
189
|
+
assert.match(getResult.content[0]?.text ?? "", /Ambiguous agent alias or name 'developer': builder, review-agent|Ambiguous agent alias or name 'developer': review-agent, builder/);
|
|
190
|
+
|
|
191
|
+
const disableResult = handleManagementAction("disable", { agent: "developer" }, ctx);
|
|
192
|
+
assert.equal(disableResult.isError, true);
|
|
193
|
+
assert.match(disableResult.content[0]?.text ?? "", /Ambiguous agent alias 'developer': builder, review-agent|Ambiguous agent alias 'developer': review-agent, builder/);
|
|
194
|
+
}));
|
|
195
|
+
});
|
|
196
|
+
|
|
156
197
|
describe("agent simple-scalar list frontmatter", () => {
|
|
157
198
|
it("discovers newline block lists for all list fields and routes MCP tools", () => {
|
|
158
199
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-agent-block-list-frontmatter-"));
|
|
@@ -316,14 +357,54 @@ Do work
|
|
|
316
357
|
assert.equal(worker?.defaultContext, "fork");
|
|
317
358
|
});
|
|
318
359
|
|
|
319
|
-
it("loads
|
|
360
|
+
it("loads builtin agents with the authoritative six-agent defaultContext map", () => {
|
|
320
361
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-builtin-default-context-"));
|
|
321
362
|
tempDirs.push(dir);
|
|
322
363
|
const agents = discoverAgentsAll(dir).builtin;
|
|
323
364
|
|
|
324
|
-
|
|
365
|
+
const expected: Record<string, "fresh" | "fork"> = {
|
|
366
|
+
architect: "fork",
|
|
367
|
+
recapper: "fork",
|
|
368
|
+
builder: "fresh",
|
|
369
|
+
commentator: "fresh",
|
|
370
|
+
explorer: "fresh",
|
|
371
|
+
researcher: "fresh",
|
|
372
|
+
};
|
|
373
|
+
assert.deepEqual(
|
|
374
|
+
agents.map((agent) => agent.name).sort(),
|
|
375
|
+
[...BUILTIN_AGENT_NAMES].sort(),
|
|
376
|
+
);
|
|
377
|
+
for (const [name, context] of Object.entries(expected)) {
|
|
325
378
|
const agent = agents.find((candidate) => candidate.name === name);
|
|
326
|
-
assert.equal(agent?.defaultContext,
|
|
379
|
+
assert.equal(agent?.defaultContext, context, `${name} should default to ${context} context`);
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
describe("bundled agent descriptions and acceptance roles", () => {
|
|
385
|
+
it("survives discovery with declared descriptions and acceptance roles", () => {
|
|
386
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-bundled-catalog-roles-"));
|
|
387
|
+
tempDirs.push(dir);
|
|
388
|
+
const agents = discoverAgentsAll(dir).builtin;
|
|
389
|
+
|
|
390
|
+
const expected: Record<string, { description: string; acceptanceRole: "read-only" | "writer" }> = {
|
|
391
|
+
architect: { description: "Read-only architecture and implementation planning", acceptanceRole: "read-only" },
|
|
392
|
+
builder: { description: "Mutation-capable scoped implementation", acceptanceRole: "writer" },
|
|
393
|
+
commentator: { description: "Read-only evidence-based review", acceptanceRole: "read-only" },
|
|
394
|
+
explorer: { description: "Read-only local codebase reconnaissance", acceptanceRole: "read-only" },
|
|
395
|
+
recapper: { description: "Read-only handoff and context synthesis", acceptanceRole: "read-only" },
|
|
396
|
+
researcher: { description: "Read-only external and code-first research", acceptanceRole: "read-only" },
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
assert.deepEqual(
|
|
400
|
+
agents.map((agent) => agent.name).sort(),
|
|
401
|
+
[...BUILTIN_AGENT_NAMES].sort(),
|
|
402
|
+
);
|
|
403
|
+
for (const [name, expectedEntry] of Object.entries(expected)) {
|
|
404
|
+
const agent = agents.find((candidate) => candidate.name === name);
|
|
405
|
+
assert.ok(agent, `bundled agent ${name} not discovered`);
|
|
406
|
+
assert.equal(agent.description, expectedEntry.description, `${name} description`);
|
|
407
|
+
assert.equal(agent.acceptanceRole, expectedEntry.acceptanceRole, `${name} acceptanceRole`);
|
|
327
408
|
}
|
|
328
409
|
});
|
|
329
410
|
});
|
|
@@ -603,6 +684,72 @@ Review nested project work.
|
|
|
603
684
|
assert.equal(agent.filePath, path.join(packageRoot, "agents", "reviewer.md"));
|
|
604
685
|
}));
|
|
605
686
|
|
|
687
|
+
it("keeps nearest project root discovery by default when a nested .pi exists", () => withTempHome(() => {
|
|
688
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-nearest-root-default-"));
|
|
689
|
+
tempDirs.push(dir);
|
|
690
|
+
const nested = path.join(dir, "packages", "app", "src");
|
|
691
|
+
const nestedConfigDir = path.join(dir, "packages", "app", ".selesai");
|
|
692
|
+
const packageRoot = path.join(dir, ".selesai", "npm", "node_modules", "outer-workflow");
|
|
693
|
+
fs.mkdirSync(nested, { recursive: true });
|
|
694
|
+
fs.mkdirSync(nestedConfigDir, { recursive: true });
|
|
695
|
+
fs.mkdirSync(path.join(dir, ".git"), { recursive: true });
|
|
696
|
+
writeJson(path.join(packageRoot, "package.json"), {
|
|
697
|
+
name: "outer-workflow",
|
|
698
|
+
"pi-subagents": { agents: ["./agents"] },
|
|
699
|
+
});
|
|
700
|
+
writeAgent(path.join(packageRoot, "agents", "planner.md"), `---
|
|
701
|
+
name: planner
|
|
702
|
+
package: outer-workflow
|
|
703
|
+
description: Plan from the outer project package.
|
|
704
|
+
---
|
|
705
|
+
|
|
706
|
+
Plan outer project work.
|
|
707
|
+
`);
|
|
708
|
+
|
|
709
|
+
const agent = discoverAgents(nested, "both").agents.find((candidate) => candidate.name === "outer-workflow.planner");
|
|
710
|
+
assert.equal(agent, undefined);
|
|
711
|
+
}));
|
|
712
|
+
|
|
713
|
+
it("can resolve project packages and overrides from the git root", () => withTempHome(() => {
|
|
714
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-git-root-resolution-"));
|
|
715
|
+
tempDirs.push(dir);
|
|
716
|
+
const nested = path.join(dir, "packages", "app", "src");
|
|
717
|
+
const nestedConfigDir = path.join(dir, "packages", "app", ".selesai");
|
|
718
|
+
const packageRoot = path.join(dir, ".selesai", "npm", "node_modules", "outer-workflow");
|
|
719
|
+
fs.mkdirSync(nested, { recursive: true });
|
|
720
|
+
fs.mkdirSync(nestedConfigDir, { recursive: true });
|
|
721
|
+
fs.writeFileSync(path.join(dir, ".git"), "gitdir: ../.git/worktrees/app\n", "utf-8");
|
|
722
|
+
writeJson(path.join(dir, ".selesai", "settings.json"), {
|
|
723
|
+
subagents: {
|
|
724
|
+
projectRootResolution: "git-root",
|
|
725
|
+
agentOverrides: {
|
|
726
|
+
commentator: { model: "openai/gpt-5.4" },
|
|
727
|
+
},
|
|
728
|
+
},
|
|
729
|
+
});
|
|
730
|
+
writeJson(path.join(packageRoot, "package.json"), {
|
|
731
|
+
name: "outer-workflow",
|
|
732
|
+
"pi-subagents": { agents: ["./agents"] },
|
|
733
|
+
});
|
|
734
|
+
writeAgent(path.join(packageRoot, "agents", "planner.md"), `---
|
|
735
|
+
name: planner
|
|
736
|
+
package: outer-workflow
|
|
737
|
+
description: Plan from the outer project package.
|
|
738
|
+
---
|
|
739
|
+
|
|
740
|
+
Plan outer project work.
|
|
741
|
+
`);
|
|
742
|
+
|
|
743
|
+
const agents = discoverAgents(nested, "both").agents;
|
|
744
|
+
const packageAgent = agents.find((candidate) => candidate.name === "outer-workflow.planner");
|
|
745
|
+
assert.ok(packageAgent);
|
|
746
|
+
assert.equal(packageAgent.source, "package");
|
|
747
|
+
assert.equal(packageAgent.filePath, path.join(packageRoot, "agents", "planner.md"));
|
|
748
|
+
const commentator = agents.find((candidate) => candidate.name === "commentator");
|
|
749
|
+
assert.equal(commentator?.model, "openai/gpt-5.4");
|
|
750
|
+
assert.equal(commentator?.override?.path, path.join(dir, ".selesai", "settings.json"));
|
|
751
|
+
}));
|
|
752
|
+
|
|
606
753
|
it("does not register legacy skill files from broad package agent roots", () => withTempHome(() => {
|
|
607
754
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-broad-package-skills-"));
|
|
608
755
|
tempDirs.push(dir);
|
|
@@ -1203,7 +1350,28 @@ Do work
|
|
|
1203
1350
|
}
|
|
1204
1351
|
});
|
|
1205
1352
|
|
|
1206
|
-
it("
|
|
1353
|
+
it("keeps the bundled architect read-only for repository tools", () => {
|
|
1354
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-builtin-architect-tools-"));
|
|
1355
|
+
const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-builtin-architect-home-"));
|
|
1356
|
+
tempDirs.push(dir, homeDir);
|
|
1357
|
+
const previousHome = process.env.HOME;
|
|
1358
|
+
const previousUserProfile = process.env.USERPROFILE;
|
|
1359
|
+
try {
|
|
1360
|
+
process.env.HOME = homeDir;
|
|
1361
|
+
process.env.USERPROFILE = homeDir;
|
|
1362
|
+
const architect = discoverAgentsAll(dir).builtin.find((candidate) => candidate.name === "architect");
|
|
1363
|
+
assert.ok(architect);
|
|
1364
|
+
assert.deepEqual(architect.tools, ["read", "grep", "find", "ls"]);
|
|
1365
|
+
assert.equal(architect.acceptanceRole, "read-only");
|
|
1366
|
+
} finally {
|
|
1367
|
+
if (previousHome === undefined) delete process.env.HOME;
|
|
1368
|
+
else process.env.HOME = previousHome;
|
|
1369
|
+
if (previousUserProfile === undefined) delete process.env.USERPROFILE;
|
|
1370
|
+
else process.env.USERPROFILE = previousUserProfile;
|
|
1371
|
+
}
|
|
1372
|
+
});
|
|
1373
|
+
|
|
1374
|
+
it("builder builtin tools exclude the bridge-injected supervisor tool", () => {
|
|
1207
1375
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-builtin-supervisor-tool-"));
|
|
1208
1376
|
const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-builtin-supervisor-tool-home-"));
|
|
1209
1377
|
tempDirs.push(dir);
|
|
@@ -1216,7 +1384,31 @@ Do work
|
|
|
1216
1384
|
process.env.USERPROFILE = homeDir;
|
|
1217
1385
|
const agent = discoverAgentsAll(dir).builtin.find((candidate) => candidate.name === "builder");
|
|
1218
1386
|
assert.ok(agent, "builder builtin should be discovered");
|
|
1219
|
-
assert.deepEqual(agent?.tools, ["read", "grep", "find", "ls", "bash", "edit", "write"
|
|
1387
|
+
assert.deepEqual(agent?.tools, ["read", "grep", "find", "ls", "bash", "edit", "write"]);
|
|
1388
|
+
assert.equal(agent?.tools?.includes("contact_supervisor"), false);
|
|
1389
|
+
} finally {
|
|
1390
|
+
if (previousHome === undefined) delete process.env.HOME;
|
|
1391
|
+
else process.env.HOME = previousHome;
|
|
1392
|
+
if (previousUserProfile === undefined) delete process.env.USERPROFILE;
|
|
1393
|
+
else process.env.USERPROFILE = previousUserProfile;
|
|
1394
|
+
}
|
|
1395
|
+
});
|
|
1396
|
+
|
|
1397
|
+
it("researcher builtin routes grep.app tools into mcpDirectTools", () => {
|
|
1398
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-builtin-researcher-tools-"));
|
|
1399
|
+
const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-builtin-researcher-tools-home-"));
|
|
1400
|
+
tempDirs.push(dir);
|
|
1401
|
+
tempDirs.push(homeDir);
|
|
1402
|
+
const previousHome = process.env.HOME;
|
|
1403
|
+
const previousUserProfile = process.env.USERPROFILE;
|
|
1404
|
+
|
|
1405
|
+
try {
|
|
1406
|
+
process.env.HOME = homeDir;
|
|
1407
|
+
process.env.USERPROFILE = homeDir;
|
|
1408
|
+
const agent = discoverAgentsAll(dir).builtin.find((candidate) => candidate.name === "researcher");
|
|
1409
|
+
assert.ok(agent, "researcher builtin should be discovered");
|
|
1410
|
+
assert.deepEqual(agent?.tools, ["read", "web_explore"]);
|
|
1411
|
+
assert.deepEqual(agent?.mcpDirectTools, ["grep_app_search", "grep_app_fetch"]);
|
|
1220
1412
|
} finally {
|
|
1221
1413
|
if (previousHome === undefined) delete process.env.HOME;
|
|
1222
1414
|
else process.env.HOME = previousHome;
|