@selesai/code 0.13.0 → 0.13.2
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 +22 -0
- package/dist/core/agent-session.d.ts +1 -1
- package/dist/core/agent-session.js +1 -1
- package/dist/core/sdk.d.ts +2 -2
- package/dist/core/sdk.js +1 -1
- package/dist/core/system-prompt.d.ts +1 -1
- package/dist/core/system-prompt.js +1 -1
- package/dist/extensions/package.json +1 -2
- package/dist/extensions/pi-hermes-memory/CHANGELOG.md +371 -0
- package/dist/extensions/pi-hermes-memory/LICENSE +21 -0
- package/dist/extensions/pi-hermes-memory/README.md +643 -0
- package/dist/extensions/pi-hermes-memory/docs/0.1/TASKS.md +197 -0
- package/dist/extensions/pi-hermes-memory/docs/0.2/PLAN.md +290 -0
- package/dist/extensions/pi-hermes-memory/docs/0.2/TASKS.md +134 -0
- package/dist/extensions/pi-hermes-memory/docs/0.2/TEST-PLAN.md +216 -0
- package/dist/extensions/pi-hermes-memory/docs/0.3/PLAN.md +330 -0
- package/dist/extensions/pi-hermes-memory/docs/0.3/TASKS.md +125 -0
- package/dist/extensions/pi-hermes-memory/docs/0.4/PLAN.md +160 -0
- package/dist/extensions/pi-hermes-memory/docs/0.4/TASKS.md +113 -0
- package/dist/extensions/pi-hermes-memory/docs/0.6/CHANGELOG.md +57 -0
- package/dist/extensions/pi-hermes-memory/docs/0.6/PLAN.md +202 -0
- package/dist/extensions/pi-hermes-memory/docs/0.6/TASKS.md +144 -0
- package/dist/extensions/pi-hermes-memory/docs/0.7/PLAN.md +349 -0
- package/dist/extensions/pi-hermes-memory/docs/0.7/TASKS.md +110 -0
- package/dist/extensions/pi-hermes-memory/docs/PUBLISHING.md +149 -0
- package/dist/extensions/pi-hermes-memory/docs/ROADMAP.md +468 -0
- package/dist/extensions/pi-hermes-memory/docs/images/memory-architecture.svg +1 -0
- package/dist/extensions/pi-hermes-memory/docs/images/pi-logo.svg +22 -0
- package/dist/extensions/pi-hermes-memory/docs/images/pi_memory.png +0 -0
- package/dist/extensions/pi-hermes-memory/docs/images/pi_memory.svg +19 -0
- package/dist/extensions/pi-hermes-memory/docs/images/security-flow.svg +1 -0
- package/dist/extensions/pi-hermes-memory/docs/images/session-lifecycle.svg +1 -0
- package/dist/extensions/pi-hermes-memory/docs/images/source-architecture.svg +1 -0
- package/dist/extensions/pi-hermes-memory/docs/mermaid/memory-architecture.mmd +49 -0
- package/dist/extensions/pi-hermes-memory/docs/mermaid/security-flow.mmd +40 -0
- package/dist/extensions/pi-hermes-memory/docs/mermaid/session-lifecycle.mmd +56 -0
- package/dist/extensions/pi-hermes-memory/docs/mermaid/source-architecture.mmd +54 -0
- package/dist/extensions/pi-hermes-memory/package-lock.json +3799 -0
- package/dist/extensions/pi-hermes-memory/package.json +66 -0
- package/dist/extensions/pi-hermes-memory/scripts/check-min-sdk.mjs +99 -0
- package/dist/extensions/pi-hermes-memory/scripts/ensure-dev.mjs +57 -0
- package/dist/extensions/pi-hermes-memory/src/auto-consolidation-warning.ts +6 -0
- package/dist/extensions/pi-hermes-memory/src/config.ts +178 -0
- package/dist/extensions/pi-hermes-memory/src/constants.ts +424 -0
- package/dist/extensions/pi-hermes-memory/src/extension-root-migration.ts +639 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/auto-consolidate.ts +401 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/background-review.ts +297 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/child-process-watchdog.mjs +90 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/correction-detector.ts +300 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/index-sessions.ts +86 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/insights.ts +78 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/interview.ts +37 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/learn-memory.ts +186 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/message-parts.ts +27 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/pi-child-process.ts +485 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/preview-context.ts +105 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/review-memory-ops.ts +506 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/session-backfill.ts +145 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/session-flush.ts +151 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/session-live-index.ts +94 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/skills-command.ts +1334 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/standing-pin.ts +111 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/switch-project.ts +75 -0
- package/dist/extensions/pi-hermes-memory/src/handlers/sync-markdown-memories.ts +266 -0
- package/dist/extensions/pi-hermes-memory/src/index.ts +378 -0
- package/dist/extensions/pi-hermes-memory/src/lifecycle-timing.ts +54 -0
- package/dist/extensions/pi-hermes-memory/src/paths.ts +61 -0
- package/dist/extensions/pi-hermes-memory/src/project-context.ts +13 -0
- package/dist/extensions/pi-hermes-memory/src/project-memory-migration.ts +93 -0
- package/dist/extensions/pi-hermes-memory/src/project.ts +157 -0
- package/dist/extensions/pi-hermes-memory/src/prompt-context.ts +55 -0
- package/dist/extensions/pi-hermes-memory/src/store/atomic-lock-coordinator.ts +375 -0
- package/dist/extensions/pi-hermes-memory/src/store/canonical-storage-path.ts +54 -0
- package/dist/extensions/pi-hermes-memory/src/store/content-scanner.ts +101 -0
- package/dist/extensions/pi-hermes-memory/src/store/db.ts +1180 -0
- package/dist/extensions/pi-hermes-memory/src/store/fts-query.ts +101 -0
- package/dist/extensions/pi-hermes-memory/src/store/markdown-mutation-lock.ts +38 -0
- package/dist/extensions/pi-hermes-memory/src/store/memory-lookup.ts +24 -0
- package/dist/extensions/pi-hermes-memory/src/store/memory-store.ts +1191 -0
- package/dist/extensions/pi-hermes-memory/src/store/recovery-maintenance.ts +66 -0
- package/dist/extensions/pi-hermes-memory/src/store/schema.ts +118 -0
- package/dist/extensions/pi-hermes-memory/src/store/session-anchor-search.ts +472 -0
- package/dist/extensions/pi-hermes-memory/src/store/session-indexer.ts +511 -0
- package/dist/extensions/pi-hermes-memory/src/store/session-parser.ts +213 -0
- package/dist/extensions/pi-hermes-memory/src/store/session-search.ts +234 -0
- package/dist/extensions/pi-hermes-memory/src/store/skill-store.ts +950 -0
- package/dist/extensions/pi-hermes-memory/src/store/skill-utils.ts +133 -0
- package/dist/extensions/pi-hermes-memory/src/store/sqlite-memory-store.ts +1002 -0
- package/dist/extensions/pi-hermes-memory/src/store/sqlite-native.ts +241 -0
- package/dist/extensions/pi-hermes-memory/src/store/standing-instructions.ts +247 -0
- package/dist/extensions/pi-hermes-memory/src/tools/memory-search-tool.ts +95 -0
- package/dist/extensions/pi-hermes-memory/src/tools/memory-tool.ts +469 -0
- package/dist/extensions/pi-hermes-memory/src/tools/session-search-tool.ts +246 -0
- package/dist/extensions/pi-hermes-memory/src/tools/shared-output-view.ts +170 -0
- package/dist/extensions/pi-hermes-memory/src/tools/skill-tool.ts +333 -0
- package/dist/extensions/pi-hermes-memory/src/tools/tool-result-views.ts +105 -0
- package/dist/extensions/pi-hermes-memory/src/types.ts +214 -0
- package/dist/extensions/pi-hermes-memory/tests/config.test.ts +434 -0
- package/dist/extensions/pi-hermes-memory/tests/extension-root-migration.test.ts +368 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/auto-consolidate.test.ts +984 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/background-review.test.ts +950 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/correction-detector.test.ts +671 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/insights.test.ts +157 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/interview.test.ts +127 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/pi-child-process.test.ts +905 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/preview-context.test.ts +152 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/prompt-context.test.ts +166 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/resources-discover.test.ts +71 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/review-memory-ops.test.ts +614 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/session-backfill.test.ts +192 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/session-flush.test.ts +677 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/session-live-index.test.ts +225 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/skills-command.test.ts +827 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/standing-pin.test.ts +134 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/sync-markdown-memories.test.ts +491 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/system-prompt.test.ts +199 -0
- package/dist/extensions/pi-hermes-memory/tests/handlers/thinking-max.test.ts +64 -0
- package/dist/extensions/pi-hermes-memory/tests/index.test.ts +30 -0
- package/dist/extensions/pi-hermes-memory/tests/integration/flow.test.ts +126 -0
- package/dist/extensions/pi-hermes-memory/tests/lifecycle-timing.test.ts +76 -0
- package/dist/extensions/pi-hermes-memory/tests/paths.test.ts +23 -0
- package/dist/extensions/pi-hermes-memory/tests/project-memory-migration.test.ts +80 -0
- package/dist/extensions/pi-hermes-memory/tests/project-rebinding.test.ts +115 -0
- package/dist/extensions/pi-hermes-memory/tests/project.test.ts +120 -0
- package/dist/extensions/pi-hermes-memory/tests/run-all-timeout.test.ts +107 -0
- package/dist/extensions/pi-hermes-memory/tests/run-all.sh +45 -0
- package/dist/extensions/pi-hermes-memory/tests/store/atomic-lock-coordinator.test.ts +381 -0
- package/dist/extensions/pi-hermes-memory/tests/store/content-scanner.test.ts +388 -0
- package/dist/extensions/pi-hermes-memory/tests/store/db.test.ts +1046 -0
- package/dist/extensions/pi-hermes-memory/tests/store/markdown-mutation-lock.test.ts +34 -0
- package/dist/extensions/pi-hermes-memory/tests/store/memory-store.test.ts +2150 -0
- package/dist/extensions/pi-hermes-memory/tests/store/recovery-maintenance.test.ts +170 -0
- package/dist/extensions/pi-hermes-memory/tests/store/session-anchor-search.test.ts +210 -0
- package/dist/extensions/pi-hermes-memory/tests/store/session-indexer.test.ts +643 -0
- package/dist/extensions/pi-hermes-memory/tests/store/session-parser.test.ts +282 -0
- package/dist/extensions/pi-hermes-memory/tests/store/session-search.test.ts +287 -0
- package/dist/extensions/pi-hermes-memory/tests/store/skill-store.test.ts +678 -0
- package/dist/extensions/pi-hermes-memory/tests/store/skill-utils.test.ts +21 -0
- package/dist/extensions/pi-hermes-memory/tests/store/sqlite-lazy-load.test.ts +78 -0
- package/dist/extensions/pi-hermes-memory/tests/store/sqlite-memory-store.test.ts +543 -0
- package/dist/extensions/pi-hermes-memory/tests/store/sqlite-native.test.ts +164 -0
- package/dist/extensions/pi-hermes-memory/tests/store/standing-instructions.test.ts +171 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/memory-search-tool.test.ts +84 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/memory-tool.test.ts +709 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/session-search-tool.test.ts +345 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/shared-output-view.test.ts +362 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/skill-tool.test.ts +478 -0
- package/dist/extensions/pi-hermes-memory/tests/tools/tool-result-renderer-wiring.test.ts +40 -0
- package/dist/extensions/pi-hermes-memory/tsconfig.json +19 -0
- package/dist/extensions/pi-rewind-hook/README.md +4 -1
- package/dist/extensions/pi-rewind-hook/index.ts +151 -21
- package/dist/extensions/pi-rewind-hook/package.json +5 -3
- package/dist/extensions/pi-subagents/.oxlintrc.json +43 -0
- package/dist/extensions/pi-subagents/AGENTS.md +5 -0
- package/dist/extensions/pi-subagents/CHANGELOG.md +157 -0
- package/dist/extensions/pi-subagents/README.md +12 -6
- package/dist/extensions/pi-subagents/VISION.md +81 -0
- package/dist/extensions/pi-subagents/agents/claude-code-writer.md +15 -0
- package/dist/extensions/pi-subagents/agents/claude-code.md +15 -0
- package/dist/extensions/pi-subagents/agents/codex-exec-writer.md +15 -0
- package/dist/extensions/pi-subagents/agents/codex-exec.md +15 -0
- package/dist/extensions/pi-subagents/agents/cursor-agent-writer.md +14 -0
- package/dist/extensions/pi-subagents/agents/cursor-agent.md +14 -0
- package/dist/extensions/pi-subagents/agents/reviewer.md +1 -3
- package/dist/extensions/pi-subagents/docs/agents.md +488 -0
- package/dist/extensions/pi-subagents/docs/configuration.md +46 -9
- package/dist/extensions/pi-subagents/docs/extension-api.md +42 -3
- package/dist/extensions/pi-subagents/docs/models.md +27 -4
- package/dist/extensions/pi-subagents/docs/observability.md +10 -9
- package/dist/extensions/pi-subagents/docs/tool-reference.md +102 -6
- package/dist/extensions/pi-subagents/docs/workflows.md +135 -0
- package/dist/extensions/pi-subagents/package-lock.json +389 -2
- package/dist/extensions/pi-subagents/package.json +3 -1
- package/dist/extensions/pi-subagents/prompts/review-loop.md +2 -2
- package/dist/extensions/pi-subagents/skills/council-mode/SKILL.md +1 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +3 -1
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +7 -3
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
- package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +26 -5
- package/dist/extensions/pi-subagents/src/agents/agent-management.ts +41 -22
- package/dist/extensions/pi-subagents/src/agents/agent-refinements.ts +4 -4
- package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +9 -2
- package/dist/extensions/pi-subagents/src/agents/agents.ts +322 -75
- package/dist/extensions/pi-subagents/src/agents/builtin-names.ts +6 -0
- package/dist/extensions/pi-subagents/src/agents/runtime-agent-events.ts +70 -0
- package/dist/extensions/pi-subagents/src/agents/runtime-agent-registry.ts +27 -20
- package/dist/extensions/pi-subagents/src/api/agents.ts +10 -5
- package/dist/extensions/pi-subagents/src/api/background-work.ts +5 -1
- package/dist/extensions/pi-subagents/src/api/delegation.ts +0 -7
- package/dist/extensions/pi-subagents/src/api/preflight.ts +34 -12
- package/dist/extensions/pi-subagents/src/extension/config.ts +70 -0
- package/dist/extensions/pi-subagents/src/extension/doctor.ts +3 -3
- package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +5 -3
- package/dist/extensions/pi-subagents/src/extension/index.ts +83 -30
- package/dist/extensions/pi-subagents/src/extension/public-execution.ts +44 -15
- package/dist/extensions/pi-subagents/src/extension/rpc.ts +55 -19
- package/dist/extensions/pi-subagents/src/extension/schemas.ts +41 -15
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -31
- package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +2 -1
- package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +2 -10
- package/dist/extensions/pi-subagents/src/inspectors/herdr/session-roots-codec.ts +42 -0
- package/dist/extensions/pi-subagents/src/integrations/herdr-status.ts +51 -7
- package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +2 -0
- package/dist/extensions/pi-subagents/src/profiles/profiles.ts +5 -6
- package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +77 -10
- package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +176 -53
- package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +19 -12
- package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +29 -27
- package/dist/extensions/pi-subagents/src/runs/background/async-retention.ts +20 -3
- package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +23 -261
- package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +73 -7
- package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +8 -3
- package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +74 -8
- package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +37 -21
- package/dist/extensions/pi-subagents/src/runs/background/inspect-rpc.ts +8 -8
- package/dist/extensions/pi-subagents/src/runs/background/notify.ts +184 -9
- package/dist/extensions/pi-subagents/src/runs/background/result-delivery-ownership.ts +45 -0
- package/dist/extensions/pi-subagents/src/runs/background/result-files.ts +28 -14
- package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +38 -15
- package/dist/extensions/pi-subagents/src/runs/background/resume-guidance.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +50 -13
- package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +93 -8
- package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +10 -4
- package/dist/extensions/pi-subagents/src/runs/background/steering.ts +4 -14
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +549 -377
- package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +58 -10
- package/dist/extensions/pi-subagents/src/runs/background/terminal-run-index.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +26 -1
- package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +23 -9
- package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +9 -2
- package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +2 -2
- package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +204 -129
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +9 -0
- package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +23 -1
- package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +773 -311
- package/dist/extensions/pi-subagents/src/runs/foreground/workflow-detach-reconcile.ts +140 -115
- package/dist/extensions/pi-subagents/src/runs/shared/abort-recovery.ts +119 -0
- package/dist/extensions/pi-subagents/src/runs/shared/async-status-projection.ts +463 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-identity.ts +19 -4
- package/dist/extensions/pi-subagents/src/runs/shared/child-launch-plan.ts +151 -0
- package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +21 -7
- package/dist/extensions/pi-subagents/src/runs/shared/claude-code-adapter.ts +129 -0
- package/dist/extensions/pi-subagents/src/runs/shared/codex-exec-adapter.ts +129 -0
- package/dist/extensions/pi-subagents/src/runs/shared/completion-evidence.ts +89 -0
- package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +5 -4
- package/dist/extensions/pi-subagents/src/runs/shared/cursor-agent-adapter.ts +114 -0
- package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +3 -3
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-contract.ts +167 -0
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-preflight.ts +122 -0
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +348 -55
- package/dist/extensions/pi-subagents/src/runs/shared/fast-mode-extension.ts +5 -5
- package/dist/extensions/pi-subagents/src/runs/shared/host-step-status.ts +230 -0
- package/dist/extensions/pi-subagents/src/runs/shared/lane-metadata.ts +105 -0
- package/dist/extensions/pi-subagents/src/runs/shared/launch-cwd.ts +16 -0
- package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +2 -1
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-config-sources.ts +422 -0
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +221 -158
- package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-grant.ts +197 -0
- package/dist/extensions/pi-subagents/src/runs/shared/model-exclusions.ts +69 -7
- package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +47 -6
- package/dist/extensions/pi-subagents/src/runs/shared/mutation-evidence.ts +7 -2
- package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +9 -3
- package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +9 -5
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +419 -7
- package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +15 -1
- package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +81 -8
- package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +13 -0
- package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +21 -1
- package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +44 -4
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +98 -13
- package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/shared/worktree-cleanup-plan.ts +847 -0
- package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +18 -0
- package/dist/extensions/pi-subagents/src/shared/child-session-name.ts +46 -0
- package/dist/extensions/pi-subagents/src/shared/extension-context.ts +24 -0
- package/dist/extensions/pi-subagents/src/shared/fork-context.ts +21 -0
- package/dist/extensions/pi-subagents/src/shared/formatters.ts +18 -3
- package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +5 -1
- package/dist/extensions/pi-subagents/src/shared/pruned-fork.ts +450 -0
- package/dist/extensions/pi-subagents/src/shared/session-file-trust.ts +19 -0
- package/dist/extensions/pi-subagents/src/shared/session-tokens.ts +14 -3
- package/dist/extensions/pi-subagents/src/shared/settings.ts +19 -105
- package/dist/extensions/pi-subagents/src/shared/shortcuts.ts +17 -0
- package/dist/extensions/pi-subagents/src/shared/types.ts +359 -40
- package/dist/extensions/pi-subagents/src/shared/utils.ts +41 -84
- package/dist/extensions/pi-subagents/src/shared/workflow-child-permit.ts +116 -0
- package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +1 -9
- package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +0 -4
- package/dist/extensions/pi-subagents/src/slash/slash-bridge.ts +1 -2
- package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +378 -88
- package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +22 -11
- package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +3 -0
- package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +147 -79
- package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +11 -5
- package/dist/extensions/pi-subagents/src/tui/fleet.ts +39 -18
- package/dist/extensions/pi-subagents/src/tui/render.ts +369 -46
- package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +1 -1
- package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +6 -3
- package/dist/extensions/pi-subagents/src/workflows/host-command.ts +230 -0
- package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +740 -58
- package/dist/extensions/pi-subagents/src/workflows/workflow-child-summary.ts +121 -0
- package/dist/extensions/pi-subagents/src/workflows/workflow-preflight.ts +270 -0
- package/dist/extensions/pi-subagents/src/workflows/workflow-receipt.ts +195 -6
- package/dist/extensions/pi-subagents/src/workflows/workflow-settlement.ts +246 -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 +1114 -260
- package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +34 -0
- package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +150 -3
- package/dist/extensions/pi-subagents/test/integration/claude-code-smoke.test.ts +52 -0
- package/dist/extensions/pi-subagents/test/integration/claude-code-writer-smoke.test.ts +55 -0
- package/dist/extensions/pi-subagents/test/integration/codex-exec-smoke.test.ts +53 -0
- package/dist/extensions/pi-subagents/test/integration/codex-exec-writer-smoke.test.ts +57 -0
- package/dist/extensions/pi-subagents/test/integration/cursor-agent-smoke.test.ts +59 -0
- package/dist/extensions/pi-subagents/test/integration/cursor-agent-writer-smoke.test.ts +62 -0
- package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +57 -1
- package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +20 -0
- package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +4 -3
- package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +54 -4
- package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +482 -4
- package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +157 -9
- package/dist/extensions/pi-subagents/test/integration/session-tokens.test.ts +5 -5
- package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1508 -291
- package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +423 -1
- package/dist/extensions/pi-subagents/test/integration/template-resolution.test.ts +8 -0
- package/dist/extensions/pi-subagents/test/support/cursor-smoke-inputs.ts +51 -0
- package/dist/extensions/pi-subagents/test/support/helpers.ts +2 -0
- package/dist/extensions/pi-subagents/test/support/mock-pi.ts +5 -5
- package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +6 -6
- package/dist/extensions/pi-subagents/test/unit/abort-recovery.test.ts +152 -0
- package/dist/extensions/pi-subagents/test/unit/active-async-capacity.test.ts +48 -0
- package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +184 -6
- package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +66 -6
- package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +77 -0
- package/dist/extensions/pi-subagents/test/unit/agent-refinements.test.ts +18 -0
- package/dist/extensions/pi-subagents/test/unit/anti-slop-oxlint.test.ts +86 -0
- package/dist/extensions/pi-subagents/test/unit/artifacts.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +101 -1
- package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +121 -0
- package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +28 -0
- package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +14 -7
- package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +53 -0
- package/dist/extensions/pi-subagents/test/unit/async-status-projection.test.ts +190 -0
- package/dist/extensions/pi-subagents/test/unit/async-status-snapshot.test.ts +42 -0
- package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +8 -4
- package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +23 -0
- package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +78 -1
- package/dist/extensions/pi-subagents/test/unit/child-launch-plan.test.ts +94 -0
- package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +21 -0
- package/dist/extensions/pi-subagents/test/unit/child-session-name.test.ts +50 -0
- package/dist/extensions/pi-subagents/test/unit/claude-code-adapter.test.ts +245 -0
- package/dist/extensions/pi-subagents/test/unit/codex-exec-adapter.test.ts +192 -0
- package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/unit/completion-evidence.test.ts +150 -0
- package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +21 -0
- package/dist/extensions/pi-subagents/test/unit/cursor-agent-adapter.test.ts +259 -0
- package/dist/extensions/pi-subagents/test/unit/cursor-smoke-inputs.test.ts +77 -0
- package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +1 -4
- package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/extension-context.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/unit/external-cli-runner.test.ts +223 -0
- package/dist/extensions/pi-subagents/test/unit/fast-mode-extension.test.ts +27 -0
- package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +208 -2
- package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +29 -1
- package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +110 -1
- package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +10 -0
- package/dist/extensions/pi-subagents/test/unit/formatters.test.ts +14 -0
- package/dist/extensions/pi-subagents/test/unit/herdr-inspector.test.ts +18 -9
- package/dist/extensions/pi-subagents/test/unit/herdr-session-roots-codec.test.ts +63 -0
- package/dist/extensions/pi-subagents/test/unit/herdr-shell-command.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/herdr-status-bridge.test.ts +136 -6
- package/dist/extensions/pi-subagents/test/unit/host-command.test.ts +156 -0
- package/dist/extensions/pi-subagents/test/unit/host-step-status.test.ts +98 -0
- package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +178 -26
- package/dist/extensions/pi-subagents/test/unit/index-segment.test.ts +2 -1
- package/dist/extensions/pi-subagents/test/unit/inspect-rpc.test.ts +21 -0
- package/dist/extensions/pi-subagents/test/unit/mcp-direct-tool-grant.test.ts +138 -0
- package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/model-exclusions.test.ts +91 -0
- package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +72 -7
- package/dist/extensions/pi-subagents/test/unit/mutation-evidence.test.ts +21 -0
- package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +20 -2
- package/dist/extensions/pi-subagents/test/unit/notify.test.ts +129 -1
- package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +2 -2
- package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +4 -0
- package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +358 -0
- package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +574 -21
- package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +109 -1
- package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +71 -1
- package/dist/extensions/pi-subagents/test/unit/profiles.test.ts +7 -7
- package/dist/extensions/pi-subagents/test/unit/pruned-fork.test.ts +214 -0
- package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +29 -8
- package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +53 -0
- package/dist/extensions/pi-subagents/test/unit/result-delivery-ownership.test.ts +34 -0
- package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +101 -3
- package/dist/extensions/pi-subagents/test/unit/retained-children.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +10 -8
- package/dist/extensions/pi-subagents/test/unit/run-fanout-budget.test.ts +71 -1
- package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +41 -7
- package/dist/extensions/pi-subagents/test/unit/runtime-agent-registration.test.ts +136 -2
- package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +137 -0
- package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +33 -12
- package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +504 -1
- package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +8 -0
- package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +12 -1
- package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +3 -5
- package/dist/extensions/pi-subagents/test/unit/steering.test.ts +5 -6
- package/dist/extensions/pi-subagents/test/unit/subagent-action-recovery.test.ts +0 -8
- package/dist/extensions/pi-subagents/test/unit/subagent-guide.test.ts +5 -0
- package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +157 -2
- package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +1 -1
- package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +63 -4
- package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +27 -23
- package/dist/extensions/pi-subagents/test/unit/wait-completions.test.ts +44 -0
- package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +1 -0
- package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +7 -5
- package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +106 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-detach-reconcile.test.ts +484 -9
- package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +38 -4
- package/dist/extensions/pi-subagents/test/unit/workflow-preflight.test.ts +155 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-receipt.test.ts +318 -0
- package/dist/extensions/pi-subagents/test/unit/workflow-resume-hint.test.ts +365 -0
- package/dist/extensions/pi-subagents/test/unit/worktree-cleanup-plan.test.ts +349 -0
- package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +21 -0
- package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +2 -7
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/effect/index.ts +13 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/effect/rules/no-service-constructor-imports.ts +52 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/index.ts +41 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-chained-type-assertions.ts +77 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-conditional-empty-object-spread.ts +49 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-known-value-widening.ts +247 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-module-mocking.ts +91 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-object-parameters.ts +126 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-reflect-apply.ts +28 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-reflect-get.ts +28 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-runtime-typeof.ts +67 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-shape-in-symbol-names.ts +39 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-parameters.ts +83 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-returns.ts +115 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-type-aliases.ts +72 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unsafe-dictionary-type.ts +134 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-widen-then-assert.ts +366 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/require-safety-comment-for-type-assertion.ts +62 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/dictionary-types.ts +502 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/lexical-type-parameters.ts +60 -0
- package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/reflect-method.ts +35 -0
- package/dist/extensions/pi-tool-display/tests/capabilities.test.ts +1 -1
- package/dist/extensions/pi-tool-display/tests/settings-inspector.test.ts +2 -2
- package/dist/extensions/pi-tool-display/tests/tool-overrides-mcp.test.ts +1 -1
- package/dist/modes/interactive/interactive-mode.js +7 -7
- package/dist/skills/workflow/SKILL.md +65 -50
- package/package.json +112 -110
- package/dist/extensions/enable-readonly-tools.test.ts +0 -63
- package/dist/extensions/enable-readonly-tools.ts +0 -24
- package/dist/extensions/model-prompt-injector/config.json +0 -16
- package/dist/extensions/model-prompt-injector/index.test.ts +0 -102
- package/dist/extensions/model-prompt-injector/index.ts +0 -148
- package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +0 -98
- package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +0 -250
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import type { Message } from "@earendil-works/pi-ai";
|
|
4
|
+
import { ABORT_RECOVERY_PROMPT, planAbortRecovery } from "../../src/runs/shared/abort-recovery.ts";
|
|
5
|
+
|
|
6
|
+
function messages(...entries: unknown[]): Message[] {
|
|
7
|
+
return entries as Message[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const progress = {
|
|
11
|
+
role: "assistant",
|
|
12
|
+
content: [{ type: "text", text: "Implemented the helper and running validation." }],
|
|
13
|
+
usage: { input: 10, output: 5, cacheRead: 0, cacheWrite: 0, cost: { total: 0 } },
|
|
14
|
+
};
|
|
15
|
+
const aborted = {
|
|
16
|
+
role: "assistant",
|
|
17
|
+
content: [],
|
|
18
|
+
stopReason: "aborted",
|
|
19
|
+
usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: { total: 0 } },
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
function base(overrides: Partial<Parameters<typeof planAbortRecovery>[0]> = {}) {
|
|
23
|
+
return {
|
|
24
|
+
messages: messages(progress, aborted),
|
|
25
|
+
processSignal: undefined,
|
|
26
|
+
sessionAvailable: true,
|
|
27
|
+
alreadyResumed: false,
|
|
28
|
+
...overrides,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
describe("planAbortRecovery", () => {
|
|
33
|
+
it("does not recover an abort without verified compaction settlement", () => {
|
|
34
|
+
assert.deepEqual(planAbortRecovery(base()), { action: "settle", reason: "compaction settlement not verified" });
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("plans the same retained-session continuation for a compaction-induced abort", () => {
|
|
38
|
+
assert.deepEqual(planAbortRecovery(base({ afterCompactionSettlement: true, processSignal: "SIGTERM" })), { action: "resume", prompt: ABORT_RECOVERY_PROMPT });
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("accepts a completed tool result as useful progress", () => {
|
|
42
|
+
const toolProgress = messages(
|
|
43
|
+
{ role: "assistant", content: [{ type: "toolCall", id: "call-1", name: "bash", arguments: {} }], usage: { output: 1 } },
|
|
44
|
+
{ role: "toolResult", toolCallId: "call-1", isError: false, content: [{ type: "text", text: "tests passed" }] },
|
|
45
|
+
aborted,
|
|
46
|
+
);
|
|
47
|
+
assert.equal(planAbortRecovery(base({ messages: toolProgress, afterCompactionSettlement: true })).action, "resume");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("fails closed without progress, a retained session, or a first-attempt permit", () => {
|
|
51
|
+
assert.equal(planAbortRecovery(base({ messages: messages(aborted) })).action, "settle");
|
|
52
|
+
assert.equal(planAbortRecovery(base({ sessionAvailable: false })).action, "settle");
|
|
53
|
+
assert.equal(planAbortRecovery(base({ alreadyResumed: true })).action, "settle");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("does not reinterpret an ordinary empty completion as an abort", () => {
|
|
57
|
+
const emptyStop = { ...aborted, stopReason: "stop" };
|
|
58
|
+
assert.equal(planAbortRecovery(base({ messages: messages(progress, emptyStop), processSignal: undefined })).action, "settle");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("does not treat a process signal alone as provider abort evidence", () => {
|
|
62
|
+
const emptyStop = { ...aborted, stopReason: "stop" };
|
|
63
|
+
assert.equal(planAbortRecovery(base({ messages: messages(progress, emptyStop), processSignal: "SIGKILL" })).action, "settle");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("does not resume when a process signal accompanies abort evidence", () => {
|
|
67
|
+
assert.deepEqual(planAbortRecovery(base({ processSignal: "SIGTERM" })), { action: "settle", reason: "process terminated by signal" });
|
|
68
|
+
assert.deepEqual(planAbortRecovery(base({
|
|
69
|
+
messages: messages(progress),
|
|
70
|
+
error: "Connection reset by provider transport",
|
|
71
|
+
processSignal: "SIGKILL",
|
|
72
|
+
})), { action: "settle", reason: "process terminated by signal" });
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("excludes operator control, timeouts, budgets, schema and acceptance failures", () => {
|
|
76
|
+
for (const excluded of [
|
|
77
|
+
{ stopped: true },
|
|
78
|
+
{ interrupted: true },
|
|
79
|
+
{ timedOut: true },
|
|
80
|
+
{ toolBudgetExhausted: true },
|
|
81
|
+
{ usageBudgetExhausted: true },
|
|
82
|
+
{ structuredOutputFailed: true },
|
|
83
|
+
{ acceptanceFailed: true },
|
|
84
|
+
]) {
|
|
85
|
+
assert.equal(planAbortRecovery(base(excluded)).action, "settle");
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("fails closed while a tool call is unresolved", () => {
|
|
90
|
+
const inFlight = messages(
|
|
91
|
+
{ role: "assistant", content: [{ type: "toolCall", id: "call-1", name: "bash", arguments: {} }], usage: { output: 1 } },
|
|
92
|
+
aborted,
|
|
93
|
+
);
|
|
94
|
+
assert.deepEqual(planAbortRecovery(base({ messages: inFlight, currentTool: "bash" })), { action: "settle", reason: "active tool 'bash' remains in flight" });
|
|
95
|
+
assert.deepEqual(planAbortRecovery(base({ messages: inFlight, currentTool: undefined })), { action: "settle", reason: "unresolved tool call remains in transcript" });
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("names the exact blocker when compaction abort recovery is unsafe", () => {
|
|
99
|
+
assert.deepEqual(planAbortRecovery(base({ sessionAvailable: false, afterCompactionSettlement: true })), {
|
|
100
|
+
action: "settle",
|
|
101
|
+
reason: "retained session unavailable",
|
|
102
|
+
diagnostic: "Compaction-induced child abort could not be resumed safely: retained session unavailable.",
|
|
103
|
+
});
|
|
104
|
+
assert.deepEqual(planAbortRecovery(base({ currentTool: "bash", afterCompactionSettlement: true })), {
|
|
105
|
+
action: "settle",
|
|
106
|
+
reason: "active tool 'bash' remains in flight",
|
|
107
|
+
diagnostic: "Compaction-induced child abort could not be resumed safely: active tool 'bash' remains in flight.",
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("requires terminal assistant abort evidence for compaction recovery", () => {
|
|
112
|
+
assert.deepEqual(planAbortRecovery(base({
|
|
113
|
+
messages: messages(progress),
|
|
114
|
+
processSignal: undefined,
|
|
115
|
+
error: "Connection reset by provider transport",
|
|
116
|
+
})), { action: "settle", reason: "compaction settlement not verified" });
|
|
117
|
+
assert.deepEqual(planAbortRecovery(base({
|
|
118
|
+
messages: messages(progress),
|
|
119
|
+
processSignal: undefined,
|
|
120
|
+
error: "Connection reset by provider transport",
|
|
121
|
+
afterCompactionSettlement: true,
|
|
122
|
+
})), { action: "settle", reason: "terminal assistant abort evidence not verified" });
|
|
123
|
+
assert.equal(planAbortRecovery(base({
|
|
124
|
+
messages: messages(progress, { ...aborted, stopReason: "error", errorMessage: "This operation was aborted" }),
|
|
125
|
+
processSignal: undefined,
|
|
126
|
+
error: "This operation was aborted",
|
|
127
|
+
afterCompactionSettlement: true,
|
|
128
|
+
})).action, "resume");
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("does not recover a generic transport abort after a normally settled compaction", () => {
|
|
132
|
+
const settled = {
|
|
133
|
+
role: "assistant",
|
|
134
|
+
content: [{ type: "text", text: "Compaction completed and the child settled normally." }],
|
|
135
|
+
stopReason: "stop",
|
|
136
|
+
usage: { input: 10, output: 5, cacheRead: 0, cacheWrite: 0, cost: { total: 0 } },
|
|
137
|
+
};
|
|
138
|
+
assert.deepEqual(planAbortRecovery(base({
|
|
139
|
+
messages: messages(progress, settled),
|
|
140
|
+
error: "Connection reset by provider transport",
|
|
141
|
+
afterCompactionSettlement: true,
|
|
142
|
+
})), { action: "settle", reason: "terminal assistant abort evidence not verified" });
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("does not reinterpret a network-flavored task tool failure as a provider abort", () => {
|
|
146
|
+
assert.equal(planAbortRecovery(base({
|
|
147
|
+
messages: messages(progress),
|
|
148
|
+
processSignal: undefined,
|
|
149
|
+
error: "bash failed (exit 1): request connection error",
|
|
150
|
+
})).action, "settle");
|
|
151
|
+
});
|
|
152
|
+
});
|
|
@@ -364,4 +364,52 @@ describe("active async capacity", () => {
|
|
|
364
364
|
fs.rmSync(rootDir, { recursive: true, force: true });
|
|
365
365
|
}
|
|
366
366
|
});
|
|
367
|
+
|
|
368
|
+
it("reclaims only old failed runs with dead runners under the abandoned-timeout policy", () => {
|
|
369
|
+
const cases = [
|
|
370
|
+
{ name: "dead old", state: "failed", pidLiveness: "dead" as const, lastActivityAt: 0, threshold: 1_000, releases: true },
|
|
371
|
+
{ name: "dead recent", state: "failed", pidLiveness: "dead" as const, lastActivityAt: 9_500, threshold: 1_000, releases: false },
|
|
372
|
+
{ name: "alive old", state: "failed", pidLiveness: "alive" as const, lastActivityAt: 0, threshold: 1_000, releases: false },
|
|
373
|
+
{ name: "unknown old", state: "failed", pidLiveness: "unknown" as const, lastActivityAt: 0, threshold: 1_000, releases: false },
|
|
374
|
+
{ name: "strict mode", state: "failed", pidLiveness: "dead" as const, lastActivityAt: 0, threshold: false as const, releases: false },
|
|
375
|
+
{ name: "successful old", state: "complete", pidLiveness: "dead" as const, lastActivityAt: 0, threshold: 1_000, releases: false },
|
|
376
|
+
];
|
|
377
|
+
for (const [index, testCase] of cases.entries()) {
|
|
378
|
+
const rootDir = tempRoot();
|
|
379
|
+
const asyncDir = path.join(rootDir, "runs", `run-${index}`);
|
|
380
|
+
try {
|
|
381
|
+
const handle = acquireActiveAsyncCapacity({ sessionId: "session-policy", limit: 1, runId: `run-${index}`, kind: "runner", asyncDir }, { rootDir });
|
|
382
|
+
assert.ok(handle);
|
|
383
|
+
handle.markStarted(`runner-${index}`);
|
|
384
|
+
writeJson(path.join(asyncDir, "status.json"), {
|
|
385
|
+
runId: `run-${index}`,
|
|
386
|
+
sessionId: "session-policy",
|
|
387
|
+
mode: "single",
|
|
388
|
+
state: testCase.state,
|
|
389
|
+
pid: 50_000 + index,
|
|
390
|
+
startedAt: 0,
|
|
391
|
+
lastActivityAt: testCase.lastActivityAt,
|
|
392
|
+
processTerminal: { version: 1, state: "unknown", runId: `run-${index}`, runnerProcessInstanceId: `runner-${index}`, reason: "stale-repair" },
|
|
393
|
+
});
|
|
394
|
+
const options = {
|
|
395
|
+
rootDir,
|
|
396
|
+
now: () => 10_000,
|
|
397
|
+
pidLiveness: () => testCase.pidLiveness,
|
|
398
|
+
abandonedSlotReleaseAfterMs: testCase.threshold,
|
|
399
|
+
};
|
|
400
|
+
const inspection = inspectActiveAsyncCapacityOwner({ runId: `run-${index}`, sessionId: "session-policy", asyncDir }, options);
|
|
401
|
+
assert.equal(inspection.release.state, testCase.releases ? "releasable" : "retained", testCase.name);
|
|
402
|
+
if (testCase.releases) {
|
|
403
|
+
assert.match(inspection.release.reason, /abandoned-timeout/);
|
|
404
|
+
assert.match(inspection.release.reason, /process proof unknown/);
|
|
405
|
+
assert.deepEqual(getActiveAsyncCapacitySnapshot("session-policy", 1, options), { used: 0, limit: 1 });
|
|
406
|
+
assert.match(fs.readFileSync(path.join(asyncDir, "events.jsonl"), "utf-8"), /"releasedBy":"abandoned-timeout"/);
|
|
407
|
+
} else {
|
|
408
|
+
assert.deepEqual(getActiveAsyncCapacitySnapshot("session-policy", 1, options), { used: 1, limit: 1 });
|
|
409
|
+
}
|
|
410
|
+
} finally {
|
|
411
|
+
fs.rmSync(rootDir, { recursive: true, force: true });
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
});
|
|
367
415
|
});
|
|
@@ -7,7 +7,7 @@ import { afterEach, describe, it } from "node:test";
|
|
|
7
7
|
import { handleManagementAction } from "../../src/agents/agent-management.ts";
|
|
8
8
|
import { serializeAgent } from "../../src/agents/agent-serializer.ts";
|
|
9
9
|
import { parseChain, serializeChain } from "../../src/agents/chain-serializer.ts";
|
|
10
|
-
import { discoverAgents, discoverAgentsAll, type AgentConfig } from "../../src/agents/agents.ts";
|
|
10
|
+
import { discoverAgents, discoverAgentsAll, inspectAgentDefinitionDirectory, type AgentConfig } from "../../src/agents/agents.ts";
|
|
11
11
|
import { parseFrontmatter } from "../../src/agents/frontmatter.ts";
|
|
12
12
|
import { buildPiArgs } from "../../src/runs/shared/pi-args.ts";
|
|
13
13
|
import { THINKING_LEVELS } from "../../src/shared/model-info.ts";
|
|
@@ -101,6 +101,38 @@ afterEach(() => {
|
|
|
101
101
|
}
|
|
102
102
|
});
|
|
103
103
|
|
|
104
|
+
describe("agent definition directory inspection", () => {
|
|
105
|
+
it("distinguishes absent, empty, candidates, unreadable, and non-directory paths", () => {
|
|
106
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-agent-inspection-"));
|
|
107
|
+
tempDirs.push(root);
|
|
108
|
+
const empty = path.join(root, "empty");
|
|
109
|
+
const candidates = path.join(root, "candidates");
|
|
110
|
+
const file = path.join(root, "not-directory");
|
|
111
|
+
fs.mkdirSync(empty);
|
|
112
|
+
fs.mkdirSync(candidates);
|
|
113
|
+
fs.writeFileSync(path.join(candidates, "worker.md"), "---\nname: worker\ndescription: Worker\n---\n", "utf-8");
|
|
114
|
+
fs.writeFileSync(file, "not a directory", "utf-8");
|
|
115
|
+
assert.equal(inspectAgentDefinitionDirectory(path.join(root, "absent")).state, "absent");
|
|
116
|
+
assert.equal(inspectAgentDefinitionDirectory(empty).state, "empty");
|
|
117
|
+
assert.deepEqual(inspectAgentDefinitionDirectory(candidates), { state: "candidates", files: [path.join(candidates, "worker.md")] });
|
|
118
|
+
assert.equal(inspectAgentDefinitionDirectory(file).state, "not-directory");
|
|
119
|
+
assert.equal(inspectAgentDefinitionDirectory(path.join(root, "blocked"), {
|
|
120
|
+
existsSync: () => true,
|
|
121
|
+
statSync: () => ({ isDirectory: () => true }),
|
|
122
|
+
readdirSync: () => { throw new Error("permission denied"); },
|
|
123
|
+
}).state, "unreadable");
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("reports cached builtin and configured project definition paths without synthesizing a root", () => withTempHome(() => {
|
|
127
|
+
const project = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-agent-report-"));
|
|
128
|
+
tempDirs.push(project);
|
|
129
|
+
writeJson(path.join(project, ".selesai", "settings.json"), { subagents: { projectRootResolution: "nearest" } });
|
|
130
|
+
const discovered = discoverAgents(project, "project");
|
|
131
|
+
assert.ok(discovered.directories.some((entry) => entry.source === "builtin"));
|
|
132
|
+
assert.deepEqual(discovered.directories.filter((entry) => entry.source === "project").map((entry) => entry.path), [path.join(project, ".agents"), path.join(project, ".selesai", "agents")]);
|
|
133
|
+
}));
|
|
134
|
+
});
|
|
135
|
+
|
|
104
136
|
describe("folded frontmatter blocks", () => {
|
|
105
137
|
it("folds ordinary lines and paragraph breaks for > and >-", () => {
|
|
106
138
|
const expected = "first line second line\nthird line";
|
|
@@ -215,6 +247,28 @@ Review carefully.`.replace(" description:", "description:"));
|
|
|
215
247
|
assert.deepEqual(discoverAgents(project, "project").agents.find((agent) => agent.name === "external")?.runner, external.runner);
|
|
216
248
|
}));
|
|
217
249
|
|
|
250
|
+
it("keeps external-cli stop code-owned while refusing capability widening", () => withTempHome(() => {
|
|
251
|
+
const project = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-runner-capabilities-"));
|
|
252
|
+
tempDirs.push(project);
|
|
253
|
+
const agentPath = path.join(project, ".selesai", "agents", "external.md");
|
|
254
|
+
writeAgent(agentPath, `---\nname: external\ndescription: External runner\nrunner:\n type: external-cli\n command: node\n capabilities:\n steer: false\n---\nReview.`);
|
|
255
|
+
assert.deepEqual(discoverAgents(project, "project").agents.find((agent) => agent.name === "external")?.runner, {
|
|
256
|
+
type: "external-cli",
|
|
257
|
+
command: "node",
|
|
258
|
+
capabilities: { steer: false },
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
writeAgent(agentPath, `---\nname: external\ndescription: External runner\nrunner:\n type: external-cli\n command: node\n capabilities:\n stop: false\n---\nReview.`);
|
|
262
|
+
const narrowedStop = discoverAgents(project, "project");
|
|
263
|
+
assert.equal(narrowedStop.agents.some((agent) => agent.name === "external"), false);
|
|
264
|
+
assert.match(narrowedStop.agentDiagnostics?.[0]?.error ?? "", /capabilities has unsupported fields: stop/);
|
|
265
|
+
|
|
266
|
+
writeAgent(agentPath, `---\nname: external\ndescription: External runner\nrunner:\n type: external-cli\n command: node\n capabilities:\n steer: true\n---\nReview.`);
|
|
267
|
+
const widened = discoverAgents(project, "project");
|
|
268
|
+
assert.equal(widened.agents.some((agent) => agent.name === "external"), false);
|
|
269
|
+
assert.match(widened.agentDiagnostics?.[0]?.error ?? "", /steer may only be false; user config cannot widen code-owned external adapter capabilities/);
|
|
270
|
+
}));
|
|
271
|
+
|
|
218
272
|
it("parses and serializes an external-job runner", () => withTempHome(() => {
|
|
219
273
|
const project = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-external-job-agent-"));
|
|
220
274
|
tempDirs.push(project);
|
|
@@ -270,6 +324,25 @@ Review carefully.`);
|
|
|
270
324
|
assert.equal(discovered.agentDiagnostics?.[0]?.name, "broken");
|
|
271
325
|
}));
|
|
272
326
|
|
|
327
|
+
it("follows symlinked agent directories once without hiding diagnostics", () => withTempHome(() => {
|
|
328
|
+
const project = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-symlinked-agent-dir-"));
|
|
329
|
+
tempDirs.push(project);
|
|
330
|
+
const legacyAgentsRoot = path.join(project, ".agents");
|
|
331
|
+
const sharedAgents = path.join(project, "shared-agents");
|
|
332
|
+
const linkedAgents = path.join(legacyAgentsRoot, "agents");
|
|
333
|
+
fs.mkdirSync(legacyAgentsRoot, { recursive: true });
|
|
334
|
+
fs.mkdirSync(sharedAgents, { recursive: true });
|
|
335
|
+
writeAgent(path.join(sharedAgents, "linked.md"), "---\nname: linked\ndescription: Linked agent\n---\nBody");
|
|
336
|
+
writeAgent(path.join(sharedAgents, "broken.md"), "---\nname: broken\ndescription: Broken\nrunner:\n type: unknown\n---\nBody");
|
|
337
|
+
fs.symlinkSync(sharedAgents, linkedAgents, process.platform === "win32" ? "junction" : "dir");
|
|
338
|
+
fs.symlinkSync(path.join(sharedAgents, "missing"), path.join(sharedAgents, "dangling"), process.platform === "win32" ? "junction" : "dir");
|
|
339
|
+
if (process.platform !== "win32") fs.symlinkSync(sharedAgents, path.join(sharedAgents, "loop"), "dir");
|
|
340
|
+
|
|
341
|
+
const discovered = discoverAgents(project, "project");
|
|
342
|
+
assert.equal(discovered.agents.find((agent) => agent.name === "linked")?.filePath, path.join(linkedAgents, "linked.md"));
|
|
343
|
+
assert.equal(discovered.agentDiagnostics?.find((diagnostic) => diagnostic.name === "broken")?.filePath, path.join(linkedAgents, "broken.md"));
|
|
344
|
+
}));
|
|
345
|
+
|
|
273
346
|
it("keeps a lower-priority agent available when a project override is malformed", () => withTempHome(() => {
|
|
274
347
|
const project = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-invalid-agent-shadow-"));
|
|
275
348
|
tempDirs.push(project);
|
|
@@ -622,7 +695,6 @@ Do work
|
|
|
622
695
|
defaultAsync: false,
|
|
623
696
|
defaultTimeoutMs: 90_000,
|
|
624
697
|
defaultToolTimeoutMs: 600_000,
|
|
625
|
-
defaultTurnBudget: { maxTurns: 12, graceTurns: 2 },
|
|
626
698
|
defaultAcceptance: { level: "none", reason: "lightweight lookup" },
|
|
627
699
|
};
|
|
628
700
|
|
|
@@ -630,7 +702,6 @@ Do work
|
|
|
630
702
|
assert.match(serialized, /^async: false$/m);
|
|
631
703
|
assert.match(serialized, /^timeoutMs: 90000$/m);
|
|
632
704
|
assert.match(serialized, /^toolTimeoutMs: 600000$/m);
|
|
633
|
-
assert.match(serialized, /^turnBudget: \{"maxTurns":12,"graceTurns":2\}$/m);
|
|
634
705
|
assert.match(serialized, /^acceptance: \{"level":"none","reason":"lightweight lookup"\}$/m);
|
|
635
706
|
writeAgent(filePath, serialized);
|
|
636
707
|
|
|
@@ -638,7 +709,6 @@ Do work
|
|
|
638
709
|
assert.equal(worker?.defaultAsync, false);
|
|
639
710
|
assert.equal(worker?.defaultTimeoutMs, 90_000);
|
|
640
711
|
assert.equal(worker?.defaultToolTimeoutMs, 600_000);
|
|
641
|
-
assert.deepEqual(worker?.defaultTurnBudget, { maxTurns: 12, graceTurns: 2 });
|
|
642
712
|
assert.deepEqual(worker?.defaultAcceptance, { level: "none", reason: "lightweight lookup" });
|
|
643
713
|
});
|
|
644
714
|
|
|
@@ -867,6 +937,59 @@ Plan the work.
|
|
|
867
937
|
assert.equal(agent.source, "package");
|
|
868
938
|
}));
|
|
869
939
|
|
|
940
|
+
it("loads bare HTTPS git packages from project Pi settings", () => withTempHome(() => {
|
|
941
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-settings-bare-git-package-"));
|
|
942
|
+
tempDirs.push(dir);
|
|
943
|
+
const packageRoot = path.join(dir, ".selesai", "git", "github.com", "user", "repo");
|
|
944
|
+
writeJson(path.join(dir, ".selesai", "settings.json"), {
|
|
945
|
+
packages: ["https://github.com/user/repo.git"],
|
|
946
|
+
});
|
|
947
|
+
writeJson(path.join(packageRoot, "package.json"), {
|
|
948
|
+
name: "bare-git-workflow",
|
|
949
|
+
"pi-subagents": { agents: ["./agents"] },
|
|
950
|
+
});
|
|
951
|
+
writeAgent(path.join(packageRoot, "agents", "planner.md"), `---
|
|
952
|
+
name: planner
|
|
953
|
+
package: bare-git-workflow
|
|
954
|
+
description: Plan from a bare HTTPS git package.
|
|
955
|
+
---
|
|
956
|
+
|
|
957
|
+
Plan the work.
|
|
958
|
+
`);
|
|
959
|
+
|
|
960
|
+
const agent = discoverAgents(dir, "both").agents.find((candidate) => candidate.name === "bare-git-workflow.planner");
|
|
961
|
+
assert.ok(agent);
|
|
962
|
+
assert.equal(agent.source, "package");
|
|
963
|
+
assert.equal(agent.packageSourceRoot, packageRoot);
|
|
964
|
+
}));
|
|
965
|
+
|
|
966
|
+
it("loads bare HTTP git packages from user Pi settings", () => withTempHome((home) => {
|
|
967
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-user-settings-bare-git-package-"));
|
|
968
|
+
tempDirs.push(dir);
|
|
969
|
+
const agentDir = path.join(home, ".selesai", "agent");
|
|
970
|
+
const packageRoot = path.join(agentDir, "git", "git.example.com", "team", "repo");
|
|
971
|
+
writeJson(path.join(agentDir, "settings.json"), {
|
|
972
|
+
packages: ["http://git.example.com/team/repo.git"],
|
|
973
|
+
});
|
|
974
|
+
writeJson(path.join(packageRoot, "package.json"), {
|
|
975
|
+
name: "user-bare-git-workflow",
|
|
976
|
+
"pi-subagents": { agents: ["./agents"] },
|
|
977
|
+
});
|
|
978
|
+
writeAgent(path.join(packageRoot, "agents", "reviewer.md"), `---
|
|
979
|
+
name: reviewer
|
|
980
|
+
package: user-bare-git-workflow
|
|
981
|
+
description: Review from a bare HTTP git package.
|
|
982
|
+
---
|
|
983
|
+
|
|
984
|
+
Review the work.
|
|
985
|
+
`);
|
|
986
|
+
|
|
987
|
+
const agent = discoverAgents(dir, "both").agents.find((candidate) => candidate.name === "user-bare-git-workflow.reviewer");
|
|
988
|
+
assert.ok(agent);
|
|
989
|
+
assert.equal(agent.source, "package");
|
|
990
|
+
assert.equal(agent.packageSourceRoot, packageRoot);
|
|
991
|
+
}));
|
|
992
|
+
|
|
870
993
|
it("discovers project package agents when cwd is nested below the project root", () => withTempHome(() => {
|
|
871
994
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-nested-package-discovery-"));
|
|
872
995
|
tempDirs.push(dir);
|
|
@@ -1313,6 +1436,39 @@ Inspect code
|
|
|
1313
1436
|
});
|
|
1314
1437
|
});
|
|
1315
1438
|
|
|
1439
|
+
describe("agent frontmatter allowNestedSubagents", () => {
|
|
1440
|
+
it("serializes and parses explicit nested fanout authorization", () => {
|
|
1441
|
+
const agent: AgentConfig = {
|
|
1442
|
+
name: "delegator",
|
|
1443
|
+
description: "Delegator",
|
|
1444
|
+
systemPrompt: "Delegate focused work",
|
|
1445
|
+
systemPromptMode: "replace",
|
|
1446
|
+
inheritProjectContext: false,
|
|
1447
|
+
inheritSkills: false,
|
|
1448
|
+
source: "project",
|
|
1449
|
+
filePath: "/tmp/delegator.md",
|
|
1450
|
+
allowNestedSubagents: true,
|
|
1451
|
+
};
|
|
1452
|
+
assert.match(serializeAgent(agent), /allowNestedSubagents: true/);
|
|
1453
|
+
|
|
1454
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-agent-nested-fanout-"));
|
|
1455
|
+
tempDirs.push(dir);
|
|
1456
|
+
const agentsDir = path.join(dir, ".selesai", "agents");
|
|
1457
|
+
fs.mkdirSync(agentsDir, { recursive: true });
|
|
1458
|
+
fs.writeFileSync(path.join(agentsDir, "delegator.md"), `---
|
|
1459
|
+
name: delegator
|
|
1460
|
+
description: Delegator
|
|
1461
|
+
allowNestedSubagents: true
|
|
1462
|
+
---
|
|
1463
|
+
|
|
1464
|
+
Delegate focused work
|
|
1465
|
+
`, "utf-8");
|
|
1466
|
+
const discovered = discoverAgents(dir, "project").agents.find((candidate) => candidate.name === "delegator");
|
|
1467
|
+
assert.equal(discovered?.allowNestedSubagents, true);
|
|
1468
|
+
assert.equal(discovered?.extraFields?.allowNestedSubagents, undefined);
|
|
1469
|
+
});
|
|
1470
|
+
});
|
|
1471
|
+
|
|
1316
1472
|
describe("agent frontmatter thinking", () => {
|
|
1317
1473
|
it("coerces frontmatter false strings to disabled thinking", () => {
|
|
1318
1474
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-agent-thinking-false-"));
|
|
@@ -1463,6 +1619,7 @@ describe("agent frontmatter prompt inheritance flags", () => {
|
|
|
1463
1619
|
systemPrompt: "Do work",
|
|
1464
1620
|
systemPromptMode: "replace",
|
|
1465
1621
|
inheritProjectContext: true,
|
|
1622
|
+
inheritGlobalContext: true,
|
|
1466
1623
|
inheritSkills: true,
|
|
1467
1624
|
source: "project",
|
|
1468
1625
|
filePath: "/tmp/worker.md",
|
|
@@ -1470,6 +1627,7 @@ describe("agent frontmatter prompt inheritance flags", () => {
|
|
|
1470
1627
|
|
|
1471
1628
|
const serialized = serializeAgent(agent);
|
|
1472
1629
|
assert.match(serialized, /inheritProjectContext: true/);
|
|
1630
|
+
assert.match(serialized, /inheritGlobalContext: true/);
|
|
1473
1631
|
assert.match(serialized, /inheritSkills: true/);
|
|
1474
1632
|
});
|
|
1475
1633
|
|
|
@@ -1482,6 +1640,7 @@ describe("agent frontmatter prompt inheritance flags", () => {
|
|
|
1482
1640
|
name: worker
|
|
1483
1641
|
description: Worker
|
|
1484
1642
|
inheritProjectContext: true
|
|
1643
|
+
inheritGlobalContext: true
|
|
1485
1644
|
inheritSkills: true
|
|
1486
1645
|
---
|
|
1487
1646
|
|
|
@@ -1491,8 +1650,27 @@ Do work
|
|
|
1491
1650
|
const result = discoverAgents(dir, "project");
|
|
1492
1651
|
const worker = result.agents.find((agent) => agent.name === "worker");
|
|
1493
1652
|
assert.equal(worker?.inheritProjectContext, true);
|
|
1653
|
+
assert.equal(worker?.inheritGlobalContext, true);
|
|
1494
1654
|
assert.equal(worker?.inheritSkills, true);
|
|
1495
1655
|
});
|
|
1656
|
+
|
|
1657
|
+
it("defaults inheritGlobalContext to false when frontmatter omits it", () => {
|
|
1658
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-agent-prompt-inheritance-frontmatter-"));
|
|
1659
|
+
tempDirs.push(dir);
|
|
1660
|
+
const agentsDir = path.join(dir, ".selesai", "agents");
|
|
1661
|
+
fs.mkdirSync(agentsDir, { recursive: true });
|
|
1662
|
+
fs.writeFileSync(path.join(agentsDir, "worker.md"), `---
|
|
1663
|
+
name: worker
|
|
1664
|
+
description: Worker
|
|
1665
|
+
---
|
|
1666
|
+
|
|
1667
|
+
Do work
|
|
1668
|
+
`, "utf-8");
|
|
1669
|
+
|
|
1670
|
+
const result = discoverAgents(dir, "project");
|
|
1671
|
+
const worker = result.agents.find((agent) => agent.name === "worker");
|
|
1672
|
+
assert.equal(worker?.inheritGlobalContext, false);
|
|
1673
|
+
});
|
|
1496
1674
|
});
|
|
1497
1675
|
|
|
1498
1676
|
describe("agent frontmatter subagentOnlyExtensions", () => {
|
|
@@ -2044,7 +2222,7 @@ Canonical prompt
|
|
|
2044
2222
|
assert.equal(result.projectDir, path.join(dir, ".selesai", "agents"));
|
|
2045
2223
|
});
|
|
2046
2224
|
|
|
2047
|
-
it("discovers project chains from .
|
|
2225
|
+
it("discovers project chains from .selesai/chains", () => {
|
|
2048
2226
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-project-chain-dirs-"));
|
|
2049
2227
|
tempDirs.push(dir);
|
|
2050
2228
|
fs.mkdirSync(path.join(dir, ".selesai", "agents"), { recursive: true });
|
|
@@ -2075,7 +2253,7 @@ Inspect canonical
|
|
|
2075
2253
|
assert.equal(result.projectChainDir, path.join(dir, ".selesai", "chains"));
|
|
2076
2254
|
});
|
|
2077
2255
|
|
|
2078
|
-
it("prefers project .
|
|
2256
|
+
it("prefers project .selesai/chains over user chains on name collisions", () => {
|
|
2079
2257
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-project-chain-collision-"));
|
|
2080
2258
|
const home = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-user-chain-home-"));
|
|
2081
2259
|
tempDirs.push(dir, home);
|
|
@@ -60,6 +60,55 @@ describe("agent management config parsing", () => {
|
|
|
60
60
|
assert.doesNotMatch(readText(result), /- scout \(builtin/);
|
|
61
61
|
});
|
|
62
62
|
|
|
63
|
+
it("rejects management attempts to widen the reserved read-only Claude profile", () => {
|
|
64
|
+
const ctx = { cwd: tempDir, modelRegistry: { getAvailable: () => [] } };
|
|
65
|
+
const writerRunner = { type: "external-cli", adapter: "claude-code-writer", command: "claude" };
|
|
66
|
+
const unsafeCreate = handleCreate({ config: { name: "claude-code", description: "Unsafe shadow", scope: "project", runner: writerRunner } }, ctx);
|
|
67
|
+
assert.equal(unsafeCreate.isError, true);
|
|
68
|
+
assert.match(readText(unsafeCreate), /reserved for the read-only 'claude-code' adapter/);
|
|
69
|
+
const unsafeLocalName = handleCreate({ config: { name: "claude-code", package: "custom", description: "Unsafe local name", scope: "project", runner: writerRunner } }, ctx);
|
|
70
|
+
assert.equal(unsafeLocalName.isError, true);
|
|
71
|
+
assert.match(readText(unsafeLocalName), /Selection name 'claude-code' is reserved/);
|
|
72
|
+
const unsafeAlias = handleCreate({ config: { name: "aliased-writer", aliases: ["claude-code"], description: "Unsafe alias", scope: "project", runner: writerRunner } }, ctx);
|
|
73
|
+
assert.equal(unsafeAlias.isError, true);
|
|
74
|
+
assert.match(readText(unsafeAlias), /Selection name 'claude-code' is reserved/);
|
|
75
|
+
|
|
76
|
+
const readOnlyCreate = handleCreate({ config: { name: "claude-code", description: "Narrow shadow", scope: "project", runner: { type: "external-cli", adapter: "claude-code", command: "claude" } } }, ctx);
|
|
77
|
+
assert.equal(readOnlyCreate.isError, false);
|
|
78
|
+
const unsafeUpdate = handleUpdate({ agent: "claude-code", agentScope: "project", config: { runner: writerRunner } }, ctx);
|
|
79
|
+
assert.equal(unsafeUpdate.isError, true);
|
|
80
|
+
assert.match(readText(unsafeUpdate), /reserved for the read-only 'claude-code' adapter/);
|
|
81
|
+
assert.match(fs.readFileSync(path.join(tempDir, ".selesai", "agents", "claude-code.md"), "utf-8"), /adapter: claude-code\n/);
|
|
82
|
+
|
|
83
|
+
const writerCreate = handleCreate({ config: { name: "custom-writer", description: "Writer", scope: "project", runner: writerRunner } }, ctx);
|
|
84
|
+
assert.equal(writerCreate.isError, false);
|
|
85
|
+
const unsafeAliasUpdate = handleUpdate({ agent: "custom-writer", agentScope: "project", config: { aliases: ["claude-code"] } }, ctx);
|
|
86
|
+
assert.equal(unsafeAliasUpdate.isError, true);
|
|
87
|
+
assert.match(readText(unsafeAliasUpdate), /Selection name 'claude-code' is reserved/);
|
|
88
|
+
const unsafeRename = handleUpdate({ agent: "custom-writer", agentScope: "project", config: { name: "claude-code" } }, ctx);
|
|
89
|
+
assert.equal(unsafeRename.isError, true);
|
|
90
|
+
assert.match(readText(unsafeRename), /reserved for the read-only 'claude-code' adapter/);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("rejects create, update, alias, and rename widening for Codex and Cursor", () => {
|
|
94
|
+
const ctx = { cwd: tempDir, modelRegistry: { getAvailable: () => [] } };
|
|
95
|
+
for (const [readOnly, writer, command] of [["codex-exec", "codex-exec-writer", "codex"], ["cursor-agent", "cursor-agent-writer", "cursor-agent"]] as const) {
|
|
96
|
+
const writerRunner = { type: "external-cli", adapter: writer, command };
|
|
97
|
+
assert.equal(handleCreate({ config: { name: readOnly, description: "Unsafe shadow", scope: "project", runner: writerRunner } }, ctx).isError, true);
|
|
98
|
+
assert.equal(handleCreate({ config: { name: readOnly, package: `custom-${readOnly}`, description: "Unsafe local name", scope: "project", runner: writerRunner } }, ctx).isError, true);
|
|
99
|
+
assert.equal(handleCreate({ config: { name: `${readOnly}-alias`, aliases: [readOnly], description: "Unsafe alias", scope: "project", runner: writerRunner } }, ctx).isError, true);
|
|
100
|
+
|
|
101
|
+
const readOnlyCreate = handleCreate({ config: { name: readOnly, description: "Narrow shadow", scope: "project", runner: { type: "external-cli", adapter: readOnly, command } } }, ctx);
|
|
102
|
+
assert.equal(readOnlyCreate.isError, false);
|
|
103
|
+
assert.equal(handleUpdate({ agent: readOnly, agentScope: "project", config: { runner: writerRunner } }, ctx).isError, true);
|
|
104
|
+
|
|
105
|
+
const customName = `custom-${writer}`;
|
|
106
|
+
assert.equal(handleCreate({ config: { name: customName, description: "Writer", scope: "project", runner: writerRunner } }, ctx).isError, false);
|
|
107
|
+
assert.equal(handleUpdate({ agent: customName, agentScope: "project", config: { aliases: [readOnly] } }, ctx).isError, true);
|
|
108
|
+
assert.equal(handleUpdate({ agent: customName, agentScope: "project", config: { name: readOnly } }, ctx).isError, true);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
63
112
|
it("lists valid agents and diagnoses malformed agent definitions", () => {
|
|
64
113
|
const agentsDir = path.join(tempDir, ".selesai", "agents");
|
|
65
114
|
fs.mkdirSync(agentsDir, { recursive: true });
|
|
@@ -499,7 +548,6 @@ Advise only.
|
|
|
499
548
|
scope: "project",
|
|
500
549
|
async: false,
|
|
501
550
|
timeoutMs: 120_000,
|
|
502
|
-
turnBudget: { maxTurns: 8, graceTurns: 2 },
|
|
503
551
|
acceptance: { level: "none", reason: "lightweight reviewer" },
|
|
504
552
|
outputMode: "file-only",
|
|
505
553
|
},
|
|
@@ -512,7 +560,6 @@ Advise only.
|
|
|
512
560
|
let content = fs.readFileSync(filePath, "utf-8");
|
|
513
561
|
assert.match(content, /^async: false$/m);
|
|
514
562
|
assert.match(content, /^timeoutMs: 120000$/m);
|
|
515
|
-
assert.match(content, /^turnBudget: \{"maxTurns":8,"graceTurns":2\}$/m);
|
|
516
563
|
assert.match(content, /^acceptance: \{"level":"none","reason":"lightweight reviewer"\}$/m);
|
|
517
564
|
assert.match(content, /^outputMode: file-only$/m);
|
|
518
565
|
|
|
@@ -520,19 +567,17 @@ Advise only.
|
|
|
520
567
|
assert.equal(got.isError, false);
|
|
521
568
|
assert.match(readText(got), /Async: false/);
|
|
522
569
|
assert.match(readText(got), /Timeout: 120000ms/);
|
|
523
|
-
assert.match(readText(got), /Turn budget: \{"maxTurns":8,"graceTurns":2\}/);
|
|
524
570
|
assert.match(readText(got), /Acceptance: \{"level":"none","reason":"lightweight reviewer"\}/);
|
|
525
571
|
assert.match(readText(got), /Output mode: file-only/);
|
|
526
572
|
|
|
527
573
|
const updated = handleUpdate(
|
|
528
|
-
{ agent: "background-reviewer", config: { async: true, timeoutMs: false,
|
|
574
|
+
{ agent: "background-reviewer", config: { async: true, timeoutMs: false, acceptance: "", outputMode: "inline" } },
|
|
529
575
|
ctx,
|
|
530
576
|
);
|
|
531
577
|
assert.equal(updated.isError, false);
|
|
532
578
|
content = fs.readFileSync(filePath, "utf-8");
|
|
533
579
|
assert.match(content, /^async: true$/m);
|
|
534
580
|
assert.doesNotMatch(content, /^timeoutMs:/m);
|
|
535
|
-
assert.doesNotMatch(content, /^turnBudget:/m);
|
|
536
581
|
assert.doesNotMatch(content, /^acceptance:/m);
|
|
537
582
|
assert.match(content, /^outputMode: inline$/m);
|
|
538
583
|
|
|
@@ -958,11 +1003,26 @@ Drive the failing test first.
|
|
|
958
1003
|
assert.match(text, /^Builtin subagent models/m);
|
|
959
1004
|
assert.match(text, /Current session model:\n openai\/gpt-5-mini/);
|
|
960
1005
|
assert.match(text, /(?:^|\n)scout\n model:\n openai\/gpt-5-mini\n source: inherits current session model(?:\n|$)/);
|
|
1006
|
+
assert.match(text, /(?:^|\n)advisor\n model:\n openai\/gpt-5-mini\n source: inherits current session model(?:\n|$)/);
|
|
1007
|
+
assert.doesNotMatch(text, /advisor\n model:\n \(builtin definition not found\)/);
|
|
961
1008
|
assert.match(text, /Available models in this session's registry/);
|
|
962
1009
|
assert.match(text, / anthropic\/claude-sonnet-4\n openai\/gpt-5-mini/);
|
|
963
1010
|
assert.match(text, /Use an exact provider\/id from this list when you pass model/);
|
|
964
1011
|
});
|
|
965
1012
|
|
|
1013
|
+
it("resolves the advisor builtin alias in a filtered model mapping", () => {
|
|
1014
|
+
const result = handleManagementAction("models", { agent: "advisor" }, {
|
|
1015
|
+
cwd: tempDir,
|
|
1016
|
+
modelRegistry: { getAvailable: () => [{ provider: "openai", id: "gpt-5-mini" }] },
|
|
1017
|
+
model: { provider: "openai", id: "gpt-5-mini" },
|
|
1018
|
+
});
|
|
1019
|
+
const text = readText(result);
|
|
1020
|
+
assert.equal(result.isError, false);
|
|
1021
|
+
assert.match(text, /Agent: advisor/);
|
|
1022
|
+
assert.match(text, /Effective model:\n openai\/gpt-5-mini/);
|
|
1023
|
+
assert.doesNotMatch(text, /Builtin agent 'advisor' not found|source: missing/);
|
|
1024
|
+
});
|
|
1025
|
+
|
|
966
1026
|
it("reports override source and disabled builtin state in runtime model mappings", () => {
|
|
967
1027
|
const projectSettingsPath = path.join(tempDir, ".selesai", "settings.json");
|
|
968
1028
|
fs.mkdirSync(path.dirname(projectSettingsPath), { recursive: true });
|
|
@@ -994,7 +1054,7 @@ Drive the failing test first.
|
|
|
994
1054
|
assert.match(text, /Source: project override/);
|
|
995
1055
|
assert.match(text, /Requested model setting:\n claude-sonnet-4/);
|
|
996
1056
|
assert.match(text, /Disabled: true/);
|
|
997
|
-
assert.match(text.replaceAll("\\", "/"), /Override file:\n .*\.
|
|
1057
|
+
assert.match(text.replaceAll("\\", "/"), /Override file:\n .*\.selesai[\\/]settings\.json/);
|
|
998
1058
|
});
|
|
999
1059
|
|
|
1000
1060
|
it("rejects unknown builtin filters for runtime model mappings", () => {
|