@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
|
@@ -53,7 +53,7 @@ describe("agent management config parsing", () => {
|
|
|
53
53
|
);
|
|
54
54
|
|
|
55
55
|
assert.equal(result.isError, false);
|
|
56
|
-
assert.match(readText(result), /- scout \(project\): Project scout override/);
|
|
56
|
+
assert.match(readText(result), /- scout \(project, context: fresh\): Project scout override/);
|
|
57
57
|
assert.doesNotMatch(readText(result), /- scout \(builtin/);
|
|
58
58
|
});
|
|
59
59
|
|
|
@@ -722,6 +722,126 @@ Drive the failing test first.
|
|
|
722
722
|
assert.match(content, /inheritSkills: false/);
|
|
723
723
|
});
|
|
724
724
|
|
|
725
|
+
it("exposes a rich human and machine catalog for a custom project agent and chain", () => {
|
|
726
|
+
const ctx = { cwd: tempDir, modelRegistry: { getAvailable: () => [] } };
|
|
727
|
+
const created = handleCreate(
|
|
728
|
+
{
|
|
729
|
+
config: {
|
|
730
|
+
name: "Catalog Writer",
|
|
731
|
+
description: "Scoped catalog writer",
|
|
732
|
+
scope: "project",
|
|
733
|
+
aliases: "catw",
|
|
734
|
+
acceptanceRole: "writer",
|
|
735
|
+
defaultContext: "fork",
|
|
736
|
+
tools: "read, grep, find, ls, bash, edit, write, mcp:fixture_search",
|
|
737
|
+
systemPrompt: "Implement scoped changes.",
|
|
738
|
+
},
|
|
739
|
+
},
|
|
740
|
+
ctx,
|
|
741
|
+
);
|
|
742
|
+
assert.equal(created.isError, false);
|
|
743
|
+
|
|
744
|
+
const chainCreated = handleCreate(
|
|
745
|
+
{ config: { name: "Review Flow", description: "Catalog review flow", scope: "project", steps: [{ agent: "catalog-writer", task: "Inspect" }] } },
|
|
746
|
+
ctx,
|
|
747
|
+
);
|
|
748
|
+
assert.equal(chainCreated.isError, false);
|
|
749
|
+
|
|
750
|
+
const listed = handleManagementAction("list", {}, ctx);
|
|
751
|
+
assert.equal(listed.isError, false);
|
|
752
|
+
const text = readText(listed);
|
|
753
|
+
assert.match(text, /Executable agents:/);
|
|
754
|
+
assert.match(
|
|
755
|
+
text,
|
|
756
|
+
/- catalog-writer \(project, context: fork, role: writer, aliases: catw, tools: read, grep, find, ls, bash, edit, write, mcp:fixture_search\): Scoped catalog writer/,
|
|
757
|
+
);
|
|
758
|
+
assert.match(text, /Chains:\n- review-flow \(project\): Catalog review flow/);
|
|
759
|
+
|
|
760
|
+
const details = (listed as { details: { catalog: unknown } }).details.catalog as {
|
|
761
|
+
version: number;
|
|
762
|
+
agents: Array<{
|
|
763
|
+
name: string;
|
|
764
|
+
source: string;
|
|
765
|
+
description: string;
|
|
766
|
+
executable: boolean;
|
|
767
|
+
aliases?: string[];
|
|
768
|
+
defaultContext: string;
|
|
769
|
+
acceptanceRole?: string;
|
|
770
|
+
tools?: string[];
|
|
771
|
+
}>;
|
|
772
|
+
chains: Array<{ name: string; source: string; description: string }>;
|
|
773
|
+
};
|
|
774
|
+
assert.equal(details.version, 1);
|
|
775
|
+
const entry = details.agents.find((agent) => agent.name === "catalog-writer");
|
|
776
|
+
assert.ok(entry, "catalog must include the custom project agent");
|
|
777
|
+
assert.equal(entry.source, "project");
|
|
778
|
+
assert.equal(entry.description, "Scoped catalog writer");
|
|
779
|
+
assert.equal(entry.executable, true);
|
|
780
|
+
assert.deepEqual(entry.aliases, ["catw"]);
|
|
781
|
+
assert.equal(entry.defaultContext, "fork");
|
|
782
|
+
assert.equal(entry.acceptanceRole, "writer");
|
|
783
|
+
assert.deepEqual(entry.tools, ["read", "grep", "find", "ls", "bash", "edit", "write", "mcp:fixture_search"]);
|
|
784
|
+
assert.deepEqual(details.chains, [{ name: "review-flow", source: "project", description: "Catalog review flow" }]);
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
it("normalizes unset defaultContext to fresh in the machine catalog", () => {
|
|
788
|
+
const ctx = { cwd: tempDir, modelRegistry: { getAvailable: () => [] } };
|
|
789
|
+
const created = handleCreate(
|
|
790
|
+
{ config: { name: "No Context", description: "No explicit context", scope: "project", systemPrompt: "Work" } },
|
|
791
|
+
ctx,
|
|
792
|
+
);
|
|
793
|
+
assert.equal(created.isError, false);
|
|
794
|
+
|
|
795
|
+
const listed = handleManagementAction("list", {}, ctx);
|
|
796
|
+
const details = (listed as { details: { catalog: unknown } }).details.catalog as {
|
|
797
|
+
agents: Array<{ name: string; defaultContext: string }>;
|
|
798
|
+
};
|
|
799
|
+
const entry = details.agents.find((agent) => agent.name === "no-context");
|
|
800
|
+
assert.ok(entry);
|
|
801
|
+
assert.equal(entry.defaultContext, "fresh");
|
|
802
|
+
assert.match(readText(listed), /- no-context \(project, context: fresh\)/);
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
it("omits disabled agents from both human text and machine catalog metadata", () => {
|
|
806
|
+
const ctx = { cwd: tempDir, modelRegistry: { getAvailable: () => [] } };
|
|
807
|
+
const created = handleCreate(
|
|
808
|
+
{ config: { name: "Hidden Writer", description: "Should stay hidden", scope: "project", systemPrompt: "Work" } },
|
|
809
|
+
ctx,
|
|
810
|
+
);
|
|
811
|
+
assert.equal(created.isError, false);
|
|
812
|
+
|
|
813
|
+
const disabled = handleManagementAction("disable", { agent: "hidden-writer" }, ctx);
|
|
814
|
+
assert.equal(disabled.isError, false);
|
|
815
|
+
|
|
816
|
+
const listed = handleManagementAction("list", {}, ctx);
|
|
817
|
+
assert.equal(listed.isError, false);
|
|
818
|
+
assert.doesNotMatch(readText(listed), /hidden-writer/);
|
|
819
|
+
const details = (listed as { details: { catalog: unknown } }).details.catalog as {
|
|
820
|
+
agents: Array<{ name: string }>;
|
|
821
|
+
};
|
|
822
|
+
assert.equal(details.agents.some((agent) => agent.name === "hidden-writer"), false);
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
it("returns (none) text and an empty versioned catalog when no agents are discovered", () => {
|
|
826
|
+
fs.mkdirSync(path.join(tempDir, "agent-home"), { recursive: true });
|
|
827
|
+
fs.writeFileSync(
|
|
828
|
+
path.join(tempDir, "agent-home", "settings.json"),
|
|
829
|
+
JSON.stringify({ subagents: { disableBuiltins: true } }, null, 2),
|
|
830
|
+
"utf-8",
|
|
831
|
+
);
|
|
832
|
+
const ctx = { cwd: tempDir, modelRegistry: { getAvailable: () => [] } };
|
|
833
|
+
const listed = handleManagementAction("list", {}, ctx);
|
|
834
|
+
assert.equal(listed.isError, false);
|
|
835
|
+
const text = readText(listed);
|
|
836
|
+
assert.match(text, /Executable agents:\n- \(none\)/);
|
|
837
|
+
assert.match(text, /Chains:\n- \(none\)/);
|
|
838
|
+
assert.deepEqual((listed as { details: { catalog: unknown } }).details.catalog, {
|
|
839
|
+
version: 1,
|
|
840
|
+
agents: [],
|
|
841
|
+
chains: [],
|
|
842
|
+
});
|
|
843
|
+
});
|
|
844
|
+
|
|
725
845
|
it("lists proactive skill subagent suggestions from repeated configured skill use", () => {
|
|
726
846
|
const ctx = { cwd: tempDir, modelRegistry: { getAvailable: () => [] } };
|
|
727
847
|
fs.mkdirSync(path.join(tempDir, ".selesai", "agents"), { recursive: true });
|
|
@@ -774,4 +894,44 @@ Inspect cleanup.
|
|
|
774
894
|
assert.doesNotMatch(readText(listed), /Proactive skill subagent suggestions:/);
|
|
775
895
|
});
|
|
776
896
|
|
|
897
|
+
it("appends explicit-only task-aware advisory routing to list output when task is provided", () => {
|
|
898
|
+
const ctx = { cwd: tempDir, modelRegistry: { getAvailable: () => [] } };
|
|
899
|
+
handleCreate(
|
|
900
|
+
{ config: { name: "Code Reviewer", description: "Reviews without editing", scope: "project", acceptanceRole: "read-only", tools: "read, grep, find, ls", systemPrompt: "Review." } },
|
|
901
|
+
ctx,
|
|
902
|
+
);
|
|
903
|
+
handleCreate(
|
|
904
|
+
{ config: { name: "Fixer", description: "Implements changes", scope: "project", acceptanceRole: "writer", tools: "read, grep, bash, edit, write", systemPrompt: "Fix." } },
|
|
905
|
+
ctx,
|
|
906
|
+
);
|
|
907
|
+
|
|
908
|
+
const implementation = handleManagementAction("list", { task: "Implement the fix" }, ctx);
|
|
909
|
+
assert.equal(implementation.isError, false);
|
|
910
|
+
assert.deepEqual((implementation as { details: { results: unknown[] } }).details.results, []);
|
|
911
|
+
const implementationText = readText(implementation);
|
|
912
|
+
assert.match(implementationText, /Task-aware advisory routing:/);
|
|
913
|
+
assert.match(implementationText, /- Intent: implementation/);
|
|
914
|
+
assert.match(implementationText, /- Recommended: fixer \(project\)/);
|
|
915
|
+
assert.match(implementationText, /- Advisory only: no subagent was launched\. To proceed, explicitly call subagent with this canonical agent name and the task\./);
|
|
916
|
+
|
|
917
|
+
const review = handleManagementAction("list", { task: "Review only; do not edit files" }, ctx);
|
|
918
|
+
assert.equal(review.isError, false);
|
|
919
|
+
const reviewText = readText(review);
|
|
920
|
+
assert.match(reviewText, /- Intent: read-only/);
|
|
921
|
+
assert.match(reviewText, /- Recommended: code-reviewer \(project\)/);
|
|
922
|
+
|
|
923
|
+
const vague = handleManagementAction("list", { task: "Look into this" }, ctx);
|
|
924
|
+
assert.equal(vague.isError, false);
|
|
925
|
+
const vagueText = readText(vague);
|
|
926
|
+
assert.match(vagueText, /- Intent: unknown/);
|
|
927
|
+
assert.match(vagueText, /- Recommendation: none/);
|
|
928
|
+
assert.match(vagueText, /Clarify whether the task is read-only analysis\/review or implementation allowed to edit files\./);
|
|
929
|
+
|
|
930
|
+
for (const noTaskParams of [{}, { task: " " }]) {
|
|
931
|
+
const noTask = handleManagementAction("list", noTaskParams, ctx);
|
|
932
|
+
assert.equal(noTask.isError, false);
|
|
933
|
+
assert.doesNotMatch(readText(noTask), /Task-aware advisory routing:/);
|
|
934
|
+
}
|
|
935
|
+
});
|
|
936
|
+
|
|
777
937
|
});
|
|
@@ -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
|
+
});
|
|
@@ -109,6 +109,14 @@ describe("async resume lookup", () => {
|
|
|
109
109
|
});
|
|
110
110
|
assert.throws(() => resolveAsyncResumeTarget({ id: "run-descriptor" }, { asyncDirRoot: asyncRoot, resultsDir }), /capabilityCeiling sources/);
|
|
111
111
|
|
|
112
|
+
writeJson(path.join(asyncDir, "recovery-descriptor.json"), {
|
|
113
|
+
...descriptor,
|
|
114
|
+
launchContractDigest: "launch-contract-digest",
|
|
115
|
+
});
|
|
116
|
+
const valid = resolveAsyncResumeTarget({ id: "run-descriptor" }, { asyncDirRoot: asyncRoot, resultsDir });
|
|
117
|
+
assert.equal(valid.launchContractDigest, "launch-contract-digest");
|
|
118
|
+
assert.equal(valid.recoveryDescriptor?.launchContractDigest, "launch-contract-digest");
|
|
119
|
+
|
|
112
120
|
writeJson(path.join(asyncDir, "recovery-descriptor.json"), { ...descriptor, sourceRunId: "another-run" });
|
|
113
121
|
assert.throws(() => resolveAsyncResumeTarget({ id: "run-descriptor" }, { asyncDirRoot: asyncRoot, resultsDir }), /different source run/);
|
|
114
122
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { describe, it } from "node:test";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { BUILTIN_AGENT_NAMES } from "../../src/agents/agents.ts";
|
|
7
|
+
|
|
8
|
+
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
9
|
+
|
|
10
|
+
const README_PATH = path.join(packageRoot, "README.md");
|
|
11
|
+
const PROMPTING_AND_ROLES_PATH = path.join(packageRoot, "skills", "pi-subagents", "references", "prompting-and-roles.md");
|
|
12
|
+
|
|
13
|
+
const README_TABLE_HEADING = "## Builtin agents in plain English";
|
|
14
|
+
const PROMPTING_AND_ROLES_TABLE_HEADING = "## Builtin Agents";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Extracts the first-column agent names from every table row under the given
|
|
18
|
+
* markdown section heading. Skips the header row and the separator row.
|
|
19
|
+
*/
|
|
20
|
+
function tableFirstColumnNames(markdown: string, sectionHeading: string): string[] {
|
|
21
|
+
const lines = markdown.split(/\r?\n/);
|
|
22
|
+
const headingIndex = lines.findIndex((line) => line.trim() === sectionHeading);
|
|
23
|
+
assert.ok(headingIndex >= 0, `missing section heading: ${sectionHeading}`);
|
|
24
|
+
|
|
25
|
+
const names: string[] = [];
|
|
26
|
+
for (let i = headingIndex + 1; i < lines.length; i++) {
|
|
27
|
+
const line = lines[i]!.trim();
|
|
28
|
+
if (line.startsWith("#")) break;
|
|
29
|
+
if (!line.startsWith("|")) continue;
|
|
30
|
+
|
|
31
|
+
const cells = line.split("|").map((cell) => cell.trim());
|
|
32
|
+
const firstCell = (cells[1] ?? "").replaceAll("`", "").trim();
|
|
33
|
+
if (firstCell === "Agent") continue;
|
|
34
|
+
if (/^:?-+:?$/.test(firstCell)) continue;
|
|
35
|
+
if (firstCell.length === 0) continue;
|
|
36
|
+
names.push(firstCell);
|
|
37
|
+
}
|
|
38
|
+
return names;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function assertExactlySixBuiltins(tablePath: string, heading: string, markdown: string): void {
|
|
42
|
+
const names = tableFirstColumnNames(markdown, heading);
|
|
43
|
+
|
|
44
|
+
assert.equal(names.length, 6, `${path.basename(tablePath)}: role table must contain exactly six builtin rows`);
|
|
45
|
+
assert.equal(new Set(names).size, names.length, `${path.basename(tablePath)}: role table contains duplicate rows`);
|
|
46
|
+
assert.deepEqual(
|
|
47
|
+
[...names].sort(),
|
|
48
|
+
[...BUILTIN_AGENT_NAMES].sort(),
|
|
49
|
+
`${path.basename(tablePath)}: role table must list exactly ${BUILTIN_AGENT_NAMES.join(", ")} once each, with no aliases`,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
describe("builtin agent documentation role tables", () => {
|
|
54
|
+
it("README lists exactly the six canonical builtins once, with no duplicates or aliases", () => {
|
|
55
|
+
const markdown = fs.readFileSync(README_PATH, "utf-8");
|
|
56
|
+
assertExactlySixBuiltins(README_PATH, README_TABLE_HEADING, markdown);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("prompting-and-roles reference lists exactly the six canonical builtins once, with no duplicates or aliases", () => {
|
|
60
|
+
const markdown = fs.readFileSync(PROMPTING_AND_ROLES_PATH, "utf-8");
|
|
61
|
+
assertExactlySixBuiltins(PROMPTING_AND_ROLES_PATH, PROMPTING_AND_ROLES_TABLE_HEADING, markdown);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import { handleList } from "../../src/agents/agent-management.ts";
|
|
4
|
+
import type { AgentConfig } from "../../src/agents/agents.ts";
|
|
5
|
+
import { resolveSubagentLaunchContract } from "../../src/api/preflight.ts";
|
|
6
|
+
import {
|
|
7
|
+
decodeSubagentCapabilityCeiling,
|
|
8
|
+
encodeSubagentCapabilityCeiling,
|
|
9
|
+
intersectSubagentCapabilityCeilings,
|
|
10
|
+
parseSubagentCapabilityCeiling,
|
|
11
|
+
registerSubagentCapabilityCeiling,
|
|
12
|
+
} from "../../src/api/capability-ceiling.ts";
|
|
13
|
+
import { runSync } from "../../src/runs/foreground/execution.ts";
|
|
14
|
+
import { buildPiArgs } from "../../src/runs/shared/pi-args.ts";
|
|
15
|
+
|
|
16
|
+
function agent(name: string): AgentConfig {
|
|
17
|
+
return {
|
|
18
|
+
name,
|
|
19
|
+
description: `${name} agent`,
|
|
20
|
+
systemPrompt: `${name} prompt`,
|
|
21
|
+
systemPromptMode: "replace",
|
|
22
|
+
inheritProjectContext: false,
|
|
23
|
+
inheritSkills: false,
|
|
24
|
+
source: "project",
|
|
25
|
+
filePath: `/tmp/${name}.md`,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe("capability ceiling agent allowlist", () => {
|
|
30
|
+
it("parses, round-trips, and intersects allowedAgents", () => {
|
|
31
|
+
const parsed = parseSubagentCapabilityCeiling({ version: 1, allowedAgents: ["worker", "reviewer", "worker"], denyExtensions: false, sources: ["plan"] });
|
|
32
|
+
assert.deepEqual(parsed.allowedAgents, ["reviewer", "worker"]);
|
|
33
|
+
assert.deepEqual(decodeSubagentCapabilityCeiling(encodeSubagentCapabilityCeiling(parsed)), parsed);
|
|
34
|
+
|
|
35
|
+
assert.deepEqual(intersectSubagentCapabilityCeilings(
|
|
36
|
+
{ version: 1, allowedAgents: ["worker", "reviewer"], denyExtensions: false, sources: ["outer"] },
|
|
37
|
+
{ version: 1, allowedAgents: ["reviewer", "scout"], denyExtensions: true, sources: ["inner"] },
|
|
38
|
+
), {
|
|
39
|
+
version: 1,
|
|
40
|
+
allowedAgents: ["reviewer"],
|
|
41
|
+
denyExtensions: true,
|
|
42
|
+
sources: ["inner", "outer"],
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
assert.deepEqual(intersectSubagentCapabilityCeilings(
|
|
46
|
+
{ version: 1, allowedTools: ["read"], denyExtensions: false, sources: ["tools-only"] },
|
|
47
|
+
{ version: 1, allowedAgents: [], denyExtensions: false, sources: ["none"] },
|
|
48
|
+
)?.allowedAgents, []);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("marks non-allowlisted agents as restricted in list output", () => {
|
|
52
|
+
const sessionId = `allowlist-list-${Date.now()}-${Math.random()}`;
|
|
53
|
+
const handle = registerSubagentCapabilityCeiling({ sessionId, source: "plan-mode", ceiling: { allowedAgents: ["commentator"] } });
|
|
54
|
+
try {
|
|
55
|
+
const result = handleList({}, { cwd: process.cwd(), currentSessionId: sessionId, modelRegistry: { getAvailable: () => [] } });
|
|
56
|
+
const text = result.content[0]?.text ?? "";
|
|
57
|
+
assert.match(text, /Executable agents:/);
|
|
58
|
+
assert.match(text, /- commentator /);
|
|
59
|
+
assert.match(text, /Restricted agents \(not executable in this session; capability ceiling: plan-mode\):/);
|
|
60
|
+
assert.match(text, /- builder /);
|
|
61
|
+
|
|
62
|
+
const catalog = (result as { details: { catalog?: unknown } }).details.catalog as
|
|
63
|
+
| undefined
|
|
64
|
+
| {
|
|
65
|
+
version: number;
|
|
66
|
+
agents: Array<{ name: string; executable: boolean; restrictionSources?: string[]; defaultContext: string }>;
|
|
67
|
+
capabilityCeilingSources?: string[];
|
|
68
|
+
};
|
|
69
|
+
assert.ok(catalog, "list result must include machine catalog metadata");
|
|
70
|
+
assert.equal(catalog.version, 1);
|
|
71
|
+
assert.deepEqual(catalog.capabilityCeilingSources, ["plan-mode"]);
|
|
72
|
+
const commentator = catalog.agents.find((entry) => entry.name === "commentator");
|
|
73
|
+
const builder = catalog.agents.find((entry) => entry.name === "builder");
|
|
74
|
+
assert.equal(commentator?.executable, true);
|
|
75
|
+
assert.equal(commentator?.restrictionSources, undefined);
|
|
76
|
+
assert.equal(commentator?.defaultContext, "fresh");
|
|
77
|
+
assert.equal(builder?.executable, false);
|
|
78
|
+
assert.deepEqual(builder?.restrictionSources, ["plan-mode"]);
|
|
79
|
+
} finally {
|
|
80
|
+
handle.dispose();
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("never recommends a capability-restricted writer for implementation list task advice", () => {
|
|
85
|
+
const sessionId = `allowlist-advice-${Date.now()}-${Math.random()}`;
|
|
86
|
+
const handle = registerSubagentCapabilityCeiling({ sessionId, source: "plan-mode", ceiling: { allowedAgents: ["commentator"] } });
|
|
87
|
+
try {
|
|
88
|
+
const result = handleList({ task: "Implement the fix" }, { cwd: process.cwd(), currentSessionId: sessionId, modelRegistry: { getAvailable: () => [] } });
|
|
89
|
+
assert.equal(result.isError, false);
|
|
90
|
+
const text = result.content[0]?.text ?? "";
|
|
91
|
+
assert.match(text, /Task-aware advisory routing:/);
|
|
92
|
+
assert.match(text, /- Intent: implementation/);
|
|
93
|
+
assert.match(text, /- Recommendation: none/);
|
|
94
|
+
assert.doesNotMatch(text, /- Recommended: /);
|
|
95
|
+
} finally {
|
|
96
|
+
handle.dispose();
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("rejects a non-allowlisted agent in preflight launch resolution", async () => {
|
|
101
|
+
const result = await resolveSubagentLaunchContract({
|
|
102
|
+
agent: "builder",
|
|
103
|
+
cwd: process.cwd(),
|
|
104
|
+
capabilityCeiling: { version: 1, allowedAgents: ["commentator"], denyExtensions: false, sources: ["plan-mode"] },
|
|
105
|
+
});
|
|
106
|
+
assert.equal(result.ok, false);
|
|
107
|
+
assert.equal(result.code, "restricted_agent");
|
|
108
|
+
assert.match(result.message, /does not allow agent 'builder'/);
|
|
109
|
+
assert.match(result.message, /Allowed agents: commentator/);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("rejects a non-allowlisted foreground launch before spawning", async () => {
|
|
113
|
+
const result = await runSync(process.cwd(), [agent("builder"), agent("commentator")], "builder", "Do work", {
|
|
114
|
+
capabilityCeiling: { version: 1, allowedAgents: ["commentator"], denyExtensions: false, sources: ["plan-mode"] },
|
|
115
|
+
});
|
|
116
|
+
assert.equal(result.exitCode, 1);
|
|
117
|
+
assert.match(result.error ?? "", /does not allow agent 'builder'/);
|
|
118
|
+
assert.deepEqual(result.capabilityCeiling?.allowedAgents, ["commentator"]);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("includes allowedAgents in propagated launch env and audit metadata", () => {
|
|
122
|
+
const { env, capabilityAudit } = buildPiArgs({
|
|
123
|
+
baseArgs: [],
|
|
124
|
+
task: "Review",
|
|
125
|
+
sessionEnabled: false,
|
|
126
|
+
inheritProjectContext: false,
|
|
127
|
+
inheritSkills: false,
|
|
128
|
+
childAgentName: "commentator",
|
|
129
|
+
capabilityCeiling: { version: 1, allowedAgents: ["commentator"], allowedTools: ["read"], denyExtensions: true, sources: ["plan-mode"] },
|
|
130
|
+
});
|
|
131
|
+
assert.equal(capabilityAudit?.agentAllowed, true);
|
|
132
|
+
assert.deepEqual(capabilityAudit?.agentRestrictionSources, ["plan-mode"]);
|
|
133
|
+
assert.ok(env.SELESAI_SUBAGENT_CAPABILITY_CEILING_V1);
|
|
134
|
+
assert.deepEqual(decodeSubagentCapabilityCeiling(env.SELESAI_SUBAGENT_CAPABILITY_CEILING_V1)?.allowedAgents, ["commentator"]);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
@@ -33,7 +33,7 @@ describe("subagent capability ceiling", () => {
|
|
|
33
33
|
});
|
|
34
34
|
|
|
35
35
|
it("rejects malformed policy and disposed updates", () => {
|
|
36
|
-
assert.throws(() => registerSubagentCapabilityCeiling({ sessionId: "x", source: "x", ceiling: {} }), /allowedTools or denyExtensions/);
|
|
36
|
+
assert.throws(() => registerSubagentCapabilityCeiling({ sessionId: "x", source: "x", ceiling: {} }), /allowedTools, allowedAgents, or denyExtensions/);
|
|
37
37
|
const handle = registerSubagentCapabilityCeiling({ sessionId: "disposed", source: "test", ceiling: { denyExtensions: true } });
|
|
38
38
|
handle.dispose();
|
|
39
39
|
assert.throws(() => handle.update({ allowedTools: ["read"] }), /disposed/);
|
|
@@ -198,6 +198,12 @@ describe("chain append requests", () => {
|
|
|
198
198
|
"reviewer:pending",
|
|
199
199
|
"auditor:pending",
|
|
200
200
|
]);
|
|
201
|
+
// Appended steps must carry their own bounded task description for fleet display.
|
|
202
|
+
assert.deepEqual(status.steps?.slice(1).map((step) => step.description), [
|
|
203
|
+
"Use {previous}",
|
|
204
|
+
"Use {previous}",
|
|
205
|
+
"Use {previous}",
|
|
206
|
+
]);
|
|
201
207
|
assert.deepEqual(status.parallelGroups, [{ start: 2, count: 2, stepIndex: 2 }]);
|
|
202
208
|
assert.equal(status.workflowGraph?.nodes[1]?.id, "step-1");
|
|
203
209
|
assert.equal(status.workflowGraph?.nodes[2]?.kind, "parallel-group");
|
|
@@ -285,7 +285,7 @@ describe("registered subagent tool prepareArguments", { skip: !schemasAvailable
|
|
|
285
285
|
const output = execFileSync(
|
|
286
286
|
process.execPath,
|
|
287
287
|
[
|
|
288
|
-
"--experimental-
|
|
288
|
+
"--experimental-strip-types",
|
|
289
289
|
"--import",
|
|
290
290
|
"./test/support/register-loader.mjs",
|
|
291
291
|
"--input-type=module",
|