@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,404 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# tests/fm-cursor-harness.test.sh - the portable regression for the Cursor
|
|
3
|
+
# Agent CLI crewmate/scout adapter.
|
|
4
|
+
#
|
|
5
|
+
# Cursor's identity, liveness, and busy checks are HARNESS-DEPENDENT: their
|
|
6
|
+
# verdicts come from what the vendor emits (a process name, an env marker, a
|
|
7
|
+
# transcript record). This suite pins the LOGIC with real processes, real
|
|
8
|
+
# symlink trees, and real transcript files and NO cursor installed, so CI
|
|
9
|
+
# enforces it everywhere; the live-harness guard in
|
|
10
|
+
# tests/fm-harness-liveness-drift-live-e2e.test.sh is what catches vendor drift
|
|
11
|
+
# against a real cursor-agent. Neither replaces the other.
|
|
12
|
+
#
|
|
13
|
+
# The load-bearing contracts:
|
|
14
|
+
# 1. `agent` and `node` are far too generic to trust by name. Cursor identity
|
|
15
|
+
# requires Cursor's own name or install tree in the path or argv[0].
|
|
16
|
+
# 2. An unrelated `node`/`agent` pane classifies `other`, which the liveness
|
|
17
|
+
# callers fold into `ambiguous` - NEVER `dead`.
|
|
18
|
+
# 3. Cursor's env marker outranks an inherited CLAUDECODE, because cursor does
|
|
19
|
+
# not clear it and whichever marker is tested first wins.
|
|
20
|
+
# 4. The transcript fold brackets a turn: a trailing turn_ended is idle, a
|
|
21
|
+
# later role:user is busy, and an unresolvable binding is unknown.
|
|
22
|
+
# 5. Cursor is a crewmate/scout adapter only and refuses a secondmate launch.
|
|
23
|
+
set -u
|
|
24
|
+
|
|
25
|
+
# shellcheck source=tests/lib.sh
|
|
26
|
+
. "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
|
|
27
|
+
|
|
28
|
+
# shellcheck source=bin/fm-cursor-lib.sh
|
|
29
|
+
. "$ROOT/bin/fm-cursor-lib.sh"
|
|
30
|
+
# shellcheck source=bin/fm-busy-lib.sh
|
|
31
|
+
. "$ROOT/bin/fm-busy-lib.sh"
|
|
32
|
+
|
|
33
|
+
HARNESS="$ROOT/bin/fm-harness.sh"
|
|
34
|
+
TMP_ROOT=$(fm_test_tmproot fm-cursor-harness)
|
|
35
|
+
trap 'rm -rf "$TMP_ROOT"' EXIT
|
|
36
|
+
|
|
37
|
+
# A fake cursor install tree with BOTH installed names, shaped exactly like the
|
|
38
|
+
# real one: ~/.local/share/cursor-agent/versions/<version>/cursor-agent with
|
|
39
|
+
# `cursor-agent` and the legacy `agent` alias symlinked at it.
|
|
40
|
+
make_cursor_tree() { # <root> -> echoes <bindir>
|
|
41
|
+
local root=$1 ver
|
|
42
|
+
ver="$root/share/cursor-agent/versions/2026.08.11-e8db854"
|
|
43
|
+
mkdir -p "$ver" "$root/bin"
|
|
44
|
+
printf '#!/bin/sh\necho "Start the Cursor Agent"\n' > "$ver/cursor-agent"
|
|
45
|
+
chmod +x "$ver/cursor-agent"
|
|
46
|
+
ln -sf "$ver/cursor-agent" "$root/bin/cursor-agent"
|
|
47
|
+
ln -sf "$ver/cursor-agent" "$root/bin/agent"
|
|
48
|
+
printf '%s' "$root/bin"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# --- 1. Process identity, against REAL processes ----------------------------
|
|
52
|
+
|
|
53
|
+
test_identity_accepts_cursor_shapes_rejects_lookalikes() {
|
|
54
|
+
local tree bin real_node_pid impostor_dir out
|
|
55
|
+
tree="$TMP_ROOT/tree1"; bin=$(make_cursor_tree "$tree")
|
|
56
|
+
|
|
57
|
+
# Positive: the two real shapes measured on a live pane. tmux reports the
|
|
58
|
+
# pane command as a bare `node` while `ps -o comm=` carries the install path,
|
|
59
|
+
# so BOTH must identify, and neither field may be load-bearing alone.
|
|
60
|
+
fm_cursor_process_matches node '' "$bin/cursor-agent" \
|
|
61
|
+
|| fail "tmux's node + cursor-agent argv[0] must identify as cursor"
|
|
62
|
+
fm_cursor_process_matches "$bin/cursor-agent" '' '' \
|
|
63
|
+
|| fail "ps's cursor-agent install path must identify as cursor"
|
|
64
|
+
fm_cursor_process_matches cursor-agent '' '' \
|
|
65
|
+
|| fail "a bare cursor-agent command name must identify as cursor"
|
|
66
|
+
# The legacy alias identifies only THROUGH the install tree it resolves into.
|
|
67
|
+
fm_cursor_process_matches agent '' "$bin/agent" \
|
|
68
|
+
|| fail "the legacy agent alias resolving into cursor's tree must identify"
|
|
69
|
+
|
|
70
|
+
# Negative: a REAL unrelated node process, and a REAL executable named agent.
|
|
71
|
+
impostor_dir="$TMP_ROOT/impostor"; mkdir -p "$impostor_dir"
|
|
72
|
+
printf '#!/bin/sh\nsleep 30\n' > "$impostor_dir/agent"; chmod +x "$impostor_dir/agent"
|
|
73
|
+
"$impostor_dir/agent" & local impostor_pid=$!
|
|
74
|
+
if command -v node >/dev/null 2>&1; then
|
|
75
|
+
node -e 'setTimeout(function(){}, 30000)' & real_node_pid=$!
|
|
76
|
+
out=$(LC_ALL=C ps -p "$real_node_pid" -o comm= 2>/dev/null || true)
|
|
77
|
+
if [ -n "$out" ]; then
|
|
78
|
+
! fm_cursor_process_matches "$out" '' "$out" \
|
|
79
|
+
|| fail "a REAL unrelated node process must not identify as cursor (comm='$out')"
|
|
80
|
+
fi
|
|
81
|
+
kill "$real_node_pid" 2>/dev/null || true
|
|
82
|
+
fi
|
|
83
|
+
out=$(LC_ALL=C ps -p "$impostor_pid" -o comm= 2>/dev/null || true)
|
|
84
|
+
if [ -n "$out" ]; then
|
|
85
|
+
! fm_cursor_process_matches "$out" '' "$out" \
|
|
86
|
+
|| fail "a REAL unrelated executable named agent must not identify (comm='$out')"
|
|
87
|
+
fi
|
|
88
|
+
kill "$impostor_pid" 2>/dev/null || true
|
|
89
|
+
|
|
90
|
+
# A path with a directory component merely named `agent/` or
|
|
91
|
+
# `cursor-agent/` is never enough.
|
|
92
|
+
! fm_cursor_process_matches node '' /opt/agent/bin/runner \
|
|
93
|
+
|| fail "an 'agent/' directory component must not identify as cursor"
|
|
94
|
+
! fm_cursor_process_matches node '' /tmp/cursor-agent/bin/runner \
|
|
95
|
+
|| fail "a cursor-agent directory outside the versioned install tree must not identify"
|
|
96
|
+
! fm_cursor_process_matches MainThread '' '' \
|
|
97
|
+
|| fail "a bare MainThread with no cursor evidence must not identify"
|
|
98
|
+
! fm_cursor_process_matches node '' '' \
|
|
99
|
+
|| fail "a node with no argv[0] evidence must not identify"
|
|
100
|
+
pass "fm_cursor_process_matches: cursor's real shapes identify; real node/agent lookalikes do not"
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
test_identity_signals_diverge() {
|
|
104
|
+
# Two independent signals carry a positive verdict: the executable NAME and
|
|
105
|
+
# the install-tree PATH. Drive them apart so neither is silently load-bearing:
|
|
106
|
+
# a cursor-named executable OUTSIDE any cursor tree, and a non-cursor-named
|
|
107
|
+
# executable INSIDE one. Both must identify.
|
|
108
|
+
local odd="$TMP_ROOT/odd" tree bin
|
|
109
|
+
mkdir -p "$odd"
|
|
110
|
+
printf '#!/bin/sh\nexit 0\n' > "$odd/cursor-agent"; chmod +x "$odd/cursor-agent"
|
|
111
|
+
fm_cursor_process_matches "$odd/cursor-agent" '' '' \
|
|
112
|
+
|| fail "name signal alone (cursor-agent outside any cursor tree) must identify"
|
|
113
|
+
tree="$TMP_ROOT/tree2"; bin=$(make_cursor_tree "$tree")
|
|
114
|
+
fm_cursor_process_matches agent '' "$bin/agent" \
|
|
115
|
+
|| fail "path signal alone (alias named 'agent' inside cursor's tree) must identify"
|
|
116
|
+
# And the divergence itself: these two really are different signals.
|
|
117
|
+
[ "$(basename "$odd/cursor-agent")" = cursor-agent ] \
|
|
118
|
+
|| fail "name-signal fixture lost its cursor-agent basename"
|
|
119
|
+
case "/$(fm_cursor_canonical_path "$bin/agent")/" in
|
|
120
|
+
*/cursor-agent/*) : ;;
|
|
121
|
+
*) fail "path-signal fixture must canonicalize into a cursor-agent tree" ;;
|
|
122
|
+
esac
|
|
123
|
+
pass "fm_cursor_process_matches: name and install-tree signals each carry a verdict alone"
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
test_verify_executable_refuses_unrelated_agent() {
|
|
127
|
+
local tree bin odd="$TMP_ROOT/verify"
|
|
128
|
+
tree="$TMP_ROOT/tree3"; bin=$(make_cursor_tree "$tree")
|
|
129
|
+
mkdir -p "$odd"
|
|
130
|
+
printf '#!/bin/sh\necho unrelated\n' > "$odd/agent"; chmod +x "$odd/agent"
|
|
131
|
+
fm_cursor_verify_executable "$bin/agent" \
|
|
132
|
+
|| fail "the alias inside cursor's install tree must verify"
|
|
133
|
+
! fm_cursor_verify_executable "$odd/agent" \
|
|
134
|
+
|| fail "an unrelated executable named agent must NOT verify as cursor"
|
|
135
|
+
pass "fm_cursor_verify_executable: the legacy alias is accepted only with cursor evidence"
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
test_resolve_binary_prefers_stable_path() {
|
|
139
|
+
# The canonical path carries a version cursor replaces on its own auto-update,
|
|
140
|
+
# so resolution must print the STABLE launcher even though identity is proven
|
|
141
|
+
# through canonicalization.
|
|
142
|
+
local tree bin out
|
|
143
|
+
tree="$TMP_ROOT/tree4"; bin=$(make_cursor_tree "$tree")
|
|
144
|
+
out=$(PATH="$bin:$PATH" fm_cursor_resolve_binary) \
|
|
145
|
+
|| fail "resolve must succeed when cursor-agent is on PATH"
|
|
146
|
+
[ "$out" = "$bin/cursor-agent" ] \
|
|
147
|
+
|| fail "resolve must print the stable launcher, got '$out'"
|
|
148
|
+
case "$out" in *versions*) fail "resolve must not pin the versioned install path" ;; esac
|
|
149
|
+
pass "fm_cursor_resolve_binary: prints the stable launcher, not the versioned target"
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
# --- 2. tmux pane liveness ---------------------------------------------------
|
|
153
|
+
|
|
154
|
+
test_tmux_classifies_cursor_pane_without_inferring_dead() {
|
|
155
|
+
local tree bin
|
|
156
|
+
tree="$TMP_ROOT/tree5"; bin=$(make_cursor_tree "$tree")
|
|
157
|
+
# shellcheck source=bin/backends/tmux.sh
|
|
158
|
+
( FM_BACKEND_LIB_DIR="$ROOT/bin"; . "$ROOT/bin/backends/tmux.sh"
|
|
159
|
+
[ "$(fm_backend_tmux_classify_process_name node "$bin/cursor-agent")" = agent ] \
|
|
160
|
+
|| fail "a cursor pane reported as node must classify agent"
|
|
161
|
+
[ "$(fm_backend_tmux_classify_process_name '' "$bin/cursor-agent")" = agent ] \
|
|
162
|
+
|| fail "the argv[0]-only call must classify a cursor pane agent"
|
|
163
|
+
# The safety half: an unrelated node is `other`, and the callers turn
|
|
164
|
+
# `other` into `ambiguous`, never `dead`.
|
|
165
|
+
[ "$(fm_backend_tmux_classify_process_name node /usr/bin/node)" = other ] \
|
|
166
|
+
|| fail "an unrelated node must stay 'other', never agent"
|
|
167
|
+
[ "$(fm_backend_tmux_classify_process_name agent /usr/local/bin/agent)" = other ] \
|
|
168
|
+
|| fail "an unrelated agent must stay 'other', never agent"
|
|
169
|
+
# Neighbours must not regress.
|
|
170
|
+
[ "$(fm_backend_tmux_classify_process_name claude '')" = agent ] || fail "claude regressed"
|
|
171
|
+
[ "$(fm_backend_tmux_classify_process_name zsh '')" = shell ] || fail "zsh regressed"
|
|
172
|
+
) || exit 1
|
|
173
|
+
pass "tmux liveness: a cursor pane is agent; an unrelated node/agent is other, never dead"
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
# --- 3. Detection ordering ---------------------------------------------------
|
|
177
|
+
|
|
178
|
+
test_cursor_marker_outranks_inherited_claudecode() {
|
|
179
|
+
local out
|
|
180
|
+
# This is the exact hazard: cursor does NOT clear an inherited CLAUDECODE, so
|
|
181
|
+
# a cursor worker under a claude primary carries both markers.
|
|
182
|
+
out=$(CLAUDECODE=1 CURSOR_AGENT=1 "$HARNESS")
|
|
183
|
+
[ "$out" = cursor ] || fail "CLAUDECODE + CURSOR_AGENT must detect cursor, got '$out'"
|
|
184
|
+
out=$(CLAUDECODE=1 CURSOR_INVOKED_AS=cursor-agent "$HARNESS")
|
|
185
|
+
[ "$out" = cursor ] || fail "CLAUDECODE + CURSOR_INVOKED_AS must detect cursor, got '$out'"
|
|
186
|
+
# Both cursor markers stand alone, and neither steals a plain claude session.
|
|
187
|
+
out=$(env -u CLAUDECODE CURSOR_AGENT=1 "$HARNESS")
|
|
188
|
+
[ "$out" = cursor ] || fail "CURSOR_AGENT alone must detect cursor, got '$out'"
|
|
189
|
+
out=$(env -u CURSOR_AGENT -u CURSOR_INVOKED_AS CLAUDECODE=1 "$HARNESS")
|
|
190
|
+
[ "$out" = claude ] || fail "CLAUDECODE alone must still detect claude, got '$out'"
|
|
191
|
+
# A CURSOR_* variable that is not the invocation identity proves nothing.
|
|
192
|
+
out=$(env -u CURSOR_AGENT CLAUDECODE=1 CURSOR_API_ENDPOINT=https://example \
|
|
193
|
+
CURSOR_INVOKED_AS=something-else "$HARNESS")
|
|
194
|
+
[ "$out" = claude ] \
|
|
195
|
+
|| fail "an unrelated CURSOR_* setting must not claim the cursor identity, got '$out'"
|
|
196
|
+
pass "fm-harness.sh: cursor's marker outranks an inherited CLAUDECODE"
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
test_harness_ancestry_rejects_cursor_named_node_script() {
|
|
200
|
+
command -v node >/dev/null 2>&1 || return 0
|
|
201
|
+
local helper="$TMP_ROOT/cursor-agent-helper.js" out
|
|
202
|
+
cat > "$helper" <<'JS'
|
|
203
|
+
const { spawnSync } = require('child_process');
|
|
204
|
+
const env = { ...process.env };
|
|
205
|
+
delete env.CURSOR_AGENT;
|
|
206
|
+
delete env.CURSOR_INVOKED_AS;
|
|
207
|
+
delete env.CLAUDECODE;
|
|
208
|
+
delete env.PI_CODING_AGENT;
|
|
209
|
+
delete env.GROK_AGENT;
|
|
210
|
+
const result = spawnSync(process.argv[2], [], { encoding: 'utf8', env });
|
|
211
|
+
process.stdout.write(result.stdout);
|
|
212
|
+
process.stderr.write(result.stderr);
|
|
213
|
+
process.exit(result.status === null ? 1 : result.status);
|
|
214
|
+
JS
|
|
215
|
+
out=$(node "$helper" "$HARNESS")
|
|
216
|
+
[ "$out" != cursor ] \
|
|
217
|
+
|| fail "a node script merely containing cursor-agent in its filename must not identify as cursor"
|
|
218
|
+
pass "fm-harness.sh: cursor-like node script names do not establish ancestry identity"
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
# --- 4. The transcript busy fold --------------------------------------------
|
|
222
|
+
|
|
223
|
+
# Build a bound cursor workspace: a project dir keyed by .workspace-trusted, a
|
|
224
|
+
# conversation transcript, and the per-task sidecar fm-spawn writes.
|
|
225
|
+
make_cursor_binding() { # <case> <conversation-id> <transcript-body> -> echoes <state-dir>
|
|
226
|
+
local case_name=$1 conv=$2 body=$3 root ws proj state
|
|
227
|
+
root="$TMP_ROOT/$case_name/projects"
|
|
228
|
+
ws="$TMP_ROOT/$case_name/worktree"
|
|
229
|
+
proj="$root/some-opaque-slug-$case_name"
|
|
230
|
+
state="$TMP_ROOT/$case_name/state"
|
|
231
|
+
mkdir -p "$proj/agent-transcripts/$conv" "$ws" "$state"
|
|
232
|
+
printf '{\n "workspacePath": "%s",\n "trustMethod": "cli-flag"\n}\n' "$ws" \
|
|
233
|
+
> "$proj/.workspace-trusted"
|
|
234
|
+
printf '%s' "$body" > "$proj/agent-transcripts/$conv/$conv.jsonl"
|
|
235
|
+
printf 'projects_root=%s\nworkspace_root=%s\n' "$root" "$ws" > "$state/task.cursor-session"
|
|
236
|
+
printf '%s' "$state"
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
test_transcript_fold_brackets_a_turn() {
|
|
240
|
+
local state out
|
|
241
|
+
# Open turn: a role:user record with no close after it.
|
|
242
|
+
state=$(make_cursor_binding open conv-a '{"role":"user"}
|
|
243
|
+
{"role":"assistant"}
|
|
244
|
+
')
|
|
245
|
+
out=$(fm_busy_classify tmux none cursor task "$state")
|
|
246
|
+
[ "$out" = "busy cursor-transcript" ] || fail "an open turn must be busy, got '$out'"
|
|
247
|
+
|
|
248
|
+
# Closed turn.
|
|
249
|
+
state=$(make_cursor_binding closed conv-b '{"role":"user"}
|
|
250
|
+
{"role":"assistant"}
|
|
251
|
+
{"type":"turn_ended","status":"success"}
|
|
252
|
+
')
|
|
253
|
+
out=$(fm_busy_classify tmux none cursor task "$state")
|
|
254
|
+
[ "$out" = "idle cursor-transcript" ] || fail "a closed turn must be idle, got '$out'"
|
|
255
|
+
|
|
256
|
+
# An ABORTED close is still a close. This is the case Claude's Stop hook
|
|
257
|
+
# misses, and it is why this source is preferred over a rendered footer.
|
|
258
|
+
state=$(make_cursor_binding aborted conv-c '{"role":"user"}
|
|
259
|
+
{"type":"turn_ended","status":"aborted","error":"User aborted/interrupted manually."}
|
|
260
|
+
')
|
|
261
|
+
out=$(fm_busy_classify tmux none cursor task "$state")
|
|
262
|
+
[ "$out" = "idle cursor-transcript" ] || fail "an aborted close must be idle, got '$out'"
|
|
263
|
+
|
|
264
|
+
# A NEW turn opened after a close reopens it.
|
|
265
|
+
state=$(make_cursor_binding reopened conv-d '{"role":"user"}
|
|
266
|
+
{"type":"turn_ended","status":"success"}
|
|
267
|
+
{"role":"user"}
|
|
268
|
+
')
|
|
269
|
+
out=$(fm_busy_classify tmux none cursor task "$state")
|
|
270
|
+
[ "$out" = "busy cursor-transcript" ] || fail "a turn reopened after a close must be busy, got '$out'"
|
|
271
|
+
pass "cursor transcript fold: role:user opens a turn, turn_ended closes it, aborts included"
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
test_transcript_fold_ignores_lifecycle_tokens_in_message_text() {
|
|
275
|
+
local state out log jq_bin awk_bin no_jq_bin
|
|
276
|
+
state=$(make_cursor_binding quoted-lifecycle conv-quoted '{"role":"user","message":"literal {\"type\":\"turn_ended\"} and \"role\":\"user\""}
|
|
277
|
+
')
|
|
278
|
+
out=$(fm_busy_classify tmux none cursor task "$state")
|
|
279
|
+
[ "$out" = "busy cursor-transcript" ] \
|
|
280
|
+
|| fail "lifecycle-shaped message text must not close an active turn, got '$out'"
|
|
281
|
+
|
|
282
|
+
jq_bin=$(command -v jq) || fail "jq is required to exercise Cursor's primary transcript parser"
|
|
283
|
+
[ -x "$jq_bin" ] || fail "jq must be executable"
|
|
284
|
+
state=$(make_cursor_binding malformed-close conv-malformed '{"role":"user"}
|
|
285
|
+
{"type":"turn_ended",broken}
|
|
286
|
+
')
|
|
287
|
+
log=$(fm_busy_cursor_transcript "$state" task) \
|
|
288
|
+
|| fail "the malformed-close transcript fixture must resolve"
|
|
289
|
+
out=$(fm_busy_cursor_turn_state "$log")
|
|
290
|
+
[ "$out" = busy ] \
|
|
291
|
+
|| fail "jq parser must keep an open turn busy after a malformed close, got '$out'"
|
|
292
|
+
|
|
293
|
+
awk_bin=$(command -v awk) || fail "awk is required to exercise Cursor's fallback transcript parser"
|
|
294
|
+
no_jq_bin="$TMP_ROOT/no-jq-bin"
|
|
295
|
+
mkdir -p "$no_jq_bin"
|
|
296
|
+
ln -sf "$awk_bin" "$no_jq_bin/awk"
|
|
297
|
+
out=$(PATH="$no_jq_bin" fm_busy_cursor_turn_state "$log")
|
|
298
|
+
[ "$out" = busy ] \
|
|
299
|
+
|| fail "no-jq parser must keep an open turn busy after a malformed close, got '$out'"
|
|
300
|
+
pass "cursor transcript fold: malformed closes cannot settle through either parser"
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
test_transcript_fold_handles_partially_appended_records() {
|
|
304
|
+
local state out
|
|
305
|
+
state=$(make_cursor_binding closed-partial conv-partial-a '{"role":"user"}
|
|
306
|
+
{"type":"turn_ended","status":"success"}
|
|
307
|
+
{"role":"user"
|
|
308
|
+
')
|
|
309
|
+
out=$(fm_busy_classify tmux none cursor task "$state")
|
|
310
|
+
[ "$out" = "unknown cursor-transcript" ] \
|
|
311
|
+
|| fail "a partial record after a close must be unknown, got '$out'"
|
|
312
|
+
|
|
313
|
+
state=$(make_cursor_binding closed-complete conv-partial-b '{"role":"user"}
|
|
314
|
+
{"type":"turn_ended","status":"success"}
|
|
315
|
+
')
|
|
316
|
+
out=$(fm_busy_classify tmux none cursor task "$state")
|
|
317
|
+
[ "$out" = "idle cursor-transcript" ] \
|
|
318
|
+
|| fail "a completed turn without trailing garbage must be idle, got '$out'"
|
|
319
|
+
|
|
320
|
+
state=$(make_cursor_binding open-partial conv-partial-c '{"role":"user"}
|
|
321
|
+
{"role":"assistant"
|
|
322
|
+
')
|
|
323
|
+
out=$(fm_busy_classify tmux none cursor task "$state")
|
|
324
|
+
[ "$out" = "busy cursor-transcript" ] \
|
|
325
|
+
|| fail "a partial record after an open must remain busy, got '$out'"
|
|
326
|
+
pass "cursor transcript fold: partial appends never make an active turn idle"
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
test_transcript_fold_is_unknown_never_idle_when_unresolvable() {
|
|
330
|
+
local state out empty_state
|
|
331
|
+
# A record-free transcript proves nothing either way.
|
|
332
|
+
state=$(make_cursor_binding norecords conv-e '{"type":"session_meta"}
|
|
333
|
+
')
|
|
334
|
+
out=$(fm_busy_classify tmux none cursor task "$state")
|
|
335
|
+
[ "$out" = "unknown cursor-transcript" ] || fail "a record-free transcript must be unknown, got '$out'"
|
|
336
|
+
|
|
337
|
+
# No sidecar at all.
|
|
338
|
+
empty_state="$TMP_ROOT/nosidecar"; mkdir -p "$empty_state"
|
|
339
|
+
out=$(fm_busy_classify tmux none cursor task "$empty_state")
|
|
340
|
+
[ "$out" = "unknown cursor-transcript" ] || fail "a missing sidecar must be unknown, got '$out'"
|
|
341
|
+
|
|
342
|
+
# A sidecar pointing at a workspace no project directory claims.
|
|
343
|
+
mkdir -p "$TMP_ROOT/unclaimed/state" "$TMP_ROOT/unclaimed/projects"
|
|
344
|
+
printf 'projects_root=%s\nworkspace_root=%s\n' \
|
|
345
|
+
"$TMP_ROOT/unclaimed/projects" "$TMP_ROOT/unclaimed/nowhere" \
|
|
346
|
+
> "$TMP_ROOT/unclaimed/state/task.cursor-session"
|
|
347
|
+
out=$(fm_busy_classify tmux none cursor task "$TMP_ROOT/unclaimed/state")
|
|
348
|
+
[ "$out" = "unknown cursor-transcript" ] || fail "an unclaimed workspace must be unknown, got '$out'"
|
|
349
|
+
pass "cursor transcript fold: an unresolvable binding is unknown, never idle"
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
test_transcript_binding_matches_workspace_exactly() {
|
|
353
|
+
# The binding matches the recorded absolute workspacePath, NOT a reconstructed
|
|
354
|
+
# slug and NOT a prefix - otherwise a nested worktree would fold its parent's
|
|
355
|
+
# transcript. The fixture slug is deliberately opaque so a slug-rebuilding
|
|
356
|
+
# implementation cannot pass this.
|
|
357
|
+
local state out proj
|
|
358
|
+
state=$(make_cursor_binding nested conv-f '{"role":"user"}
|
|
359
|
+
')
|
|
360
|
+
out=$(fm_busy_classify tmux none cursor task "$state")
|
|
361
|
+
[ "$out" = "busy cursor-transcript" ] || fail "exact workspace match must resolve, got '$out'"
|
|
362
|
+
# Point the project at a PREFIX of the bound workspace: must no longer match.
|
|
363
|
+
proj=$(dirname "$state")/projects/some-opaque-slug-nested
|
|
364
|
+
printf '{\n "workspacePath": "%s"\n}\n' "$(dirname "$state")/worktre" > "$proj/.workspace-trusted"
|
|
365
|
+
out=$(fm_busy_classify tmux none cursor task "$state")
|
|
366
|
+
[ "$out" = "unknown cursor-transcript" ] \
|
|
367
|
+
|| fail "a prefix of the workspace path must NOT bind, got '$out'"
|
|
368
|
+
pass "cursor transcript binding: exact recorded workspacePath only, never a prefix or rebuilt slug"
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
test_transcript_fold_excludes_prior_conversations() {
|
|
372
|
+
# A relaunch in a reused worktree must fold ITS turn, not its predecessor's.
|
|
373
|
+
local state proj out
|
|
374
|
+
state=$(make_cursor_binding prior conv-old '{"role":"user"}
|
|
375
|
+
')
|
|
376
|
+
proj="$TMP_ROOT/prior/projects/some-opaque-slug-prior"
|
|
377
|
+
printf 'prior_conversation=conv-old\n' >> "$state/task.cursor-session"
|
|
378
|
+
# Only the retired conversation exists, so nothing new resolves.
|
|
379
|
+
out=$(fm_busy_classify tmux none cursor task "$state")
|
|
380
|
+
[ "$out" = "unknown cursor-transcript" ] \
|
|
381
|
+
|| fail "a retired conversation must not be folded, got '$out'"
|
|
382
|
+
# The relaunched pane's own conversation resolves and wins.
|
|
383
|
+
mkdir -p "$proj/agent-transcripts/conv-new"
|
|
384
|
+
printf '{"role":"user"}\n{"type":"turn_ended","status":"success"}\n' \
|
|
385
|
+
> "$proj/agent-transcripts/conv-new/conv-new.jsonl"
|
|
386
|
+
out=$(fm_busy_classify tmux none cursor task "$state")
|
|
387
|
+
[ "$out" = "idle cursor-transcript" ] \
|
|
388
|
+
|| fail "the relaunched pane's own conversation must resolve, got '$out'"
|
|
389
|
+
pass "cursor transcript fold: a prior conversation is excluded so a relaunch folds its own turn"
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
test_identity_accepts_cursor_shapes_rejects_lookalikes
|
|
393
|
+
test_identity_signals_diverge
|
|
394
|
+
test_verify_executable_refuses_unrelated_agent
|
|
395
|
+
test_resolve_binary_prefers_stable_path
|
|
396
|
+
test_tmux_classifies_cursor_pane_without_inferring_dead
|
|
397
|
+
test_cursor_marker_outranks_inherited_claudecode
|
|
398
|
+
test_harness_ancestry_rejects_cursor_named_node_script
|
|
399
|
+
test_transcript_fold_brackets_a_turn
|
|
400
|
+
test_transcript_fold_ignores_lifecycle_tokens_in_message_text
|
|
401
|
+
test_transcript_fold_handles_partially_appended_records
|
|
402
|
+
test_transcript_fold_is_unknown_never_idle_when_unresolvable
|
|
403
|
+
test_transcript_binding_matches_workspace_exactly
|
|
404
|
+
test_transcript_fold_excludes_prior_conversations
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Opt-in live guard for Cursor Agent CLI as a firstmate PRIMARY.
|
|
3
|
+
#
|
|
4
|
+
# The Cursor primary integration rests on facts only the real cursor-agent can
|
|
5
|
+
# answer: that its `stop` hook is awaited so a park can hold the turn boundary,
|
|
6
|
+
# that a returned followup_message genuinely starts another turn, that
|
|
7
|
+
# `sessionStart` carries additional_context into model context, that Cursor's own
|
|
8
|
+
# process appears in the session-lock ancestry, and that an idle Cursor composer
|
|
9
|
+
# can be proven empty so an away-mode escalation can be delivered. A stub can
|
|
10
|
+
# only confirm the assumption already written into the stub, so this exercises
|
|
11
|
+
# the installed binary end to end.
|
|
12
|
+
#
|
|
13
|
+
# tests/fm-cursor-primary.test.sh and the Cursor cases in
|
|
14
|
+
# tests/fm-tmux-agent-liveness.test.sh are the portable regressions that run
|
|
15
|
+
# everywhere; this is the harness-and-credential-gated counterpart. Run it after
|
|
16
|
+
# every Cursor upgrade and before trusting refreshed per-harness evidence in
|
|
17
|
+
# docs/verification/supervision.md and docs/verification/runtime-backends.md.
|
|
18
|
+
#
|
|
19
|
+
# Isolation: a throwaway firstmate home under a temp dir, a private tmux socket,
|
|
20
|
+
# and a Cursor workspace Cursor has never seen. It never touches the fleet's tmux
|
|
21
|
+
# server, never writes a user-scope or global hook, and never runs against a live
|
|
22
|
+
# home. Cursor still records its own per-project transcript under
|
|
23
|
+
# ~/.cursor/projects/<slug of the temp path>, which is keyed to the throwaway
|
|
24
|
+
# path and is the only state left outside the temp dir.
|
|
25
|
+
set -u
|
|
26
|
+
|
|
27
|
+
if [ "${FM_CURSOR_PRIMARY_LIVE_E2E:-0}" != 1 ]; then
|
|
28
|
+
echo "skip: set FM_CURSOR_PRIMARY_LIVE_E2E=1 to run the live Cursor primary guard"
|
|
29
|
+
exit 0
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
# shellcheck source=tests/lib.sh
|
|
33
|
+
. "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
|
|
34
|
+
|
|
35
|
+
CURSOR_BIN=${FM_CURSOR_BIN:-$(command -v cursor-agent || true)}
|
|
36
|
+
[ -n "$CURSOR_BIN" ] && [ -x "$CURSOR_BIN" ] \
|
|
37
|
+
|| fail "cursor-agent not found; install it or set FM_CURSOR_BIN. This guard refuses to pass without checking the real harness."
|
|
38
|
+
REAL_TMUX=$(command -v tmux) || fail "tmux not found"
|
|
39
|
+
command -v jq >/dev/null 2>&1 || fail "jq not found"
|
|
40
|
+
CURSOR_VERSION=$("$CURSOR_BIN" --version 2>/dev/null | head -1)
|
|
41
|
+
[ -n "$CURSOR_VERSION" ] || fail "cursor-agent did not report a version; refusing to claim a verified result"
|
|
42
|
+
printf 'harness: cursor-agent %s\n' "$CURSOR_VERSION"
|
|
43
|
+
|
|
44
|
+
HARNESS_LABEL="cursor-agent $CURSOR_VERSION"
|
|
45
|
+
harness_fail() { # <message>
|
|
46
|
+
fail "$1 [harness: $HARNESS_LABEL]"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
SOCKET="fm-cursor-primary-$$"
|
|
50
|
+
LAB=$(mktemp -d "${TMPDIR:-/tmp}/fm-cursor-primary.XXXXXX")
|
|
51
|
+
HOME_DIR="$LAB/home"
|
|
52
|
+
MARKER="FM_CURSOR_LIVE_MARKER_$$"
|
|
53
|
+
|
|
54
|
+
cleanup_all() {
|
|
55
|
+
"$REAL_TMUX" -L "$SOCKET" kill-server >/dev/null 2>&1 || true
|
|
56
|
+
[ -n "${LAB:-}" ] && rm -rf "$LAB"
|
|
57
|
+
}
|
|
58
|
+
trap cleanup_all EXIT
|
|
59
|
+
|
|
60
|
+
# A plain (non-worktree) checkout of the CURRENT working tree, so the guard
|
|
61
|
+
# tests the code under review rather than whatever is committed.
|
|
62
|
+
mkdir -p "$HOME_DIR"
|
|
63
|
+
(cd "$ROOT" && tar --exclude=.git --exclude=state --exclude=projects --exclude=node_modules -cf - .) \
|
|
64
|
+
| (cd "$HOME_DIR" && tar -xf -) \
|
|
65
|
+
|| harness_fail "could not stage the working tree into the throwaway home"
|
|
66
|
+
git init -q "$HOME_DIR"
|
|
67
|
+
git -C "$HOME_DIR" add -A >/dev/null 2>&1 || true
|
|
68
|
+
git -C "$HOME_DIR" -c user.email=fmtest@example.invalid -c user.name=fmtest \
|
|
69
|
+
commit -q -m "live-e2e fixture" >/dev/null 2>&1 || true
|
|
70
|
+
[ "$(git -C "$HOME_DIR" rev-parse --git-dir)" = "$(git -C "$HOME_DIR" rev-parse --git-common-dir)" ] \
|
|
71
|
+
|| harness_fail "the fixture home must be a plain checkout for primary scope to match"
|
|
72
|
+
[ -f "$HOME_DIR/.cursor/hooks.json" ] \
|
|
73
|
+
|| harness_fail "the working tree ships no .cursor/hooks.json; there is nothing to verify"
|
|
74
|
+
|
|
75
|
+
mkdir -p "$HOME_DIR/state" "$HOME_DIR/data" "$HOME_DIR/config"
|
|
76
|
+
# A unique token the session-start digest must carry into model context.
|
|
77
|
+
printf '# Captain\n\nLive marker: %s\n' "$MARKER" > "$HOME_DIR/data/captain.md"
|
|
78
|
+
printf '# Backlog\n\n- live probe\n' > "$HOME_DIR/data/backlog.md"
|
|
79
|
+
# One in-flight task so supervision is genuinely needed, plus a captain-relevant
|
|
80
|
+
# status line the watcher's own backstop must surface as a real wake.
|
|
81
|
+
cat > "$HOME_DIR/state/probe.meta" <<EOF
|
|
82
|
+
id=probe
|
|
83
|
+
project=probe
|
|
84
|
+
harness=cursor
|
|
85
|
+
backend=tmux
|
|
86
|
+
window=fm-probe
|
|
87
|
+
EOF
|
|
88
|
+
printf 'blocked: fixture needs a decision\n' > "$HOME_DIR/state/probe.status"
|
|
89
|
+
|
|
90
|
+
"$REAL_TMUX" -L "$SOCKET" new-session -d -s primary -x 220 -y 60 -c "$HOME_DIR" \
|
|
91
|
+
"cd '$HOME_DIR' && FM_HOME='$HOME_DIR' FM_HEARTBEAT=30 FM_HEARTBEAT_MAX=30 exec '$CURSOR_BIN' --trust --yolo --workspace '$HOME_DIR'" \
|
|
92
|
+
|| harness_fail "could not start the private tmux server"
|
|
93
|
+
|
|
94
|
+
pane_text() {
|
|
95
|
+
"$REAL_TMUX" -L "$SOCKET" capture-pane -p -t primary 2>/dev/null
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
wait_for_file() { # <path> <seconds> <what>
|
|
99
|
+
local path=$1 limit=$2 what=$3 i=0
|
|
100
|
+
while [ "$i" -lt "$((limit * 2))" ]; do
|
|
101
|
+
[ -e "$path" ] && return 0
|
|
102
|
+
sleep 0.5
|
|
103
|
+
i=$((i + 1))
|
|
104
|
+
done
|
|
105
|
+
harness_fail "$what did not appear within ${limit}s"
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
wait_for_pane() { # <needle> <seconds> <what>
|
|
109
|
+
local needle=$1 limit=$2 what=$3 i=0
|
|
110
|
+
while [ "$i" -lt "$((limit * 2))" ]; do
|
|
111
|
+
case "$(pane_text)" in *"$needle"*) return 0 ;; esac
|
|
112
|
+
sleep 0.5
|
|
113
|
+
i=$((i + 1))
|
|
114
|
+
done
|
|
115
|
+
printf 'pane at failure:\n%s\n' "$(pane_text)" >&2
|
|
116
|
+
harness_fail "$what did not appear within ${limit}s"
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
submit() { # <text>
|
|
120
|
+
"$REAL_TMUX" -L "$SOCKET" send-keys -t primary -l "$1"
|
|
121
|
+
sleep 1
|
|
122
|
+
"$REAL_TMUX" -L "$SOCKET" send-keys -t primary Enter
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
# --- 1. run-tier session start ----------------------------------------------
|
|
126
|
+
|
|
127
|
+
wait_for_file "$HOME_DIR/state/.lock" 180 "the fleet session lock"
|
|
128
|
+
LOCK_PID=$(cat "$HOME_DIR/state/.lock" 2>/dev/null)
|
|
129
|
+
PANE_PID=$("$REAL_TMUX" -L "$SOCKET" display-message -p -t primary '#{pane_pid}' 2>/dev/null)
|
|
130
|
+
[ -n "$LOCK_PID" ] && [ "$LOCK_PID" = "$PANE_PID" ] \
|
|
131
|
+
|| harness_fail "the session lock must be owned by the Cursor pane process (lock=$LOCK_PID pane=$PANE_PID); Cursor is not resolving in the session-lock ancestry"
|
|
132
|
+
pass "cursor primary: the sessionStart hook takes the fleet lock as the Cursor process itself"
|
|
133
|
+
|
|
134
|
+
wait_for_file "$HOME_DIR/state/.session-start-complete" 240 "the completed session-start record"
|
|
135
|
+
pass "cursor primary: the run-tier session start completes every stage"
|
|
136
|
+
|
|
137
|
+
submit "Answer only from the context you were given at session start. Do not run any command. Reply with the exact live marker token you can see, and nothing else."
|
|
138
|
+
wait_for_pane "$MARKER" 180 "the session-start digest marker quoted back from model context"
|
|
139
|
+
pass "cursor primary: sessionStart additional_context reaches model context before the first turn"
|
|
140
|
+
|
|
141
|
+
# --- 2. the stop-hook park ---------------------------------------------------
|
|
142
|
+
|
|
143
|
+
# The turn that just ended must have parked, armed a watcher, and delivered a
|
|
144
|
+
# real wake as one follow-up carrying the operational watcher kind.
|
|
145
|
+
wait_for_pane "FIRSTMATE_OP: v1 watcher:" 300 "a watcher wake delivered as a stop-hook follow-up"
|
|
146
|
+
pass "cursor primary: the stop-hook park delivers a real watcher wake as one follow-up"
|
|
147
|
+
|
|
148
|
+
wait_for_file "$HOME_DIR/state/.cursor-park-owner" 60 "the park ownership record"
|
|
149
|
+
PARK_PID=$(sed -n 's/^seq=[0-9][0-9]* pid=\([0-9][0-9]*\) .*/\1/p' "$HOME_DIR/state/.cursor-park-owner")
|
|
150
|
+
[ -n "$PARK_PID" ] || harness_fail "the park never recorded an owner pid"
|
|
151
|
+
BEAT="$HOME_DIR/state/.last-watcher-beat"
|
|
152
|
+
[ -e "$BEAT" ] || harness_fail "the park armed no watcher: there is no liveness beacon"
|
|
153
|
+
pass "cursor primary: the park owns exactly one arm cycle with a live watcher beacon"
|
|
154
|
+
|
|
155
|
+
# --- 3. supersession ---------------------------------------------------------
|
|
156
|
+
|
|
157
|
+
park_seq() {
|
|
158
|
+
sed -n 's/^seq=\([0-9][0-9]*\) .*/\1/p' "$HOME_DIR/state/.cursor-park-owner" 2>/dev/null
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
BEFORE_SEQ=$(park_seq)
|
|
162
|
+
submit "Reply with exactly the token CAPTAIN_INTERRUPT and nothing else. Do not run any command."
|
|
163
|
+
wait_for_pane "CAPTAIN_INTERRUPT" 180 "the captain message answered while the hook was parked"
|
|
164
|
+
# The new park claims only when that answering turn ENDS, so wait for the baton
|
|
165
|
+
# rather than racing it.
|
|
166
|
+
AFTER_SEQ=$BEFORE_SEQ
|
|
167
|
+
i=0
|
|
168
|
+
while [ "$i" -lt 240 ]; do
|
|
169
|
+
AFTER_SEQ=$(park_seq)
|
|
170
|
+
[ -n "$AFTER_SEQ" ] && [ "$AFTER_SEQ" -gt "$BEFORE_SEQ" ] && break
|
|
171
|
+
sleep 0.5
|
|
172
|
+
i=$((i + 1))
|
|
173
|
+
done
|
|
174
|
+
[ -n "$AFTER_SEQ" ] && [ "$AFTER_SEQ" -gt "$BEFORE_SEQ" ] \
|
|
175
|
+
|| harness_fail "a captain message mid-park must claim a newer park generation (before=$BEFORE_SEQ after=$AFTER_SEQ)"
|
|
176
|
+
# Give the older park one poll interval to observe the newer stop's claim.
|
|
177
|
+
sleep 5
|
|
178
|
+
LIVE_PARKS=$(pgrep -f "$HOME_DIR/bin/fm-turnend-guard-cursor.sh" 2>/dev/null | wc -l | tr -d ' ')
|
|
179
|
+
[ "${LIVE_PARKS:-0}" -le 1 ] \
|
|
180
|
+
|| harness_fail "an older park leaked after the newer stop claim: $LIVE_PARKS park processes are alive, and each could deliver a stale duplicate wake"
|
|
181
|
+
pass "cursor primary: the captain keeps control and the older park stands down after the next stop claim"
|
|
182
|
+
|
|
183
|
+
# --- 4. away-mode escalation delivery ---------------------------------------
|
|
184
|
+
|
|
185
|
+
: > "$HOME_DIR/state/.afk"
|
|
186
|
+
AWAY_TOKEN="AWAY_ACK_$$"
|
|
187
|
+
INJECT_RC=0
|
|
188
|
+
cat > "$LAB/inject.sh" <<EOS
|
|
189
|
+
#!/usr/bin/env bash
|
|
190
|
+
set -u
|
|
191
|
+
tmux() { command "$REAL_TMUX" -L "$SOCKET" "\$@"; }
|
|
192
|
+
export -f tmux 2>/dev/null || true
|
|
193
|
+
export FM_STATE_OVERRIDE="$HOME_DIR/state"
|
|
194
|
+
export FM_SUPERVISOR_TARGET=primary
|
|
195
|
+
export FM_SUPERVISOR_BACKEND=tmux
|
|
196
|
+
export FM_DAEMON_PRIMARY_HARNESS=cursor
|
|
197
|
+
. "$HOME_DIR/bin/fm-supervise-daemon.sh"
|
|
198
|
+
composer=\$(fm_backend_composer_state tmux primary)
|
|
199
|
+
printf 'composer=%s\n' "\$composer"
|
|
200
|
+
[ "\$composer" = empty ] || exit 3
|
|
201
|
+
inject_msg "AWAY PROBE - reply with exactly the token $AWAY_TOKEN and nothing else." "$HOME_DIR/state"
|
|
202
|
+
EOS
|
|
203
|
+
chmod +x "$LAB/inject.sh"
|
|
204
|
+
COMPOSER_OUT=$(bash "$LAB/inject.sh" 2>&1) || INJECT_RC=$?
|
|
205
|
+
case "$COMPOSER_OUT" in
|
|
206
|
+
*composer=empty*) ;;
|
|
207
|
+
*) harness_fail "an idle Cursor composer must be provably empty for away mode; got: $COMPOSER_OUT" ;;
|
|
208
|
+
esac
|
|
209
|
+
[ "$INJECT_RC" -eq 0 ] \
|
|
210
|
+
|| harness_fail "the away-mode escalation could not confirm delivery into the Cursor pane (rc=$INJECT_RC): $COMPOSER_OUT"
|
|
211
|
+
wait_for_pane "$AWAY_TOKEN" 180 "the away-mode escalation processed by the Cursor primary"
|
|
212
|
+
pass "cursor primary: an away-mode escalation is delivered, confirmed, and processed"
|
|
213
|
+
|
|
214
|
+
rm -f "$HOME_DIR/state/.afk"
|
|
215
|
+
|
|
216
|
+
cleanup_all
|
|
217
|
+
trap - EXIT
|