@selesai/code 0.5.27 → 0.5.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/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 +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- 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/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 +85 -0
- package/dist/extensions/pi-subagents/LICENSE +21 -0
- package/dist/extensions/pi-subagents/README.md +146 -52
- package/dist/extensions/pi-subagents/agents/architect.md +1 -0
- package/dist/extensions/pi-subagents/agents/builder.md +1 -0
- 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 +21 -989
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +256 -0
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +430 -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 +282 -0
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +71 -30
- 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/api/delegation.ts +3 -0
- package/dist/extensions/pi-subagents/src/api/preflight.ts +16 -12
- package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +17 -1
- package/dist/extensions/pi-subagents/src/extension/index.ts +17 -7
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +248 -6
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +31 -6
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +8 -7
- 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 +63 -16
- 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 +29 -4
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +29 -6
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +29 -3
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +372 -28
- 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 +143 -43
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +527 -247
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +42 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +426 -123
- package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +15 -7
- 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/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 +1 -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 +155 -10
- package/dist/extensions/pi-subagents/src/shared/utils.ts +73 -4
- package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +5 -0
- 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 +27 -28
- 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 +2 -2
- package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +348 -7
- 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 +26 -1
- 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 +3 -3
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +213 -13
- package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +34 -0
- 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 +118 -12
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +850 -7
- 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/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-frontmatter.test.ts +128 -0
- 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/capability-ceiling-agent-allowlist.test.ts +102 -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 +4 -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 +11 -11
- 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 +10 -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 +46 -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 +34 -2
- 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-intent.test.ts +3 -0
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +1 -1
- 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/extensions/question/index.ts +14 -1
- package/dist/extensions/question/tests/wizard.test.ts +11 -8
- 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/batch-grill-me/SKILL.md +3 -1
- 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/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 +15 -6
- package/dist/extensions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
|
@@ -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,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/);
|
|
@@ -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-"));
|
|
@@ -603,6 +644,72 @@ Review nested project work.
|
|
|
603
644
|
assert.equal(agent.filePath, path.join(packageRoot, "agents", "reviewer.md"));
|
|
604
645
|
}));
|
|
605
646
|
|
|
647
|
+
it("keeps nearest project root discovery by default when a nested .pi exists", () => withTempHome(() => {
|
|
648
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-nearest-root-default-"));
|
|
649
|
+
tempDirs.push(dir);
|
|
650
|
+
const nested = path.join(dir, "packages", "app", "src");
|
|
651
|
+
const nestedConfigDir = path.join(dir, "packages", "app", ".selesai");
|
|
652
|
+
const packageRoot = path.join(dir, ".selesai", "npm", "node_modules", "outer-workflow");
|
|
653
|
+
fs.mkdirSync(nested, { recursive: true });
|
|
654
|
+
fs.mkdirSync(nestedConfigDir, { recursive: true });
|
|
655
|
+
fs.mkdirSync(path.join(dir, ".git"), { recursive: true });
|
|
656
|
+
writeJson(path.join(packageRoot, "package.json"), {
|
|
657
|
+
name: "outer-workflow",
|
|
658
|
+
"pi-subagents": { agents: ["./agents"] },
|
|
659
|
+
});
|
|
660
|
+
writeAgent(path.join(packageRoot, "agents", "planner.md"), `---
|
|
661
|
+
name: planner
|
|
662
|
+
package: outer-workflow
|
|
663
|
+
description: Plan from the outer project package.
|
|
664
|
+
---
|
|
665
|
+
|
|
666
|
+
Plan outer project work.
|
|
667
|
+
`);
|
|
668
|
+
|
|
669
|
+
const agent = discoverAgents(nested, "both").agents.find((candidate) => candidate.name === "outer-workflow.planner");
|
|
670
|
+
assert.equal(agent, undefined);
|
|
671
|
+
}));
|
|
672
|
+
|
|
673
|
+
it("can resolve project packages and overrides from the git root", () => withTempHome(() => {
|
|
674
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-git-root-resolution-"));
|
|
675
|
+
tempDirs.push(dir);
|
|
676
|
+
const nested = path.join(dir, "packages", "app", "src");
|
|
677
|
+
const nestedConfigDir = path.join(dir, "packages", "app", ".selesai");
|
|
678
|
+
const packageRoot = path.join(dir, ".selesai", "npm", "node_modules", "outer-workflow");
|
|
679
|
+
fs.mkdirSync(nested, { recursive: true });
|
|
680
|
+
fs.mkdirSync(nestedConfigDir, { recursive: true });
|
|
681
|
+
fs.writeFileSync(path.join(dir, ".git"), "gitdir: ../.git/worktrees/app\n", "utf-8");
|
|
682
|
+
writeJson(path.join(dir, ".selesai", "settings.json"), {
|
|
683
|
+
subagents: {
|
|
684
|
+
projectRootResolution: "git-root",
|
|
685
|
+
agentOverrides: {
|
|
686
|
+
commentator: { model: "openai/gpt-5.4" },
|
|
687
|
+
},
|
|
688
|
+
},
|
|
689
|
+
});
|
|
690
|
+
writeJson(path.join(packageRoot, "package.json"), {
|
|
691
|
+
name: "outer-workflow",
|
|
692
|
+
"pi-subagents": { agents: ["./agents"] },
|
|
693
|
+
});
|
|
694
|
+
writeAgent(path.join(packageRoot, "agents", "planner.md"), `---
|
|
695
|
+
name: planner
|
|
696
|
+
package: outer-workflow
|
|
697
|
+
description: Plan from the outer project package.
|
|
698
|
+
---
|
|
699
|
+
|
|
700
|
+
Plan outer project work.
|
|
701
|
+
`);
|
|
702
|
+
|
|
703
|
+
const agents = discoverAgents(nested, "both").agents;
|
|
704
|
+
const packageAgent = agents.find((candidate) => candidate.name === "outer-workflow.planner");
|
|
705
|
+
assert.ok(packageAgent);
|
|
706
|
+
assert.equal(packageAgent.source, "package");
|
|
707
|
+
assert.equal(packageAgent.filePath, path.join(packageRoot, "agents", "planner.md"));
|
|
708
|
+
const commentator = agents.find((candidate) => candidate.name === "commentator");
|
|
709
|
+
assert.equal(commentator?.model, "openai/gpt-5.4");
|
|
710
|
+
assert.equal(commentator?.override?.path, path.join(dir, ".selesai", "settings.json"));
|
|
711
|
+
}));
|
|
712
|
+
|
|
606
713
|
it("does not register legacy skill files from broad package agent roots", () => withTempHome(() => {
|
|
607
714
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-broad-package-skills-"));
|
|
608
715
|
tempDirs.push(dir);
|
|
@@ -1203,6 +1310,27 @@ Do work
|
|
|
1203
1310
|
}
|
|
1204
1311
|
});
|
|
1205
1312
|
|
|
1313
|
+
it("keeps the bundled architect read-only for repository tools", () => {
|
|
1314
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-builtin-architect-tools-"));
|
|
1315
|
+
const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-builtin-architect-home-"));
|
|
1316
|
+
tempDirs.push(dir, homeDir);
|
|
1317
|
+
const previousHome = process.env.HOME;
|
|
1318
|
+
const previousUserProfile = process.env.USERPROFILE;
|
|
1319
|
+
try {
|
|
1320
|
+
process.env.HOME = homeDir;
|
|
1321
|
+
process.env.USERPROFILE = homeDir;
|
|
1322
|
+
const architect = discoverAgentsAll(dir).builtin.find((candidate) => candidate.name === "architect");
|
|
1323
|
+
assert.ok(architect);
|
|
1324
|
+
assert.deepEqual(architect.tools, ["read", "grep", "find", "ls"]);
|
|
1325
|
+
assert.equal(architect.acceptanceRole, "read-only");
|
|
1326
|
+
} finally {
|
|
1327
|
+
if (previousHome === undefined) delete process.env.HOME;
|
|
1328
|
+
else process.env.HOME = previousHome;
|
|
1329
|
+
if (previousUserProfile === undefined) delete process.env.USERPROFILE;
|
|
1330
|
+
else process.env.USERPROFILE = previousUserProfile;
|
|
1331
|
+
}
|
|
1332
|
+
});
|
|
1333
|
+
|
|
1206
1334
|
it("builder includes the child-facing supervisor tool", () => {
|
|
1207
1335
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-builtin-supervisor-tool-"));
|
|
1208
1336
|
const homeDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-builtin-supervisor-tool-home-"));
|
|
@@ -3,7 +3,7 @@ import * as fs from "node:fs";
|
|
|
3
3
|
import * as os from "node:os";
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import { afterEach, beforeEach, describe, it } from "node:test";
|
|
6
|
-
import { buildBuiltinOverrideConfig, discoverAgents, discoverAgentsAll, removeBuiltinAgentOverride } from "../../src/agents/agents.ts";
|
|
6
|
+
import { buildBuiltinOverrideConfig, discoverAgents, discoverAgentsAll, removeBuiltinAgentOverride, saveBuiltinAgentOverride } from "../../src/agents/agents.ts";
|
|
7
7
|
|
|
8
8
|
let tempHome = "";
|
|
9
9
|
let tempProject = "";
|
|
@@ -178,6 +178,22 @@ describe("builtin agent overrides", () => {
|
|
|
178
178
|
assert.equal(agents.find((agent) => agent.name === "architect-copy")?.model, "deepseek-v4-flash");
|
|
179
179
|
});
|
|
180
180
|
|
|
181
|
+
it("overrides builtin and custom agent descriptions from settings", () => {
|
|
182
|
+
writeJson(path.join(tempHome, ".selesai", "agent", "settings.json"), {
|
|
183
|
+
subagents: {
|
|
184
|
+
agentOverrides: {
|
|
185
|
+
commentator: { description: " Priced commentator " },
|
|
186
|
+
implementer: { description: "Priced implementer" },
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
writeProjectAgent(tempProject, "implementer", `---\nname: implementer\ndescription: Original implementer\n---\n\nImplement it.\n`);
|
|
191
|
+
|
|
192
|
+
const agents = discoverAgents(tempProject, "both").agents;
|
|
193
|
+
assert.equal(agents.find((agent) => agent.name === "commentator")?.description, "Priced commentator");
|
|
194
|
+
assert.equal(agents.find((agent) => agent.name === "implementer")?.description, "Priced implementer");
|
|
195
|
+
});
|
|
196
|
+
|
|
181
197
|
it("applies user settings overrides to builtin agents", () => {
|
|
182
198
|
writeJson(path.join(tempHome, ".selesai", "agent", "settings.json"), {
|
|
183
199
|
subagents: {
|
|
@@ -625,6 +641,22 @@ describe("builtin agent overrides", () => {
|
|
|
625
641
|
);
|
|
626
642
|
});
|
|
627
643
|
|
|
644
|
+
it("surfaces malformed description override values", () => {
|
|
645
|
+
const settingsPath = path.join(tempHome, ".selesai", "agent", "settings.json");
|
|
646
|
+
for (const description of ["", 42]) {
|
|
647
|
+
writeJson(settingsPath, {
|
|
648
|
+
subagents: { agentOverrides: { commentator: { description } } },
|
|
649
|
+
});
|
|
650
|
+
assert.throws(
|
|
651
|
+
() => discoverAgents(tempProject, "both"),
|
|
652
|
+
(error: unknown) => error instanceof Error
|
|
653
|
+
&& error.message.includes(settingsPath)
|
|
654
|
+
&& error.message.includes("commentator")
|
|
655
|
+
&& error.message.includes("description"),
|
|
656
|
+
);
|
|
657
|
+
}
|
|
658
|
+
});
|
|
659
|
+
|
|
628
660
|
it("surfaces malformed completion guard override values", () => {
|
|
629
661
|
const settingsPath = path.join(tempHome, ".selesai", "agent", "settings.json");
|
|
630
662
|
writeJson(settingsPath, {
|
|
@@ -646,9 +678,10 @@ describe("builtin agent overrides", () => {
|
|
|
646
678
|
);
|
|
647
679
|
});
|
|
648
680
|
|
|
649
|
-
it("builds false sentinels when an override clears builtin fields", () => {
|
|
681
|
+
it("builds description changes and false sentinels when an override clears builtin fields", () => {
|
|
650
682
|
const override = buildBuiltinOverrideConfig(
|
|
651
683
|
{
|
|
684
|
+
description: "Base description",
|
|
652
685
|
model: "openai-codex/gpt-5.4-mini",
|
|
653
686
|
fallbackModels: ["openai/gpt-5-mini"],
|
|
654
687
|
thinking: "high",
|
|
@@ -665,6 +698,7 @@ describe("builtin agent overrides", () => {
|
|
|
665
698
|
completionGuard: false,
|
|
666
699
|
},
|
|
667
700
|
{
|
|
701
|
+
description: "Override description",
|
|
668
702
|
model: undefined,
|
|
669
703
|
fallbackModels: undefined,
|
|
670
704
|
thinking: undefined,
|
|
@@ -683,6 +717,7 @@ describe("builtin agent overrides", () => {
|
|
|
683
717
|
);
|
|
684
718
|
|
|
685
719
|
assert.deepEqual(override, {
|
|
720
|
+
description: "Override description",
|
|
686
721
|
model: false,
|
|
687
722
|
fallbackModels: false,
|
|
688
723
|
thinking: false,
|
|
@@ -695,5 +730,15 @@ describe("builtin agent overrides", () => {
|
|
|
695
730
|
subagentOnlyExtensions: false,
|
|
696
731
|
completionGuard: true,
|
|
697
732
|
});
|
|
733
|
+
assert.ok(override);
|
|
734
|
+
fs.mkdirSync(path.join(tempProject, ".selesai"), { recursive: true });
|
|
735
|
+
saveBuiltinAgentOverride(tempProject, "commentator", "project", override);
|
|
736
|
+
assert.equal(discoverAgents(tempProject, "both").agents.find((agent) => agent.name === "commentator")?.description, "Override description");
|
|
737
|
+
|
|
738
|
+
const whitespaceDescription = buildBuiltinOverrideConfig(
|
|
739
|
+
{ description: "Base description" },
|
|
740
|
+
{ description: " " } as Parameters<typeof buildBuiltinOverrideConfig>[1],
|
|
741
|
+
);
|
|
742
|
+
assert.equal(whitespaceDescription, undefined);
|
|
698
743
|
});
|
|
699
744
|
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as os from "node:os";
|
|
4
|
+
import * as path from "node:path";
|
|
5
|
+
import { describe, it } from "node:test";
|
|
6
|
+
import { readAsyncRecoveryDescriptor } from "../../src/runs/background/async-resume.ts";
|
|
7
|
+
|
|
8
|
+
describe("async recovery descriptor", () => {
|
|
9
|
+
it("accepts launchContractDigest written by async execution", () => {
|
|
10
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-async-recovery-digest-"));
|
|
11
|
+
try {
|
|
12
|
+
const digest = "launch-contract-digest";
|
|
13
|
+
fs.writeFileSync(path.join(root, "recovery-descriptor.json"), JSON.stringify({
|
|
14
|
+
version: 1,
|
|
15
|
+
launchContractDigest: digest,
|
|
16
|
+
sourceRunId: "run-digest",
|
|
17
|
+
agent: "worker",
|
|
18
|
+
cwd: root,
|
|
19
|
+
systemPromptMode: "replace",
|
|
20
|
+
inheritProjectContext: false,
|
|
21
|
+
inheritSkills: false,
|
|
22
|
+
outputMode: "inline",
|
|
23
|
+
maxSubagentDepth: 2,
|
|
24
|
+
share: false,
|
|
25
|
+
}), "utf-8");
|
|
26
|
+
|
|
27
|
+
const descriptor = readAsyncRecoveryDescriptor(root);
|
|
28
|
+
|
|
29
|
+
assert.equal(descriptor?.launchContractDigest, digest);
|
|
30
|
+
} finally {
|
|
31
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("rejects malformed launchContractDigest values", () => {
|
|
36
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-async-recovery-bad-digest-"));
|
|
37
|
+
try {
|
|
38
|
+
fs.writeFileSync(path.join(root, "recovery-descriptor.json"), JSON.stringify({
|
|
39
|
+
version: 1,
|
|
40
|
+
launchContractDigest: {},
|
|
41
|
+
sourceRunId: "run-digest",
|
|
42
|
+
agent: "worker",
|
|
43
|
+
cwd: root,
|
|
44
|
+
systemPromptMode: "replace",
|
|
45
|
+
inheritProjectContext: false,
|
|
46
|
+
inheritSkills: false,
|
|
47
|
+
outputMode: "inline",
|
|
48
|
+
maxSubagentDepth: 2,
|
|
49
|
+
share: false,
|
|
50
|
+
}), "utf-8");
|
|
51
|
+
|
|
52
|
+
assert.throws(
|
|
53
|
+
() => readAsyncRecoveryDescriptor(root),
|
|
54
|
+
/launchContractDigest must be a non-empty string/,
|
|
55
|
+
);
|
|
56
|
+
} finally {
|
|
57
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|