@zerwiz/ymir 0.1.3 → 0.1.5
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/.agents/README.md +291 -0
- package/.agents/agents/bragi-marketer.md +111 -0
- package/.agents/agents/brokk.md +352 -0
- package/.agents/agents/forseti-reviewer.md +93 -0
- package/.agents/agents/frigg-consent.md +77 -0
- package/.agents/agents/groa-update.md +77 -0
- package/.agents/agents/hnoss-designer.md +69 -0
- package/.agents/agents/huginn-researcher.md +99 -0
- package/.agents/agents/jord-projects.md +78 -0
- package/.agents/agents/kvasir-scout.md +91 -0
- package/.agents/agents/mimir-planner.md +92 -0
- package/.agents/agents/muninn-stow.md +77 -0
- package/.agents/agents/saga-bearings.md +78 -0
- package/.agents/agents/sindri-developer.md +114 -0
- package/.agents/agents/snotra-documenter.md +105 -0
- package/.agents/agents/syn-recovery.md +78 -0
- package/.agents/agents/tyr-check.md +78 -0
- package/.agents/agents/urdh-hold.md +77 -0
- package/.agents/agents/volundr-smith.md +80 -0
- package/.agents/agents/vor-diagnostics.md +77 -0
- package/.agents/assets/agents/naming.md +50 -0
- package/.agents/assets/agents/registry.md +93 -0
- package/.agents/assets/agents/runtime.md +36 -0
- package/.agents/assets/agents/toon-tasks-cli.md +42 -0
- package/.agents/assets/templates/company_entity.template.md +37 -0
- package/.agents/backend/backends/cmux.sh +649 -0
- package/.agents/backend/backends/herdr-eventwait.py +157 -0
- package/.agents/backend/backends/herdr-workspace-move.py +114 -0
- package/.agents/backend/backends/herdr.sh +3386 -0
- package/.agents/backend/backends/orca.sh +290 -0
- package/.agents/backend/backends/tmux.sh +357 -0
- package/.agents/backend/backends/zellij.sh +700 -0
- package/.agents/backend/fm-afk-launch.sh +654 -0
- package/.agents/backend/fm-afk-return.sh +241 -0
- package/.agents/backend/fm-afk-start.sh +172 -0
- package/.agents/backend/fm-arm-command-policy.mjs +960 -0
- package/.agents/backend/fm-arm-pretool-check.sh +200 -0
- package/.agents/backend/fm-backend-hometag-lib.sh +52 -0
- package/.agents/backend/fm-backend.sh +981 -0
- package/.agents/backend/fm-backlog-handoff.sh +909 -0
- package/.agents/backend/fm-backlog-receive.sh +187 -0
- package/.agents/backend/fm-backlog-transition-lib.sh +779 -0
- package/.agents/backend/fm-bearings-board.sh +204 -0
- package/.agents/backend/fm-bearings-snapshot.sh +546 -0
- package/.agents/backend/fm-bootstrap.sh +1568 -0
- package/.agents/backend/fm-branch-outcome.sh +203 -0
- package/.agents/backend/fm-branch-prompt.sh +101 -0
- package/.agents/backend/fm-brief.sh +452 -0
- package/.agents/backend/fm-busy-event.sh +234 -0
- package/.agents/backend/fm-busy-lib.sh +986 -0
- package/.agents/backend/fm-captain-hold.sh +1001 -0
- package/.agents/backend/fm-cd-command-policy.mjs +153 -0
- package/.agents/backend/fm-cd-pretool-check.sh +190 -0
- package/.agents/backend/fm-check-lib.sh +74 -0
- package/.agents/backend/fm-check-register.sh +42 -0
- package/.agents/backend/fm-check-unregister.sh +52 -0
- package/.agents/backend/fm-classify-lib.sh +1770 -0
- package/.agents/backend/fm-claude-stop-autoarm.sh +334 -0
- package/.agents/backend/fm-composer-lib.sh +1416 -0
- package/.agents/backend/fm-config-inherit-lib.sh +1202 -0
- package/.agents/backend/fm-config-push.sh +254 -0
- package/.agents/backend/fm-control-lib.sh +251 -0
- package/.agents/backend/fm-control.sh +878 -0
- package/.agents/backend/fm-crew-state.sh +625 -0
- package/.agents/backend/fm-cursor-lib.sh +243 -0
- package/.agents/backend/fm-decision-hold.sh +232 -0
- package/.agents/backend/fm-doc-audience-check.sh +269 -0
- package/.agents/backend/fm-dod-lib.sh +67 -0
- package/.agents/backend/fm-ensure-agents-md.sh +253 -0
- package/.agents/backend/fm-extension-launch-barrier.mjs +129 -0
- package/.agents/backend/fm-extension.mjs +2577 -0
- package/.agents/backend/fm-extension.sh +16 -0
- package/.agents/backend/fm-ff-lib.sh +420 -0
- package/.agents/backend/fm-fleet-snapshot.sh +1463 -0
- package/.agents/backend/fm-fleet-sync.sh +458 -0
- package/.agents/backend/fm-fleet-view.sh +96 -0
- package/.agents/backend/fm-gate-refuse-lib.sh +102 -0
- package/.agents/backend/fm-guard.sh +242 -0
- package/.agents/backend/fm-harness.sh +195 -0
- package/.agents/backend/fm-herdr-ci-cleanup.sh +115 -0
- package/.agents/backend/fm-herdr-lab.sh +346 -0
- package/.agents/backend/fm-herdr-session-cleanup.sh +337 -0
- package/.agents/backend/fm-home-seed.sh +984 -0
- package/.agents/backend/fm-home-summary-refresh.sh +255 -0
- package/.agents/backend/fm-hook-host-lib.sh +36 -0
- package/.agents/backend/fm-inactive-reconcile.sh +531 -0
- package/.agents/backend/fm-inbox.sh +399 -0
- package/.agents/backend/fm-install-actionlint.sh +84 -0
- package/.agents/backend/fm-install-herdr.sh +96 -0
- package/.agents/backend/fm-install-shellcheck.sh +84 -0
- package/.agents/backend/fm-install-treehouse.sh +95 -0
- package/.agents/backend/fm-kimi-turnend-hook.sh +276 -0
- package/.agents/backend/fm-lease-lib.sh +218 -0
- package/.agents/backend/fm-lease.sh +189 -0
- package/.agents/backend/fm-line-cap-lib.sh +51 -0
- package/.agents/backend/fm-lint-workflows.sh +137 -0
- package/.agents/backend/fm-lint.sh +591 -0
- package/.agents/backend/fm-lock-lib.sh +104 -0
- package/.agents/backend/fm-lock.sh +107 -0
- package/.agents/backend/fm-marker-lib.sh +12 -0
- package/.agents/backend/fm-merge-local.sh +74 -0
- package/.agents/backend/fm-merge-outcome-lib.sh +138 -0
- package/.agents/backend/fm-nm-run-lib.sh +124 -0
- package/.agents/backend/fm-on.sh +125 -0
- package/.agents/backend/fm-operational-input.sh +253 -0
- package/.agents/backend/fm-peek.sh +46 -0
- package/.agents/backend/fm-pending-reply-lib.sh +1409 -0
- package/.agents/backend/fm-pr-check.sh +135 -0
- package/.agents/backend/fm-pr-lib.sh +1016 -0
- package/.agents/backend/fm-pr-merge.sh +707 -0
- package/.agents/backend/fm-pr-poll.sh +110 -0
- package/.agents/backend/fm-primary-scope-lib.sh +33 -0
- package/.agents/backend/fm-procevent-extension-capture.pl +259 -0
- package/.agents/backend/fm-procevent-lavish.sh +628 -0
- package/.agents/backend/fm-procevent-lib.sh +892 -0
- package/.agents/backend/fm-procevent-quota.sh +290 -0
- package/.agents/backend/fm-procevent-remote-reply.sh +577 -0
- package/.agents/backend/fm-procevent-when.sh +504 -0
- package/.agents/backend/fm-procevent.sh +1466 -0
- package/.agents/backend/fm-project-mode.sh +92 -0
- package/.agents/backend/fm-project-origin-lib.sh +180 -0
- package/.agents/backend/fm-promote.sh +282 -0
- package/.agents/backend/fm-public-followup-emit.sh +260 -0
- package/.agents/backend/fm-public-followup-lib.sh +398 -0
- package/.agents/backend/fm-public-followup.sh +1330 -0
- package/.agents/backend/fm-push-transition-lib.sh +168 -0
- package/.agents/backend/fm-quota-axi-lib.sh +93 -0
- package/.agents/backend/fm-quota-choose.sh +384 -0
- package/.agents/backend/fm-remote-delta-read.sh +189 -0
- package/.agents/backend/fm-remote-doctor.sh +800 -0
- package/.agents/backend/fm-remote-entrypoint.sh +193 -0
- package/.agents/backend/fm-remote-file.sh +234 -0
- package/.agents/backend/fm-remote-home-provision.sh +259 -0
- package/.agents/backend/fm-remote-home-seed.sh +259 -0
- package/.agents/backend/fm-remote-inherit-push.sh +90 -0
- package/.agents/backend/fm-remote-inherit.sh +179 -0
- package/.agents/backend/fm-remote-job-lib.sh +1241 -0
- package/.agents/backend/fm-remote-job-reap-orphans.sh +137 -0
- package/.agents/backend/fm-remote-job-worker.sh +1124 -0
- package/.agents/backend/fm-remote-readiness-lib.sh +44 -0
- package/.agents/backend/fm-remote-secondmate-control.sh +340 -0
- package/.agents/backend/fm-review-diff.sh +158 -0
- package/.agents/backend/fm-secondmate-charter-lib.sh +44 -0
- package/.agents/backend/fm-secondmate-nudge-lib.sh +68 -0
- package/.agents/backend/fm-secondmate-parent-lib.sh +70 -0
- package/.agents/backend/fm-secondmate-reconcile.sh +371 -0
- package/.agents/backend/fm-secondmate-registry-lib.sh +311 -0
- package/.agents/backend/fm-secondmate-report.sh +88 -0
- package/.agents/backend/fm-send.sh +1059 -0
- package/.agents/backend/fm-session-lock-lib.sh +176 -0
- package/.agents/backend/fm-session-start.sh +970 -0
- package/.agents/backend/fm-sessionstart-cursor.sh +40 -0
- package/.agents/backend/fm-sessionstart-nudge.sh +45 -0
- package/.agents/backend/fm-sessionstart-run.sh +145 -0
- package/.agents/backend/fm-spawn.sh +3153 -0
- package/.agents/backend/fm-startup-memory-budget-lib.sh +224 -0
- package/.agents/backend/fm-startup-memory-budget.sh +94 -0
- package/.agents/backend/fm-startup-network.sh +642 -0
- package/.agents/backend/fm-stow-cascade.sh +251 -0
- package/.agents/backend/fm-subagent-pretool-check.sh +207 -0
- package/.agents/backend/fm-supervise-daemon.sh +1732 -0
- package/.agents/backend/fm-supervision-instructions.sh +215 -0
- package/.agents/backend/fm-supervision-lib.sh +90 -0
- package/.agents/backend/fm-supervisor-target-lib.sh +78 -0
- package/.agents/backend/fm-tangle-lib.sh +53 -0
- package/.agents/backend/fm-task-inbox-lib.sh +402 -0
- package/.agents/backend/fm-tasks-axi-lib.sh +123 -0
- package/.agents/backend/fm-teardown.sh +2922 -0
- package/.agents/backend/fm-test-isolation-proof.sh +588 -0
- package/.agents/backend/fm-test-run.sh +2191 -0
- package/.agents/backend/fm-timeout-lib.sh +141 -0
- package/.agents/backend/fm-timing-lib.sh +179 -0
- package/.agents/backend/fm-tmux-lib.sh +291 -0
- package/.agents/backend/fm-tool-update-check.sh +898 -0
- package/.agents/backend/fm-trace-context-lib.sh +227 -0
- package/.agents/backend/fm-transition-lib.sh +103 -0
- package/.agents/backend/fm-turnend-guard-cursor.sh +391 -0
- package/.agents/backend/fm-turnend-guard-grok.sh +90 -0
- package/.agents/backend/fm-turnend-guard.sh +432 -0
- package/.agents/backend/fm-update.sh +110 -0
- package/.agents/backend/fm-vendor-auth-probe.sh +190 -0
- package/.agents/backend/fm-voice-client.py +1373 -0
- package/.agents/backend/fm-voice-relay.py +1256 -0
- package/.agents/backend/fm-wake-drain.sh +592 -0
- package/.agents/backend/fm-wake-grant.sh +127 -0
- package/.agents/backend/fm-wake-lib.sh +1849 -0
- package/.agents/backend/fm-watch-arm.sh +602 -0
- package/.agents/backend/fm-watch-checkpoint.sh +109 -0
- package/.agents/backend/fm-watch.sh +1962 -0
- package/.agents/backend/fm-x-dismiss.sh +116 -0
- package/.agents/backend/fm-x-followup.sh +286 -0
- package/.agents/backend/fm-x-lib.sh +1000 -0
- package/.agents/backend/fm-x-link.sh +234 -0
- package/.agents/backend/fm-x-poll.sh +185 -0
- package/.agents/backend/fm-x-reply.sh +385 -0
- package/.agents/backend/fm_voice_frame.py +166 -0
- package/.agents/backend/fm_voice_records.py +574 -0
- package/.agents/backend/model-bridge.py +290 -0
- package/.agents/backend/opencode-go-bridge.py +30 -0
- package/.agents/bus/README.md +12 -0
- package/.agents/bus/messages.json +1 -0
- package/.agents/config/agents.machine.example.yaml +16 -0
- package/.agents/config/agents.yaml +50 -0
- package/.agents/config/agents.yaml.example +72 -0
- package/.agents/config/crew-dispatch.json +22 -0
- package/.agents/config/cron.yaml +9 -0
- package/.agents/config/eindri-dispatch.json +67 -0
- package/.agents/config/eindri-harness +1 -0
- package/.agents/config/startup-memory-budget +1 -0
- package/.agents/config/tailscale-sync.yaml +27 -0
- package/.agents/filebrowser/.filebrowser.json +6 -0
- package/.agents/filebrowser/README.md +11 -0
- package/.agents/gateway/README.md +12 -0
- package/.agents/github/README.md +15 -0
- package/.agents/github/webhooks/.gitkeep +0 -0
- package/.agents/github/workflows/.gitkeep +0 -0
- package/.agents/harness/opencode/plugins/lib/rodd-operational-input.js +37 -0
- package/.agents/harness/opencode/plugins/package.json +4 -0
- package/.agents/harness/opencode/plugins/saga-sessionstart.js +77 -0
- package/.agents/harness/opencode/plugins/syn-cd-check.js +61 -0
- package/.agents/harness/opencode/plugins/syn-pretool-check.js +68 -0
- package/.agents/harness/opencode/plugins/syn-turnend-guard.js +105 -0
- package/.agents/harness/opencode/plugins/syn-watch-arm.js +521 -0
- package/.agents/memory/README.md +46 -0
- package/.agents/memory/kaia.engram +0 -0
- package/.agents/memory/kaia.engram-shm +0 -0
- package/.agents/memory/kaia.engram-wal +0 -0
- package/.agents/memory/runes_audit.md +5 -0
- package/.agents/memory/well/episodes.jsonl +367 -0
- package/.agents/memory/well/workspace.jsonl +27 -0
- package/.agents/migrations/0001-hodd-layout.sh +38 -0
- package/.agents/migrations/0002-a2a-mcp.sh +27 -0
- package/.agents/migrations/0003-private-data-separation.sh +111 -0
- package/.agents/migrations/0004-hoard-and-realms.sh +104 -0
- package/.agents/sandbox/Dockerfile.utgard +19 -0
- package/.agents/sandbox/README.md +14 -0
- package/.agents/sandbox/utgard.config.json +14 -0
- package/.agents/skills/README.md +59 -0
- package/.agents/skills/bragi-marketing/README.md +3 -0
- package/.agents/skills/bragi-marketing/SKILL.md +82 -0
- package/.agents/skills/eindri-homes/README.md +3 -0
- package/.agents/skills/eindri-homes/SKILL.md +291 -0
- package/.agents/skills/eindri-homes/assets/control-plane.md +122 -0
- package/.agents/skills/eindri-homes/assets/dispatch.md +80 -0
- package/.agents/skills/frigg-consent/README.md +3 -0
- package/.agents/skills/frigg-consent/SKILL.md +56 -0
- package/.agents/skills/galdr-ymirsystem/README.md +3 -0
- package/.agents/skills/galdr-ymirsystem/SKILL.md +158 -0
- package/.agents/skills/galdr-ymirsystem/assets/README.md +74 -0
- package/.agents/skills/galdr-ymirsystem/assets/brokk-distro-runtime.md +390 -0
- package/.agents/skills/galdr-ymirsystem/assets/build-method.md +113 -0
- package/.agents/skills/galdr-ymirsystem/assets/build-tool-categories.md +178 -0
- package/.agents/skills/galdr-ymirsystem/assets/eindri-orchestration.md +518 -0
- package/.agents/skills/galdr-ymirsystem/assets/eindri-profiles.md +136 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/README.md +673 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/claude-code.md +197 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/codex.md +191 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/cursor.md +193 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/opencode.md +262 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/pi.md +295 -0
- package/.agents/skills/galdr-ymirsystem/assets/hlidskjalf-ui.md +496 -0
- package/.agents/skills/galdr-ymirsystem/assets/installation.md +571 -0
- package/.agents/skills/galdr-ymirsystem/assets/local-models/HOST-DATA.example.md +72 -0
- package/.agents/skills/galdr-ymirsystem/assets/local-models.md +274 -0
- package/.agents/skills/galdr-ymirsystem/assets/memory-well.md +161 -0
- package/.agents/skills/galdr-ymirsystem/assets/nornir-jobs.md +377 -0
- package/.agents/skills/galdr-ymirsystem/assets/norse-naming.md +325 -0
- package/.agents/skills/galdr-ymirsystem/assets/odrerir-hall.md +129 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/einherjar-spawn.schema.json +81 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/herdr-profile.toml +75 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/pi-profile.yml +96 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/supervision-tree.yml +163 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot-guide.md +58 -0
- package/.agents/skills/galdr-ymirsystem/assets/porting-upstream-to-norse.md +301 -0
- package/.agents/skills/galdr-ymirsystem/assets/principles.md +385 -0
- package/.agents/skills/galdr-ymirsystem/assets/reference-adoption.md +99 -0
- package/.agents/skills/galdr-ymirsystem/assets/registry.md +379 -0
- package/.agents/skills/galdr-ymirsystem/assets/runtime-compliance.md +463 -0
- package/.agents/skills/galdr-ymirsystem/assets/runtime-components.md +553 -0
- package/.agents/skills/galdr-ymirsystem/assets/smidja.md +175 -0
- package/.agents/skills/galdr-ymirsystem/schemas/toon-schemas.md +190 -0
- package/.agents/skills/galdr-ymirsystem/scripts/README.md +45 -0
- package/.agents/skills/galdr-ymirsystem/scripts/bench-one.sh +248 -0
- package/.agents/skills/galdr-ymirsystem/scripts/compliance-check.sh +360 -0
- package/.agents/skills/galdr-ymirsystem/scripts/gpu-sample.sh +43 -0
- package/.agents/skills/galdr-ymirsystem/scripts/stop-all.sh +34 -0
- package/.agents/skills/galdr-ymirsystem/scripts/toon-check.py +188 -0
- package/.agents/skills/gjallarhorn-relay/README.md +3 -0
- package/.agents/skills/gjallarhorn-relay/SKILL.md +283 -0
- package/.agents/skills/groa-update/SKILL.md +70 -0
- package/.agents/skills/hamr-adapters/README.md +3 -0
- package/.agents/skills/hamr-adapters/SKILL.md +123 -0
- package/.agents/skills/hamr-adapters/references/common/control-and-recovery.md +37 -0
- package/.agents/skills/hamr-adapters/references/common/dispatch.md +32 -0
- package/.agents/skills/hamr-adapters/references/common/model-and-effort.md +42 -0
- package/.agents/skills/hamr-adapters/references/common/primary-hooks.md +40 -0
- package/.agents/skills/hamr-adapters/references/harness/claude.md +55 -0
- package/.agents/skills/hamr-adapters/references/harness/codex.md +43 -0
- package/.agents/skills/hamr-adapters/references/harness/cursor.md +75 -0
- package/.agents/skills/hamr-adapters/references/harness/grok.md +69 -0
- package/.agents/skills/hamr-adapters/references/harness/kimi.md +51 -0
- package/.agents/skills/hamr-adapters/references/harness/muse.md +70 -0
- package/.agents/skills/hamr-adapters/references/harness/opencode.md +42 -0
- package/.agents/skills/hamr-adapters/references/harness/pi.md +56 -0
- package/.agents/skills/herdr-panes/README.md +3 -0
- package/.agents/skills/herdr-panes/SKILL.md +92 -0
- package/.agents/skills/herdr-panes/assets/herdr-backend.md +346 -0
- package/.agents/skills/herdr-panes/assets/tmux-backend.md +115 -0
- package/.agents/skills/hnoss-design/DESIGN.md +19 -0
- package/.agents/skills/hnoss-design/README.md +3 -0
- package/.agents/skills/hnoss-design/SKILL.md +83 -0
- package/.agents/skills/hvild-afk/README.md +3 -0
- package/.agents/skills/hvild-afk/SKILL.md +241 -0
- package/.agents/skills/jord-projects/README.md +3 -0
- package/.agents/skills/jord-projects/SKILL.md +92 -0
- package/.agents/skills/lifecycle/SKILL.md +56 -0
- package/.agents/skills/lifecycle/smoke_test.sh +52 -0
- package/.agents/skills/lifecycle/start.sh +21 -0
- package/.agents/skills/lifecycle/status.sh +35 -0
- package/.agents/skills/lifecycle/stop.sh +16 -0
- package/.agents/skills/muninn-stow/README.md +3 -0
- package/.agents/skills/muninn-stow/SKILL.md +309 -0
- package/.agents/skills/no-mistakes/SKILL.md +379 -0
- package/.agents/skills/nornir-schedule/README.md +3 -0
- package/.agents/skills/nornir-schedule/SKILL.md +25 -0
- package/.agents/skills/nornir-schedule/assets/events.md +137 -0
- package/.agents/skills/nornir-schedule/assets/quota.md +131 -0
- package/.agents/skills/nsr-compliance/README.md +3 -0
- package/.agents/skills/nsr-compliance/SKILL.md +29 -0
- package/.agents/skills/nsr-compliance/assets/nsr/README.md +40 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/README.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/git-workflow.md +18 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/security.md +22 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/tech-stack.md +8 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/SKILL.md +71 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/config/core_four.yaml +16 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/check_danger.sh +102 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/check_wiring.sh +69 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/validate_code.sh +29 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/verify_docs.py +66 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/generate.sh +109 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/envelopes/result_envelope.json +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/envelopes/task_envelope.json +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/runner.py +303 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/telemetry/logger.py +112 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/README.md +18 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/config/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/README.md +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_env.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_paths.sh +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_platform.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/harness/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/harness/envelopes/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/installer/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/installer/install.sh +125 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/telemetry/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/README.md +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/features/README.md +36 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/features/SKILL-template.md +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/README.md +25 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/SKILL.md +13 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/create_branch.sh +6 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/safe_commit.sh +9 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/sync_upstream.sh +6 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/README.md +27 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/SKILL.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/smoke_test.sh +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/start.sh +19 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/status.sh +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/stop.sh +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/README.md +18 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/config/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/config/core_four.yaml +13 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/README.md +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_danger.sh +102 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_env.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_paths.sh +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_platform.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_wiring.sh +69 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/result_envelope.json +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/task_envelope.json +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/runner.py +303 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/installer/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/installer/install.sh +125 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/telemetry/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/telemetry/logger.py +112 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/README.md +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/api.md +17 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/compliance-wiring.md +155 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/frontend.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/README.md +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/clients/README.md +16 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/clients/template-README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/deploy.sh +49 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/README.md +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/development.env.example +17 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/production.env.example +17 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/staging.env.example +17 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/tenants/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/tenants/template.env.example +8 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/README.md +26 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/agent.md +7 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/developers/dev-1.md +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/linux.md +9 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/macos.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/shared.md +19 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/windows.md +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/README.md +25 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/_template.md +41 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/hosting-1.md +41 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/README.md +21 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/README.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/deployment.md +19 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/disaster-recovery.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/ops-tasks.md +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/features/README.md +16 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/project-skills.md +146 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/research/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/research/software-compliance-research.md +269 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/working-with-agents.md +260 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/AGENTS.md +38 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/ARCHITECTURE.md +36 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/BEST_PRACTICES.md +27 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/CI_CD.md +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/FEATURES.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/README.md +22 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/RULES.md +37 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/STRUCTURE.md +45 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/TECH_STACK.md +28 -0
- package/.agents/skills/nsr-compliance/assets/nsr/scaffold-spec.md +63 -0
- package/.agents/skills/nsr-compliance/assets/nsr/scripts/scaffold.sh +103 -0
- package/.agents/skills/nsr-compliance/assets/nsr/scripts/validate.sh +52 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/SKILL.md +71 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/config/core_four.yaml +16 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/check_danger.sh +102 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/check_wiring.sh +69 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/validate_code.sh +29 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/verify_docs.py +66 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/generate.sh +109 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/envelopes/result_envelope.json +14 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/envelopes/task_envelope.json +20 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/runner.py +303 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/telemetry/logger.py +112 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/README.md +18 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/config/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/README.md +12 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_env.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_paths.sh +20 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_platform.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/harness/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/harness/envelopes/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/installer/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/installer/install.sh +125 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/telemetry/README.md +11 -0
- package/.agents/skills/pr-ops/README.md +3 -0
- package/.agents/skills/pr-ops/SKILL.md +109 -0
- package/.agents/skills/ratatoskr-a2a/README.md +3 -0
- package/.agents/skills/ratatoskr-a2a/SKILL.md +148 -0
- package/.agents/skills/rules-check-drift/SKILL.md +81 -0
- package/.agents/skills/saga-bearings/README.md +3 -0
- package/.agents/skills/saga-bearings/SKILL.md +26 -0
- package/.agents/skills/saga-bearings/assets/bearings.md +161 -0
- package/.agents/skills/saga-bearings/assets/board-template.html +731 -0
- package/.agents/skills/saga-bearings/assets/recap.md +56 -0
- package/.agents/skills/syn-recovery/README.md +3 -0
- package/.agents/skills/syn-recovery/SKILL.md +54 -0
- package/.agents/skills/tyr-check/README.md +3 -0
- package/.agents/skills/tyr-check/SKILL.md +218 -0
- package/.agents/skills/urdh-hold/README.md +3 -0
- package/.agents/skills/urdh-hold/SKILL.md +25 -0
- package/.agents/skills/urdh-hold/assets/decisions.md +15 -0
- package/.agents/skills/urdh-hold/assets/hold.md +54 -0
- package/.agents/skills/vor-diagnostics/README.md +3 -0
- package/.agents/skills/vor-diagnostics/SKILL.md +68 -0
- package/.agents/skills/ymir-host/README.md +3 -0
- package/.agents/skills/ymir-host/SKILL.md +34 -0
- package/.agents/skills/ymir-host/assets/desktop.md +36 -0
- package/.agents/skills/ymir-host/assets/omarchy.md +297 -0
- package/.agents/skills/ymir-host/assets/runbooks.md +15 -0
- package/.agents/skills/ymir-host/assets/thjazi.md +220 -0
- package/.agents/skills/ymir-host/assets/update.md +64 -0
- package/.agents/tests/assets/board-render-harness.mjs +117 -0
- package/.agents/tests/cmux-test-safety.sh +51 -0
- package/.agents/tests/fixtures.sh +291 -0
- package/.agents/tests/fm-afk-inject-e2e.test.sh +428 -0
- package/.agents/tests/fm-afk-inject-herdr-e2e.test.sh +536 -0
- package/.agents/tests/fm-afk-launch.test.sh +961 -0
- package/.agents/tests/fm-afk-pi-herdr-return-e2e.test.sh +297 -0
- package/.agents/tests/fm-afk-return.test.sh +283 -0
- package/.agents/tests/fm-arm-pretool-check.test.sh +482 -0
- package/.agents/tests/fm-ask-user-authority.test.sh +42 -0
- package/.agents/tests/fm-backend-autodetect-smoke.test.sh +176 -0
- package/.agents/tests/fm-backend-cmux-smoke.test.sh +188 -0
- package/.agents/tests/fm-backend-cmux.test.sh +1166 -0
- package/.agents/tests/fm-backend-herdr-eventwait-smoke.test.sh +136 -0
- package/.agents/tests/fm-backend-herdr-eventwait.test.py +106 -0
- package/.agents/tests/fm-backend-herdr-focus-flash-e2e.test.sh +409 -0
- package/.agents/tests/fm-backend-herdr-launcher-workspace-e2e.test.sh +437 -0
- package/.agents/tests/fm-backend-herdr-presentation-e2e.test.sh +1424 -0
- package/.agents/tests/fm-backend-herdr-prune-safety-e2e.test.sh +180 -0
- package/.agents/tests/fm-backend-herdr-respawn-idem-e2e.test.sh +182 -0
- package/.agents/tests/fm-backend-herdr-smoke.test.sh +355 -0
- package/.agents/tests/fm-backend-herdr-workspace-per-home-e2e.test.sh +251 -0
- package/.agents/tests/fm-backend-herdr.test.sh +4606 -0
- package/.agents/tests/fm-backend-orca.test.sh +1357 -0
- package/.agents/tests/fm-backend-tmux-smoke.test.sh +173 -0
- package/.agents/tests/fm-backend-zellij-smoke.test.sh +205 -0
- package/.agents/tests/fm-backend-zellij.test.sh +1360 -0
- package/.agents/tests/fm-backend.test.sh +1142 -0
- package/.agents/tests/fm-backlog-atomicity.test.sh +2302 -0
- package/.agents/tests/fm-backlog-handoff.test.sh +1360 -0
- package/.agents/tests/fm-bearings-board-render.test.sh +135 -0
- package/.agents/tests/fm-bearings-board.test.sh +414 -0
- package/.agents/tests/fm-bearings-snapshot.test.sh +1990 -0
- package/.agents/tests/fm-bootstrap-network-parallel.test.sh +316 -0
- package/.agents/tests/fm-bootstrap.test.sh +1178 -0
- package/.agents/tests/fm-branch-supervision.test.sh +552 -0
- package/.agents/tests/fm-brief.test.sh +785 -0
- package/.agents/tests/fm-busy-adapter-wiring.test.sh +324 -0
- package/.agents/tests/fm-busy-state.test.sh +465 -0
- package/.agents/tests/fm-calm-pi-extension.test.sh +3979 -0
- package/.agents/tests/fm-captain-hold-lifecycle.test.sh +1187 -0
- package/.agents/tests/fm-cd-pretool-check.test.sh +400 -0
- package/.agents/tests/fm-check-unregister.test.sh +198 -0
- package/.agents/tests/fm-classify-corr-token.test.sh +543 -0
- package/.agents/tests/fm-classify-decision-key.test.sh +340 -0
- package/.agents/tests/fm-claude-stop-autoarm-live-e2e.test.sh +164 -0
- package/.agents/tests/fm-claude-stop-autoarm.test.sh +1190 -0
- package/.agents/tests/fm-cmux-claude-composer-live-e2e.test.sh +110 -0
- package/.agents/tests/fm-codex-continuity-live-e2e.test.sh +55 -0
- package/.agents/tests/fm-composer-ghost.test.sh +716 -0
- package/.agents/tests/fm-composer-lib.test.sh +666 -0
- package/.agents/tests/fm-composer-matrix-live-e2e.test.sh +220 -0
- package/.agents/tests/fm-control-herdr-smoke.test.sh +149 -0
- package/.agents/tests/fm-control-relaunch.test.sh +1530 -0
- package/.agents/tests/fm-control.test.sh +910 -0
- package/.agents/tests/fm-crew-state.test.sh +1610 -0
- package/.agents/tests/fm-cursor-harness.test.sh +404 -0
- package/.agents/tests/fm-cursor-primary-live-e2e.test.sh +217 -0
- package/.agents/tests/fm-cursor-primary.test.sh +708 -0
- package/.agents/tests/fm-daemon.test.sh +2740 -0
- package/.agents/tests/fm-documentation-audiences.test.sh +141 -0
- package/.agents/tests/fm-ensure-agents-md.test.sh +371 -0
- package/.agents/tests/fm-extension-binding.test.sh +2187 -0
- package/.agents/tests/fm-fleet-snapshot-view.test.sh +816 -0
- package/.agents/tests/fm-fleet-sync.test.sh +721 -0
- package/.agents/tests/fm-gate-refuse.test.sh +356 -0
- package/.agents/tests/fm-gitignore-config.test.sh +89 -0
- package/.agents/tests/fm-gotmp.test.sh +230 -0
- package/.agents/tests/fm-grok-continuity-live-e2e.test.sh +112 -0
- package/.agents/tests/fm-grok-harness.test.sh +117 -0
- package/.agents/tests/fm-grok-stop-live-e2e.test.sh +219 -0
- package/.agents/tests/fm-guard-stale-banner.test.sh +709 -0
- package/.agents/tests/fm-harness-adapter-instructions-live-e2e.test.sh +134 -0
- package/.agents/tests/fm-harness-adapter-references.test.sh +30 -0
- package/.agents/tests/fm-harness-liveness-drift-live-e2e.test.sh +151 -0
- package/.agents/tests/fm-herdr-lab.test.sh +243 -0
- package/.agents/tests/fm-herdr-session-cleanup-e2e.test.sh +146 -0
- package/.agents/tests/fm-herdr-session-cleanup.test.sh +329 -0
- package/.agents/tests/fm-herdr-submit-confirm-live-e2e.test.sh +125 -0
- package/.agents/tests/fm-herdr-version-floor-live-e2e.test.sh +144 -0
- package/.agents/tests/fm-home-summary-refresh.test.sh +971 -0
- package/.agents/tests/fm-inactive-reconcile.test.sh +485 -0
- package/.agents/tests/fm-kimi-harness.test.sh +687 -0
- package/.agents/tests/fm-lint-workflows.test.sh +532 -0
- package/.agents/tests/fm-lint.test.sh +1023 -0
- package/.agents/tests/fm-muse-harness.test.sh +932 -0
- package/.agents/tests/fm-muse-signals-live-e2e.test.sh +205 -0
- package/.agents/tests/fm-no-mistakes-required.test.sh +72 -0
- package/.agents/tests/fm-on.test.sh +507 -0
- package/.agents/tests/fm-opencode-primary-live-e2e.test.sh +357 -0
- package/.agents/tests/fm-operational-input.test.sh +160 -0
- package/.agents/tests/fm-peek-remote.test.sh +110 -0
- package/.agents/tests/fm-pending-reply.test.sh +1288 -0
- package/.agents/tests/fm-pi-branch-extension.test.sh +3182 -0
- package/.agents/tests/fm-pi-branch-live-e2e.test.sh +527 -0
- package/.agents/tests/fm-pi-primary-live-e2e.test.sh +345 -0
- package/.agents/tests/fm-pi-primary-types.test.sh +68 -0
- package/.agents/tests/fm-pi-watch-extension.test.sh +2843 -0
- package/.agents/tests/fm-pr-check-security.test.sh +2140 -0
- package/.agents/tests/fm-pr-merge.test.sh +2135 -0
- package/.agents/tests/fm-procevent-quota.test.sh +225 -0
- package/.agents/tests/fm-procevent-when.test.sh +406 -0
- package/.agents/tests/fm-procevent.test.sh +1745 -0
- package/.agents/tests/fm-project-origin.test.sh +110 -0
- package/.agents/tests/fm-public-followup.test.sh +2272 -0
- package/.agents/tests/fm-quota-array-dispatch-live-e2e.test.sh +526 -0
- package/.agents/tests/fm-quota-choose.test.sh +626 -0
- package/.agents/tests/fm-remote-backlog-handoff.test.sh +453 -0
- package/.agents/tests/fm-remote-doctor.test.sh +625 -0
- package/.agents/tests/fm-remote-entrypoint.test.sh +59 -0
- package/.agents/tests/fm-remote-job-orphan-reap.test.sh +205 -0
- package/.agents/tests/fm-remote-job.test.sh +768 -0
- package/.agents/tests/fm-remote-reply.test.sh +520 -0
- package/.agents/tests/fm-remote-secondmate-lifecycle-e2e.test.sh +1256 -0
- package/.agents/tests/fm-remote-secondmate-parent-binding.test.sh +326 -0
- package/.agents/tests/fm-remote-secondmate-trace-context.test.sh +310 -0
- package/.agents/tests/fm-remote-transport-lanes.test.sh +431 -0
- package/.agents/tests/fm-review-diff.test.sh +176 -0
- package/.agents/tests/fm-secondmate-harness.test.sh +2600 -0
- package/.agents/tests/fm-secondmate-lifecycle-e2e.test.sh +259 -0
- package/.agents/tests/fm-secondmate-liveness.test.sh +559 -0
- package/.agents/tests/fm-secondmate-reconcile.test.sh +732 -0
- package/.agents/tests/fm-secondmate-safety.test.sh +2972 -0
- package/.agents/tests/fm-secondmate-sync.test.sh +913 -0
- package/.agents/tests/fm-send-inbox-doorbell-live-e2e.test.sh +206 -0
- package/.agents/tests/fm-send-inbox.test.sh +352 -0
- package/.agents/tests/fm-send-popup-settle.test.sh +167 -0
- package/.agents/tests/fm-send-remote-delivery.test.sh +796 -0
- package/.agents/tests/fm-send-resolve-key.test.sh +551 -0
- package/.agents/tests/fm-send-secondmate-marker-herdr-e2e.test.sh +187 -0
- package/.agents/tests/fm-send-secondmate-marker.test.sh +278 -0
- package/.agents/tests/fm-send-settle.test.sh +147 -0
- package/.agents/tests/fm-send-strict.test.sh +241 -0
- package/.agents/tests/fm-session-lock-ancestry.test.sh +365 -0
- package/.agents/tests/fm-session-start.test.sh +2515 -0
- package/.agents/tests/fm-sessionstart-hook-live-e2e.test.sh +631 -0
- package/.agents/tests/fm-sessionstart-instruction-refresh-live-e2e.test.sh +230 -0
- package/.agents/tests/fm-sessionstart-nudge.test.sh +1039 -0
- package/.agents/tests/fm-shared-captain-inheritance.test.sh +404 -0
- package/.agents/tests/fm-spawn-batch.test.sh +148 -0
- package/.agents/tests/fm-spawn-dispatch-profile.test.sh +827 -0
- package/.agents/tests/fm-spawn-pool-base-freshen.test.sh +440 -0
- package/.agents/tests/fm-spawn-worktree-settle.test.sh +147 -0
- package/.agents/tests/fm-startup-memory-budget.test.sh +333 -0
- package/.agents/tests/fm-startup-network.test.sh +712 -0
- package/.agents/tests/fm-stow-cascade.test.sh +370 -0
- package/.agents/tests/fm-subagent-pretool-check.test.sh +291 -0
- package/.agents/tests/fm-supervision-events.test.sh +156 -0
- package/.agents/tests/fm-supervision-instructions.test.sh +189 -0
- package/.agents/tests/fm-tangle-guard.test.sh +277 -0
- package/.agents/tests/fm-task-delivery.test.sh +420 -0
- package/.agents/tests/fm-task-inbox.test.sh +513 -0
- package/.agents/tests/fm-teardown-endpoint-safety.test.sh +374 -0
- package/.agents/tests/fm-teardown.test.sh +2665 -0
- package/.agents/tests/fm-test-fixture-cleanup.test.sh +172 -0
- package/.agents/tests/fm-test-fixtures.test.sh +132 -0
- package/.agents/tests/fm-test-isolation-proof.test.sh +278 -0
- package/.agents/tests/fm-test-run.test.sh +1196 -0
- package/.agents/tests/fm-tmux-agent-liveness.test.sh +354 -0
- package/.agents/tests/fm-tmux-submit-busy.test.sh +340 -0
- package/.agents/tests/fm-tool-update-check.test.sh +1044 -0
- package/.agents/tests/fm-trace-context-lib.test.sh +253 -0
- package/.agents/tests/fm-trace-context-spawn.test.sh +581 -0
- package/.agents/tests/fm-transition-lib.test.sh +54 -0
- package/.agents/tests/fm-turnend-guard.test.sh +1822 -0
- package/.agents/tests/fm-update.test.sh +304 -0
- package/.agents/tests/fm-vendor-auth-probe.test.sh +395 -0
- package/.agents/tests/fm-voice-relay.test.sh +4741 -0
- package/.agents/tests/fm-wake-daemon-lifecycle-e2e.test.sh +171 -0
- package/.agents/tests/fm-wake-drain-open-decisions-cursor.test.sh +356 -0
- package/.agents/tests/fm-wake-drain-open-decisions.test.sh +226 -0
- package/.agents/tests/fm-wake-drain-unread-status.test.sh +379 -0
- package/.agents/tests/fm-wake-queue.test.sh +1224 -0
- package/.agents/tests/fm-watch-arm.test.sh +821 -0
- package/.agents/tests/fm-watch-checkpoint.test.sh +87 -0
- package/.agents/tests/fm-watch-recovery-loop.test.sh +223 -0
- package/.agents/tests/fm-watch-triage.test.sh +3889 -0
- package/.agents/tests/fm-watcher-lock.test.sh +1133 -0
- package/.agents/tests/fm-x-mode.test.sh +3042 -0
- package/.agents/tests/gleipnir-guard-pretool-check.test.sh +51 -0
- package/.agents/tests/gleipnir-machine-lock.test.sh +130 -0
- package/.agents/tests/herdr-test-safety.sh +42 -0
- package/.agents/tests/lib.sh +315 -0
- package/.agents/tests/remote-herdr-fixture.sh +125 -0
- package/.agents/tests/secondmate-helpers.sh +193 -0
- package/.agents/tests/smoke.test.sh +93 -0
- package/.agents/tests/wake-helpers.sh +338 -0
- package/.agents/tests/zellij-test-safety.sh +60 -0
- package/.agents/tools/README.md +10 -0
- package/.agents/tools/bin/tasks-cli +267 -0
- package/.agents/tools/tasks-cli.ts +216 -0
- package/AGENTS.md +454 -0
- package/CHANGELOG.md +881 -0
- package/LICENSE +1 -1
- package/NOTICE +63 -0
- package/README.md +113 -39
- package/RULES/01-domains.md +51 -0
- package/RULES/02-agents.md +78 -0
- package/RULES/03-houses.md +61 -0
- package/RULES/04-hoard.md +65 -0
- package/RULES/05-platforms.md +67 -0
- package/RULES/06-append-only.md +58 -0
- package/RULES/07-config.md +45 -0
- package/RULES/08-delivery-gate.md +75 -0
- package/RULES/README.md +20 -0
- package/bin/README.md +107 -0
- package/bin/a2a-mcp.sh +98 -0
- package/bin/a2a-serve.py +103 -0
- package/bin/a2a-serve.sh +8 -0
- package/bin/a2a-talk.sh +50 -0
- package/bin/a2abridge-ensure.sh +108 -0
- package/bin/agent-run.sh +43 -0
- package/bin/agents-config.sh +233 -0
- package/bin/apodex-smoke-test.sh +92 -0
- package/bin/bifrost-bridge.sh +112 -0
- package/bin/bifrost-ingress.sh +77 -0
- package/bin/bootstrap-macos.sh +107 -0
- package/bin/bootstrap-windows.ps1 +112 -0
- package/bin/branch-guard.sh +64 -0
- package/bin/brokk +73 -0
- package/bin/brokk-classify-lib.sh +1770 -0
- package/bin/brokk-lease-lib.sh +222 -0
- package/bin/brokk-lease.sh +193 -0
- package/bin/brokk-lint.sh +65 -0
- package/bin/brokk-send.sh +38 -0
- package/bin/brokk-update.sh +9 -0
- package/bin/brokk-wake-grant.sh +127 -0
- package/bin/brokk-wake-lib.sh +1849 -0
- package/bin/changelog-guard.sh +165 -0
- package/bin/crash-sense.sh +160 -0
- package/bin/desktop-place.sh +224 -0
- package/bin/docs-guard.sh +39 -0
- package/bin/editor-place.sh +207 -0
- package/bin/eindri-acclaim.sh +34 -0
- package/bin/eindri-control.sh +28 -0
- package/bin/eindri-role.sh +83 -0
- package/bin/eindri-seen.sh +41 -0
- package/bin/eindri-send.sh +15 -0
- package/bin/eindri-start.sh +85 -0
- package/bin/eindri-watch.sh +57 -0
- package/bin/einherjar-spawn.sh +576 -0
- package/bin/eir-doctor.sh +112 -0
- package/bin/erindi-brief.sh +271 -0
- package/bin/fleet-apply.sh +68 -0
- package/bin/github-deploy.sh +81 -0
- package/bin/gjallarhorn-expose.sh +102 -0
- package/bin/gjallarhorn-notify.sh +58 -0
- package/bin/gjallarhorn-purge.sh +54 -0
- package/bin/gjallarhorn-tunnel.sh +72 -0
- package/bin/gleipnir-lock-lib.sh +284 -0
- package/bin/groa-update.sh +122 -0
- package/bin/hall-snapshot.sh +92 -0
- package/bin/hamr-harness.sh +246 -0
- package/bin/heimdall-ssh-keys.sh +374 -0
- package/bin/herdr-agents.py +44 -0
- package/bin/herdr-ensure.sh +104 -0
- package/bin/herdr-run.sh +431 -0
- package/bin/hermes-ensure.sh +88 -0
- package/bin/hoard-lib.sh +25 -0
- package/bin/hodd.sh +78 -0
- package/bin/host-sense.sh +199 -0
- package/bin/huginn-research-worker.sh +108 -0
- package/bin/local-model-lock.sh +51 -0
- package/bin/mimir-bridge.py +226 -0
- package/bin/mimir-bridge.sh +87 -0
- package/bin/mimir-ingest.sh +131 -0
- package/bin/mimir.sh +113 -0
- package/bin/mjollnir-webhook.sh +59 -0
- package/bin/mjollnir.sh +85 -0
- package/bin/model-hardware.sh +82 -0
- package/bin/model-resolve.sh +147 -0
- package/bin/models-detect.sh +178 -0
- package/bin/nornir-cron-start.sh +162 -0
- package/bin/nornir-job-daily-briefing.sh +191 -0
- package/bin/nornir-job-git-sync.sh +152 -0
- package/bin/nornir-job-memory-housekeeping.sh +114 -0
- package/bin/nornir-job-observer.sh +166 -0
- package/bin/nornir-job-skillopt-sleep.sh +76 -0
- package/bin/omarchy-hook-install.sh +60 -0
- package/bin/omarchy-install.sh +148 -0
- package/bin/omarchy-plugins.sh +174 -0
- package/bin/omarchy-sense.sh +149 -0
- package/bin/perm-guard.sh +30 -0
- package/bin/pi-agent.sh +68 -0
- package/bin/pi-ensure.sh +77 -0
- package/bin/pi-local.sh +37 -0
- package/bin/pi-seat.sh +63 -0
- package/bin/prereq-ensure.sh +166 -0
- package/bin/private-guard.sh +38 -0
- package/bin/project-git.sh +55 -0
- package/bin/public-guard.sh +70 -0
- package/bin/ratatoskr.sh +49 -0
- package/bin/realm-lib.sh +32 -0
- package/bin/repo-scrub.sh +62 -0
- package/bin/rodd-operational-input.sh +250 -0
- package/bin/runes-append.sh +198 -0
- package/bin/saga-session-start.sh +172 -0
- package/bin/saga-sessionstart-run.sh +79 -0
- package/bin/saga-wake-drain.sh +41 -0
- package/bin/secret-guard.sh +63 -0
- package/bin/sessrumnir-ensure.sh +100 -0
- package/bin/sessrumnir-sync.sh +237 -0
- package/bin/sessrumnir.sh +91 -0
- package/bin/skillopt-setup.sh +76 -0
- package/bin/skuld-branch-outcome.sh +203 -0
- package/bin/skuld-branch-prompt.sh +101 -0
- package/bin/smidja-bootstrap.sh +90 -0
- package/bin/smidja-observe.sh +86 -0
- package/bin/syn-arm-pretool-check.sh +57 -0
- package/bin/syn-asset-pretool-check.sh +76 -0
- package/bin/syn-cd-pretool-check.sh +28 -0
- package/bin/syn-guard-pretool-check.sh +83 -0
- package/bin/syn-turnend-guard.sh +36 -0
- package/bin/syn-watch-arm.sh +99 -0
- package/bin/tailscale-sync.sh +190 -0
- package/bin/telegram-bot.sh +69 -0
- package/bin/toolchain.sh +74 -0
- package/bin/utgard.sh +111 -0
- package/bin/valhalla.sh +115 -0
- package/bin/valknut-load.sh +260 -0
- package/bin/vor-crew-state.sh +124 -0
- package/bin/wedge-notify.sh +47 -0
- package/bin/workspace-provision.sh +80 -0
- package/bin/workspace-rag.sh +150 -0
- package/bin/wyrd-db.sh +47 -0
- package/bin/yggdrasil.sh +152 -0
- package/bin/ymir-edit.sh +145 -0
- package/bin/ymir-install.sh +641 -0
- package/bin/ymir-invite.sh +93 -0
- package/bin/ymir-isolation.sh +88 -0
- package/bin/ymir-migrate.sh +61 -0
- package/bin/ymir-platform.sh +348 -0
- package/bin/ymir-say.sh +97 -0
- package/bin/ymir-setup-auth.sh +108 -0
- package/bin/ymir-validate.sh +173 -0
- package/bin/ymir.js +74 -16
- package/docs/Architecture.md +339 -0
- package/docs/design.md +351 -0
- package/docs/installations/README.md +63 -0
- package/docs/installations/ymir-home.md +93 -0
- package/docs/integration.md +105 -0
- package/docs/lore.md +1056 -0
- package/docs/research/agent-harnesses.md +290 -0
- package/docs/runbooks/README.md +19 -0
- package/docs/runbooks/a2a.md +91 -0
- package/docs/runbooks/agent-permissions.md +99 -0
- package/docs/runbooks/agents.md +57 -0
- package/docs/runbooks/models.md +69 -0
- package/docs/runbooks/realm-onboarding.md +60 -0
- package/docs/runbooks/secrets-and-hoard.md +60 -0
- package/docs/runbooks/updates-and-migrations.md +110 -0
- package/docs/runbooks/worktrees-isolation.md +72 -0
- package/docs/session-start.md +105 -0
- package/docs/skillopt-integration.md +321 -0
- package/docs/sync-system.md +66 -0
- package/docs/workspaces.md +104 -0
- package/docs/ymir-rut.md +260 -0
- package/package.json +44 -14
- package/packaging/build.sh +74 -0
- package/packaging/macos/Ymir Installer.command +43 -0
- package/packaging/windows/ymir-setup.nsi +74 -0
- package/scripts/README.md +22 -0
- package/scripts/electron.sh +210 -0
- package/scripts/start.sh +167 -0
- package/scripts/stop.sh +113 -0
- package/install.sh +0 -35
|
@@ -0,0 +1,1357 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# tests/fm-backend-orca.test.sh - fake-Orca-CLI unit tests for the Orca
|
|
3
|
+
# terminal adapter primitives in bin/backends/orca.sh.
|
|
4
|
+
set -u
|
|
5
|
+
|
|
6
|
+
# shellcheck source=tests/lib.sh
|
|
7
|
+
. "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
|
|
8
|
+
|
|
9
|
+
TMP_ROOT=$(fm_test_tmproot fm-backend-orca-tests)
|
|
10
|
+
|
|
11
|
+
make_orca_fakebin() { # <dir> -> echoes fakebin dir
|
|
12
|
+
local fb="$1/fakebin"
|
|
13
|
+
mkdir -p "$fb"
|
|
14
|
+
cat > "$fb/orca" <<'SH'
|
|
15
|
+
#!/usr/bin/env bash
|
|
16
|
+
set -u
|
|
17
|
+
LOG="${FM_ORCA_LOG:?}"
|
|
18
|
+
RESP="${FM_ORCA_RESPONSES:?}"
|
|
19
|
+
COUNT_FILE="$RESP/.count"
|
|
20
|
+
next=$(( $(cat "$COUNT_FILE" 2>/dev/null || echo 0) + 1 ))
|
|
21
|
+
{
|
|
22
|
+
printf 'orca'
|
|
23
|
+
for a in "$@"; do printf '\x1f%s' "$a"; done
|
|
24
|
+
printf '\n'
|
|
25
|
+
} >> "$LOG"
|
|
26
|
+
if [ "${1:-}" = status ] && [ "${FM_ORCA_STATUS_RESPONSE:-ready}" != sequence ]; then
|
|
27
|
+
printf '{"ok":true,"result":{"runtime":{"reachable":true,"state":"ready"}}}\n'
|
|
28
|
+
exit 0
|
|
29
|
+
fi
|
|
30
|
+
n=$next
|
|
31
|
+
echo "$n" > "$COUNT_FILE"
|
|
32
|
+
if [ -f "$RESP/$n.exit" ]; then
|
|
33
|
+
exit "$(cat "$RESP/$n.exit")"
|
|
34
|
+
fi
|
|
35
|
+
[ -f "$RESP/$n.out" ] && cat "$RESP/$n.out"
|
|
36
|
+
exit 0
|
|
37
|
+
SH
|
|
38
|
+
chmod +x "$fb/orca"
|
|
39
|
+
printf '%s\n' "$fb"
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
orca_case() { # <name> -> sets CASE_DIR LOG RESP FB
|
|
43
|
+
CASE_DIR="$TMP_ROOT/$1"
|
|
44
|
+
mkdir -p "$CASE_DIR/responses"
|
|
45
|
+
LOG="$CASE_DIR/log"
|
|
46
|
+
RESP="$CASE_DIR/responses"
|
|
47
|
+
: > "$LOG"
|
|
48
|
+
FB=$(make_orca_fakebin "$CASE_DIR")
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
neutral_fm_root() { # <dir> -> echoes a minimal root with a quiet guard
|
|
52
|
+
local root="$1/root"
|
|
53
|
+
mkdir -p "$root/bin"
|
|
54
|
+
cat > "$root/bin/fm-guard.sh" <<'SH'
|
|
55
|
+
#!/usr/bin/env bash
|
|
56
|
+
exit 0
|
|
57
|
+
SH
|
|
58
|
+
chmod +x "$root/bin/fm-guard.sh"
|
|
59
|
+
printf '%s\n' "$root"
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
add_tmux_fake() {
|
|
63
|
+
local fb=$1
|
|
64
|
+
cat > "$fb/tmux" <<'SH'
|
|
65
|
+
#!/usr/bin/env bash
|
|
66
|
+
set -u
|
|
67
|
+
LOG="${FM_ORCA_LOG:?}"
|
|
68
|
+
{
|
|
69
|
+
printf 'tmux'
|
|
70
|
+
for a in "$@"; do printf '\x1f%s' "$a"; done
|
|
71
|
+
printf '\n'
|
|
72
|
+
} >> "$LOG"
|
|
73
|
+
exit 0
|
|
74
|
+
SH
|
|
75
|
+
chmod +x "$fb/tmux"
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
test_capture_reads_terminal_tail_json() {
|
|
79
|
+
local out
|
|
80
|
+
orca_case capture-tail
|
|
81
|
+
printf '{"result":{"terminal":{"tail":["line one","line two"]}}}\n' > "$RESP/1.out"
|
|
82
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
83
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_capture term-123 40' "$ROOT" )
|
|
84
|
+
[ "$out" = $'line one\nline two' ] || fail "capture should print result.terminal.tail joined by newlines, got '$out'"
|
|
85
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''read'$'\x1f''--terminal'$'\x1f''term-123'$'\x1f''--limit'$'\x1f''40'$'\x1f''--json' \
|
|
86
|
+
"capture did not call orca terminal read with terminal/limit/json"
|
|
87
|
+
pass "fm_backend_orca_capture: parses result.terminal.tail and calls terminal read"
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
test_capture_falls_back_to_text_fields() {
|
|
91
|
+
local out
|
|
92
|
+
orca_case capture-text
|
|
93
|
+
printf '{"result":{"text":"plain text output"}}\n' > "$RESP/1.out"
|
|
94
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
95
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_capture term-abc 5' "$ROOT" )
|
|
96
|
+
[ "$out" = "plain text output" ] || fail "capture should fall back to result.text, got '$out'"
|
|
97
|
+
pass "fm_backend_orca_capture: falls back to result text fields"
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
test_capture_fails_on_orca_error_json() {
|
|
101
|
+
local out status
|
|
102
|
+
orca_case capture-error-json
|
|
103
|
+
printf '{"ok":false,"error":{"code":"terminal_handle_stale","message":"terminal handle stale"}}\n' > "$RESP/1.out"
|
|
104
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
105
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_capture term-stale 5' "$ROOT" 2>&1 )
|
|
106
|
+
status=$?
|
|
107
|
+
[ "$status" -ne 0 ] || fail "capture should fail on Orca ok:false read JSON"
|
|
108
|
+
assert_contains "$out" "terminal handle stale" "capture should surface the Orca read error message"
|
|
109
|
+
pass "fm_backend_orca_capture: fails closed on Orca read error JSON"
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
test_runtime_check_accepts_ready_orca_status() {
|
|
113
|
+
local out
|
|
114
|
+
orca_case runtime-ready
|
|
115
|
+
printf '{"ok":true,"result":{"runtime":{"reachable":true,"state":"ready"}}}\n' > "$RESP/1.out"
|
|
116
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" FM_ORCA_STATUS_RESPONSE=sequence \
|
|
117
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_runtime_check' "$ROOT" )
|
|
118
|
+
[ -z "$out" ] || fail "runtime_check should be quiet on ready status, got '$out'"
|
|
119
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''status'$'\x1f''--json' \
|
|
120
|
+
"runtime_check did not call orca status --json"
|
|
121
|
+
pass "fm_backend_orca_runtime_check: accepts reachable ready runtime"
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
test_runtime_check_refuses_unready_orca_status() {
|
|
125
|
+
local out status
|
|
126
|
+
orca_case runtime-unready
|
|
127
|
+
printf '{"ok":true,"result":{"runtime":{"reachable":false,"state":"starting"}}}\n' > "$RESP/1.out"
|
|
128
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" FM_ORCA_STATUS_RESPONSE=sequence \
|
|
129
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_runtime_check' "$ROOT" 2>&1 )
|
|
130
|
+
status=$?
|
|
131
|
+
[ "$status" -ne 0 ] || fail "runtime_check should fail when Orca runtime is not ready"
|
|
132
|
+
assert_contains "$out" "requires a ready Orca runtime" "runtime_check should explain the readiness requirement"
|
|
133
|
+
pass "fm_backend_orca_runtime_check: fails closed when runtime is not ready"
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
test_send_text_submit_verifies_empty_composer_after_enter() {
|
|
137
|
+
local out
|
|
138
|
+
orca_case send-submit
|
|
139
|
+
printf '{"ok":true,"result":{"send":{"handle":"term-123","accepted":true}}}\n' > "$RESP/1.out"
|
|
140
|
+
printf '{"ok":true,"result":{"send":{"handle":"term-123","accepted":true}}}\n' > "$RESP/2.out"
|
|
141
|
+
printf '{"ok":true,"result":{"terminal":{"tail":["╭───╮","│ > │","╰───╯"]}}}\n' > "$RESP/3.out"
|
|
142
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
143
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_send_text_submit term-123 "hello captain" 3 0.01 0.01' "$ROOT" )
|
|
144
|
+
[ "$out" = empty ] || fail "send_text_submit should report empty on successful Orca send, got '$out'"
|
|
145
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''send'$'\x1f''--terminal'$'\x1f''term-123'$'\x1f''--text'$'\x1f''hello captain'$'\x1f''--json' \
|
|
146
|
+
"send_text_submit did not type the text literally before Enter"
|
|
147
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''send'$'\x1f''--terminal'$'\x1f''term-123'$'\x1f''--text'$'\x1f\x1f''--enter'$'\x1f''--json' \
|
|
148
|
+
"send_text_submit did not send Enter after typing"
|
|
149
|
+
# The composer read is ONE bounded tail read: the old backward paging
|
|
150
|
+
# (--cursor follow-ups on a limited page) is deleted, because paging into
|
|
151
|
+
# scrollback is what let a stale startup banner compete with the live
|
|
152
|
+
# composer (audit fm-composer-consolidation-audit-s1, section 3.3).
|
|
153
|
+
assert_not_contains "$(cat "$LOG")" $'\x1f''--cursor'$'\x1f' \
|
|
154
|
+
"the composer read must never page backward into scrollback"
|
|
155
|
+
pass "fm_backend_orca_send_text_submit: verifies empty composer after Enter with one bounded read"
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
test_send_text_submit_borderless_claude_confirms() {
|
|
159
|
+
# The #2029 analogue this adapter never received: a borderless claude
|
|
160
|
+
# composer (bare `❯` row between horizontal rules) must confirm a submit.
|
|
161
|
+
# Before consolidation orca knew only the bordered shape, so every steer to
|
|
162
|
+
# a borderless harness exited unconfirmed and --resolve-key never closed.
|
|
163
|
+
local out
|
|
164
|
+
orca_case send-submit-borderless
|
|
165
|
+
printf '{"ok":true,"result":{"send":{"handle":"term-123","accepted":true}}}\n' > "$RESP/1.out"
|
|
166
|
+
printf '{"ok":true,"result":{"send":{"handle":"term-123","accepted":true}}}\n' > "$RESP/2.out"
|
|
167
|
+
printf '{"ok":true,"result":{"terminal":{"tail":["────────────────","❯","────────────────"]}}}\n' > "$RESP/3.out"
|
|
168
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
169
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_send_text_submit term-123 "hello captain" 3 0.01 0.01' "$ROOT" )
|
|
170
|
+
[ "$out" = empty ] || fail "a borderless claude composer should confirm the submit, got '$out'"
|
|
171
|
+
pass "fm_backend_orca_send_text_submit: a borderless claude composer confirms delivery (the missing #2029 shape)"
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
test_composer_state_stale_banner_never_wins() {
|
|
175
|
+
# The audit's confidently-wrong case (section 3.3): codex's startup banner
|
|
176
|
+
# (`│ permissions: YOLO mode │` inside a rounded box) classified as the
|
|
177
|
+
# composer, reading `pending` for a row that is not a composer at all. With
|
|
178
|
+
# the full shape catalogue the live bare row below the banner wins; with a
|
|
179
|
+
# plain capture its trailing hint text is unreadable, so the verdict is
|
|
180
|
+
# `unknown` (defer) - never the banner's false `pending`.
|
|
181
|
+
local out
|
|
182
|
+
orca_case composer-stale-banner
|
|
183
|
+
printf '{"ok":true,"result":{"terminal":{"tail":["╭────────────────────────╮","│ permissions: YOLO mode │","╰────────────────────────╯","› Use /skills to list available skills"]}}}\n' > "$RESP/1.out"
|
|
184
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
185
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_composer_state term-123' "$ROOT" )
|
|
186
|
+
[ "$out" != pending ] || fail "a stale startup banner must never classify as pending composer text"
|
|
187
|
+
[ "$out" = unknown ] || fail "the plain-capture codex hint should defer as unknown, got '$out'"
|
|
188
|
+
pass "fm_backend_orca_composer_state: a stale startup banner cannot outrank the live composer row"
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
test_send_text_submit_retries_when_composer_stays_pending() {
|
|
192
|
+
local out log_text enter_count
|
|
193
|
+
orca_case send-submit-pending
|
|
194
|
+
printf '{"ok":true,"result":{"send":{"handle":"term-123","accepted":true}}}\n' > "$RESP/1.out"
|
|
195
|
+
printf '{"ok":true,"result":{"send":{"handle":"term-123","accepted":true}}}\n' > "$RESP/2.out"
|
|
196
|
+
printf '{"ok":true,"result":{"terminal":{"tail":["╭─────────────────╮","│ > hello captain │","╰─────────────────╯"]}}}\n' > "$RESP/3.out"
|
|
197
|
+
printf '{"ok":true,"result":{"send":{"handle":"term-123","accepted":true}}}\n' > "$RESP/4.out"
|
|
198
|
+
printf '{"ok":true,"result":{"terminal":{"tail":["╭─────────────────╮","│ > │","╰─────────────────╯"]}}}\n' > "$RESP/5.out"
|
|
199
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
200
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_send_text_submit term-123 "hello captain" 3 0.01 0.01' "$ROOT" )
|
|
201
|
+
[ "$out" = empty ] || fail "send_text_submit should retry Enter until the composer clears, got '$out'"
|
|
202
|
+
log_text=$(cat "$LOG")
|
|
203
|
+
enter_count=$(printf '%s\n' "$log_text" | grep -c $'orca\x1fterminal\x1fsend\x1f--terminal\x1fterm-123\x1f--text\x1f\x1f--enter\x1f--json')
|
|
204
|
+
[ "$enter_count" -eq 2 ] || fail "send_text_submit should send Enter twice when the first read is pending, got $enter_count"
|
|
205
|
+
pass "fm_backend_orca_send_text_submit: retries Enter while composer remains pending"
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
test_composer_state_popup_placeholder_fill_is_pending() {
|
|
209
|
+
local out
|
|
210
|
+
orca_case composer-popup-placeholder
|
|
211
|
+
printf '{"ok":true,"result":{"terminal":{"tail":[" ╭──────────────────────────────────────╮"," │ ❯ /compact compaction instructions │"," ╰──────────────── Composer ────────────╯",""," Enter:send"]}}}\n' > "$RESP/1.out"
|
|
212
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
213
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_composer_state term-123' "$ROOT" )
|
|
214
|
+
[ "$out" = pending ] || fail "a popup-close-with-placeholder-fill must still read as pending (not yet submitted), got '$out'"
|
|
215
|
+
pass "fm_backend_orca_composer_state: a slash-command popup's argument-hint placeholder still reads pending"
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
# Dead-shell injection safety (task fm-composer-shellglyph-safety): a pane whose
|
|
219
|
+
# agent has exited to a bare login shell has no bordered composer row, so the
|
|
220
|
+
# classifier finds nothing and reports `unknown` - NOT a safe (empty) injection
|
|
221
|
+
# target. Covers the same guarantee herdr/cmux/tmux tests pin for their backends.
|
|
222
|
+
test_composer_state_bare_shell_prompt_is_unknown() {
|
|
223
|
+
local out
|
|
224
|
+
orca_case composer-bare-shell
|
|
225
|
+
printf '{"ok":true,"result":{"terminal":{"tail":["some earlier output","kunchen@mac firstmate $ "]}}}\n' > "$RESP/1.out"
|
|
226
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
227
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_composer_state term-123' "$ROOT" )
|
|
228
|
+
[ "$out" = unknown ] || fail "a bare dead-shell prompt (no bordered composer row) must read unknown, got '$out'"
|
|
229
|
+
pass "fm_backend_orca_composer_state: a bare dead-shell prompt reads unknown (unsafe-for-injection), never empty"
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
test_send_text_submit_popup_autocomplete_requires_second_enter() {
|
|
233
|
+
local out log_text enter_count
|
|
234
|
+
orca_case send-submit-popup-autocomplete
|
|
235
|
+
# 1: literal send "/compact"
|
|
236
|
+
# 2: Enter #1 closes the popup and fills the placeholder
|
|
237
|
+
# 3: read - composer still holds real pending text
|
|
238
|
+
printf '{"ok":true,"result":{"send":{"handle":"term-123","accepted":true}}}\n' > "$RESP/1.out"
|
|
239
|
+
printf '{"ok":true,"result":{"send":{"handle":"term-123","accepted":true}}}\n' > "$RESP/2.out"
|
|
240
|
+
printf '{"ok":true,"result":{"terminal":{"tail":[" ╭──────────────────────────────────────╮"," │ ❯ /compact compaction instructions │"," ╰──────────────── Composer ────────────╯",""," Enter:send"]}}}\n' > "$RESP/3.out"
|
|
241
|
+
# 4: Enter #2 actually submits
|
|
242
|
+
# 5: read - composer is empty
|
|
243
|
+
printf '{"ok":true,"result":{"send":{"handle":"term-123","accepted":true}}}\n' > "$RESP/4.out"
|
|
244
|
+
printf '{"ok":true,"result":{"terminal":{"tail":[" ╭────────────────────────╮"," │ ❯ │"," ╰──────── Composer ──────╯",""," Shift+Tab:mode"]}}}\n' > "$RESP/5.out"
|
|
245
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
246
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_send_text_submit term-123 "/compact" 3 0.01 1.2' "$ROOT" )
|
|
247
|
+
[ "$out" = empty ] || fail "send_text_submit should eventually report empty once the SECOND Enter actually clears the composer, got '$out'"
|
|
248
|
+
log_text=$(cat "$LOG")
|
|
249
|
+
enter_count=$(printf '%s\n' "$log_text" | grep -c $'orca\x1fterminal\x1fsend\x1f--terminal\x1fterm-123\x1f--text\x1f\x1f--enter\x1f--json')
|
|
250
|
+
[ "$enter_count" -eq 2 ] || fail "send_text_submit must send a SECOND Enter after the popup-placeholder fill still reads pending, got $enter_count Enter(s)"
|
|
251
|
+
pass "fm_backend_orca_send_text_submit: a slash-command popup's placeholder fill on Enter #1 does not short-circuit as submitted; Enter #2 is retried and lands it"
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
test_send_literal_constructs_non_enter_send() {
|
|
255
|
+
orca_case send-literal
|
|
256
|
+
PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
257
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_send_literal term-123 "typed only"' "$ROOT"
|
|
258
|
+
expect_code 0 $? "send_literal should succeed"
|
|
259
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''send'$'\x1f''--terminal'$'\x1f''term-123'$'\x1f''--text'$'\x1f''typed only'$'\x1f''--json' \
|
|
260
|
+
"send_literal did not send text without --enter"
|
|
261
|
+
assert_not_contains "$(cat "$LOG")" $'\x1f''--enter' "send_literal should not submit Enter"
|
|
262
|
+
pass "fm_backend_orca_send_literal: sends text without submitting"
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
test_send_text_submit_reports_send_failed() {
|
|
266
|
+
local out
|
|
267
|
+
orca_case send-fail
|
|
268
|
+
printf '1\n' > "$RESP/1.exit"
|
|
269
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
270
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_send_text_submit term-123 "hello" 1 0.01 0.01' "$ROOT" )
|
|
271
|
+
[ "$out" = send-failed ] || fail "failed Orca send should report send-failed, got '$out'"
|
|
272
|
+
pass "fm_backend_orca_send_text_submit: reports send-failed when Orca send fails"
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
test_send_helpers_reject_orca_error_json() {
|
|
276
|
+
local out status
|
|
277
|
+
orca_case send-error-json
|
|
278
|
+
printf '{"ok":false,"error":{"code":"terminal_handle_stale","message":"terminal handle stale"}}\n' > "$RESP/1.out"
|
|
279
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
280
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_send_text_line term-stale "hello"' "$ROOT" 2>&1 )
|
|
281
|
+
status=$?
|
|
282
|
+
[ "$status" -ne 0 ] || fail "send_text_line should fail on Orca ok:false JSON"
|
|
283
|
+
assert_contains "$out" "terminal handle stale" "send_text_line should surface the Orca send error"
|
|
284
|
+
printf '{"ok":false,"error":{"code":"terminal_handle_stale","message":"terminal handle stale"}}\n' > "$RESP/2.out"
|
|
285
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
286
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_send_literal term-stale "typed"' "$ROOT" 2>&1 )
|
|
287
|
+
status=$?
|
|
288
|
+
[ "$status" -ne 0 ] || fail "send_literal should fail on Orca ok:false JSON"
|
|
289
|
+
printf '{"ok":false,"error":{"code":"terminal_handle_stale","message":"terminal handle stale"}}\n' > "$RESP/3.out"
|
|
290
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
291
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_send_key term-stale Enter' "$ROOT" 2>&1 )
|
|
292
|
+
status=$?
|
|
293
|
+
[ "$status" -ne 0 ] || fail "send_key should fail on Orca ok:false JSON"
|
|
294
|
+
printf '{"ok":false,"error":{"code":"terminal_handle_stale","message":"terminal handle stale"}}\n' > "$RESP/4.out"
|
|
295
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
296
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_send_text_submit term-stale "hello" 1 0.01 0.01' "$ROOT" 2>/dev/null )
|
|
297
|
+
[ "$out" = send-failed ] || fail "send_text_submit should report send-failed on Orca ok:false JSON, got '$out'"
|
|
298
|
+
pass "Orca send helpers: fail closed on ok:false JSON"
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
test_send_key_enter_and_interrupt() {
|
|
302
|
+
orca_case send-key
|
|
303
|
+
PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
304
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_send_key term-123 Enter; fm_backend_orca_send_key term-123 C-c' "$ROOT"
|
|
305
|
+
expect_code 0 $? "send_key Enter and C-c should succeed"
|
|
306
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''send'$'\x1f''--terminal'$'\x1f''term-123'$'\x1f''--text'$'\x1f\x1f''--enter'$'\x1f''--json' \
|
|
307
|
+
"send_key Enter did not send empty text with --enter"
|
|
308
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''send'$'\x1f''--terminal'$'\x1f''term-123'$'\x1f''--interrupt'$'\x1f''--json' \
|
|
309
|
+
"send_key C-c did not send --interrupt"
|
|
310
|
+
pass "fm_backend_orca_send_key: Enter maps to empty enter, C-c maps to interrupt"
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
test_send_key_refuses_unknown_key() {
|
|
314
|
+
local out status
|
|
315
|
+
orca_case send-key-unknown
|
|
316
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
317
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_send_key term-123 F12' "$ROOT" 2>&1 )
|
|
318
|
+
status=$?
|
|
319
|
+
[ "$status" -ne 0 ] || fail "send_key should refuse unsupported Orca keys"
|
|
320
|
+
assert_contains "$out" "unsupported Orca key 'F12'" "send_key did not name the unsupported key"
|
|
321
|
+
pass "fm_backend_orca_send_key: refuses unsupported keys loudly"
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
test_send_key_refuses_escape_until_supported() {
|
|
325
|
+
local out status
|
|
326
|
+
orca_case send-key-escape
|
|
327
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
328
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_send_key term-123 Escape' "$ROOT" 2>&1 )
|
|
329
|
+
status=$?
|
|
330
|
+
[ "$status" -ne 0 ] || fail "send_key should refuse Escape until Orca exposes a real Escape primitive"
|
|
331
|
+
assert_contains "$out" "unsupported Orca key 'Escape'" "send_key did not name Escape as unsupported"
|
|
332
|
+
[ ! -s "$LOG" ] || fail "unsupported Escape should not call orca terminal send"
|
|
333
|
+
pass "fm_backend_orca_send_key: refuses Escape instead of mapping it to interrupt"
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
test_kill_is_best_effort_close() {
|
|
337
|
+
orca_case kill
|
|
338
|
+
printf '1\n' > "$RESP/1.exit"
|
|
339
|
+
PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
340
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_kill term-123' "$ROOT"
|
|
341
|
+
expect_code 0 $? "kill should stay best-effort when Orca close fails"
|
|
342
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''close'$'\x1f''--terminal'$'\x1f''term-123'$'\x1f''--json' \
|
|
343
|
+
"kill did not call orca terminal close"
|
|
344
|
+
pass "fm_backend_orca_kill: calls terminal close and stays best-effort"
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
test_remove_worktree_refuses_empty_id() {
|
|
348
|
+
local out status
|
|
349
|
+
orca_case remove-empty
|
|
350
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
351
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_remove_worktree ""' "$ROOT" 2>&1 )
|
|
352
|
+
status=$?
|
|
353
|
+
[ "$status" -ne 0 ] || fail "remove_worktree should fail when the Orca worktree id is empty"
|
|
354
|
+
assert_contains "$out" "missing Orca worktree id" "remove_worktree did not explain the missing id"
|
|
355
|
+
[ ! -s "$LOG" ] || fail "remove_worktree should not call Orca with an empty id"
|
|
356
|
+
pass "fm_backend_orca_remove_worktree: refuses empty worktree ids"
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
test_remove_worktree_rejects_orca_error_json() {
|
|
360
|
+
local out status
|
|
361
|
+
orca_case remove-error-json
|
|
362
|
+
printf '{"ok":false,"error":{"code":"worktree_not_found","message":"worktree not found"}}\n' > "$RESP/1.out"
|
|
363
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
364
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_remove_worktree wt-gone' "$ROOT" 2>&1 )
|
|
365
|
+
status=$?
|
|
366
|
+
[ "$status" -ne 0 ] || fail "remove_worktree should fail on Orca ok:false JSON"
|
|
367
|
+
assert_contains "$out" "worktree not found" "remove_worktree should surface the Orca removal error"
|
|
368
|
+
pass "fm_backend_orca_remove_worktree: fails closed on ok:false JSON"
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
test_worktree_path_resolves_id() {
|
|
372
|
+
local out
|
|
373
|
+
orca_case path-resolve
|
|
374
|
+
printf '{"ok":true,"result":{"worktree":{"id":"wt-123","path":"/tmp/orca-wt"}}}\n' > "$RESP/1.out"
|
|
375
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
376
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_worktree_path wt-123' "$ROOT" )
|
|
377
|
+
[ "$out" = /tmp/orca-wt ] || fail "worktree path helper should print the resolved path, got '$out'"
|
|
378
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''worktree'$'\x1f''show'$'\x1f''--worktree'$'\x1f''id:wt-123'$'\x1f''--json' \
|
|
379
|
+
"worktree path helper did not call orca worktree show"
|
|
380
|
+
pass "fm_backend_orca_worktree_path: resolves an Orca worktree id to its path"
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
test_json_get_ignores_undocumented_terminal_id_shapes() {
|
|
384
|
+
local out status wt_id wt_path term
|
|
385
|
+
orca_case parser-pruned-terminal-shapes
|
|
386
|
+
|
|
387
|
+
set +e
|
|
388
|
+
out=$( printf '{"ok":true,"result":{"id":"term-root-id"}}\n' | \
|
|
389
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_json_get terminal-handle' "$ROOT" )
|
|
390
|
+
status=$?
|
|
391
|
+
set +e
|
|
392
|
+
[ "$status" -ne 0 ] || fail "terminal-handle should not treat undocumented result.id as a terminal handle, got '$out'"
|
|
393
|
+
|
|
394
|
+
printf '1\n' > "$RESP/1.exit"
|
|
395
|
+
printf '{"ok":true,"result":{"repo":{"id":"repo-123"}}}\n' > "$RESP/2.out"
|
|
396
|
+
printf '{"ok":true,"result":{"worktree":{"id":"wt-123","path":"/tmp/orca-wt","terminal":{"handle":"term-nested"}}}}\n' > "$RESP/3.out"
|
|
397
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
398
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_worktree_create /repo/path fm-task' "$ROOT" )
|
|
399
|
+
wt_id=${out%%$'\t'*}
|
|
400
|
+
wt_path=${out#*$'\t'}
|
|
401
|
+
term=${wt_path#*$'\t'}
|
|
402
|
+
wt_path=${wt_path%%$'\t'*}
|
|
403
|
+
[ "$wt_id" = wt-123 ] || fail "worktree helper should still print worktree id, got '$wt_id'"
|
|
404
|
+
[ "$wt_path" = /tmp/orca-wt ] || fail "worktree helper should still print worktree path, got '$wt_path'"
|
|
405
|
+
[ "$term" = "$wt_path" ] || fail "worktree helper should ignore undocumented result.worktree.terminal and omit an implicit terminal, got '$out'"
|
|
406
|
+
pass "fm_backend_orca_json_get: ignores undocumented terminal id shapes"
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
test_worktree_and_terminal_helpers_parse_json() {
|
|
410
|
+
local out wt_id wt_path term
|
|
411
|
+
orca_case lifecycle-helpers
|
|
412
|
+
printf '1\n' > "$RESP/1.exit"
|
|
413
|
+
printf '{"ok":true,"result":{"repo":{"id":"repo-123"}}}\n' > "$RESP/2.out"
|
|
414
|
+
printf '{"ok":true,"result":{"worktree":{"id":"wt-123","path":"/tmp/orca-wt"}}}\n' > "$RESP/3.out"
|
|
415
|
+
printf '{"ok":true,"result":{"terminal":{"handle":"term-123"}}}\n' > "$RESP/4.out"
|
|
416
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
417
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_worktree_create /repo/path fm-task' "$ROOT" )
|
|
418
|
+
wt_id=${out%%$'\t'*}
|
|
419
|
+
wt_path=${out#*$'\t'}
|
|
420
|
+
[ "$wt_id" = wt-123 ] || fail "worktree helper should print worktree id, got '$wt_id'"
|
|
421
|
+
[ "$wt_path" = /tmp/orca-wt ] || fail "worktree helper should print worktree path, got '$wt_path'"
|
|
422
|
+
term=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
423
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_terminal_create wt-123 fm-task' "$ROOT" )
|
|
424
|
+
[ "$term" = term-123 ] || fail "terminal helper should print terminal handle, got '$term'"
|
|
425
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''repo'$'\x1f''show'$'\x1f''--repo'$'\x1f''path:/repo/path'$'\x1f''--json' \
|
|
426
|
+
"worktree helper should first check repo registration"
|
|
427
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''repo'$'\x1f''add'$'\x1f''--path'$'\x1f''/repo/path'$'\x1f''--json' \
|
|
428
|
+
"worktree helper should register an absent repo"
|
|
429
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''worktree'$'\x1f''create'$'\x1f''--repo'$'\x1f''id:repo-123'$'\x1f''--name'$'\x1f''fm-task'$'\x1f''--no-parent'$'\x1f''--setup'$'\x1f''skip'$'\x1f''--json' \
|
|
430
|
+
"worktree helper did not create an independent no-hook worktree"
|
|
431
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''create'$'\x1f''--worktree'$'\x1f''id:wt-123'$'\x1f''--title'$'\x1f''fm-task'$'\x1f''--json' \
|
|
432
|
+
"terminal helper did not create a titled terminal for the worktree"
|
|
433
|
+
pass "Orca lifecycle helpers: register repo, create worktree, create terminal, parse stable ids"
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
test_worktree_create_removes_worktree_when_path_missing() {
|
|
437
|
+
local out status
|
|
438
|
+
orca_case lifecycle-missing-path
|
|
439
|
+
printf '1\n' > "$RESP/1.exit"
|
|
440
|
+
printf '{"ok":true,"result":{"repo":{"id":"repo-no-path"}}}\n' > "$RESP/2.out"
|
|
441
|
+
printf '{"ok":true,"result":{"worktree":{"id":"wt-no-path"},"terminal":{"handle":"term-no-path"}}}\n' > "$RESP/3.out"
|
|
442
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
443
|
+
bash -c '. "$0/bin/backends/orca.sh"; fm_backend_orca_worktree_create /repo/path fm-task' "$ROOT" 2>&1 )
|
|
444
|
+
status=$?
|
|
445
|
+
[ "$status" -ne 0 ] || fail "worktree helper should fail when Orca omits the worktree path"
|
|
446
|
+
assert_contains "$out" "orca worktree create did not return a path for fm-task" \
|
|
447
|
+
"worktree helper did not explain the missing path"
|
|
448
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''close'$'\x1f''--terminal'$'\x1f''term-no-path'$'\x1f''--json' \
|
|
449
|
+
"worktree helper did not close the implicit terminal when path parsing failed"
|
|
450
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''worktree'$'\x1f''rm'$'\x1f''--worktree'$'\x1f''id:wt-no-path'$'\x1f''--force'$'\x1f''--json' \
|
|
451
|
+
"worktree helper did not remove the pathless Orca worktree"
|
|
452
|
+
pass "fm_backend_orca_worktree_create: removes created worktree when path is missing"
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
test_spawn_preserves_orca_metadata_when_pathless_worktree_cleanup_fails() {
|
|
456
|
+
local proj data state config id out status
|
|
457
|
+
id="orcapathlessz6"
|
|
458
|
+
proj="$TMP_ROOT/pathless-cleanup-project"
|
|
459
|
+
data="$TMP_ROOT/pathless-cleanup-data"
|
|
460
|
+
state="$TMP_ROOT/pathless-cleanup-state"
|
|
461
|
+
config="$TMP_ROOT/pathless-cleanup-config"
|
|
462
|
+
fm_git_init_commit "$proj"
|
|
463
|
+
mkdir -p "$data/$id" "$state" "$config"
|
|
464
|
+
printf 'brief\n' > "$data/$id/brief.md"
|
|
465
|
+
touch "$state/.last-watcher-beat"
|
|
466
|
+
orca_case pathless-cleanup-fail
|
|
467
|
+
printf '1\n' > "$RESP/1.exit"
|
|
468
|
+
printf '{"ok":true,"result":{"repo":{"id":"repo-pathless-cleanup"}}}\n' > "$RESP/2.out"
|
|
469
|
+
printf '{"ok":true,"result":{"worktree":{"id":"wt-pathless-cleanup"}}}\n' > "$RESP/3.out"
|
|
470
|
+
printf '{"ok":false,"error":{"code":"worktree_not_removed","message":"worktree not removed"}}\n' > "$RESP/4.out"
|
|
471
|
+
printf '{"ok":false,"error":{"code":"worktree_not_removed","message":"worktree not removed"}}\n' > "$RESP/5.out"
|
|
472
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
473
|
+
FM_ROOT_OVERRIDE="$ROOT" FM_STATE_OVERRIDE="$state" FM_DATA_OVERRIDE="$data" FM_CONFIG_OVERRIDE="$config" \
|
|
474
|
+
FM_PROJECTS_OVERRIDE="$TMP_ROOT/unused-projects" FM_SPAWN_NO_GUARD=1 \
|
|
475
|
+
"$ROOT/bin/fm-spawn.sh" "$id" "$proj" claude --mode no-mistakes --yolo off --backend orca 2>&1 )
|
|
476
|
+
status=$?
|
|
477
|
+
[ "$status" -ne 0 ] || fail "Orca spawn should fail when path parsing and cleanup fail"
|
|
478
|
+
assert_contains "$out" "orca worktree create did not return a path" \
|
|
479
|
+
"pathless worktree failure should explain the missing path"
|
|
480
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''worktree'$'\x1f''rm'$'\x1f''--worktree'$'\x1f''id:wt-pathless-cleanup'$'\x1f''--force'$'\x1f''--json' \
|
|
481
|
+
"pathless cleanup should attempt helper-backed worktree removal"
|
|
482
|
+
assert_present "$state/$id.meta" "failed pathless cleanup should preserve metadata"
|
|
483
|
+
assert_grep "window=fm-$id" "$state/$id.meta" "preserved pathless metadata missing stable window alias"
|
|
484
|
+
assert_grep "backend=orca" "$state/$id.meta" "preserved pathless metadata missing backend=orca"
|
|
485
|
+
assert_grep "orca_worktree_id=wt-pathless-cleanup" "$state/$id.meta" "preserved pathless metadata missing Orca worktree id"
|
|
486
|
+
assert_no_grep "terminal=" "$state/$id.meta" "preserved pathless metadata should not invent a terminal handle"
|
|
487
|
+
pass "fm-spawn.sh --backend orca: preserves metadata when pathless cleanup fails"
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
test_spawn_writes_orca_metadata_and_launches_harness() {
|
|
491
|
+
local proj wt data state config id out log
|
|
492
|
+
id="orcaspawnz1"
|
|
493
|
+
proj="$TMP_ROOT/spawn-project"
|
|
494
|
+
wt="$TMP_ROOT/spawn-wt"
|
|
495
|
+
data="$TMP_ROOT/spawn-data"
|
|
496
|
+
state="$TMP_ROOT/spawn-state"
|
|
497
|
+
config="$TMP_ROOT/spawn-config"
|
|
498
|
+
fm_git_worktree "$proj" "$wt" "fm/$id"
|
|
499
|
+
mkdir -p "$data/$id" "$state" "$config"
|
|
500
|
+
printf 'brief\n' > "$data/$id/brief.md"
|
|
501
|
+
touch "$state/.last-watcher-beat"
|
|
502
|
+
orca_case spawn
|
|
503
|
+
log="$LOG"
|
|
504
|
+
printf '1\n' > "$RESP/1.exit"
|
|
505
|
+
printf '{"ok":true,"result":{"repo":{"id":"repo-spawn"}}}\n' > "$RESP/2.out"
|
|
506
|
+
printf '{"ok":true,"result":{"worktree":{"id":"wt-spawn","path":"%s"},"terminal":{"handle":"term-spawn"}}}\n' "$wt" > "$RESP/3.out"
|
|
507
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
508
|
+
FM_ROOT_OVERRIDE="$ROOT" FM_STATE_OVERRIDE="$state" FM_DATA_OVERRIDE="$data" FM_CONFIG_OVERRIDE="$config" \
|
|
509
|
+
FM_PROJECTS_OVERRIDE="$TMP_ROOT/unused-projects" FM_SPAWN_NO_GUARD=1 \
|
|
510
|
+
"$ROOT/bin/fm-spawn.sh" "$id" "$proj" claude --mode no-mistakes --yolo off --backend orca 2>&1 )
|
|
511
|
+
expect_code 0 $? "fm-spawn.sh --backend orca should succeed with fake Orca"$'\n'"$out"
|
|
512
|
+
assert_contains "$out" "spawned $id harness=claude kind=ship mode=no-mistakes yolo=off window=fm-$id worktree=$wt" \
|
|
513
|
+
"spawn output missing Orca window/worktree summary"
|
|
514
|
+
assert_grep "backend=orca" "$state/$id.meta" "meta missing backend=orca"
|
|
515
|
+
assert_grep "window=fm-$id" "$state/$id.meta" "meta missing stable Orca window alias"
|
|
516
|
+
assert_grep "terminal=term-spawn" "$state/$id.meta" "meta missing terminal handle"
|
|
517
|
+
assert_grep "orca_worktree_id=wt-spawn" "$state/$id.meta" "meta missing Orca worktree id"
|
|
518
|
+
assert_grep "worktree=$wt" "$state/$id.meta" "meta missing Orca worktree path"
|
|
519
|
+
assert_not_contains "$(cat "$log")" $'orca\x1f''terminal'$'\x1f''create' \
|
|
520
|
+
"spawn should reuse the implicit terminal returned by Orca worktree creation"
|
|
521
|
+
assert_contains "$(cat "$log")" $'orca\x1f''terminal'$'\x1f''send'$'\x1f''--terminal'$'\x1f''term-spawn'$'\x1f''--text'$'\x1f''export GOTMPDIR=/tmp/fm-orcaspawnz1/gotmp'$'\x1f''--enter'$'\x1f''--json' \
|
|
522
|
+
"spawn did not export GOTMPDIR through the Orca terminal"
|
|
523
|
+
assert_contains "$(cat "$log")" "CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION=false claude --dangerously-skip-permissions" \
|
|
524
|
+
"spawn did not send the selected harness launch command through Orca"
|
|
525
|
+
rm -rf "/tmp/fm-$id"
|
|
526
|
+
pass "fm-spawn.sh --backend orca: reuses implicit terminal, records metadata, launches harness"
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
test_spawn_refuses_orca_secondmate_before_home_mutation() {
|
|
530
|
+
local home subhome data state config id out status
|
|
531
|
+
id="orcasmz1"
|
|
532
|
+
home="$TMP_ROOT/secondmate-refusal-home"
|
|
533
|
+
subhome="$TMP_ROOT/secondmate-refusal-subhome"
|
|
534
|
+
data="$home/data"
|
|
535
|
+
state="$home/state"
|
|
536
|
+
config="$home/config"
|
|
537
|
+
mkdir -p "$data" "$state" "$config" "$subhome/bin" "$subhome/data" "$subhome/state" "$subhome/projects"
|
|
538
|
+
printf '%s\n' "$id" > "$subhome/.fm-secondmate-home"
|
|
539
|
+
printf 'firstmate\n' > "$subhome/AGENTS.md"
|
|
540
|
+
printf 'claude\n' > "$config/crew-harness"
|
|
541
|
+
touch "$state/.last-watcher-beat"
|
|
542
|
+
set +e
|
|
543
|
+
out=$( FM_ROOT_OVERRIDE="$ROOT" FM_HOME="$home" FM_STATE_OVERRIDE="$state" FM_DATA_OVERRIDE="$data" FM_CONFIG_OVERRIDE="$config" \
|
|
544
|
+
FM_PROJECTS_OVERRIDE="$home/projects" FM_SPAWN_NO_GUARD=1 \
|
|
545
|
+
"$ROOT/bin/fm-spawn.sh" "$id" "$subhome" claude --backend orca --secondmate 2>&1 )
|
|
546
|
+
status=$?
|
|
547
|
+
set +e
|
|
548
|
+
[ "$status" -ne 0 ] || fail "backend=orca --secondmate should be refused"
|
|
549
|
+
assert_contains "$out" "backend=orca does not support --secondmate spawns yet" \
|
|
550
|
+
"orca secondmate refusal should happen at backend selection"
|
|
551
|
+
assert_absent "$subhome/config/crew-harness" \
|
|
552
|
+
"orca secondmate refusal should not propagate inherited local material into the secondmate home"
|
|
553
|
+
pass "fm-spawn.sh --backend orca --secondmate: refuses before secondmate-home mutation"
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
test_spawn_refuses_orca_when_runtime_not_ready() {
|
|
557
|
+
local proj data state config id out status
|
|
558
|
+
id="orcaruntimez6"
|
|
559
|
+
proj="$TMP_ROOT/runtime-down-project"
|
|
560
|
+
data="$TMP_ROOT/runtime-down-data"
|
|
561
|
+
state="$TMP_ROOT/runtime-down-state"
|
|
562
|
+
config="$TMP_ROOT/runtime-down-config"
|
|
563
|
+
fm_git_init_commit "$proj"
|
|
564
|
+
mkdir -p "$data/$id" "$state" "$config"
|
|
565
|
+
printf 'brief\n' > "$data/$id/brief.md"
|
|
566
|
+
touch "$state/.last-watcher-beat"
|
|
567
|
+
orca_case runtime-down-spawn
|
|
568
|
+
printf '{"ok":true,"result":{"runtime":{"reachable":false,"state":"starting"}}}\n' > "$RESP/1.out"
|
|
569
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" FM_ORCA_STATUS_RESPONSE=sequence \
|
|
570
|
+
FM_ROOT_OVERRIDE="$ROOT" FM_STATE_OVERRIDE="$state" FM_DATA_OVERRIDE="$data" FM_CONFIG_OVERRIDE="$config" \
|
|
571
|
+
FM_PROJECTS_OVERRIDE="$TMP_ROOT/unused-projects" FM_SPAWN_NO_GUARD=1 \
|
|
572
|
+
"$ROOT/bin/fm-spawn.sh" "$id" "$proj" claude --mode no-mistakes --yolo off --backend orca 2>&1 )
|
|
573
|
+
status=$?
|
|
574
|
+
[ "$status" -ne 0 ] || fail "fm-spawn.sh --backend orca should refuse when Orca runtime is not ready"
|
|
575
|
+
assert_contains "$out" "requires a ready Orca runtime" \
|
|
576
|
+
"runtime readiness refusal should explain the Orca requirement"
|
|
577
|
+
assert_absent "$state/$id.meta" "runtime refusal must not record metadata"
|
|
578
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''status'$'\x1f''--json' \
|
|
579
|
+
"spawn did not probe Orca runtime readiness"
|
|
580
|
+
assert_not_contains "$(cat "$LOG")" $'orca\x1f''repo' \
|
|
581
|
+
"spawn should fail before repo/worktree creation when runtime is not ready"
|
|
582
|
+
pass "fm-spawn.sh --backend orca: refuses before mutation when Orca runtime is not ready"
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
test_spawn_refuses_orca_nonisolated_worktree() {
|
|
586
|
+
local proj data state config id out status
|
|
587
|
+
id="orcabadwtz4"
|
|
588
|
+
proj="$TMP_ROOT/bad-spawn-project"
|
|
589
|
+
data="$TMP_ROOT/bad-spawn-data"
|
|
590
|
+
state="$TMP_ROOT/bad-spawn-state"
|
|
591
|
+
config="$TMP_ROOT/bad-spawn-config"
|
|
592
|
+
fm_git_init_commit "$proj"
|
|
593
|
+
mkdir -p "$data/$id" "$state" "$config"
|
|
594
|
+
printf 'brief\n' > "$data/$id/brief.md"
|
|
595
|
+
touch "$state/.last-watcher-beat"
|
|
596
|
+
orca_case bad-spawn
|
|
597
|
+
printf '1\n' > "$RESP/1.exit"
|
|
598
|
+
printf '{"ok":true,"result":{"repo":{"id":"repo-bad"}}}\n' > "$RESP/2.out"
|
|
599
|
+
printf '{"ok":true,"result":{"worktree":{"id":"wt-bad","path":"%s"},"terminal":{"handle":"term-bad"}}}\n' "$proj" > "$RESP/3.out"
|
|
600
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
601
|
+
FM_ROOT_OVERRIDE="$ROOT" FM_STATE_OVERRIDE="$state" FM_DATA_OVERRIDE="$data" FM_CONFIG_OVERRIDE="$config" \
|
|
602
|
+
FM_PROJECTS_OVERRIDE="$TMP_ROOT/unused-projects" FM_SPAWN_NO_GUARD=1 \
|
|
603
|
+
"$ROOT/bin/fm-spawn.sh" "$id" "$proj" claude --mode no-mistakes --yolo off --backend orca 2>&1 )
|
|
604
|
+
status=$?
|
|
605
|
+
expect_code 1 "$status" "fm-spawn.sh --backend orca should refuse a primary checkout worktree"
|
|
606
|
+
assert_contains "$out" "orca worktree create did not yield an isolated worktree" \
|
|
607
|
+
"Orca spawn should reuse the isolated-worktree guard"
|
|
608
|
+
assert_absent "$state/$id.meta" "aborted Orca spawn must not record meta"
|
|
609
|
+
assert_not_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''create' \
|
|
610
|
+
"Orca spawn should validate the worktree before creating a terminal"
|
|
611
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''close'$'\x1f''--terminal'$'\x1f''term-bad'$'\x1f''--json' \
|
|
612
|
+
"Orca spawn should close the implicit terminal after validation aborts"
|
|
613
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''worktree'$'\x1f''rm'$'\x1f''--worktree'$'\x1f''id:wt-bad'$'\x1f''--force'$'\x1f''--json' \
|
|
614
|
+
"Orca spawn should remove the worktree after validation aborts"
|
|
615
|
+
pass "fm-spawn.sh --backend orca: refuses non-isolated worktrees and closes implicit terminals"
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
test_spawn_removes_orca_worktree_when_terminal_create_fails() {
|
|
619
|
+
local proj wt data state config id out status
|
|
620
|
+
id="orcatermfailz8"
|
|
621
|
+
proj="$TMP_ROOT/terminal-fail-project"
|
|
622
|
+
wt="$TMP_ROOT/terminal-fail-wt"
|
|
623
|
+
data="$TMP_ROOT/terminal-fail-data"
|
|
624
|
+
state="$TMP_ROOT/terminal-fail-state"
|
|
625
|
+
config="$TMP_ROOT/terminal-fail-config"
|
|
626
|
+
fm_git_worktree "$proj" "$wt" "fm/$id"
|
|
627
|
+
mkdir -p "$data/$id" "$state" "$config"
|
|
628
|
+
printf 'brief\n' > "$data/$id/brief.md"
|
|
629
|
+
touch "$state/.last-watcher-beat"
|
|
630
|
+
orca_case terminal-fail
|
|
631
|
+
printf '1\n' > "$RESP/1.exit"
|
|
632
|
+
printf '{"ok":true,"result":{"repo":{"id":"repo-terminal-fail"}}}\n' > "$RESP/2.out"
|
|
633
|
+
printf '{"ok":true,"result":{"worktree":{"id":"wt-terminal-fail","path":"%s"}}}\n' "$wt" > "$RESP/3.out"
|
|
634
|
+
printf '1\n' > "$RESP/4.exit"
|
|
635
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
636
|
+
FM_ROOT_OVERRIDE="$ROOT" FM_STATE_OVERRIDE="$state" FM_DATA_OVERRIDE="$data" FM_CONFIG_OVERRIDE="$config" \
|
|
637
|
+
FM_PROJECTS_OVERRIDE="$TMP_ROOT/unused-projects" FM_SPAWN_NO_GUARD=1 \
|
|
638
|
+
"$ROOT/bin/fm-spawn.sh" "$id" "$proj" claude --mode no-mistakes --yolo off --backend orca 2>&1 )
|
|
639
|
+
status=$?
|
|
640
|
+
[ "$status" -ne 0 ] || fail "Orca spawn should fail when terminal creation fails"
|
|
641
|
+
assert_absent "$state/$id.meta" "terminal-create abort should not record metadata after successful cleanup"
|
|
642
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''create'$'\x1f''--worktree'$'\x1f''id:wt-terminal-fail'$'\x1f''--title'$'\x1f'"fm-$id"$'\x1f''--json' \
|
|
643
|
+
"Orca spawn should attempt terminal creation before abort cleanup"
|
|
644
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''worktree'$'\x1f''rm'$'\x1f''--worktree'$'\x1f''id:wt-terminal-fail'$'\x1f''--force'$'\x1f''--json' \
|
|
645
|
+
"Orca spawn should remove the worktree when terminal creation fails"
|
|
646
|
+
assert_not_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''close' \
|
|
647
|
+
"Orca spawn should not close a terminal when no handle was recorded"
|
|
648
|
+
pass "fm-spawn.sh --backend orca: removes worktree when terminal creation fails"
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
test_spawn_preserves_orca_metadata_when_abort_cleanup_fails() {
|
|
652
|
+
local proj wt data state config id out status
|
|
653
|
+
id="orcacleanupleakz0"
|
|
654
|
+
proj="$TMP_ROOT/cleanup-fail-project"
|
|
655
|
+
wt="$TMP_ROOT/cleanup-fail-wt"
|
|
656
|
+
data="$TMP_ROOT/cleanup-fail-data"
|
|
657
|
+
state="$TMP_ROOT/cleanup-fail-state"
|
|
658
|
+
config="$TMP_ROOT/cleanup-fail-config"
|
|
659
|
+
fm_git_worktree "$proj" "$wt" "fm/$id"
|
|
660
|
+
mkdir -p "$data/$id" "$state" "$config"
|
|
661
|
+
printf 'brief\n' > "$data/$id/brief.md"
|
|
662
|
+
touch "$state/.last-watcher-beat"
|
|
663
|
+
orca_case cleanup-fail
|
|
664
|
+
printf '1\n' > "$RESP/1.exit"
|
|
665
|
+
printf '{"ok":true,"result":{"repo":{"id":"repo-cleanup-fail"}}}\n' > "$RESP/2.out"
|
|
666
|
+
printf '{"ok":true,"result":{"worktree":{"id":"wt-cleanup-fail","path":"%s"}}}\n' "$wt" > "$RESP/3.out"
|
|
667
|
+
printf '1\n' > "$RESP/4.exit"
|
|
668
|
+
printf '1\n' > "$RESP/5.exit"
|
|
669
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
670
|
+
FM_ROOT_OVERRIDE="$ROOT" FM_STATE_OVERRIDE="$state" FM_DATA_OVERRIDE="$data" FM_CONFIG_OVERRIDE="$config" \
|
|
671
|
+
FM_PROJECTS_OVERRIDE="$TMP_ROOT/unused-projects" FM_SPAWN_NO_GUARD=1 \
|
|
672
|
+
"$ROOT/bin/fm-spawn.sh" "$id" "$proj" claude --mode no-mistakes --yolo off --backend orca 2>&1 )
|
|
673
|
+
status=$?
|
|
674
|
+
[ "$status" -ne 0 ] || fail "Orca spawn should fail when terminal creation and abort cleanup fail"
|
|
675
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''worktree'$'\x1f''rm'$'\x1f''--worktree'$'\x1f''id:wt-cleanup-fail'$'\x1f''--force'$'\x1f''--json' \
|
|
676
|
+
"Orca spawn should attempt helper cleanup before preserving metadata"
|
|
677
|
+
assert_present "$state/$id.meta" "failed Orca abort cleanup should preserve metadata"
|
|
678
|
+
assert_grep "window=fm-$id" "$state/$id.meta" "preserved metadata missing stable window alias"
|
|
679
|
+
assert_grep "backend=orca" "$state/$id.meta" "preserved metadata missing backend=orca"
|
|
680
|
+
assert_grep "orca_worktree_id=wt-cleanup-fail" "$state/$id.meta" "preserved metadata missing Orca worktree id"
|
|
681
|
+
assert_no_grep "terminal=" "$state/$id.meta" "preserved metadata should not invent a terminal handle"
|
|
682
|
+
pass "fm-spawn.sh --backend orca: preserves metadata when abort cleanup fails"
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
test_spawn_releases_orca_resources_when_metadata_write_fails() {
|
|
686
|
+
local proj wt data state config id out status
|
|
687
|
+
id="orcametafailz9"
|
|
688
|
+
proj="$TMP_ROOT/meta-fail-project"
|
|
689
|
+
wt="$TMP_ROOT/meta-fail-wt"
|
|
690
|
+
data="$TMP_ROOT/meta-fail-data"
|
|
691
|
+
state="$TMP_ROOT/meta-fail-state"
|
|
692
|
+
config="$TMP_ROOT/meta-fail-config"
|
|
693
|
+
fm_git_worktree "$proj" "$wt" "fm/$id"
|
|
694
|
+
mkdir -p "$data/$id" "$state/$id.meta" "$config"
|
|
695
|
+
printf 'brief\n' > "$data/$id/brief.md"
|
|
696
|
+
orca_case meta-fail
|
|
697
|
+
printf '1\n' > "$RESP/1.exit"
|
|
698
|
+
printf '{"ok":true,"result":{"repo":{"id":"repo-meta-fail"}}}\n' > "$RESP/2.out"
|
|
699
|
+
printf '{"ok":true,"result":{"worktree":{"id":"wt-meta-fail","path":"%s"}}}\n' "$wt" > "$RESP/3.out"
|
|
700
|
+
printf '{"ok":true,"result":{"terminal":{"handle":"term-meta-fail"}}}\n' > "$RESP/4.out"
|
|
701
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
702
|
+
FM_ROOT_OVERRIDE="$ROOT" FM_STATE_OVERRIDE="$state" FM_DATA_OVERRIDE="$data" FM_CONFIG_OVERRIDE="$config" \
|
|
703
|
+
FM_PROJECTS_OVERRIDE="$TMP_ROOT/unused-projects" FM_SPAWN_NO_GUARD=1 \
|
|
704
|
+
"$ROOT/bin/fm-spawn.sh" "$id" "$proj" claude --mode no-mistakes --yolo off --backend orca 2>&1 )
|
|
705
|
+
status=$?
|
|
706
|
+
[ "$status" -ne 0 ] || fail "Orca spawn should fail when metadata cannot be written"
|
|
707
|
+
assert_contains "$out" "task record for $id could not be published" \
|
|
708
|
+
"spawn should report metadata publication failure without relying on platform-specific mv output"
|
|
709
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''close'$'\x1f''--terminal'$'\x1f''term-meta-fail'$'\x1f''--json' \
|
|
710
|
+
"Orca spawn should close the recorded terminal when a later abort occurs"
|
|
711
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''worktree'$'\x1f''rm'$'\x1f''--worktree'$'\x1f''id:wt-meta-fail'$'\x1f''--force'$'\x1f''--json' \
|
|
712
|
+
"Orca spawn should remove the recorded worktree when a later abort occurs"
|
|
713
|
+
[ ! -f "$state/$id.meta" ] || fail "metadata-write abort should not publish a regular metadata file"
|
|
714
|
+
pass "fm-spawn.sh --backend orca: releases terminal and worktree on later aborts"
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
test_peek_send_and_crew_state_route_through_orca_meta() {
|
|
718
|
+
local wt state id out neutral record body
|
|
719
|
+
id="orcaiopathz2"
|
|
720
|
+
wt="$TMP_ROOT/io-wt"
|
|
721
|
+
fm_git_init_commit "$wt"
|
|
722
|
+
state="$TMP_ROOT/io-state"; mkdir -p "$state"
|
|
723
|
+
fm_write_meta "$state/$id.meta" \
|
|
724
|
+
"window=fm-$id" "endpoint_task_id=$id" "terminal=term-io" "worktree=$wt" "project=$wt" "harness=claude" "kind=scout" "backend=orca"
|
|
725
|
+
touch "$state/.last-watcher-beat"
|
|
726
|
+
orca_case io-path
|
|
727
|
+
neutral=$(neutral_fm_root "$CASE_DIR/neutral")
|
|
728
|
+
printf '{"ok":true,"result":{"terminal":{"tail":["ready"]}}}\n' > "$RESP/1.out"
|
|
729
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
730
|
+
FM_ROOT_OVERRIDE="$neutral" FM_STATE_OVERRIDE="$state" FM_SEND_SETTLE=0 \
|
|
731
|
+
"$ROOT/bin/fm-peek.sh" "fm-$id" 10 )
|
|
732
|
+
[ "$out" = ready ] || fail "fm-peek should read through Orca metadata, got '$out'"
|
|
733
|
+
printf '{"ok":true,"result":{"send":{"handle":"term-io","accepted":true}}}\n' > "$RESP/2.out"
|
|
734
|
+
printf '{"ok":true,"result":{"send":{"handle":"term-io","accepted":true}}}\n' > "$RESP/3.out"
|
|
735
|
+
printf '{"ok":true,"result":{"terminal":{"tail":["│ > │"]}}}\n' > "$RESP/4.out"
|
|
736
|
+
PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
737
|
+
FM_ROOT_OVERRIDE="$neutral" FM_HOME="$neutral" FM_STATE_OVERRIDE="$state" FM_SEND_SETTLE=0 \
|
|
738
|
+
"$ROOT/bin/fm-send.sh" "fm-$id" "hello orca"
|
|
739
|
+
printf '{"ok":true,"result":{"terminal":{"tail":["idle prompt"]}}}\n' > "$RESP/5.out"
|
|
740
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
741
|
+
FM_ROOT_OVERRIDE="$ROOT" FM_STATE_OVERRIDE="$state" "$ROOT/bin/fm-crew-state.sh" "$id" )
|
|
742
|
+
assert_contains "$out" "state: unknown" "crew-state should fall back cleanly for an idle Orca scout"
|
|
743
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''read'$'\x1f''--terminal'$'\x1f''term-io' \
|
|
744
|
+
"peek/crew-state did not read the recorded Orca terminal"
|
|
745
|
+
assert_not_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''read'$'\x1f''--terminal'$'\x1f'"fm-$id" \
|
|
746
|
+
"crew-state should not read the stable Orca alias as a terminal handle"
|
|
747
|
+
record="$state/$id.inbox/001.msg"
|
|
748
|
+
[ -f "$record" ] || fail "send did not enqueue through the task inbox"
|
|
749
|
+
body=$(bash -c '. "$1"; fm_task_inbox_body "$2"' _ "$ROOT/bin/fm-task-inbox-lib.sh" "$record")
|
|
750
|
+
[ "$body" = "hello orca" ] || fail "Orca task inbox did not preserve the send body, got '$body'"
|
|
751
|
+
assert_not_contains "$(cat "$LOG")" $'--text\x1fhello orca\x1f' \
|
|
752
|
+
"send typed the payload instead of recording it"
|
|
753
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''send'$'\x1f''--terminal'$'\x1f''term-io'$'\x1f''--text'$'\x1f''Firstmate instruction waiting:' \
|
|
754
|
+
"send did not ring the inbox doorbell through the recorded Orca terminal"
|
|
755
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''send'$'\x1f''--terminal'$'\x1f''term-io'$'\x1f''--text'$'\x1f\x1f''--enter'$'\x1f''--json' \
|
|
756
|
+
"send did not submit the doorbell through the recorded Orca terminal"
|
|
757
|
+
pass "fm-peek/fm-send/fm-crew-state route through backend=orca metadata and its durable inbox"
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
test_peek_and_crew_state_fail_closed_on_orca_error_json() {
|
|
761
|
+
local wt state id out status neutral
|
|
762
|
+
id="orcareaderrz7"
|
|
763
|
+
wt="$TMP_ROOT/read-error-wt"
|
|
764
|
+
fm_git_init_commit "$wt"
|
|
765
|
+
state="$TMP_ROOT/read-error-state"; mkdir -p "$state"
|
|
766
|
+
fm_write_meta "$state/$id.meta" \
|
|
767
|
+
"window=fm-$id" "endpoint_task_id=$id" "terminal=term-stale" "worktree=$wt" "project=$wt" "harness=claude" "kind=scout" "backend=orca"
|
|
768
|
+
touch "$state/.last-watcher-beat"
|
|
769
|
+
orca_case read-error-json
|
|
770
|
+
neutral=$(neutral_fm_root "$CASE_DIR/neutral")
|
|
771
|
+
printf '{"ok":false,"error":{"code":"terminal_handle_stale","message":"terminal handle stale"}}\n' > "$RESP/1.out"
|
|
772
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
773
|
+
FM_ROOT_OVERRIDE="$neutral" FM_STATE_OVERRIDE="$state" "$ROOT/bin/fm-peek.sh" "fm-$id" 10 2>&1 )
|
|
774
|
+
status=$?
|
|
775
|
+
[ "$status" -ne 0 ] || fail "fm-peek should fail when Orca reports a stale terminal"
|
|
776
|
+
assert_contains "$out" "terminal handle stale" "fm-peek should surface the Orca read error message"
|
|
777
|
+
printf '{"ok":false,"error":{"code":"terminal_handle_stale","message":"terminal handle stale"}}\n' > "$RESP/2.out"
|
|
778
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
779
|
+
FM_ROOT_OVERRIDE="$ROOT" FM_STATE_OVERRIDE="$state" "$ROOT/bin/fm-crew-state.sh" "$id" )
|
|
780
|
+
assert_contains "$out" "state: unknown" "crew-state should not treat an Orca read error as a live endpoint"
|
|
781
|
+
assert_contains "$out" "backend target gone: term-stale" "crew-state should report the stale Orca terminal as gone"
|
|
782
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''read'$'\x1f''--terminal'$'\x1f''term-stale' \
|
|
783
|
+
"fm-peek/fm-crew-state did not read the recorded Orca terminal"
|
|
784
|
+
pass "fm-peek/fm-crew-state: Orca read error JSON fails closed"
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
test_target_exists_rejects_orca_error_json() {
|
|
788
|
+
local status
|
|
789
|
+
orca_case target-exists-error-json
|
|
790
|
+
printf '{"ok":false,"error":{"code":"terminal_handle_stale","message":"terminal handle stale"}}\n' > "$RESP/1.out"
|
|
791
|
+
set +e
|
|
792
|
+
PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
793
|
+
bash -c '. "$0/bin/fm-backend.sh"; fm_backend_target_exists orca term-stale fm-task' "$ROOT"
|
|
794
|
+
status=$?
|
|
795
|
+
set -e
|
|
796
|
+
[ "$status" -ne 0 ] || fail "fm_backend_target_exists should reject Orca ok:false read JSON"
|
|
797
|
+
pass "fm_backend_target_exists: Orca ok:false read JSON is not live"
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
test_scout_teardown_removes_orca_worktree_via_helper() {
|
|
801
|
+
local proj wt data state config id out rc neutral
|
|
802
|
+
id="orcateardownz3"
|
|
803
|
+
proj="$TMP_ROOT/teardown-project"
|
|
804
|
+
wt="$TMP_ROOT/teardown-wt"
|
|
805
|
+
data="$TMP_ROOT/teardown-data"
|
|
806
|
+
state="$TMP_ROOT/teardown-state"
|
|
807
|
+
config="$TMP_ROOT/teardown-config"
|
|
808
|
+
fm_git_worktree "$proj" "$wt" "fm/$id"
|
|
809
|
+
mkdir -p "$data/$id" "$state" "$config"
|
|
810
|
+
printf 'report\n' > "$data/$id/report.md"
|
|
811
|
+
touch "$state/.last-watcher-beat"
|
|
812
|
+
fm_write_meta "$state/$id.meta" \
|
|
813
|
+
"window=fm-$id" "endpoint_task_id=$id" "terminal=term-teardown" "worktree=$wt" "project=$proj" \
|
|
814
|
+
"harness=claude" "kind=scout" "mode=no-mistakes" "yolo=off" \
|
|
815
|
+
"backend=orca" "orca_worktree_id=wt-teardown" \
|
|
816
|
+
"decisions_reviewed=1" "decision_keys="
|
|
817
|
+
orca_case teardown
|
|
818
|
+
printf '{"ok":true,"result":{"worktree":{"id":"wt-teardown","path":"%s"}}}\n' "$wt" > "$RESP/1.out"
|
|
819
|
+
neutral=$(neutral_fm_root "$CASE_DIR/neutral")
|
|
820
|
+
set +e
|
|
821
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
822
|
+
FM_ROOT_OVERRIDE="$neutral" FM_STATE_OVERRIDE="$state" FM_DATA_OVERRIDE="$data" FM_CONFIG_OVERRIDE="$config" \
|
|
823
|
+
"$ROOT/bin/fm-teardown.sh" "$id" 2>&1 )
|
|
824
|
+
rc=$?
|
|
825
|
+
set -e
|
|
826
|
+
expect_code 0 "$rc" "Orca scout teardown should succeed once report exists"$'\n'"$out"
|
|
827
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''close'$'\x1f''--terminal'$'\x1f''term-teardown'$'\x1f''--json' \
|
|
828
|
+
"teardown did not close the recorded Orca terminal"
|
|
829
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''worktree'$'\x1f''rm'$'\x1f''--worktree'$'\x1f''id:wt-teardown'$'\x1f''--force'$'\x1f''--json' \
|
|
830
|
+
"teardown did not remove the Orca worktree through orca worktree rm"
|
|
831
|
+
assert_absent "$state/$id.meta" "teardown should remove task metadata"
|
|
832
|
+
pass "fm-teardown.sh backend=orca: scout report gate then helper-backed worktree removal"
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
test_scout_teardown_refuses_orca_id_path_mismatch() {
|
|
836
|
+
local proj wt other_wt data state config id out rc neutral
|
|
837
|
+
id="orcascoutmismatchz5"
|
|
838
|
+
proj="$TMP_ROOT/scout-mismatch-project"
|
|
839
|
+
wt="$TMP_ROOT/scout-mismatch-wt"
|
|
840
|
+
other_wt="$TMP_ROOT/scout-mismatch-other-wt"
|
|
841
|
+
data="$TMP_ROOT/scout-mismatch-data"
|
|
842
|
+
state="$TMP_ROOT/scout-mismatch-state"
|
|
843
|
+
config="$TMP_ROOT/scout-mismatch-config"
|
|
844
|
+
fm_git_worktree "$proj" "$wt" "fm/$id"
|
|
845
|
+
git -C "$proj" worktree add --quiet -b "fm/$id-other" "$other_wt"
|
|
846
|
+
mkdir -p "$data/$id" "$state" "$config"
|
|
847
|
+
printf 'report\n' > "$data/$id/report.md"
|
|
848
|
+
touch "$state/.last-watcher-beat"
|
|
849
|
+
fm_write_meta "$state/$id.meta" \
|
|
850
|
+
"window=fm-$id" "endpoint_task_id=$id" "terminal=term-scout-mismatch" "worktree=$wt" "project=$proj" \
|
|
851
|
+
"harness=claude" "kind=scout" "mode=no-mistakes" "yolo=off" \
|
|
852
|
+
"backend=orca" "orca_worktree_id=wt-scout-mismatch" \
|
|
853
|
+
"decisions_reviewed=1" "decision_keys="
|
|
854
|
+
orca_case scout-mismatch
|
|
855
|
+
printf '{"ok":true,"result":{"worktree":{"id":"wt-scout-mismatch","path":"%s"}}}\n' "$other_wt" > "$RESP/1.out"
|
|
856
|
+
neutral=$(neutral_fm_root "$CASE_DIR/neutral")
|
|
857
|
+
set +e
|
|
858
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
859
|
+
FM_ROOT_OVERRIDE="$neutral" FM_STATE_OVERRIDE="$state" FM_DATA_OVERRIDE="$data" FM_CONFIG_OVERRIDE="$config" \
|
|
860
|
+
"$ROOT/bin/fm-teardown.sh" "$id" 2>&1 )
|
|
861
|
+
rc=$?
|
|
862
|
+
set -e
|
|
863
|
+
[ "$rc" -ne 0 ] || fail "Orca scout teardown should refuse when id path differs from worktree="
|
|
864
|
+
assert_contains "$out" "not inspected worktree" \
|
|
865
|
+
"mismatched Orca scout worktree path refusal should name the mismatch"
|
|
866
|
+
assert_not_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''close' \
|
|
867
|
+
"refused mismatched Orca scout teardown should not close terminals"
|
|
868
|
+
assert_not_contains "$(cat "$LOG")" $'orca\x1f''worktree'$'\x1f''rm' \
|
|
869
|
+
"refused mismatched Orca scout teardown should not remove worktrees"
|
|
870
|
+
assert_present "$state/$id.meta" "refused mismatched scout teardown should preserve metadata"
|
|
871
|
+
pass "fm-teardown.sh backend=orca: scout teardown refuses id/path mismatches"
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
test_teardown_removes_orca_worktree_when_path_missing() {
|
|
875
|
+
local proj wt data state config id out rc neutral
|
|
876
|
+
id="orcamissingpathz7"
|
|
877
|
+
proj="$TMP_ROOT/missing-path-project"
|
|
878
|
+
wt="$TMP_ROOT/missing-path-wt"
|
|
879
|
+
data="$TMP_ROOT/missing-path-data"
|
|
880
|
+
state="$TMP_ROOT/missing-path-state"
|
|
881
|
+
config="$TMP_ROOT/missing-path-config"
|
|
882
|
+
mkdir -p "$data/$id" "$state" "$config"
|
|
883
|
+
printf 'report\n' > "$data/$id/report.md"
|
|
884
|
+
touch "$state/.last-watcher-beat"
|
|
885
|
+
fm_write_meta "$state/$id.meta" \
|
|
886
|
+
"window=fm-$id" "endpoint_task_id=$id" "terminal=term-missing-path" "worktree=$wt" "project=$proj" \
|
|
887
|
+
"harness=claude" "kind=scout" "mode=no-mistakes" "yolo=off" \
|
|
888
|
+
"backend=orca" "orca_worktree_id=wt-missing-path" \
|
|
889
|
+
"decisions_reviewed=1" "decision_keys="
|
|
890
|
+
orca_case missing-path
|
|
891
|
+
neutral=$(neutral_fm_root "$CASE_DIR/neutral")
|
|
892
|
+
set +e
|
|
893
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
894
|
+
FM_ROOT_OVERRIDE="$neutral" FM_STATE_OVERRIDE="$state" FM_DATA_OVERRIDE="$data" FM_CONFIG_OVERRIDE="$config" \
|
|
895
|
+
"$ROOT/bin/fm-teardown.sh" "$id" 2>&1 )
|
|
896
|
+
rc=$?
|
|
897
|
+
set -e
|
|
898
|
+
expect_code 0 "$rc" "Orca teardown should release helpers even when the path is absent"$'\n'"$out"
|
|
899
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''close'$'\x1f''--terminal'$'\x1f''term-missing-path'$'\x1f''--json' \
|
|
900
|
+
"teardown did not close the recorded Orca terminal when the path was absent"
|
|
901
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''worktree'$'\x1f''rm'$'\x1f''--worktree'$'\x1f''id:wt-missing-path'$'\x1f''--force'$'\x1f''--json' \
|
|
902
|
+
"teardown did not remove the recorded Orca worktree when the path was absent"
|
|
903
|
+
assert_absent "$state/$id.meta" "successful helper cleanup should remove task metadata"
|
|
904
|
+
pass "fm-teardown.sh backend=orca: releases terminal/worktree when path is absent"
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
test_teardown_preserves_metadata_when_orca_remove_error_json() {
|
|
908
|
+
local proj wt data state config id out rc neutral
|
|
909
|
+
id="orcaremoveerrz2"
|
|
910
|
+
proj="$TMP_ROOT/remove-error-project"
|
|
911
|
+
wt="$TMP_ROOT/remove-error-wt"
|
|
912
|
+
data="$TMP_ROOT/remove-error-data"
|
|
913
|
+
state="$TMP_ROOT/remove-error-state"
|
|
914
|
+
config="$TMP_ROOT/remove-error-config"
|
|
915
|
+
mkdir -p "$data/$id" "$state" "$config"
|
|
916
|
+
printf 'report\n' > "$data/$id/report.md"
|
|
917
|
+
touch "$state/.last-watcher-beat"
|
|
918
|
+
fm_write_meta "$state/$id.meta" \
|
|
919
|
+
"window=fm-$id" "endpoint_task_id=$id" "terminal=term-remove-error" "worktree=$wt" "project=$proj" \
|
|
920
|
+
"harness=claude" "kind=scout" "mode=no-mistakes" "yolo=off" \
|
|
921
|
+
"backend=orca" "orca_worktree_id=wt-remove-error" \
|
|
922
|
+
"decisions_reviewed=1" "decision_keys="
|
|
923
|
+
orca_case remove-error-teardown
|
|
924
|
+
printf '{"ok":true,"result":{}}\n' > "$RESP/1.out"
|
|
925
|
+
printf '{"ok":false,"error":{"code":"worktree_not_removed","message":"worktree not removed"}}\n' > "$RESP/2.out"
|
|
926
|
+
neutral=$(neutral_fm_root "$CASE_DIR/neutral")
|
|
927
|
+
set +e
|
|
928
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
929
|
+
FM_ROOT_OVERRIDE="$neutral" FM_STATE_OVERRIDE="$state" FM_DATA_OVERRIDE="$data" FM_CONFIG_OVERRIDE="$config" \
|
|
930
|
+
"$ROOT/bin/fm-teardown.sh" "$id" 2>&1 )
|
|
931
|
+
rc=$?
|
|
932
|
+
set -e
|
|
933
|
+
[ "$rc" -ne 0 ] || fail "Orca teardown should fail when worktree removal returns ok:false JSON"
|
|
934
|
+
assert_contains "$out" "worktree not removed" "teardown should surface the Orca removal error"
|
|
935
|
+
assert_present "$state/$id.meta" "failed Orca removal should preserve task metadata"
|
|
936
|
+
pass "fm-teardown.sh backend=orca: preserves metadata on remove ok:false JSON"
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
test_scout_teardown_refuses_orca_missing_report_when_path_missing() {
|
|
940
|
+
local proj wt data state config id out rc neutral
|
|
941
|
+
id="orcanoreportz4"
|
|
942
|
+
proj="$TMP_ROOT/missing-report-project"
|
|
943
|
+
wt="$TMP_ROOT/missing-report-wt"
|
|
944
|
+
data="$TMP_ROOT/missing-report-data"
|
|
945
|
+
state="$TMP_ROOT/missing-report-state"
|
|
946
|
+
config="$TMP_ROOT/missing-report-config"
|
|
947
|
+
mkdir -p "$data/$id" "$state" "$config"
|
|
948
|
+
touch "$state/.last-watcher-beat"
|
|
949
|
+
fm_write_meta "$state/$id.meta" \
|
|
950
|
+
"window=fm-$id" "endpoint_task_id=$id" "terminal=term-missing-report" "worktree=$wt" "project=$proj" \
|
|
951
|
+
"harness=claude" "kind=scout" "mode=no-mistakes" "yolo=off" \
|
|
952
|
+
"backend=orca" "orca_worktree_id=wt-missing-report"
|
|
953
|
+
orca_case missing-report
|
|
954
|
+
neutral=$(neutral_fm_root "$CASE_DIR/neutral")
|
|
955
|
+
set +e
|
|
956
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
957
|
+
FM_ROOT_OVERRIDE="$neutral" FM_STATE_OVERRIDE="$state" FM_DATA_OVERRIDE="$data" FM_CONFIG_OVERRIDE="$config" \
|
|
958
|
+
"$ROOT/bin/fm-teardown.sh" "$id" 2>&1 )
|
|
959
|
+
rc=$?
|
|
960
|
+
set -e
|
|
961
|
+
[ "$rc" -ne 0 ] || fail "Orca scout teardown should refuse without a report even when the path is absent"
|
|
962
|
+
assert_contains "$out" "has no report" "Orca scout teardown should explain the missing report"
|
|
963
|
+
[ ! -s "$LOG" ] || fail "refused Orca scout teardown should not close terminals or remove worktrees"
|
|
964
|
+
assert_present "$state/$id.meta" "refused Orca scout teardown should preserve metadata"
|
|
965
|
+
pass "fm-teardown.sh backend=orca: scout report gate precedes pathless helper cleanup"
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
test_ship_teardown_refuses_orca_missing_worktree_path() {
|
|
969
|
+
local proj wt data state config id out rc neutral
|
|
970
|
+
id="orcashipmissingz8"
|
|
971
|
+
proj="$TMP_ROOT/missing-ship-project"
|
|
972
|
+
wt="$TMP_ROOT/missing-ship-wt"
|
|
973
|
+
data="$TMP_ROOT/missing-ship-data"
|
|
974
|
+
state="$TMP_ROOT/missing-ship-state"
|
|
975
|
+
config="$TMP_ROOT/missing-ship-config"
|
|
976
|
+
fm_git_init_commit "$proj"
|
|
977
|
+
mkdir -p "$data/$id" "$state" "$config"
|
|
978
|
+
touch "$state/.last-watcher-beat"
|
|
979
|
+
fm_write_meta "$state/$id.meta" \
|
|
980
|
+
"window=fm-$id" "endpoint_task_id=$id" "terminal=term-missing-ship" "worktree=$wt" "project=$proj" \
|
|
981
|
+
"harness=claude" "kind=ship" "mode=no-mistakes" "yolo=off" \
|
|
982
|
+
"backend=orca" "orca_worktree_id=wt-missing-ship"
|
|
983
|
+
orca_case missing-ship-path
|
|
984
|
+
neutral=$(neutral_fm_root "$CASE_DIR/neutral")
|
|
985
|
+
set +e
|
|
986
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
987
|
+
FM_ROOT_OVERRIDE="$neutral" FM_STATE_OVERRIDE="$state" FM_DATA_OVERRIDE="$data" FM_CONFIG_OVERRIDE="$config" \
|
|
988
|
+
"$ROOT/bin/fm-teardown.sh" "$id" 2>&1 )
|
|
989
|
+
rc=$?
|
|
990
|
+
set -e
|
|
991
|
+
[ "$rc" -ne 0 ] || fail "Orca ship teardown should refuse a missing worktree path"
|
|
992
|
+
assert_contains "$out" "no inspectable git worktree" \
|
|
993
|
+
"Orca ship teardown should explain the fail-closed worktree requirement"
|
|
994
|
+
[ ! -s "$LOG" ] || fail "refused Orca ship teardown should not close terminals or remove worktrees"
|
|
995
|
+
assert_present "$state/$id.meta" "refused Orca ship teardown should preserve metadata"
|
|
996
|
+
pass "fm-teardown.sh backend=orca: ship teardown fails closed when worktree path is missing"
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
test_ship_teardown_removes_orca_worktree_when_id_path_matches() {
|
|
1000
|
+
local proj wt data state config id out rc neutral
|
|
1001
|
+
id="orcashipmatchz2"
|
|
1002
|
+
proj="$TMP_ROOT/ship-match-project"
|
|
1003
|
+
wt="$TMP_ROOT/ship-match-wt"
|
|
1004
|
+
data="$TMP_ROOT/ship-match-data"
|
|
1005
|
+
state="$TMP_ROOT/ship-match-state"
|
|
1006
|
+
config="$TMP_ROOT/ship-match-config"
|
|
1007
|
+
fm_git_worktree "$proj" "$wt" "fm/$id"
|
|
1008
|
+
mkdir -p "$data/$id" "$state" "$config"
|
|
1009
|
+
touch "$state/.last-watcher-beat"
|
|
1010
|
+
fm_write_meta "$state/$id.meta" \
|
|
1011
|
+
"window=fm-$id" "endpoint_task_id=$id" "terminal=term-ship-match" "worktree=$wt" "project=$proj" \
|
|
1012
|
+
"harness=claude" "kind=ship" "mode=local-only" "yolo=off" \
|
|
1013
|
+
"backend=orca" "orca_worktree_id=wt-ship-match"
|
|
1014
|
+
orca_case ship-match
|
|
1015
|
+
printf '{"ok":true,"result":{"worktree":{"id":"wt-ship-match","path":"%s"}}}\n' "$wt" > "$RESP/1.out"
|
|
1016
|
+
neutral=$(neutral_fm_root "$CASE_DIR/neutral")
|
|
1017
|
+
set +e
|
|
1018
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
1019
|
+
FM_ROOT_OVERRIDE="$neutral" FM_STATE_OVERRIDE="$state" FM_DATA_OVERRIDE="$data" FM_CONFIG_OVERRIDE="$config" \
|
|
1020
|
+
"$ROOT/bin/fm-teardown.sh" "$id" 2>&1 )
|
|
1021
|
+
rc=$?
|
|
1022
|
+
set -e
|
|
1023
|
+
expect_code 0 "$rc" "Orca ship teardown should succeed when the id path matches the inspected worktree"$'\n'"$out"
|
|
1024
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''worktree'$'\x1f''show'$'\x1f''--worktree'$'\x1f''id:wt-ship-match'$'\x1f''--json' \
|
|
1025
|
+
"teardown did not resolve the Orca worktree id before removal"
|
|
1026
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''close'$'\x1f''--terminal'$'\x1f''term-ship-match'$'\x1f''--json' \
|
|
1027
|
+
"teardown did not close the matched Orca terminal"
|
|
1028
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''worktree'$'\x1f''rm'$'\x1f''--worktree'$'\x1f''id:wt-ship-match'$'\x1f''--force'$'\x1f''--json' \
|
|
1029
|
+
"teardown did not remove the matched Orca worktree"
|
|
1030
|
+
assert_absent "$state/$id.meta" "successful matched teardown should remove task metadata"
|
|
1031
|
+
pass "fm-teardown.sh backend=orca: ship teardown requires a matching Orca id path"
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
test_ship_teardown_refuses_orca_unresolvable_worktree_id() {
|
|
1035
|
+
local proj wt data state config id out rc neutral
|
|
1036
|
+
id="orcashipunresolvedz1"
|
|
1037
|
+
proj="$TMP_ROOT/ship-unresolved-project"
|
|
1038
|
+
wt="$TMP_ROOT/ship-unresolved-wt"
|
|
1039
|
+
data="$TMP_ROOT/ship-unresolved-data"
|
|
1040
|
+
state="$TMP_ROOT/ship-unresolved-state"
|
|
1041
|
+
config="$TMP_ROOT/ship-unresolved-config"
|
|
1042
|
+
fm_git_worktree "$proj" "$wt" "fm/$id"
|
|
1043
|
+
mkdir -p "$data/$id" "$state" "$config"
|
|
1044
|
+
touch "$state/.last-watcher-beat"
|
|
1045
|
+
fm_write_meta "$state/$id.meta" \
|
|
1046
|
+
"window=fm-$id" "endpoint_task_id=$id" "terminal=term-ship-unresolved" "worktree=$wt" "project=$proj" \
|
|
1047
|
+
"harness=claude" "kind=ship" "mode=local-only" "yolo=off" \
|
|
1048
|
+
"backend=orca" "orca_worktree_id=wt-ship-unresolved"
|
|
1049
|
+
orca_case ship-unresolved
|
|
1050
|
+
printf '1\n' > "$RESP/1.exit"
|
|
1051
|
+
neutral=$(neutral_fm_root "$CASE_DIR/neutral")
|
|
1052
|
+
set +e
|
|
1053
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
1054
|
+
FM_ROOT_OVERRIDE="$neutral" FM_STATE_OVERRIDE="$state" FM_DATA_OVERRIDE="$data" FM_CONFIG_OVERRIDE="$config" \
|
|
1055
|
+
"$ROOT/bin/fm-teardown.sh" "$id" 2>&1 )
|
|
1056
|
+
rc=$?
|
|
1057
|
+
set -e
|
|
1058
|
+
[ "$rc" -ne 0 ] || fail "Orca ship teardown should refuse when the worktree id cannot be resolved"
|
|
1059
|
+
assert_contains "$out" "cannot resolve Orca worktree id wt-ship-unresolved" \
|
|
1060
|
+
"unresolvable Orca worktree id refusal should explain the fail-closed check"
|
|
1061
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''worktree'$'\x1f''show'$'\x1f''--worktree'$'\x1f''id:wt-ship-unresolved'$'\x1f''--json' \
|
|
1062
|
+
"teardown did not attempt to resolve the Orca worktree id"
|
|
1063
|
+
assert_not_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''close' \
|
|
1064
|
+
"refused unresolved Orca ship teardown should not close terminals"
|
|
1065
|
+
assert_not_contains "$(cat "$LOG")" $'orca\x1f''worktree'$'\x1f''rm' \
|
|
1066
|
+
"refused unresolved Orca ship teardown should not remove worktrees"
|
|
1067
|
+
assert_present "$state/$id.meta" "refused unresolved Orca ship teardown should preserve metadata"
|
|
1068
|
+
pass "fm-teardown.sh backend=orca: ship teardown fails closed when id resolution fails"
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
test_ship_teardown_refuses_orca_id_path_mismatch() {
|
|
1072
|
+
local proj wt other_wt data state config id out rc neutral
|
|
1073
|
+
id="orcashipmismatchz9"
|
|
1074
|
+
proj="$TMP_ROOT/ship-mismatch-project"
|
|
1075
|
+
wt="$TMP_ROOT/ship-mismatch-wt"
|
|
1076
|
+
other_wt="$TMP_ROOT/ship-mismatch-other-wt"
|
|
1077
|
+
data="$TMP_ROOT/ship-mismatch-data"
|
|
1078
|
+
state="$TMP_ROOT/ship-mismatch-state"
|
|
1079
|
+
config="$TMP_ROOT/ship-mismatch-config"
|
|
1080
|
+
fm_git_worktree "$proj" "$wt" "fm/$id"
|
|
1081
|
+
git -C "$proj" worktree add --quiet -b "fm/$id-other" "$other_wt"
|
|
1082
|
+
mkdir -p "$data/$id" "$state" "$config"
|
|
1083
|
+
touch "$state/.last-watcher-beat"
|
|
1084
|
+
fm_write_meta "$state/$id.meta" \
|
|
1085
|
+
"window=fm-$id" "endpoint_task_id=$id" "terminal=term-ship-mismatch" "worktree=$wt" "project=$proj" \
|
|
1086
|
+
"harness=claude" "kind=ship" "mode=local-only" "yolo=off" \
|
|
1087
|
+
"backend=orca" "orca_worktree_id=wt-ship-mismatch"
|
|
1088
|
+
orca_case ship-mismatch
|
|
1089
|
+
printf '{"ok":true,"result":{"worktree":{"id":"wt-ship-mismatch","path":"%s"}}}\n' "$other_wt" > "$RESP/1.out"
|
|
1090
|
+
neutral=$(neutral_fm_root "$CASE_DIR/neutral")
|
|
1091
|
+
set +e
|
|
1092
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
1093
|
+
FM_ROOT_OVERRIDE="$neutral" FM_STATE_OVERRIDE="$state" FM_DATA_OVERRIDE="$data" FM_CONFIG_OVERRIDE="$config" \
|
|
1094
|
+
"$ROOT/bin/fm-teardown.sh" "$id" 2>&1 )
|
|
1095
|
+
rc=$?
|
|
1096
|
+
set -e
|
|
1097
|
+
[ "$rc" -ne 0 ] || fail "Orca ship teardown should refuse when the id path differs from worktree="
|
|
1098
|
+
assert_contains "$out" "not inspected worktree" \
|
|
1099
|
+
"mismatched Orca worktree path refusal should name the mismatch"
|
|
1100
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''worktree'$'\x1f''show'$'\x1f''--worktree'$'\x1f''id:wt-ship-mismatch'$'\x1f''--json' \
|
|
1101
|
+
"teardown did not resolve the mismatched Orca worktree id"
|
|
1102
|
+
assert_not_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''close' \
|
|
1103
|
+
"refused mismatched Orca ship teardown should not close terminals"
|
|
1104
|
+
assert_not_contains "$(cat "$LOG")" $'orca\x1f''worktree'$'\x1f''rm' \
|
|
1105
|
+
"refused mismatched Orca ship teardown should not remove worktrees"
|
|
1106
|
+
assert_present "$state/$id.meta" "refused mismatched Orca ship teardown should preserve metadata"
|
|
1107
|
+
pass "fm-teardown.sh backend=orca: ship teardown refuses id/path mismatches"
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
test_teardown_refuses_orca_missing_worktree_id() {
|
|
1111
|
+
local proj wt data state config id out rc neutral
|
|
1112
|
+
id="orcamissingidz5"
|
|
1113
|
+
proj="$TMP_ROOT/missing-id-project"
|
|
1114
|
+
wt="$TMP_ROOT/missing-id-wt"
|
|
1115
|
+
data="$TMP_ROOT/missing-id-data"
|
|
1116
|
+
state="$TMP_ROOT/missing-id-state"
|
|
1117
|
+
config="$TMP_ROOT/missing-id-config"
|
|
1118
|
+
fm_git_worktree "$proj" "$wt" "fm/$id"
|
|
1119
|
+
mkdir -p "$data/$id" "$state" "$config"
|
|
1120
|
+
printf 'report\n' > "$data/$id/report.md"
|
|
1121
|
+
touch "$state/.last-watcher-beat"
|
|
1122
|
+
fm_write_meta "$state/$id.meta" \
|
|
1123
|
+
"window=fm-$id" "endpoint_task_id=$id" "terminal=term-missing-id" "worktree=$wt" "project=$proj" \
|
|
1124
|
+
"harness=claude" "kind=scout" "mode=no-mistakes" "yolo=off" "backend=orca" \
|
|
1125
|
+
"decisions_reviewed=1" "decision_keys="
|
|
1126
|
+
orca_case missing-id
|
|
1127
|
+
neutral=$(neutral_fm_root "$CASE_DIR/neutral")
|
|
1128
|
+
set +e
|
|
1129
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
1130
|
+
FM_ROOT_OVERRIDE="$neutral" FM_STATE_OVERRIDE="$state" FM_DATA_OVERRIDE="$data" FM_CONFIG_OVERRIDE="$config" \
|
|
1131
|
+
"$ROOT/bin/fm-teardown.sh" "$id" 2>&1 )
|
|
1132
|
+
rc=$?
|
|
1133
|
+
set -e
|
|
1134
|
+
[ "$rc" -ne 0 ] || fail "Orca teardown should refuse missing orca_worktree_id"
|
|
1135
|
+
assert_contains "$out" "missing orca_worktree_id" "teardown did not explain the missing Orca worktree id"
|
|
1136
|
+
assert_present "$state/$id.meta" "failed teardown must preserve task metadata"
|
|
1137
|
+
[ ! -s "$LOG" ] || fail "teardown should fail before closing terminals or removing worktrees without an Orca worktree id"
|
|
1138
|
+
pass "fm-teardown.sh backend=orca: refuses missing worktree ids before cleanup"
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
test_teardown_refuses_orca_worktree_without_terminal_handle() {
|
|
1142
|
+
local proj wt data state config id out rc neutral
|
|
1143
|
+
id="orcanotermz0"
|
|
1144
|
+
proj="$TMP_ROOT/no-terminal-project"
|
|
1145
|
+
wt="$TMP_ROOT/no-terminal-wt"
|
|
1146
|
+
data="$TMP_ROOT/no-terminal-data"
|
|
1147
|
+
state="$TMP_ROOT/no-terminal-state"
|
|
1148
|
+
config="$TMP_ROOT/no-terminal-config"
|
|
1149
|
+
fm_git_worktree "$proj" "$wt" "fm/$id"
|
|
1150
|
+
mkdir -p "$data/$id" "$state" "$config"
|
|
1151
|
+
printf 'report\n' > "$data/$id/report.md"
|
|
1152
|
+
touch "$state/.last-watcher-beat"
|
|
1153
|
+
fm_write_meta "$state/$id.meta" \
|
|
1154
|
+
"window=fm-$id" "endpoint_task_id=$id" "worktree=$wt" "project=$proj" \
|
|
1155
|
+
"harness=claude" "kind=scout" "mode=no-mistakes" "yolo=off" \
|
|
1156
|
+
"backend=orca" "orca_worktree_id=wt-no-terminal" \
|
|
1157
|
+
"decisions_reviewed=1" "decision_keys="
|
|
1158
|
+
orca_case no-terminal
|
|
1159
|
+
neutral=$(neutral_fm_root "$CASE_DIR/neutral")
|
|
1160
|
+
set +e
|
|
1161
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
1162
|
+
FM_ROOT_OVERRIDE="$neutral" FM_STATE_OVERRIDE="$state" FM_DATA_OVERRIDE="$data" FM_CONFIG_OVERRIDE="$config" \
|
|
1163
|
+
"$ROOT/bin/fm-teardown.sh" "$id" 2>&1 )
|
|
1164
|
+
rc=$?
|
|
1165
|
+
set -e
|
|
1166
|
+
[ "$rc" -ne 0 ] || fail "Orca teardown accepted metadata without a terminal handle"
|
|
1167
|
+
assert_contains "$out" "missing terminal" "teardown did not explain the incomplete Orca endpoint"
|
|
1168
|
+
[ ! -s "$LOG" ] || fail "teardown dispatched to Orca before rejecting the incomplete endpoint"
|
|
1169
|
+
assert_present "$state/$id.meta" "missing-terminal refusal removed task metadata"
|
|
1170
|
+
pass "fm-teardown.sh backend=orca: refuses incomplete worktree-only endpoint metadata before runtime dispatch"
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
test_secondmate_force_teardown_removes_orca_child_via_orca() {
|
|
1174
|
+
local home subhome childproj childwt child_id neutral out rc
|
|
1175
|
+
home="$TMP_ROOT/orca-child-parent"
|
|
1176
|
+
subhome="$TMP_ROOT/orca-child-secondmate"
|
|
1177
|
+
childproj="$subhome/projects/alpha"
|
|
1178
|
+
childwt="$TMP_ROOT/orca-child-worktree"
|
|
1179
|
+
child_id="orcachildz6"
|
|
1180
|
+
mkdir -p "$home/state" "$home/data" "$subhome/state" "$subhome/projects"
|
|
1181
|
+
printf 'domain\n' > "$subhome/.fm-secondmate-home"
|
|
1182
|
+
fm_git_worktree "$childproj" "$childwt" "fm/$child_id"
|
|
1183
|
+
fm_write_meta "$home/state/domain.meta" \
|
|
1184
|
+
"window=firstmate:fm-domain" "worktree=$subhome" "project=$subhome" \
|
|
1185
|
+
"harness=echo" "kind=secondmate" "mode=secondmate" "yolo=off" \
|
|
1186
|
+
"home=$subhome" "projects=alpha"
|
|
1187
|
+
printf '%s\n' "- domain - Orca child cleanup (home: $subhome; scope: orca cleanup; projects: alpha; added 2026-07-03)" \
|
|
1188
|
+
> "$home/data/secondmates.md"
|
|
1189
|
+
fm_write_meta "$subhome/state/$child_id.meta" \
|
|
1190
|
+
"window=fm-$child_id" "endpoint_task_id=$child_id" \
|
|
1191
|
+
"terminal=term-child-cleanup" "worktree=$childwt" "project=$childproj" \
|
|
1192
|
+
"harness=claude" "kind=ship" "mode=no-mistakes" "yolo=off" \
|
|
1193
|
+
"backend=orca" "orca_worktree_id=wt-child-cleanup"
|
|
1194
|
+
orca_case secondmate-child-cleanup
|
|
1195
|
+
printf '{"ok":true,"result":{"worktree":{"id":"wt-child-cleanup","path":"%s"}}}\n' "$childwt" > "$RESP/1.out"
|
|
1196
|
+
printf '{"ok":true,"result":{"worktree":{"id":"wt-child-cleanup","path":"%s"}}}\n' "$childwt" > "$RESP/2.out"
|
|
1197
|
+
printf '{"ok":true,"result":{}}\n' > "$RESP/3.out"
|
|
1198
|
+
printf '{"ok":true,"result":{}}\n' > "$RESP/4.out"
|
|
1199
|
+
add_tmux_fake "$FB"
|
|
1200
|
+
neutral=$(neutral_fm_root "$CASE_DIR/neutral")
|
|
1201
|
+
set +e
|
|
1202
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
1203
|
+
FM_ROOT_OVERRIDE="$neutral" FM_HOME="$home" "$ROOT/bin/fm-teardown.sh" domain --force 2>&1 )
|
|
1204
|
+
rc=$?
|
|
1205
|
+
set -e
|
|
1206
|
+
expect_code 0 "$rc" "forced secondmate teardown should remove Orca child work through Orca"$'\n'"$out"
|
|
1207
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''close'$'\x1f''--terminal'$'\x1f''term-child-cleanup'$'\x1f''--json' \
|
|
1208
|
+
"child cleanup did not close the recorded Orca terminal"
|
|
1209
|
+
assert_contains "$(cat "$LOG")" $'orca\x1f''worktree'$'\x1f''rm'$'\x1f''--worktree'$'\x1f''id:wt-child-cleanup'$'\x1f''--force'$'\x1f''--json' \
|
|
1210
|
+
"child cleanup did not remove the Orca worktree through orca worktree rm"
|
|
1211
|
+
assert_not_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''close'$'\x1f''--terminal'$'\x1f'"fm-$child_id" \
|
|
1212
|
+
"child cleanup closed the stable alias instead of the Orca terminal"
|
|
1213
|
+
assert_absent "$home/state/domain.meta" "parent metadata should be removed after forced teardown"
|
|
1214
|
+
pass "fm-teardown.sh --force: removes Orca secondmate children through Orca"
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
test_secondmate_force_teardown_refuses_orca_child_id_path_mismatch() {
|
|
1218
|
+
local home subhome childproj childwt other_wt child_id neutral out rc
|
|
1219
|
+
home="$TMP_ROOT/orca-child-mismatch-parent"
|
|
1220
|
+
subhome="$TMP_ROOT/orca-child-mismatch-secondmate"
|
|
1221
|
+
childproj="$subhome/projects/alpha"
|
|
1222
|
+
childwt="$TMP_ROOT/orca-child-mismatch-worktree"
|
|
1223
|
+
other_wt="$TMP_ROOT/orca-child-mismatch-other-worktree"
|
|
1224
|
+
child_id="orcachildmismatchz1"
|
|
1225
|
+
mkdir -p "$home/state" "$home/data" "$subhome/state" "$subhome/projects"
|
|
1226
|
+
printf 'domain\n' > "$subhome/.fm-secondmate-home"
|
|
1227
|
+
fm_git_worktree "$childproj" "$childwt" "fm/$child_id"
|
|
1228
|
+
git -C "$childproj" worktree add --quiet -b "fm/$child_id-other" "$other_wt"
|
|
1229
|
+
fm_write_meta "$home/state/domain.meta" \
|
|
1230
|
+
"window=firstmate:fm-domain" "worktree=$subhome" "project=$subhome" \
|
|
1231
|
+
"harness=echo" "kind=secondmate" "mode=secondmate" "yolo=off" \
|
|
1232
|
+
"home=$subhome" "projects=alpha"
|
|
1233
|
+
printf '%s\n' "- domain - Orca child cleanup (home: $subhome; scope: orca cleanup; projects: alpha; added 2026-07-03)" \
|
|
1234
|
+
> "$home/data/secondmates.md"
|
|
1235
|
+
fm_write_meta "$subhome/state/$child_id.meta" \
|
|
1236
|
+
"window=fm-$child_id" "endpoint_task_id=$child_id" \
|
|
1237
|
+
"terminal=term-child-mismatch" "worktree=$childwt" "project=$childproj" \
|
|
1238
|
+
"harness=claude" "kind=ship" "mode=no-mistakes" "yolo=off" \
|
|
1239
|
+
"backend=orca" "orca_worktree_id=wt-child-mismatch"
|
|
1240
|
+
orca_case secondmate-child-mismatch
|
|
1241
|
+
printf '{"ok":true,"result":{"worktree":{"id":"wt-child-mismatch","path":"%s"}}}\n' "$other_wt" > "$RESP/1.out"
|
|
1242
|
+
add_tmux_fake "$FB"
|
|
1243
|
+
neutral=$(neutral_fm_root "$CASE_DIR/neutral")
|
|
1244
|
+
set +e
|
|
1245
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
1246
|
+
FM_ROOT_OVERRIDE="$neutral" FM_HOME="$home" "$ROOT/bin/fm-teardown.sh" domain --force 2>&1 )
|
|
1247
|
+
rc=$?
|
|
1248
|
+
set -e
|
|
1249
|
+
[ "$rc" -ne 0 ] || fail "forced secondmate teardown should refuse mismatched Orca child id/path"
|
|
1250
|
+
assert_contains "$out" "not inspected worktree" \
|
|
1251
|
+
"mismatched Orca child worktree path refusal should name the mismatch"
|
|
1252
|
+
assert_not_contains "$(cat "$LOG")" $'orca\x1f''terminal'$'\x1f''close' \
|
|
1253
|
+
"refused mismatched Orca child cleanup should not close terminals"
|
|
1254
|
+
assert_not_contains "$(cat "$LOG")" $'orca\x1f''worktree'$'\x1f''rm' \
|
|
1255
|
+
"refused mismatched Orca child cleanup should not remove worktrees"
|
|
1256
|
+
assert_present "$home/state/domain.meta" "refused forced secondmate teardown should preserve parent metadata"
|
|
1257
|
+
pass "fm-teardown.sh --force: refuses Orca child id/path mismatches"
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
test_secondmate_force_teardown_refuses_partial_orca_child() {
|
|
1261
|
+
local home subhome childproj childwt child_id neutral out rc
|
|
1262
|
+
home="$TMP_ROOT/orca-partial-child-parent"
|
|
1263
|
+
subhome="$TMP_ROOT/orca-partial-child-secondmate"
|
|
1264
|
+
childproj="$subhome/projects/alpha"
|
|
1265
|
+
childwt="$TMP_ROOT/orca-partial-child-worktree"
|
|
1266
|
+
child_id="orcapartialz9"
|
|
1267
|
+
mkdir -p "$home/state" "$home/data" "$subhome/state" "$subhome/projects"
|
|
1268
|
+
printf 'domain\n' > "$subhome/.fm-secondmate-home"
|
|
1269
|
+
fm_git_worktree "$childproj" "$childwt" "fm/$child_id"
|
|
1270
|
+
fm_write_meta "$home/state/domain.meta" \
|
|
1271
|
+
"window=firstmate:fm-domain" "worktree=$subhome" "project=$subhome" \
|
|
1272
|
+
"harness=echo" "kind=secondmate" "mode=secondmate" "yolo=off" \
|
|
1273
|
+
"home=$subhome" "projects=alpha"
|
|
1274
|
+
printf '%s\n' "- domain - Orca partial child cleanup (home: $subhome; scope: orca cleanup; projects: alpha; added 2026-07-03)" \
|
|
1275
|
+
> "$home/data/secondmates.md"
|
|
1276
|
+
fm_write_meta "$subhome/state/$child_id.meta" \
|
|
1277
|
+
"window=fm-$child_id" "endpoint_task_id=$child_id" \
|
|
1278
|
+
"worktree=$childwt" "project=$childproj" \
|
|
1279
|
+
"harness=claude" "kind=ship" "mode=no-mistakes" "yolo=off" \
|
|
1280
|
+
"backend=orca" "orca_worktree_id=wt-partial-child"
|
|
1281
|
+
orca_case secondmate-partial-child-cleanup
|
|
1282
|
+
add_tmux_fake "$FB"
|
|
1283
|
+
neutral=$(neutral_fm_root "$CASE_DIR/neutral")
|
|
1284
|
+
set +e
|
|
1285
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
1286
|
+
FM_ROOT_OVERRIDE="$neutral" FM_HOME="$home" "$ROOT/bin/fm-teardown.sh" domain --force 2>&1 )
|
|
1287
|
+
rc=$?
|
|
1288
|
+
set -e
|
|
1289
|
+
[ "$rc" -ne 0 ] || fail "forced secondmate teardown accepted a child with no terminal identity"
|
|
1290
|
+
assert_contains "$out" "missing terminal" "partial child refusal did not explain the incomplete endpoint"
|
|
1291
|
+
[ ! -s "$LOG" ] || fail "partial child refusal dispatched to Orca or tmux"
|
|
1292
|
+
assert_present "$home/state/domain.meta" "partial child refusal removed parent metadata"
|
|
1293
|
+
assert_present "$subhome/state/$child_id.meta" "partial child refusal removed child metadata"
|
|
1294
|
+
pass "fm-teardown.sh --force: refuses partial Orca secondmate children before runtime dispatch"
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
test_dispatcher_sources_orca_and_routes_primitives() {
|
|
1298
|
+
local out
|
|
1299
|
+
orca_case dispatch
|
|
1300
|
+
printf '{"result":{"terminal":{"tail":["via dispatch"]}}}\n' > "$RESP/1.out"
|
|
1301
|
+
out=$( PATH="$FB:$PATH" FM_ORCA_LOG="$LOG" FM_ORCA_RESPONSES="$RESP" \
|
|
1302
|
+
bash -c '. "$0/bin/fm-backend.sh"; fm_backend_validate orca; fm_backend_capture orca term-123 9' "$ROOT" )
|
|
1303
|
+
[ "$out" = "via dispatch" ] || fail "dispatcher should route capture to the Orca adapter, got '$out'"
|
|
1304
|
+
pass "fm-backend dispatcher: accepts orca and routes capture through bin/backends/orca.sh"
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
test_capture_reads_terminal_tail_json
|
|
1308
|
+
test_capture_falls_back_to_text_fields
|
|
1309
|
+
test_capture_fails_on_orca_error_json
|
|
1310
|
+
test_runtime_check_accepts_ready_orca_status
|
|
1311
|
+
test_runtime_check_refuses_unready_orca_status
|
|
1312
|
+
test_send_text_submit_verifies_empty_composer_after_enter
|
|
1313
|
+
test_send_text_submit_borderless_claude_confirms
|
|
1314
|
+
test_composer_state_stale_banner_never_wins
|
|
1315
|
+
test_send_text_submit_retries_when_composer_stays_pending
|
|
1316
|
+
test_composer_state_popup_placeholder_fill_is_pending
|
|
1317
|
+
test_composer_state_bare_shell_prompt_is_unknown
|
|
1318
|
+
test_send_text_submit_popup_autocomplete_requires_second_enter
|
|
1319
|
+
test_send_literal_constructs_non_enter_send
|
|
1320
|
+
test_send_text_submit_reports_send_failed
|
|
1321
|
+
test_send_helpers_reject_orca_error_json
|
|
1322
|
+
test_send_key_enter_and_interrupt
|
|
1323
|
+
test_send_key_refuses_unknown_key
|
|
1324
|
+
test_send_key_refuses_escape_until_supported
|
|
1325
|
+
test_kill_is_best_effort_close
|
|
1326
|
+
test_remove_worktree_refuses_empty_id
|
|
1327
|
+
test_remove_worktree_rejects_orca_error_json
|
|
1328
|
+
test_worktree_path_resolves_id
|
|
1329
|
+
test_dispatcher_sources_orca_and_routes_primitives
|
|
1330
|
+
test_json_get_ignores_undocumented_terminal_id_shapes
|
|
1331
|
+
test_worktree_and_terminal_helpers_parse_json
|
|
1332
|
+
test_worktree_create_removes_worktree_when_path_missing
|
|
1333
|
+
test_spawn_preserves_orca_metadata_when_pathless_worktree_cleanup_fails
|
|
1334
|
+
test_spawn_writes_orca_metadata_and_launches_harness
|
|
1335
|
+
test_spawn_refuses_orca_secondmate_before_home_mutation
|
|
1336
|
+
test_spawn_refuses_orca_when_runtime_not_ready
|
|
1337
|
+
test_spawn_refuses_orca_nonisolated_worktree
|
|
1338
|
+
test_spawn_removes_orca_worktree_when_terminal_create_fails
|
|
1339
|
+
test_spawn_preserves_orca_metadata_when_abort_cleanup_fails
|
|
1340
|
+
test_spawn_releases_orca_resources_when_metadata_write_fails
|
|
1341
|
+
test_peek_send_and_crew_state_route_through_orca_meta
|
|
1342
|
+
test_peek_and_crew_state_fail_closed_on_orca_error_json
|
|
1343
|
+
test_target_exists_rejects_orca_error_json
|
|
1344
|
+
test_scout_teardown_removes_orca_worktree_via_helper
|
|
1345
|
+
test_scout_teardown_refuses_orca_id_path_mismatch
|
|
1346
|
+
test_teardown_removes_orca_worktree_when_path_missing
|
|
1347
|
+
test_teardown_preserves_metadata_when_orca_remove_error_json
|
|
1348
|
+
test_scout_teardown_refuses_orca_missing_report_when_path_missing
|
|
1349
|
+
test_ship_teardown_refuses_orca_missing_worktree_path
|
|
1350
|
+
test_ship_teardown_removes_orca_worktree_when_id_path_matches
|
|
1351
|
+
test_ship_teardown_refuses_orca_unresolvable_worktree_id
|
|
1352
|
+
test_ship_teardown_refuses_orca_id_path_mismatch
|
|
1353
|
+
test_teardown_refuses_orca_missing_worktree_id
|
|
1354
|
+
test_teardown_refuses_orca_worktree_without_terminal_handle
|
|
1355
|
+
test_secondmate_force_teardown_removes_orca_child_via_orca
|
|
1356
|
+
test_secondmate_force_teardown_refuses_orca_child_id_path_mismatch
|
|
1357
|
+
test_secondmate_force_teardown_refuses_partial_orca_child
|