@zerwiz/ymir 0.1.4 → 0.1.7
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/README.md +74 -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 +360 -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.example +72 -0
- package/.agents/config/crew-dispatch.json +22 -0
- package/.agents/config/cron.yaml +11 -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/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/runes_audit.md +5 -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 +121 -0
- package/.agents/migrations/0004-hoard-and-realms.sh +104 -0
- package/.agents/migrations/0005-roots-out-of-tree.sh +158 -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 +159 -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 +736 -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 +539 -0
- package/.agents/skills/galdr-ymirsystem/assets/installation.md +763 -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 +163 -0
- package/.agents/skills/galdr-ymirsystem/assets/nornir-jobs.md +415 -0
- package/.agents/skills/galdr-ymirsystem/assets/norse-naming.md +325 -0
- package/.agents/skills/galdr-ymirsystem/assets/odrerir-hall.md +133 -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 +101 -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 +180 -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 +503 -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 +90 -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 +57 -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 +35 -0
- package/.agents/skills/ymir-host/assets/desktop.md +36 -0
- package/.agents/skills/ymir-host/assets/install.md +69 -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 +498 -0
- package/CHANGELOG.md +1913 -0
- package/LICENSE +1 -1
- package/NOTICE +63 -0
- package/README.md +114 -60
- 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 +97 -0
- package/RULES/05-platforms.md +67 -0
- package/RULES/06-append-only.md +108 -0
- package/RULES/07-config.md +101 -0
- package/RULES/08-delivery-gate.md +75 -0
- package/RULES/09-electron.md +58 -0
- package/RULES/README.md +22 -0
- package/bin/README.md +107 -0
- package/bin/a2a-mcp.sh +133 -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 +256 -0
- package/bin/apodex-smoke-test.sh +105 -0
- package/bin/bifrost-bridge.sh +131 -0
- package/bin/bifrost-ingress.sh +77 -0
- package/bin/bootstrap-macos.sh +112 -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 +51 -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-assemble.sh +154 -0
- package/bin/changelog-guard.sh +197 -0
- package/bin/crash-sense.sh +173 -0
- package/bin/design-check.sh +80 -0
- package/bin/design-icon.sh +153 -0
- package/bin/desktop-place.sh +224 -0
- package/bin/docs-guard.sh +39 -0
- package/bin/editor-place.sh +225 -0
- package/bin/eindri-acclaim.sh +47 -0
- package/bin/eindri-control.sh +28 -0
- package/bin/eindri-role.sh +83 -0
- package/bin/eindri-seat.sh +83 -0
- package/bin/eindri-seen.sh +54 -0
- package/bin/eindri-send.sh +15 -0
- package/bin/eindri-start.sh +98 -0
- package/bin/eindri-watch.sh +57 -0
- package/bin/einherjar-spawn.sh +576 -0
- package/bin/eir-doctor.sh +158 -0
- package/bin/erindi-brief.sh +271 -0
- package/bin/feature-inventory.sh +73 -0
- package/bin/fleet-apply.sh +81 -0
- package/bin/github-deploy.sh +94 -0
- package/bin/gjallarhorn-expose.sh +136 -0
- package/bin/gjallarhorn-notify.sh +71 -0
- package/bin/gjallarhorn-purge.sh +67 -0
- package/bin/gjallarhorn-tunnel.sh +85 -0
- package/bin/gleipnir-lock-lib.sh +284 -0
- package/bin/groa-update.sh +130 -0
- package/bin/hall-snapshot.sh +111 -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 +452 -0
- package/bin/hermes-ensure.sh +88 -0
- package/bin/hlidskjalf-agents.sh +172 -0
- package/bin/hlidskjalf-usage.sh +196 -0
- package/bin/hoard-guard.sh +135 -0
- package/bin/hoard-lib.sh +105 -0
- package/bin/hodd.sh +102 -0
- package/bin/host-sense.sh +199 -0
- package/bin/huginn-research-worker.sh +121 -0
- package/bin/local-model-lock.sh +70 -0
- package/bin/mimir-bridge.py +259 -0
- package/bin/mimir-bridge.sh +100 -0
- package/bin/mimir-ingest.sh +131 -0
- package/bin/mimir-reflect.sh +27 -0
- package/bin/mimir.sh +113 -0
- package/bin/mjollnir-webhook.sh +72 -0
- package/bin/mjollnir.sh +104 -0
- package/bin/model-hardware.sh +96 -0
- package/bin/model-resolve.sh +160 -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-hall-snapshot.sh +28 -0
- package/bin/nornir-job-memory-housekeeping.sh +114 -0
- package/bin/nornir-job-nsr-compliance.sh +54 -0
- package/bin/nornir-job-observer.sh +166 -0
- package/bin/nornir-job-skillopt-sleep.sh +76 -0
- package/bin/npm-publish.sh +136 -0
- package/bin/omarchy-hook-install.sh +60 -0
- package/bin/omarchy-install.sh +161 -0
- package/bin/omarchy-plugins.sh +187 -0
- package/bin/omarchy-sense.sh +162 -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-model-agnostic.sh +71 -0
- package/bin/pi-seat.sh +63 -0
- package/bin/prereq-ensure.sh +166 -0
- package/bin/private-guard.sh +58 -0
- package/bin/project-git.sh +69 -0
- package/bin/public-guard.sh +71 -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 +104 -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 +94 -0
- package/bin/smidja-observe.sh +86 -0
- package/bin/syn-arm-pretool-check.sh +57 -0
- package/bin/syn-asset-pretool-check.sh +89 -0
- package/bin/syn-cd-pretool-check.sh +28 -0
- package/bin/syn-guard-pretool-check.sh +83 -0
- package/bin/syn-spawn-pretool-check.sh +58 -0
- package/bin/syn-turnend-guard.sh +36 -0
- package/bin/syn-watch-arm.sh +99 -0
- package/bin/tailscale-sync.sh +203 -0
- package/bin/telegram-bot.sh +82 -0
- package/bin/toolchain.sh +74 -0
- package/bin/ui-truth-check.sh +75 -0
- package/bin/utgard.sh +111 -0
- package/bin/valhalla.sh +115 -0
- package/bin/valknut-load.sh +298 -0
- package/bin/vor-crew-state.sh +124 -0
- package/bin/wedge-notify.sh +60 -0
- package/bin/workspace-provision.sh +80 -0
- package/bin/workspace-rag.sh +163 -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 +806 -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-plan.sh +356 -0
- package/bin/ymir-platform.sh +348 -0
- package/bin/ymir-say.sh +110 -0
- package/bin/ymir-setup-auth.sh +119 -0
- package/bin/ymir-validate.sh +193 -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 +1060 -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 +54 -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 +269 -0
- package/scripts/lower.sh +34 -0
- package/scripts/raise.sh +42 -0
- package/scripts/start.sh +217 -0
- package/scripts/stop.sh +113 -0
- package/install.sh +0 -35
|
@@ -0,0 +1,932 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Behavior tests for the muse (Muse Code) crewmate adapter: harness detection,
|
|
3
|
+
# spawn launch shape and credential preflight, the secondmate refusal, the
|
|
4
|
+
# session-log busy source, and teardown cleanup of the busy binding.
|
|
5
|
+
#
|
|
6
|
+
# The session-log fixtures below reproduce muse 0.1.0-R708.1's real record
|
|
7
|
+
# shapes, including the nested "record":{"kind":"terminal"} cleanup payload that
|
|
8
|
+
# is NOT a run terminal. That decoy is the whole reason the fold matches an
|
|
9
|
+
# anchored structural prefix instead of searching for "kind":"terminal", so a
|
|
10
|
+
# fixture without it would let a naive implementation pass.
|
|
11
|
+
set -u
|
|
12
|
+
|
|
13
|
+
# shellcheck source=tests/lib.sh
|
|
14
|
+
. "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
|
|
15
|
+
|
|
16
|
+
# bin/fm-harness.sh checks verified ENV markers before ancestry. Muse is
|
|
17
|
+
# markerless, so an inherited Cursor/Claude/Pi/Grok marker would outrank the
|
|
18
|
+
# versioned muse-bin ancestor these detection cases launch. Drop the ambient
|
|
19
|
+
# markers so the asserted verdict does not depend on which harness launched
|
|
20
|
+
# the suite.
|
|
21
|
+
unset CLAUDECODE PI_CODING_AGENT FM_PI_HARNESS GROK_AGENT CURSOR_AGENT CURSOR_INVOKED_AS
|
|
22
|
+
|
|
23
|
+
SPAWN="$ROOT/bin/fm-spawn.sh"
|
|
24
|
+
TEARDOWN="$ROOT/bin/fm-teardown.sh"
|
|
25
|
+
HARNESS="$ROOT/bin/fm-harness.sh"
|
|
26
|
+
TMP_ROOT=$(fm_test_tmproot fm-muse-harness)
|
|
27
|
+
|
|
28
|
+
# --- session-log fixtures ---------------------------------------------------
|
|
29
|
+
|
|
30
|
+
# muse_log_metadata <workspace-root>: the first record of every session log,
|
|
31
|
+
# which is what binds a log to a task worktree.
|
|
32
|
+
muse_log_metadata() {
|
|
33
|
+
printf '{"schema_version":1,"id":"d77de583","stream":{"kind":"session","id":"52f21aea"},"sequence":1,"record_type":"event","durability":"durable","payload_type":"runtime.session.metadata","payload":{"kind":"metadata","record":{"workspace_root":"%s","provider_id":"meta","build":{"sha":"427a430436","semver":"0.1.0"}}}}\n' "$1"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
muse_log_run_started() { # <run-id>
|
|
37
|
+
printf '{"schema_version":1,"payload_type":"runtime.session","payload":{"kind":"run","run_id":"%s","event":{"kind":"started","prompt":"launch brief"}}}\n' "$1"
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
muse_log_run_terminal() { # <run-id> <completed|cancelled>
|
|
41
|
+
printf '{"schema_version":1,"payload_type":"runtime.session","payload":{"kind":"run","run_id":"%s","event":{"kind":"terminal","terminal":"%s","reason":null,"turn_duration_ms":8152}}}\n' "$1" "$2"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# The decoy: a cleanup-effect payload whose NESTED record is "terminal". It is
|
|
45
|
+
# not a run lifecycle terminal and must not settle an open run.
|
|
46
|
+
muse_log_cleanup_terminal_decoy() { # <run-id>
|
|
47
|
+
printf '{"schema_version":1,"payload_type":"runtime.session","payload":{"kind":"reminder_cleanup_effect","run_id":"%s","record":{"kind":"terminal","cleanup_effect_id":1,"outcome":{"kind":"applied"}}}}\n' "$1"
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
muse_log_noise() { # <run-id>
|
|
51
|
+
printf '{"schema_version":1,"payload_type":"runtime.session","payload":{"kind":"run","run_id":"%s","event":{"kind":"context_block_diagnostic","block_id":"rules_file","message":"mentions kind terminal and kind started in prose"}}}\n' "$1"
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# write_session_log <sessions-root> <yyyy> <mm> <dd> <uuid> <workspace-root>
|
|
55
|
+
# Body records are read from stdin. Writes the log at muse's real depth
|
|
56
|
+
# (<root>/YYYY/MM/DD/<uuid>/session.jsonl) and echoes the path.
|
|
57
|
+
write_session_log() {
|
|
58
|
+
local root=$1 y=$2 m=$3 d=$4 uuid=$5 ws=$6 dir path
|
|
59
|
+
dir="$root/$y/$m/$d/$uuid"
|
|
60
|
+
mkdir -p "$dir"
|
|
61
|
+
path="$dir/session.jsonl"
|
|
62
|
+
muse_log_metadata "$ws" > "$path"
|
|
63
|
+
cat >> "$path"
|
|
64
|
+
printf '%s\n' "$path"
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
# --- spawn scaffolding ------------------------------------------------------
|
|
68
|
+
|
|
69
|
+
make_spawn_fakebin() {
|
|
70
|
+
local dir=$1 fakebin
|
|
71
|
+
fakebin=$(fm_fakebin "$dir")
|
|
72
|
+
cat > "$fakebin/tmux" <<'SH'
|
|
73
|
+
#!/usr/bin/env bash
|
|
74
|
+
set -u
|
|
75
|
+
case "$*" in
|
|
76
|
+
*"#{pane_current_path}"*) printf '%s\n' "${FM_FAKE_PANE_PATH:-}"; exit 0 ;;
|
|
77
|
+
esac
|
|
78
|
+
case "${1:-}" in
|
|
79
|
+
show-environment)
|
|
80
|
+
[ "${FM_FAKE_WORKER_META_KEY:-}" = present ] || exit 1
|
|
81
|
+
printf 'META_API_KEY=worker-key\n'
|
|
82
|
+
exit 0
|
|
83
|
+
;;
|
|
84
|
+
display-message) printf 'firstmate\n'; exit 0 ;;
|
|
85
|
+
list-windows) exit 0 ;;
|
|
86
|
+
has-session|new-session|new-window|kill-window) exit 0 ;;
|
|
87
|
+
send-keys)
|
|
88
|
+
prev=
|
|
89
|
+
for arg in "$@"; do
|
|
90
|
+
if [ "$prev" = -l ]; then
|
|
91
|
+
printf '%s\n' "$arg" >> "$FM_FAKE_LAUNCH_LOG"
|
|
92
|
+
if [ "${FM_FAKE_EXECUTE_MUSE_LAUNCH:-}" = 1 ]; then
|
|
93
|
+
case "$arg" in
|
|
94
|
+
*"$FM_FAKE_MUSE_EXECUTABLE"*) (cd "$FM_FAKE_PANE_PATH" && bash -c "$arg") ;;
|
|
95
|
+
esac
|
|
96
|
+
fi
|
|
97
|
+
break
|
|
98
|
+
fi
|
|
99
|
+
prev=$arg
|
|
100
|
+
done
|
|
101
|
+
exit 0
|
|
102
|
+
;;
|
|
103
|
+
esac
|
|
104
|
+
exit 0
|
|
105
|
+
SH
|
|
106
|
+
chmod +x "$fakebin/tmux"
|
|
107
|
+
cp "$(command -v bash)" "$fakebin/muse-bin-test-version"
|
|
108
|
+
cat > "$fakebin/muse" <<'SH'
|
|
109
|
+
#!/usr/bin/env bash
|
|
110
|
+
set -u
|
|
111
|
+
[ -n "${FM_FAKE_HARNESS_RESULT:-}" ] || exit 0
|
|
112
|
+
exec "$FM_FAKE_MUSE_VERSIONED" -c 'result=$($FM_FAKE_HARNESS_PROBE); printf "%s" "$result" > "$FM_FAKE_HARNESS_RESULT"'
|
|
113
|
+
SH
|
|
114
|
+
chmod +x "$fakebin/muse"
|
|
115
|
+
fm_fake_exit0 "$fakebin" treehouse gh-axi gh
|
|
116
|
+
printf '%s\n' "$fakebin"
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
make_spawn_case() {
|
|
120
|
+
local name=$1 case_dir home proj wt fakebin id
|
|
121
|
+
case_dir="$TMP_ROOT/$name"
|
|
122
|
+
home="$case_dir/home"
|
|
123
|
+
proj="$case_dir/project"
|
|
124
|
+
wt="$case_dir/wt"
|
|
125
|
+
fakebin=$(make_spawn_fakebin "$case_dir/fake")
|
|
126
|
+
id="muse-$name-x1"
|
|
127
|
+
mkdir -p "$home/data/$id" "$home/projects" "$home/state" "$home/config" \
|
|
128
|
+
"$home/xdgconfig" "$home/xdgdata"
|
|
129
|
+
printf 'brief\n' > "$home/data/$id/brief.md"
|
|
130
|
+
fm_git_worktree "$proj" "$wt" "fm/$id"
|
|
131
|
+
touch "$home/state/.last-watcher-beat"
|
|
132
|
+
printf '%s\n' "$case_dir|$home|$proj|$wt|$fakebin|$id"
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
run_muse_spawn() { # <home> <proj> <wt> <fakebin> <id> [extra args...]
|
|
136
|
+
local home=$1 proj=$2 wt=$3 fakebin=$4 id=$5
|
|
137
|
+
shift 5
|
|
138
|
+
FM_ROOT_OVERRIDE='' FM_HOME="$home" \
|
|
139
|
+
FM_STATE_OVERRIDE="$home/state" FM_DATA_OVERRIDE="$home/data" \
|
|
140
|
+
FM_PROJECTS_OVERRIDE="$home/projects" FM_CONFIG_OVERRIDE="$home/config" \
|
|
141
|
+
FM_SPAWN_NO_GUARD=1 FM_FAKE_PANE_PATH="$wt" TMUX="fake,1,0" \
|
|
142
|
+
FM_FAKE_LAUNCH_LOG="$home/launch.log" \
|
|
143
|
+
FM_FAKE_MUSE_EXECUTABLE="$fakebin/muse" \
|
|
144
|
+
FM_FAKE_MUSE_VERSIONED="$fakebin/muse-bin-test-version" \
|
|
145
|
+
FM_FAKE_HARNESS_PROBE="$HARNESS" \
|
|
146
|
+
FM_FAKE_EXECUTE_MUSE_LAUNCH="${FM_FAKE_EXECUTE_MUSE_LAUNCH:-}" \
|
|
147
|
+
FM_FAKE_HARNESS_RESULT="${FM_FAKE_HARNESS_RESULT:-}" \
|
|
148
|
+
FM_FAKE_WORKER_META_KEY="${FM_TEST_MUSE_WORKER_KEY-present}" \
|
|
149
|
+
META_API_KEY="${FM_TEST_MUSE_KEY-test-key}" \
|
|
150
|
+
XDG_CONFIG_HOME="${FM_TEST_MUSE_CONFIG_HOME-$home/xdgconfig}" \
|
|
151
|
+
XDG_DATA_HOME="${FM_TEST_MUSE_DATA_HOME-$home/xdgdata}" \
|
|
152
|
+
PATH="$fakebin:$PATH" \
|
|
153
|
+
"$SPAWN" "$id" "$proj" muse "$@" 2>&1
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
# --- detection --------------------------------------------------------------
|
|
157
|
+
|
|
158
|
+
# The installed muse launcher execs a VERSION-SUFFIXED binary
|
|
159
|
+
# (~/.local/bin/muse-bin-<version>), so the name in the process tree changes on
|
|
160
|
+
# every auto-update. Detection must follow a real running process rather than a
|
|
161
|
+
# string, so each case launches an actual renamed executable and asks
|
|
162
|
+
# fm-harness.sh from a child of it.
|
|
163
|
+
#
|
|
164
|
+
# The foreign env markers, including Cursor's, are cleared because muse is
|
|
165
|
+
# markerless and the marker layer deliberately outranks ancestry: with one
|
|
166
|
+
# retained, these cases would assert the marker's verdict instead of the
|
|
167
|
+
# ancestry match they exist to pin.
|
|
168
|
+
# The command substitution around the probe is load-bearing: a bare `-c <cmd>`
|
|
169
|
+
# lets the shell exec the probe in place, which REPLACES the muse-bin-* process
|
|
170
|
+
# name the walk is supposed to find. Real muse keeps its TUI process alive and
|
|
171
|
+
# runs tools as children, so forcing a fork is what reproduces that shape.
|
|
172
|
+
test_detects_versioned_process_ancestor() {
|
|
173
|
+
local dir bin out
|
|
174
|
+
dir="$TMP_ROOT/detect"
|
|
175
|
+
mkdir -p "$dir"
|
|
176
|
+
for bin in muse-bin-0.1.0-R708.1 muse-bin-9.9.9-RZZZ.9 muse; do
|
|
177
|
+
cp "$(command -v bash)" "$dir/$bin"
|
|
178
|
+
out=$(env -u CLAUDECODE -u PI_CODING_AGENT -u FM_PI_HARNESS -u GROK_AGENT \
|
|
179
|
+
-u CURSOR_AGENT -u CURSOR_INVOKED_AS \
|
|
180
|
+
"$dir/$bin" -c "r=\$(\"$HARNESS\"); printf '%s' \"\$r\"")
|
|
181
|
+
[ "$out" = muse ] || fail "fm-harness.sh under process '$bin' reported '$out', expected muse"
|
|
182
|
+
done
|
|
183
|
+
pass "muse is detected through any versioned muse-bin ancestor"
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
# The match must be anchored: an unrelated command whose name merely CONTAINS
|
|
187
|
+
# muse is a different program and must not be claimed by this adapter.
|
|
188
|
+
test_detection_is_anchored() {
|
|
189
|
+
local dir bin out
|
|
190
|
+
dir="$TMP_ROOT/detect-neg"
|
|
191
|
+
mkdir -p "$dir"
|
|
192
|
+
for bin in musescore amuse notmuse-bin muse-binary muse-bind; do
|
|
193
|
+
cp "$(command -v bash)" "$dir/$bin"
|
|
194
|
+
out=$(env -u CLAUDECODE -u PI_CODING_AGENT -u FM_PI_HARNESS -u GROK_AGENT \
|
|
195
|
+
-u CURSOR_AGENT -u CURSOR_INVOKED_AS \
|
|
196
|
+
"$dir/$bin" -c "r=\$(\"$HARNESS\"); printf '%s' \"\$r\"")
|
|
197
|
+
[ "$out" != muse ] || fail "fm-harness.sh misdetected unrelated process '$bin' as muse"
|
|
198
|
+
done
|
|
199
|
+
pass "muse detection does not claim unrelated muse-containing commands"
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
test_spawn_clears_inherited_foreign_harness_markers() {
|
|
203
|
+
local rec case_dir home proj wt fakebin id result out status
|
|
204
|
+
rec=$(make_spawn_case inherited-markers)
|
|
205
|
+
IFS='|' read -r case_dir home proj wt fakebin id <<EOF
|
|
206
|
+
$rec
|
|
207
|
+
EOF
|
|
208
|
+
result="$case_dir/harness-result"
|
|
209
|
+
out=$(CLAUDECODE=1 PI_CODING_AGENT=true GROK_AGENT=1 FM_PI_HARNESS=pi-signed \
|
|
210
|
+
CURSOR_AGENT=1 CURSOR_INVOKED_AS=cursor-agent \
|
|
211
|
+
FM_FAKE_EXECUTE_MUSE_LAUNCH=1 FM_FAKE_HARNESS_RESULT="$result" \
|
|
212
|
+
run_muse_spawn "$home" "$proj" "$wt" "$fakebin" "$id" --mode no-mistakes --yolo off)
|
|
213
|
+
status=$?
|
|
214
|
+
expect_code 0 "$status" "muse spawn from a marked backend should succeed: $out"
|
|
215
|
+
[ -f "$result" ] || fail "the generated muse launch never executed its harness probe"
|
|
216
|
+
[ "$(cat "$result")" = muse ] \
|
|
217
|
+
|| fail "muse worker inherited a foreign harness identity: $(cat "$result")"
|
|
218
|
+
pass "muse launch clears foreign harness markers before ancestry detection"
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
# --- spawn ------------------------------------------------------------------
|
|
222
|
+
|
|
223
|
+
test_spawn_launch_shape() {
|
|
224
|
+
local rec case_dir home proj wt fakebin id out status launch
|
|
225
|
+
rec=$(make_spawn_case launch)
|
|
226
|
+
IFS='|' read -r case_dir home proj wt fakebin id <<EOF
|
|
227
|
+
$rec
|
|
228
|
+
EOF
|
|
229
|
+
out=$(run_muse_spawn "$home" "$proj" "$wt" "$fakebin" "$id" --mode no-mistakes --yolo off)
|
|
230
|
+
status=$?
|
|
231
|
+
expect_code 0 "$status" "muse spawn should succeed"
|
|
232
|
+
assert_contains "$out" "spawned $id harness=muse" "muse spawn did not report success"
|
|
233
|
+
|
|
234
|
+
launch=$(cat "$home/launch.log")
|
|
235
|
+
# --yolo is what makes a crewmate pane viable at all: without it muse holds
|
|
236
|
+
# every tool call for approval and sandboxes the network to proxy-only.
|
|
237
|
+
assert_contains "$launch" ' --yolo ' "muse launch omitted --yolo"
|
|
238
|
+
# The privacy control. Its absence would ship the operator's foreign personal
|
|
239
|
+
# rules to Meta-hosted inference on every crewmate turn.
|
|
240
|
+
assert_contains "$launch" 'MUSE_EXPERIMENTAL_FOREIGN_PERSONAL_CONTEXT_KILL=on' \
|
|
241
|
+
"muse launch omitted the foreign-personal-context kill"
|
|
242
|
+
# exec-only flag: the interactive TUI exits with "unexpected argument" on it.
|
|
243
|
+
assert_not_contains "$launch" '--no-foreign-personal-context' \
|
|
244
|
+
"muse launch passed the exec-only foreign-context flag to the TUI"
|
|
245
|
+
# The captain accepted muse's self-update risk, so firstmate must not pin it.
|
|
246
|
+
assert_not_contains "$launch" 'MUSE_NO_AUTO_UPDATE' \
|
|
247
|
+
"muse launch pinned auto-update, which the captain declined"
|
|
248
|
+
assert_contains "$launch" "XDG_CONFIG_HOME='$home/xdgconfig'" \
|
|
249
|
+
"muse launch did not forward its non-secret config root"
|
|
250
|
+
assert_contains "$launch" "XDG_DATA_HOME='$home/xdgdata'" \
|
|
251
|
+
"muse launch did not forward its non-secret data root"
|
|
252
|
+
assert_not_contains "$launch" 'META_API_KEY' "muse launch exposed META_API_KEY in worker argv"
|
|
253
|
+
assert_not_contains "$launch" 'test-key' "muse launch exposed the credential value in worker argv"
|
|
254
|
+
assert_contains "$launch" 'encode launch-brief' "muse launch did not deliver the brief positionally"
|
|
255
|
+
assert_grep 'harness=muse' "$home/state/$id.meta" "muse harness was not recorded in meta"
|
|
256
|
+
pass "muse spawn launches with autonomy, privacy control, and a positional brief"
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
test_spawn_maps_effort_and_model() {
|
|
260
|
+
local rec case_dir home proj wt fakebin id launch
|
|
261
|
+
local -a cases=(
|
|
262
|
+
"low|--reasoning-effort 'low'"
|
|
263
|
+
"medium|--reasoning-effort 'medium'"
|
|
264
|
+
"high|--reasoning-effort 'high'"
|
|
265
|
+
"xhigh|--reasoning-effort 'xhigh'"
|
|
266
|
+
"max|--reasoning-effort 'ultra'"
|
|
267
|
+
)
|
|
268
|
+
local entry effort expect
|
|
269
|
+
for entry in "${cases[@]}"; do
|
|
270
|
+
effort=${entry%%|*}
|
|
271
|
+
expect=${entry#*|}
|
|
272
|
+
rec=$(make_spawn_case "effort-$effort")
|
|
273
|
+
IFS='|' read -r case_dir home proj wt fakebin id <<EOF
|
|
274
|
+
$rec
|
|
275
|
+
EOF
|
|
276
|
+
run_muse_spawn "$home" "$proj" "$wt" "$fakebin" "$id" \
|
|
277
|
+
--mode no-mistakes --yolo off --model muse-spark-1.2 --effort "$effort" >/dev/null \
|
|
278
|
+
|| fail "muse spawn with effort $effort failed"
|
|
279
|
+
launch=$(cat "$home/launch.log")
|
|
280
|
+
assert_contains "$launch" "$expect" "muse effort $effort did not map to '$expect'"
|
|
281
|
+
assert_contains "$launch" "--model 'muse-spark-1.2'" "muse spawn dropped the model axis"
|
|
282
|
+
done
|
|
283
|
+
# ultra is muse's max-class level and must be reachable ONLY through an
|
|
284
|
+
# explicit max, never as the fallback when no effort was chosen.
|
|
285
|
+
rec=$(make_spawn_case effort-default)
|
|
286
|
+
IFS='|' read -r case_dir home proj wt fakebin id <<EOF
|
|
287
|
+
$rec
|
|
288
|
+
EOF
|
|
289
|
+
run_muse_spawn "$home" "$proj" "$wt" "$fakebin" "$id" --mode no-mistakes --yolo off >/dev/null \
|
|
290
|
+
|| fail "muse spawn without an effort axis failed"
|
|
291
|
+
launch=$(cat "$home/launch.log")
|
|
292
|
+
assert_not_contains "$launch" '--reasoning-effort' "muse spawn invented an effort when none was chosen"
|
|
293
|
+
pass "muse maps the shared effort vocabulary and reaches ultra only via explicit max"
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
# An unauthenticated muse pane does not exit: it sits on an OAuth device-code
|
|
297
|
+
# prompt forever, which supervision would read as a wedged worker rather than a
|
|
298
|
+
# missing credential. The spawn must refuse before an endpoint exists.
|
|
299
|
+
test_spawn_refuses_without_credential() {
|
|
300
|
+
local rec case_dir home proj wt fakebin id out status
|
|
301
|
+
rec=$(make_spawn_case no-cred)
|
|
302
|
+
IFS='|' read -r case_dir home proj wt fakebin id <<EOF
|
|
303
|
+
$rec
|
|
304
|
+
EOF
|
|
305
|
+
mkdir -p "$home/xdgconfig/muse"
|
|
306
|
+
out=$(FM_TEST_MUSE_KEY='' FM_TEST_MUSE_WORKER_KEY='' run_muse_spawn "$home" "$proj" "$wt" "$fakebin" "$id" \
|
|
307
|
+
--mode no-mistakes --yolo off)
|
|
308
|
+
status=$?
|
|
309
|
+
[ "$status" -ne 0 ] || fail "muse spawn succeeded with no credential available"
|
|
310
|
+
assert_contains "$out" "no worker-reachable credential" "muse spawn did not name the missing credential"
|
|
311
|
+
assert_absent "$home/state/$id.meta" "refused muse spawn still published task metadata"
|
|
312
|
+
pass "muse spawn refuses when no credential can reach the provider"
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
test_spawn_refuses_caller_only_environment_credential() {
|
|
316
|
+
local rec case_dir home proj wt fakebin id out status
|
|
317
|
+
rec=$(make_spawn_case caller-only-cred)
|
|
318
|
+
IFS='|' read -r case_dir home proj wt fakebin id <<EOF
|
|
319
|
+
$rec
|
|
320
|
+
EOF
|
|
321
|
+
out=$(FM_TEST_MUSE_KEY='caller-only-secret' FM_TEST_MUSE_WORKER_KEY='' \
|
|
322
|
+
run_muse_spawn "$home" "$proj" "$wt" "$fakebin" "$id" --mode no-mistakes --yolo off)
|
|
323
|
+
status=$?
|
|
324
|
+
[ "$status" -ne 0 ] || fail "muse spawn accepted a caller-only META_API_KEY"
|
|
325
|
+
assert_contains "$out" "set for fm-spawn but cannot be proven present" \
|
|
326
|
+
"muse spawn did not explain that the caller credential cannot reach the worker"
|
|
327
|
+
assert_contains "$out" "$home/xdgconfig/muse/auth.json" \
|
|
328
|
+
"muse spawn did not name the supported stored credential path"
|
|
329
|
+
assert_absent "$home/launch.log" "caller-only credential refusal created an endpoint"
|
|
330
|
+
pass "muse spawn refuses a META_API_KEY that cannot reach the worker"
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
test_spawn_accepts_stored_credential() {
|
|
334
|
+
local rec case_dir home proj wt fakebin id status
|
|
335
|
+
rec=$(make_spawn_case stored-cred)
|
|
336
|
+
IFS='|' read -r case_dir home proj wt fakebin id <<EOF
|
|
337
|
+
$rec
|
|
338
|
+
EOF
|
|
339
|
+
mkdir -p "$home/xdgconfig/muse"
|
|
340
|
+
printf '{"schema_version":1}\n' > "$home/xdgconfig/muse/auth.json"
|
|
341
|
+
FM_TEST_MUSE_KEY='' FM_TEST_MUSE_WORKER_KEY='' \
|
|
342
|
+
run_muse_spawn "$home" "$proj" "$wt" "$fakebin" "$id" \
|
|
343
|
+
--mode no-mistakes --yolo off >/dev/null
|
|
344
|
+
status=$?
|
|
345
|
+
expect_code 0 "$status" "muse spawn should accept a stored credential"
|
|
346
|
+
pass "muse spawn accepts a stored credential without META_API_KEY"
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
test_spawn_resolves_relative_xdg_roots() {
|
|
350
|
+
local rec case_dir home proj wt fakebin id caller resolved_caller launch binding out status
|
|
351
|
+
rec=$(make_spawn_case relative-xdg)
|
|
352
|
+
IFS='|' read -r case_dir home proj wt fakebin id <<EOF
|
|
353
|
+
$rec
|
|
354
|
+
EOF
|
|
355
|
+
caller="$case_dir/caller"
|
|
356
|
+
mkdir -p "$caller/cfg/muse" "$caller/data"
|
|
357
|
+
resolved_caller=$(cd "$caller" && pwd -P)
|
|
358
|
+
printf '{"schema_version":1}\n' > "$caller/cfg/muse/auth.json"
|
|
359
|
+
out=$(cd "$caller" && FM_TEST_MUSE_KEY='' FM_TEST_MUSE_WORKER_KEY='' \
|
|
360
|
+
FM_TEST_MUSE_CONFIG_HOME=cfg FM_TEST_MUSE_DATA_HOME=data \
|
|
361
|
+
run_muse_spawn "$home" "$proj" "$wt" "$fakebin" "$id" --mode no-mistakes --yolo off)
|
|
362
|
+
status=$?
|
|
363
|
+
expect_code 0 "$status" "muse spawn with relative XDG roots should succeed: $out"
|
|
364
|
+
launch=$(cat "$home/launch.log")
|
|
365
|
+
assert_contains "$launch" "XDG_CONFIG_HOME='$resolved_caller/cfg'" \
|
|
366
|
+
"muse launch did not forward the resolved config root"
|
|
367
|
+
assert_contains "$launch" "XDG_DATA_HOME='$resolved_caller/data'" \
|
|
368
|
+
"muse launch did not forward the resolved data root"
|
|
369
|
+
binding="$home/state/$id.muse-session"
|
|
370
|
+
assert_grep "sessions_root=$resolved_caller/data/muse/sessions" "$binding" \
|
|
371
|
+
"muse busy binding did not use the worker's resolved data root"
|
|
372
|
+
pass "muse resolves relative XDG roots before preflight and launch"
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
# muse has no primary supervision protocol, and its Claude-compatible hook
|
|
376
|
+
# dialect rejects the model-reawakening handlers a firstmate primary needs, so a
|
|
377
|
+
# secondmate on muse could never arm a supervision cycle.
|
|
378
|
+
test_spawn_refuses_secondmate() {
|
|
379
|
+
local case_dir home fakebin id out status
|
|
380
|
+
case_dir="$TMP_ROOT/secondmate"
|
|
381
|
+
home="$case_dir/home"
|
|
382
|
+
fakebin=$(make_spawn_fakebin "$case_dir/fake")
|
|
383
|
+
id="muse-secondmate-x1"
|
|
384
|
+
mkdir -p "$home/data/$id" "$home/projects" "$home/state" "$home/config" "$case_dir/muse"
|
|
385
|
+
printf 'charter\n' > "$home/data/$id/brief.md"
|
|
386
|
+
out=$(cd "$case_dir" && FM_ROOT_OVERRIDE='' FM_HOME="$home" \
|
|
387
|
+
FM_STATE_OVERRIDE="$home/state" FM_DATA_OVERRIDE="$home/data" \
|
|
388
|
+
FM_PROJECTS_OVERRIDE="$home/projects" FM_CONFIG_OVERRIDE="$home/config" \
|
|
389
|
+
FM_SPAWN_NO_GUARD=1 TMUX="fake,1,0" META_API_KEY=test-key \
|
|
390
|
+
PATH="$fakebin:$PATH" \
|
|
391
|
+
"$SPAWN" "$id" muse --secondmate 2>&1)
|
|
392
|
+
status=$?
|
|
393
|
+
[ "$status" -ne 0 ] || fail "muse was accepted as a secondmate harness"
|
|
394
|
+
assert_contains "$out" "crewmate/scout adapter only" "muse secondmate refusal did not explain the boundary"
|
|
395
|
+
pass "muse is refused as a secondmate harness"
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
test_spawn_writes_busy_binding_and_teardown_removes_it() {
|
|
399
|
+
local rec case_dir home proj wt fakebin id binding prior
|
|
400
|
+
rec=$(make_spawn_case binding)
|
|
401
|
+
IFS='|' read -r case_dir home proj wt fakebin id <<EOF
|
|
402
|
+
$rec
|
|
403
|
+
EOF
|
|
404
|
+
prior=$(write_session_log "$case_dir/xdgdata/muse/sessions" 2026 08 05 prior "$wt" </dev/null)
|
|
405
|
+
prior=$(printf '%s\n' "$prior" | sed 's://*:/:g')
|
|
406
|
+
FM_TEST_MUSE_DATA_HOME="$case_dir/xdgdata" \
|
|
407
|
+
run_muse_spawn "$home" "$proj" "$wt" "$fakebin" "$id" --mode no-mistakes --yolo off >/dev/null \
|
|
408
|
+
|| fail "muse spawn failed"
|
|
409
|
+
|
|
410
|
+
binding="$home/state/$id.muse-session"
|
|
411
|
+
assert_present "$binding" "muse spawn did not write the session binding"
|
|
412
|
+
assert_grep "sessions_root=$case_dir/xdgdata/muse/sessions" "$binding" \
|
|
413
|
+
"muse binding did not record the resolved sessions root"
|
|
414
|
+
assert_grep "workspace_root=$wt" "$binding" "muse binding did not record the task worktree"
|
|
415
|
+
assert_grep "prior_log=$prior" "$binding" \
|
|
416
|
+
"muse binding did not exclude the pre-existing session: $(tr '\n' ';' < "$binding")"
|
|
417
|
+
# No busy record is armed for muse: the source is pull-only with no writer, so
|
|
418
|
+
# a seeded busy record could never be settled.
|
|
419
|
+
assert_absent "$home/state/$id.busy-gen" "muse spawn armed a busy record it can never clear"
|
|
420
|
+
printf 'binding_id=retired\nsession_log=%s\n' "$prior" > "$home/state/$id.muse-session-current"
|
|
421
|
+
|
|
422
|
+
FM_ROOT_OVERRIDE="$ROOT" FM_HOME="$home" FM_STATE_OVERRIDE="$home/state" \
|
|
423
|
+
PATH="$fakebin:$PATH" "$TEARDOWN" "$id" --force >/dev/null 2>&1 \
|
|
424
|
+
|| fail "muse teardown failed"
|
|
425
|
+
assert_absent "$binding" "muse session binding survived teardown"
|
|
426
|
+
assert_absent "$home/state/$id.muse-session-current" "muse session cache survived teardown"
|
|
427
|
+
pass "muse spawn writes a session binding that teardown removes"
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
# --- interrupt --------------------------------------------------------------
|
|
431
|
+
|
|
432
|
+
# muse RESTORES the interrupted prompt into the composer after Escape, as real
|
|
433
|
+
# bright text. Left there, the next steer types onto the end of it and submits
|
|
434
|
+
# both as one garbled message, so the interrupt is not complete until the
|
|
435
|
+
# composer is cleared.
|
|
436
|
+
make_send_case() { # <name> <harness>
|
|
437
|
+
local name=$1 harness=$2 case_dir home fakebin id
|
|
438
|
+
case_dir="$TMP_ROOT/send-$name"
|
|
439
|
+
home="$case_dir/home"
|
|
440
|
+
fakebin=$(fm_fakebin "$case_dir/fake")
|
|
441
|
+
id="send-$name"
|
|
442
|
+
mkdir -p "$home/state"
|
|
443
|
+
cat > "$fakebin/tmux" <<'SH'
|
|
444
|
+
#!/usr/bin/env bash
|
|
445
|
+
set -u
|
|
446
|
+
case "${1:-}" in
|
|
447
|
+
display-message) printf 'fakepane\n'; exit 0 ;;
|
|
448
|
+
has-session) exit 0 ;;
|
|
449
|
+
list-panes|list-windows) printf 'fm-send:0\n'; exit 0 ;;
|
|
450
|
+
send-keys)
|
|
451
|
+
shift
|
|
452
|
+
printf '%s\n' "$*" >> "$FM_FAKE_KEY_LOG"
|
|
453
|
+
[ "${FM_FAKE_KEY_FAIL:-}" = "$*" ] && exit 1
|
|
454
|
+
exit 0
|
|
455
|
+
;;
|
|
456
|
+
esac
|
|
457
|
+
exit 0
|
|
458
|
+
SH
|
|
459
|
+
chmod +x "$fakebin/tmux"
|
|
460
|
+
fm_write_meta "$home/state/$id.meta" \
|
|
461
|
+
"window=fm-send:0" "endpoint_task_id=$id" "worktree=$case_dir" \
|
|
462
|
+
"project=$case_dir" "harness=$harness" "kind=ship" "mode=no-mistakes" "yolo=off"
|
|
463
|
+
printf '%s\n' "$case_dir|$home|$fakebin|$id"
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
run_send_key() { # <home> <fakebin> <id> <key> <keylog>
|
|
467
|
+
FM_ROOT_OVERRIDE="$ROOT" FM_HOME="$1" FM_STATE_OVERRIDE="$1/state" \
|
|
468
|
+
FM_FAKE_KEY_LOG="$5" PATH="$2:$PATH" \
|
|
469
|
+
"$ROOT/bin/fm-send.sh" "$3" --key "$4" 2>&1
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
test_muse_escape_aliases_clear_the_composer() {
|
|
473
|
+
local entry name key rec case_dir home fakebin id keylog out status
|
|
474
|
+
for entry in exact:Escape lower:escape short:Esc short-lower:esc; do
|
|
475
|
+
name=${entry%%:*}
|
|
476
|
+
key=${entry#*:}
|
|
477
|
+
rec=$(make_send_case "muse-$name" muse)
|
|
478
|
+
IFS='|' read -r case_dir home fakebin id <<EOF
|
|
479
|
+
$rec
|
|
480
|
+
EOF
|
|
481
|
+
keylog="$case_dir/keys.log"
|
|
482
|
+
: > "$keylog"
|
|
483
|
+
out=$(run_send_key "$home" "$fakebin" "$id" "$key" "$keylog")
|
|
484
|
+
status=$?
|
|
485
|
+
expect_code 0 "$status" "muse $key send should succeed: $out"
|
|
486
|
+
assert_grep "$key" "$keylog" "$key never reached the muse pane"
|
|
487
|
+
assert_grep 'C-u' "$keylog" "muse $key did not clear the restored composer"
|
|
488
|
+
[ "$(grep -c . "$keylog")" -ge 2 ] || fail "expected both the interrupt and the clear for $key"
|
|
489
|
+
head -1 "$keylog" | grep -q "$key" || fail "the clear was sent before the $key interrupt"
|
|
490
|
+
done
|
|
491
|
+
pass "every accepted muse Escape alias clears the restored composer"
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
test_non_muse_escape_does_not_clear() {
|
|
495
|
+
local rec case_dir home fakebin id keylog
|
|
496
|
+
rec=$(make_send_case codex codex)
|
|
497
|
+
IFS='|' read -r case_dir home fakebin id <<EOF
|
|
498
|
+
$rec
|
|
499
|
+
EOF
|
|
500
|
+
keylog="$case_dir/keys.log"
|
|
501
|
+
: > "$keylog"
|
|
502
|
+
run_send_key "$home" "$fakebin" "$id" Escape "$keylog" >/dev/null
|
|
503
|
+
assert_grep 'Escape' "$keylog" "Escape never reached the codex pane"
|
|
504
|
+
assert_no_grep 'C-u' "$keylog" "a non-muse interrupt sent a composer clear it does not need"
|
|
505
|
+
pass "the composer clear is scoped to muse and does not touch other adapters"
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
# A silent clear failure would leave the restored prompt in place and corrupt
|
|
509
|
+
# the next steer, so the failure has to be loud.
|
|
510
|
+
test_failed_clear_is_reported() {
|
|
511
|
+
local rec case_dir home fakebin id keylog out status
|
|
512
|
+
rec=$(make_send_case clearfail muse)
|
|
513
|
+
IFS='|' read -r case_dir home fakebin id <<EOF
|
|
514
|
+
$rec
|
|
515
|
+
EOF
|
|
516
|
+
keylog="$case_dir/keys.log"
|
|
517
|
+
: > "$keylog"
|
|
518
|
+
out=$(FM_FAKE_KEY_FAIL='-t fm-send:0 C-u' run_send_key "$home" "$fakebin" "$id" Escape "$keylog")
|
|
519
|
+
status=$?
|
|
520
|
+
[ "$status" -ne 0 ] || fail "a failed muse composer clear was reported as success"
|
|
521
|
+
assert_contains "$out" "could not be cleared" "the failed clear did not explain the pane state"
|
|
522
|
+
pass "a failed muse composer clear fails loudly instead of leaving stale input"
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
# --- busy source ------------------------------------------------------------
|
|
526
|
+
|
|
527
|
+
classify_muse() { # <state-dir> <id>
|
|
528
|
+
(
|
|
529
|
+
# shellcheck source=bin/fm-busy-lib.sh
|
|
530
|
+
. "$ROOT/bin/fm-busy-lib.sh"
|
|
531
|
+
fm_busy_classify tmux fake:0 muse "$2" "$1"
|
|
532
|
+
)
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
run_state() { # <log>
|
|
536
|
+
(
|
|
537
|
+
# shellcheck source=bin/fm-busy-lib.sh
|
|
538
|
+
. "$ROOT/bin/fm-busy-lib.sh"
|
|
539
|
+
fm_busy_muse_run_state "$1"
|
|
540
|
+
)
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
test_run_fold_tracks_open_and_settled_turns() {
|
|
544
|
+
local dir log out
|
|
545
|
+
dir="$TMP_ROOT/fold"
|
|
546
|
+
mkdir -p "$dir"
|
|
547
|
+
|
|
548
|
+
log=$(write_session_log "$dir/open" 2026 08 05 aaaa "$dir/ws" <<EOF
|
|
549
|
+
$(muse_log_run_started run-1)
|
|
550
|
+
$(muse_log_noise run-1)
|
|
551
|
+
EOF
|
|
552
|
+
)
|
|
553
|
+
out=$(run_state "$log")
|
|
554
|
+
[ "$out" = busy ] || fail "an open run folded to '$out', expected busy"
|
|
555
|
+
|
|
556
|
+
log=$(write_session_log "$dir/settled" 2026 08 05 bbbb "$dir/ws" <<EOF
|
|
557
|
+
$(muse_log_run_started run-1)
|
|
558
|
+
$(muse_log_run_terminal run-1 completed)
|
|
559
|
+
EOF
|
|
560
|
+
)
|
|
561
|
+
out=$(run_state "$log")
|
|
562
|
+
[ "$out" = settled ] || fail "a completed run folded to '$out', expected settled"
|
|
563
|
+
|
|
564
|
+
# An Escape interrupt closes its run with terminal=cancelled, so unlike a
|
|
565
|
+
# Stop-hook adapter this source covers the interrupt path itself.
|
|
566
|
+
log=$(write_session_log "$dir/cancelled" 2026 08 05 cccc "$dir/ws" <<EOF
|
|
567
|
+
$(muse_log_run_started run-1)
|
|
568
|
+
$(muse_log_run_terminal run-1 cancelled)
|
|
569
|
+
EOF
|
|
570
|
+
)
|
|
571
|
+
out=$(run_state "$log")
|
|
572
|
+
[ "$out" = settled ] || fail "an interrupted run folded to '$out', expected settled"
|
|
573
|
+
|
|
574
|
+
# A second turn reopens the fold after the first settled.
|
|
575
|
+
log=$(write_session_log "$dir/second" 2026 08 05 dddd "$dir/ws" <<EOF
|
|
576
|
+
$(muse_log_run_started run-1)
|
|
577
|
+
$(muse_log_run_terminal run-1 completed)
|
|
578
|
+
$(muse_log_run_started run-2)
|
|
579
|
+
EOF
|
|
580
|
+
)
|
|
581
|
+
out=$(run_state "$log")
|
|
582
|
+
[ "$out" = busy ] || fail "a reopened second turn folded to '$out', expected busy"
|
|
583
|
+
|
|
584
|
+
# A log with no run lifecycle at all (an unauthenticated pane stuck on the
|
|
585
|
+
# sign-in prompt produces exactly this) is not a settled turn.
|
|
586
|
+
log=$(write_session_log "$dir/none" 2026 08 05 eeee "$dir/ws" </dev/null)
|
|
587
|
+
out=$(run_state "$log")
|
|
588
|
+
[ "$out" = none ] || fail "a run-free log folded to '$out', expected none"
|
|
589
|
+
pass "the run fold tracks open, settled, interrupted, reopened, and run-free logs"
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
test_nested_terminal_record_does_not_settle_a_run() {
|
|
593
|
+
local dir log out
|
|
594
|
+
dir="$TMP_ROOT/decoy"
|
|
595
|
+
mkdir -p "$dir"
|
|
596
|
+
log=$(write_session_log "$dir/root" 2026 08 05 ffff "$dir/ws" <<EOF
|
|
597
|
+
$(muse_log_run_started run-1)
|
|
598
|
+
$(muse_log_cleanup_terminal_decoy run-1)
|
|
599
|
+
$(muse_log_noise run-1)
|
|
600
|
+
EOF
|
|
601
|
+
)
|
|
602
|
+
out=$(run_state "$log")
|
|
603
|
+
[ "$out" = busy ] \
|
|
604
|
+
|| fail "a nested cleanup 'terminal' record settled an open run (folded '$out', expected busy)"
|
|
605
|
+
pass "a nested terminal record never settles an in-flight run"
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
test_binding_selects_the_matching_main_log() {
|
|
609
|
+
local dir state id verdict root
|
|
610
|
+
dir="$TMP_ROOT/bind"
|
|
611
|
+
state="$dir/state"
|
|
612
|
+
root="$dir/sessions"
|
|
613
|
+
id=bindtask
|
|
614
|
+
mkdir -p "$state"
|
|
615
|
+
|
|
616
|
+
# Another task's log lives in the same root and must never be folded here.
|
|
617
|
+
write_session_log "$root" 2026 08 05 other "$dir/other-ws" >/dev/null <<EOF
|
|
618
|
+
$(muse_log_run_started other-run)
|
|
619
|
+
EOF
|
|
620
|
+
|
|
621
|
+
write_session_log "$root" 2026 08 05 mine "$dir/my-ws" >/dev/null <<EOF
|
|
622
|
+
$(muse_log_run_started my-run)
|
|
623
|
+
$(muse_log_run_terminal my-run completed)
|
|
624
|
+
EOF
|
|
625
|
+
|
|
626
|
+
printf 'sessions_root=%s\nworkspace_root=%s\n' "$root" "$dir/my-ws" > "$state/$id.muse-session"
|
|
627
|
+
verdict=$(classify_muse "$state" "$id")
|
|
628
|
+
# This task's own log is settled; the OTHER task's open run must not leak in
|
|
629
|
+
# as busy. With the idle half verified, this task's settled log reads idle.
|
|
630
|
+
[ "$verdict" = "idle muse-session-log" ] \
|
|
631
|
+
|| fail "binding leaked another workspace's run state: got '$verdict'"
|
|
632
|
+
|
|
633
|
+
printf 'sessions_root=%s\nworkspace_root=%s\n' "$root" "$dir/other-ws" > "$state/$id.muse-session"
|
|
634
|
+
verdict=$(classify_muse "$state" "$id")
|
|
635
|
+
[ "$verdict" = "busy muse-session-log" ] \
|
|
636
|
+
|| fail "binding did not fold the workspace it was pointed at: got '$verdict'"
|
|
637
|
+
pass "the session binding folds only the log matching this task's worktree"
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
test_workspace_binding_treats_glob_characters_literally() {
|
|
641
|
+
local dir state id root verdict
|
|
642
|
+
dir="$TMP_ROOT/workspace-literal"
|
|
643
|
+
state="$dir/state"
|
|
644
|
+
root="$dir/sessions"
|
|
645
|
+
id=literal-task
|
|
646
|
+
mkdir -p "$state"
|
|
647
|
+
|
|
648
|
+
write_session_log "$root" 2026 08 05 own "$dir/ws[1]" >/dev/null <<EOF
|
|
649
|
+
$(muse_log_run_started own-run)
|
|
650
|
+
$(muse_log_run_terminal own-run completed)
|
|
651
|
+
EOF
|
|
652
|
+
write_session_log "$root" 2026 08 05 decoy "$dir/ws1" >/dev/null <<EOF
|
|
653
|
+
$(muse_log_run_started decoy-run)
|
|
654
|
+
EOF
|
|
655
|
+
|
|
656
|
+
printf 'sessions_root=%s\nworkspace_root=%s\n' \
|
|
657
|
+
"$root" "$dir/ws[1]" > "$state/$id.muse-session"
|
|
658
|
+
verdict=$(classify_muse "$state" "$id")
|
|
659
|
+
[ "$verdict" = "idle muse-session-log" ] \
|
|
660
|
+
|| fail "a bracketed workspace imported another session's busy state: got '$verdict'"
|
|
661
|
+
pass "workspace bindings compare decoded paths literally"
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
test_binding_excludes_preexisting_log_when_mtimes_tie() {
|
|
665
|
+
local dir state id root old current verdict
|
|
666
|
+
dir="$TMP_ROOT/mtime-tie"
|
|
667
|
+
state="$dir/state"
|
|
668
|
+
root="$dir/sessions"
|
|
669
|
+
id=tietask
|
|
670
|
+
mkdir -p "$state"
|
|
671
|
+
|
|
672
|
+
old=$(write_session_log "$root" 2026 08 05 aaaa-old "$dir/ws" <<EOF
|
|
673
|
+
$(muse_log_run_started old-run)
|
|
674
|
+
$(muse_log_run_terminal old-run completed)
|
|
675
|
+
EOF
|
|
676
|
+
)
|
|
677
|
+
current=$(write_session_log "$root" 2026 08 05 zzzz-current "$dir/ws" <<EOF
|
|
678
|
+
$(muse_log_run_started current-run)
|
|
679
|
+
EOF
|
|
680
|
+
)
|
|
681
|
+
old=$(printf '%s\n' "$old" | sed 's://*:/:g')
|
|
682
|
+
current=$(printf '%s\n' "$current" | sed 's://*:/:g')
|
|
683
|
+
touch -t 202608050101.01 "$old" "$current"
|
|
684
|
+
{ [ ! "$old" -nt "$current" ] && [ ! "$current" -nt "$old" ]; } \
|
|
685
|
+
|| fail "the session-selection regression does not reproduce equal mtimes"
|
|
686
|
+
|
|
687
|
+
printf 'sessions_root=%s\nworkspace_root=%s\nprior_log=%s\n' \
|
|
688
|
+
"$root" "$dir/ws" "$old" > "$state/$id.muse-session"
|
|
689
|
+
verdict=$(classify_muse "$state" "$id")
|
|
690
|
+
[ "$verdict" = "busy muse-session-log" ] \
|
|
691
|
+
|| fail "the current open session lost an mtime tie to the prior settled session: got '$verdict'"
|
|
692
|
+
pass "spawn-time exclusions select the current session across equal mtimes"
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
test_session_log_cache_reuses_and_refreshes_binding() {
|
|
696
|
+
local dir state id root old fresh verdict fakebin
|
|
697
|
+
dir="$TMP_ROOT/cache"
|
|
698
|
+
state="$dir/state"
|
|
699
|
+
root="$dir/sessions"
|
|
700
|
+
id=cachetask
|
|
701
|
+
mkdir -p "$state"
|
|
702
|
+
|
|
703
|
+
old=$(write_session_log "$root" 2026 08 05 old "$dir/ws" <<EOF
|
|
704
|
+
$(muse_log_run_started old-run)
|
|
705
|
+
EOF
|
|
706
|
+
)
|
|
707
|
+
old=$(printf '%s\n' "$old" | sed 's://*:/:g')
|
|
708
|
+
printf 'sessions_root=%s\nworkspace_root=%s\nbinding_id=incarnation-one\n' \
|
|
709
|
+
"$root" "$dir/ws" > "$state/$id.muse-session"
|
|
710
|
+
verdict=$(classify_muse "$state" "$id")
|
|
711
|
+
[ "$verdict" = "busy muse-session-log" ] \
|
|
712
|
+
|| fail "the initial session did not resolve before caching: got '$verdict'"
|
|
713
|
+
|
|
714
|
+
fakebin=$(fm_fakebin "$dir/fake")
|
|
715
|
+
cat > "$fakebin/node" <<'SH'
|
|
716
|
+
#!/usr/bin/env bash
|
|
717
|
+
exit 97
|
|
718
|
+
SH
|
|
719
|
+
chmod +x "$fakebin/node"
|
|
720
|
+
verdict=$(PATH="$fakebin:$PATH" classify_muse "$state" "$id")
|
|
721
|
+
[ "$verdict" = "busy muse-session-log" ] \
|
|
722
|
+
|| fail "a cached session triggered another tree resolution: got '$verdict'"
|
|
723
|
+
|
|
724
|
+
muse_log_run_terminal old-run completed >> "$old"
|
|
725
|
+
fresh=$(write_session_log "$root" 2026 08 05 fresh "$dir/ws" <<EOF
|
|
726
|
+
$(muse_log_run_started fresh-run)
|
|
727
|
+
EOF
|
|
728
|
+
)
|
|
729
|
+
printf 'sessions_root=%s\nworkspace_root=%s\nbinding_id=incarnation-two\nprior_log=%s\n' \
|
|
730
|
+
"$root" "$dir/ws" "$old" > "$state/$id.muse-session"
|
|
731
|
+
verdict=$(classify_muse "$state" "$id")
|
|
732
|
+
[ "$verdict" = "busy muse-session-log" ] \
|
|
733
|
+
|| fail "a fresh session did not supersede the prior cached session: got '$verdict'"
|
|
734
|
+
|
|
735
|
+
rm -f "$fresh"
|
|
736
|
+
verdict=$(classify_muse "$state" "$id")
|
|
737
|
+
[ "$verdict" = "unknown muse-session-log" ] \
|
|
738
|
+
|| fail "a missing cached session produced '$verdict' instead of unknown"
|
|
739
|
+
|
|
740
|
+
write_session_log "$root" 2026 08 05 ambiguous-a "$dir/ws" >/dev/null <<EOF
|
|
741
|
+
$(muse_log_run_started ambiguous-a)
|
|
742
|
+
EOF
|
|
743
|
+
write_session_log "$root" 2026 08 05 ambiguous-b "$dir/ws" >/dev/null <<EOF
|
|
744
|
+
$(muse_log_run_started ambiguous-b)
|
|
745
|
+
EOF
|
|
746
|
+
verdict=$(classify_muse "$state" "$id")
|
|
747
|
+
[ "$verdict" = "unknown muse-session-log" ] \
|
|
748
|
+
|| fail "ambiguous replacement sessions produced '$verdict' instead of unknown"
|
|
749
|
+
pass "the Muse session cache avoids rescans and refreshes safely across incarnations"
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
test_cached_session_revalidates_after_namespace_change() {
|
|
753
|
+
local dir state id root second_log verdict today year month day
|
|
754
|
+
dir="$TMP_ROOT/cache-ambiguity"
|
|
755
|
+
state="$dir/state"
|
|
756
|
+
root="$dir/sessions"
|
|
757
|
+
id=cacheambiguity
|
|
758
|
+
mkdir -p "$state"
|
|
759
|
+
today=$(date '+%Y/%m/%d')
|
|
760
|
+
year=${today%%/*}
|
|
761
|
+
today=${today#*/}
|
|
762
|
+
month=${today%%/*}
|
|
763
|
+
day=${today#*/}
|
|
764
|
+
|
|
765
|
+
write_session_log "$root" "$year" "$month" "$day" first "$dir/ws" >/dev/null <<EOF
|
|
766
|
+
$(muse_log_run_started first-run)
|
|
767
|
+
EOF
|
|
768
|
+
printf 'sessions_root=%s\nworkspace_root=%s\nbinding_id=cache-ambiguity\n' \
|
|
769
|
+
"$root" "$dir/ws" > "$state/$id.muse-session"
|
|
770
|
+
verdict=$(classify_muse "$state" "$id")
|
|
771
|
+
[ "$verdict" = "busy muse-session-log" ] \
|
|
772
|
+
|| fail "the first session did not resolve before the ambiguity check: got '$verdict'"
|
|
773
|
+
|
|
774
|
+
second_log="$root/$year/$month/$day/second/session.jsonl"
|
|
775
|
+
mkdir -p "${second_log%/*}"
|
|
776
|
+
: > "$second_log"
|
|
777
|
+
verdict=$(classify_muse "$state" "$id")
|
|
778
|
+
[ "$verdict" = "busy muse-session-log" ] \
|
|
779
|
+
|| fail "an uninitialized second session changed the resolved verdict to '$verdict'"
|
|
780
|
+
|
|
781
|
+
write_session_log "$root" "$year" "$month" "$day" second "$dir/ws" >/dev/null <<EOF
|
|
782
|
+
$(muse_log_run_started second-run)
|
|
783
|
+
EOF
|
|
784
|
+
verdict=$(classify_muse "$state" "$id")
|
|
785
|
+
[ "$verdict" = "unknown muse-session-log" ] \
|
|
786
|
+
|| fail "a second concurrent main session left the cached verdict at '$verdict'"
|
|
787
|
+
pass "a changed Muse namespace revalidates cached session uniqueness"
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
# muse's own native sub-agents write independent run lifecycles one directory
|
|
791
|
+
# deeper, under subagent/<child-session-id>/. Folding a child's log would report
|
|
792
|
+
# the parent busy long after the parent's turn ended.
|
|
793
|
+
test_subagent_logs_are_excluded() {
|
|
794
|
+
local dir state id root verdict child
|
|
795
|
+
dir="$TMP_ROOT/subagent"
|
|
796
|
+
state="$dir/state"
|
|
797
|
+
root="$dir/sessions"
|
|
798
|
+
id=subtask
|
|
799
|
+
mkdir -p "$state"
|
|
800
|
+
|
|
801
|
+
write_session_log "$root" 2026 08 05 parent "$dir/ws" >/dev/null <<EOF
|
|
802
|
+
$(muse_log_run_started parent-run)
|
|
803
|
+
$(muse_log_run_terminal parent-run completed)
|
|
804
|
+
EOF
|
|
805
|
+
|
|
806
|
+
child="$root/2026/08/05/parent/subagent/child-session"
|
|
807
|
+
mkdir -p "$child"
|
|
808
|
+
{
|
|
809
|
+
muse_log_metadata "$dir/ws"
|
|
810
|
+
muse_log_run_started child-run
|
|
811
|
+
} > "$child/session.jsonl"
|
|
812
|
+
# Make the child log strictly newer, so a depth-blind resolver that also
|
|
813
|
+
# ranks by mtime would pick it.
|
|
814
|
+
touch "$child/session.jsonl"
|
|
815
|
+
|
|
816
|
+
# Prove the child fixture really is an open run, so the exclusion below is
|
|
817
|
+
# doing work rather than passing on an inert file.
|
|
818
|
+
[ "$(run_state "$child/session.jsonl")" = busy ] \
|
|
819
|
+
|| fail "the sub-agent fixture is not an open run, so the exclusion case would be vacuous"
|
|
820
|
+
|
|
821
|
+
printf 'sessions_root=%s\nworkspace_root=%s\nbinding_id=subagent-incarnation\n' \
|
|
822
|
+
"$root" "$dir/ws" > "$state/$id.muse-session"
|
|
823
|
+
verdict=$(classify_muse "$state" "$id")
|
|
824
|
+
[ "$verdict" != "busy muse-session-log" ] \
|
|
825
|
+
|| fail "a sub-agent's open run was folded as the parent task's busy state"
|
|
826
|
+
# And prove the parent log was genuinely resolved, so the non-busy verdict is
|
|
827
|
+
# the exclusion working rather than the binding silently failing.
|
|
828
|
+
[ "$(run_state "$root/2026/08/05/parent/session.jsonl")" = settled ] \
|
|
829
|
+
|| fail "the parent fixture did not fold as settled"
|
|
830
|
+
printf 'binding_id=subagent-incarnation\nsession_log=%s\n' \
|
|
831
|
+
"$child/session.jsonl" > "$state/$id.muse-session-current"
|
|
832
|
+
verdict=$(classify_muse "$state" "$id")
|
|
833
|
+
[ "$verdict" != "busy muse-session-log" ] \
|
|
834
|
+
|| fail "a cached sub-agent log was folded as the parent task's busy state"
|
|
835
|
+
pass "sub-agent session logs are excluded from the parent's busy fold"
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
# Every path with no positive proof of an in-flight turn must be unknown, never
|
|
839
|
+
# idle: unknown is not promoted to either boolean pole, while a wrong idle would
|
|
840
|
+
# report a working crewmate as finished.
|
|
841
|
+
test_missing_and_unreadable_bindings_are_unknown_never_idle() {
|
|
842
|
+
local dir state id verdict root
|
|
843
|
+
dir="$TMP_ROOT/unknowns"
|
|
844
|
+
state="$dir/state"
|
|
845
|
+
root="$dir/sessions"
|
|
846
|
+
id=unk
|
|
847
|
+
mkdir -p "$state"
|
|
848
|
+
|
|
849
|
+
verdict=$(classify_muse "$state" "$id")
|
|
850
|
+
[ "$verdict" = "unknown muse-session-log" ] || fail "absent binding classified '$verdict'"
|
|
851
|
+
|
|
852
|
+
printf 'sessions_root=%s\nworkspace_root=%s\n' "$root/missing" "$dir/ws" > "$state/$id.muse-session"
|
|
853
|
+
verdict=$(classify_muse "$state" "$id")
|
|
854
|
+
[ "$verdict" = "unknown muse-session-log" ] || fail "missing sessions root classified '$verdict'"
|
|
855
|
+
|
|
856
|
+
write_session_log "$root" 2026 08 05 nomatch "$dir/somewhere-else" >/dev/null <<EOF
|
|
857
|
+
$(muse_log_run_started r1)
|
|
858
|
+
EOF
|
|
859
|
+
printf 'sessions_root=%s\nworkspace_root=%s\n' "$root" "$dir/ws" > "$state/$id.muse-session"
|
|
860
|
+
verdict=$(classify_muse "$state" "$id")
|
|
861
|
+
[ "$verdict" = "unknown muse-session-log" ] || fail "unmatched workspace classified '$verdict'"
|
|
862
|
+
|
|
863
|
+
printf 'garbage\n' > "$state/$id.muse-session"
|
|
864
|
+
verdict=$(classify_muse "$state" "$id")
|
|
865
|
+
[ "$verdict" = "unknown muse-session-log" ] || fail "malformed binding classified '$verdict'"
|
|
866
|
+
pass "every unproven muse binding classifies unknown rather than idle"
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
# The credentialed multi-step smoke proved one real turn stays inside one run
|
|
870
|
+
# pair, so a settled log is a finished turn and reads idle with no opt-in. Both
|
|
871
|
+
# terminal shapes settle: a completed turn and an interrupted one.
|
|
872
|
+
test_settled_log_reads_idle() {
|
|
873
|
+
local dir state id root verdict terminal
|
|
874
|
+
dir="$TMP_ROOT/idle"
|
|
875
|
+
state="$dir/state"
|
|
876
|
+
root="$dir/sessions"
|
|
877
|
+
mkdir -p "$state"
|
|
878
|
+
|
|
879
|
+
for terminal in completed cancelled; do
|
|
880
|
+
id="idle-$terminal"
|
|
881
|
+
write_session_log "$root" 2026 08 05 "settled-$terminal" "$dir/ws-$terminal" >/dev/null <<EOF
|
|
882
|
+
$(muse_log_run_started r1)
|
|
883
|
+
$(muse_log_run_terminal r1 "$terminal")
|
|
884
|
+
EOF
|
|
885
|
+
printf 'sessions_root=%s\nworkspace_root=%s\n' \
|
|
886
|
+
"$root" "$dir/ws-$terminal" > "$state/$id.muse-session"
|
|
887
|
+
|
|
888
|
+
verdict=$(classify_muse "$state" "$id")
|
|
889
|
+
[ "$verdict" = "idle muse-session-log" ] \
|
|
890
|
+
|| fail "a log settled by a '$terminal' terminal classified '$verdict'"
|
|
891
|
+
done
|
|
892
|
+
pass "a settled session log reads idle for both completed and interrupted turns"
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
# muse records nothing, so it must trust no record source. A trusted source with
|
|
896
|
+
# no writer would seed a busy record that nothing could ever settle.
|
|
897
|
+
test_muse_trusts_no_record_sources() {
|
|
898
|
+
local out
|
|
899
|
+
out=$(
|
|
900
|
+
# shellcheck source=bin/fm-busy-lib.sh
|
|
901
|
+
. "$ROOT/bin/fm-busy-lib.sh"
|
|
902
|
+
fm_busy_sources_for_harness muse
|
|
903
|
+
)
|
|
904
|
+
[ -z "$out" ] || fail "muse trusts record sources it has no writer for: '$out'"
|
|
905
|
+
pass "muse trusts no busy record source"
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
test_detects_versioned_process_ancestor
|
|
909
|
+
test_detection_is_anchored
|
|
910
|
+
test_spawn_clears_inherited_foreign_harness_markers
|
|
911
|
+
test_spawn_launch_shape
|
|
912
|
+
test_spawn_maps_effort_and_model
|
|
913
|
+
test_spawn_refuses_without_credential
|
|
914
|
+
test_spawn_refuses_caller_only_environment_credential
|
|
915
|
+
test_spawn_accepts_stored_credential
|
|
916
|
+
test_spawn_resolves_relative_xdg_roots
|
|
917
|
+
test_spawn_refuses_secondmate
|
|
918
|
+
test_spawn_writes_busy_binding_and_teardown_removes_it
|
|
919
|
+
test_muse_escape_aliases_clear_the_composer
|
|
920
|
+
test_non_muse_escape_does_not_clear
|
|
921
|
+
test_failed_clear_is_reported
|
|
922
|
+
test_run_fold_tracks_open_and_settled_turns
|
|
923
|
+
test_nested_terminal_record_does_not_settle_a_run
|
|
924
|
+
test_binding_selects_the_matching_main_log
|
|
925
|
+
test_workspace_binding_treats_glob_characters_literally
|
|
926
|
+
test_binding_excludes_preexisting_log_when_mtimes_tie
|
|
927
|
+
test_session_log_cache_reuses_and_refreshes_binding
|
|
928
|
+
test_cached_session_revalidates_after_namespace_change
|
|
929
|
+
test_subagent_logs_are_excluded
|
|
930
|
+
test_missing_and_unreadable_bindings_are_unknown_never_idle
|
|
931
|
+
test_settled_log_reads_idle
|
|
932
|
+
test_muse_trusts_no_record_sources
|