@zerwiz/ymir 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/README.md +291 -0
- package/.agents/agents/bragi-marketer.md +111 -0
- package/.agents/agents/brokk.md +352 -0
- package/.agents/agents/forseti-reviewer.md +93 -0
- package/.agents/agents/frigg-consent.md +77 -0
- package/.agents/agents/groa-update.md +77 -0
- package/.agents/agents/hnoss-designer.md +69 -0
- package/.agents/agents/huginn-researcher.md +99 -0
- package/.agents/agents/jord-projects.md +78 -0
- package/.agents/agents/kvasir-scout.md +91 -0
- package/.agents/agents/mimir-planner.md +92 -0
- package/.agents/agents/muninn-stow.md +77 -0
- package/.agents/agents/saga-bearings.md +78 -0
- package/.agents/agents/sindri-developer.md +114 -0
- package/.agents/agents/snotra-documenter.md +105 -0
- package/.agents/agents/syn-recovery.md +78 -0
- package/.agents/agents/tyr-check.md +78 -0
- package/.agents/agents/urdh-hold.md +77 -0
- package/.agents/agents/volundr-smith.md +80 -0
- package/.agents/agents/vor-diagnostics.md +77 -0
- package/.agents/assets/agents/naming.md +50 -0
- package/.agents/assets/agents/registry.md +93 -0
- package/.agents/assets/agents/runtime.md +36 -0
- package/.agents/assets/agents/toon-tasks-cli.md +42 -0
- package/.agents/assets/templates/company_entity.template.md +37 -0
- package/.agents/backend/backends/cmux.sh +649 -0
- package/.agents/backend/backends/herdr-eventwait.py +157 -0
- package/.agents/backend/backends/herdr-workspace-move.py +114 -0
- package/.agents/backend/backends/herdr.sh +3386 -0
- package/.agents/backend/backends/orca.sh +290 -0
- package/.agents/backend/backends/tmux.sh +357 -0
- package/.agents/backend/backends/zellij.sh +700 -0
- package/.agents/backend/fm-afk-launch.sh +654 -0
- package/.agents/backend/fm-afk-return.sh +241 -0
- package/.agents/backend/fm-afk-start.sh +172 -0
- package/.agents/backend/fm-arm-command-policy.mjs +960 -0
- package/.agents/backend/fm-arm-pretool-check.sh +200 -0
- package/.agents/backend/fm-backend-hometag-lib.sh +52 -0
- package/.agents/backend/fm-backend.sh +981 -0
- package/.agents/backend/fm-backlog-handoff.sh +909 -0
- package/.agents/backend/fm-backlog-receive.sh +187 -0
- package/.agents/backend/fm-backlog-transition-lib.sh +779 -0
- package/.agents/backend/fm-bearings-board.sh +204 -0
- package/.agents/backend/fm-bearings-snapshot.sh +546 -0
- package/.agents/backend/fm-bootstrap.sh +1568 -0
- package/.agents/backend/fm-branch-outcome.sh +203 -0
- package/.agents/backend/fm-branch-prompt.sh +101 -0
- package/.agents/backend/fm-brief.sh +452 -0
- package/.agents/backend/fm-busy-event.sh +234 -0
- package/.agents/backend/fm-busy-lib.sh +986 -0
- package/.agents/backend/fm-captain-hold.sh +1001 -0
- package/.agents/backend/fm-cd-command-policy.mjs +153 -0
- package/.agents/backend/fm-cd-pretool-check.sh +190 -0
- package/.agents/backend/fm-check-lib.sh +74 -0
- package/.agents/backend/fm-check-register.sh +42 -0
- package/.agents/backend/fm-check-unregister.sh +52 -0
- package/.agents/backend/fm-classify-lib.sh +1770 -0
- package/.agents/backend/fm-claude-stop-autoarm.sh +334 -0
- package/.agents/backend/fm-composer-lib.sh +1416 -0
- package/.agents/backend/fm-config-inherit-lib.sh +1202 -0
- package/.agents/backend/fm-config-push.sh +254 -0
- package/.agents/backend/fm-control-lib.sh +251 -0
- package/.agents/backend/fm-control.sh +878 -0
- package/.agents/backend/fm-crew-state.sh +625 -0
- package/.agents/backend/fm-cursor-lib.sh +243 -0
- package/.agents/backend/fm-decision-hold.sh +232 -0
- package/.agents/backend/fm-doc-audience-check.sh +269 -0
- package/.agents/backend/fm-dod-lib.sh +67 -0
- package/.agents/backend/fm-ensure-agents-md.sh +253 -0
- package/.agents/backend/fm-extension-launch-barrier.mjs +129 -0
- package/.agents/backend/fm-extension.mjs +2577 -0
- package/.agents/backend/fm-extension.sh +16 -0
- package/.agents/backend/fm-ff-lib.sh +420 -0
- package/.agents/backend/fm-fleet-snapshot.sh +1463 -0
- package/.agents/backend/fm-fleet-sync.sh +458 -0
- package/.agents/backend/fm-fleet-view.sh +96 -0
- package/.agents/backend/fm-gate-refuse-lib.sh +102 -0
- package/.agents/backend/fm-guard.sh +242 -0
- package/.agents/backend/fm-harness.sh +195 -0
- package/.agents/backend/fm-herdr-ci-cleanup.sh +115 -0
- package/.agents/backend/fm-herdr-lab.sh +346 -0
- package/.agents/backend/fm-herdr-session-cleanup.sh +337 -0
- package/.agents/backend/fm-home-seed.sh +984 -0
- package/.agents/backend/fm-home-summary-refresh.sh +255 -0
- package/.agents/backend/fm-hook-host-lib.sh +36 -0
- package/.agents/backend/fm-inactive-reconcile.sh +531 -0
- package/.agents/backend/fm-inbox.sh +399 -0
- package/.agents/backend/fm-install-actionlint.sh +84 -0
- package/.agents/backend/fm-install-herdr.sh +96 -0
- package/.agents/backend/fm-install-shellcheck.sh +84 -0
- package/.agents/backend/fm-install-treehouse.sh +95 -0
- package/.agents/backend/fm-kimi-turnend-hook.sh +276 -0
- package/.agents/backend/fm-lease-lib.sh +218 -0
- package/.agents/backend/fm-lease.sh +189 -0
- package/.agents/backend/fm-line-cap-lib.sh +51 -0
- package/.agents/backend/fm-lint-workflows.sh +137 -0
- package/.agents/backend/fm-lint.sh +591 -0
- package/.agents/backend/fm-lock-lib.sh +104 -0
- package/.agents/backend/fm-lock.sh +107 -0
- package/.agents/backend/fm-marker-lib.sh +12 -0
- package/.agents/backend/fm-merge-local.sh +74 -0
- package/.agents/backend/fm-merge-outcome-lib.sh +138 -0
- package/.agents/backend/fm-nm-run-lib.sh +124 -0
- package/.agents/backend/fm-on.sh +125 -0
- package/.agents/backend/fm-operational-input.sh +253 -0
- package/.agents/backend/fm-peek.sh +46 -0
- package/.agents/backend/fm-pending-reply-lib.sh +1409 -0
- package/.agents/backend/fm-pr-check.sh +135 -0
- package/.agents/backend/fm-pr-lib.sh +1016 -0
- package/.agents/backend/fm-pr-merge.sh +707 -0
- package/.agents/backend/fm-pr-poll.sh +110 -0
- package/.agents/backend/fm-primary-scope-lib.sh +33 -0
- package/.agents/backend/fm-procevent-extension-capture.pl +259 -0
- package/.agents/backend/fm-procevent-lavish.sh +628 -0
- package/.agents/backend/fm-procevent-lib.sh +892 -0
- package/.agents/backend/fm-procevent-quota.sh +290 -0
- package/.agents/backend/fm-procevent-remote-reply.sh +577 -0
- package/.agents/backend/fm-procevent-when.sh +504 -0
- package/.agents/backend/fm-procevent.sh +1466 -0
- package/.agents/backend/fm-project-mode.sh +92 -0
- package/.agents/backend/fm-project-origin-lib.sh +180 -0
- package/.agents/backend/fm-promote.sh +282 -0
- package/.agents/backend/fm-public-followup-emit.sh +260 -0
- package/.agents/backend/fm-public-followup-lib.sh +398 -0
- package/.agents/backend/fm-public-followup.sh +1330 -0
- package/.agents/backend/fm-push-transition-lib.sh +168 -0
- package/.agents/backend/fm-quota-axi-lib.sh +93 -0
- package/.agents/backend/fm-quota-choose.sh +384 -0
- package/.agents/backend/fm-remote-delta-read.sh +189 -0
- package/.agents/backend/fm-remote-doctor.sh +800 -0
- package/.agents/backend/fm-remote-entrypoint.sh +193 -0
- package/.agents/backend/fm-remote-file.sh +234 -0
- package/.agents/backend/fm-remote-home-provision.sh +259 -0
- package/.agents/backend/fm-remote-home-seed.sh +259 -0
- package/.agents/backend/fm-remote-inherit-push.sh +90 -0
- package/.agents/backend/fm-remote-inherit.sh +179 -0
- package/.agents/backend/fm-remote-job-lib.sh +1241 -0
- package/.agents/backend/fm-remote-job-reap-orphans.sh +137 -0
- package/.agents/backend/fm-remote-job-worker.sh +1124 -0
- package/.agents/backend/fm-remote-readiness-lib.sh +44 -0
- package/.agents/backend/fm-remote-secondmate-control.sh +340 -0
- package/.agents/backend/fm-review-diff.sh +158 -0
- package/.agents/backend/fm-secondmate-charter-lib.sh +44 -0
- package/.agents/backend/fm-secondmate-nudge-lib.sh +68 -0
- package/.agents/backend/fm-secondmate-parent-lib.sh +70 -0
- package/.agents/backend/fm-secondmate-reconcile.sh +371 -0
- package/.agents/backend/fm-secondmate-registry-lib.sh +311 -0
- package/.agents/backend/fm-secondmate-report.sh +88 -0
- package/.agents/backend/fm-send.sh +1059 -0
- package/.agents/backend/fm-session-lock-lib.sh +176 -0
- package/.agents/backend/fm-session-start.sh +970 -0
- package/.agents/backend/fm-sessionstart-cursor.sh +40 -0
- package/.agents/backend/fm-sessionstart-nudge.sh +45 -0
- package/.agents/backend/fm-sessionstart-run.sh +145 -0
- package/.agents/backend/fm-spawn.sh +3153 -0
- package/.agents/backend/fm-startup-memory-budget-lib.sh +224 -0
- package/.agents/backend/fm-startup-memory-budget.sh +94 -0
- package/.agents/backend/fm-startup-network.sh +642 -0
- package/.agents/backend/fm-stow-cascade.sh +251 -0
- package/.agents/backend/fm-subagent-pretool-check.sh +207 -0
- package/.agents/backend/fm-supervise-daemon.sh +1732 -0
- package/.agents/backend/fm-supervision-instructions.sh +215 -0
- package/.agents/backend/fm-supervision-lib.sh +90 -0
- package/.agents/backend/fm-supervisor-target-lib.sh +78 -0
- package/.agents/backend/fm-tangle-lib.sh +53 -0
- package/.agents/backend/fm-task-inbox-lib.sh +402 -0
- package/.agents/backend/fm-tasks-axi-lib.sh +123 -0
- package/.agents/backend/fm-teardown.sh +2922 -0
- package/.agents/backend/fm-test-isolation-proof.sh +588 -0
- package/.agents/backend/fm-test-run.sh +2191 -0
- package/.agents/backend/fm-timeout-lib.sh +141 -0
- package/.agents/backend/fm-timing-lib.sh +179 -0
- package/.agents/backend/fm-tmux-lib.sh +291 -0
- package/.agents/backend/fm-tool-update-check.sh +898 -0
- package/.agents/backend/fm-trace-context-lib.sh +227 -0
- package/.agents/backend/fm-transition-lib.sh +103 -0
- package/.agents/backend/fm-turnend-guard-cursor.sh +391 -0
- package/.agents/backend/fm-turnend-guard-grok.sh +90 -0
- package/.agents/backend/fm-turnend-guard.sh +432 -0
- package/.agents/backend/fm-update.sh +110 -0
- package/.agents/backend/fm-vendor-auth-probe.sh +190 -0
- package/.agents/backend/fm-voice-client.py +1373 -0
- package/.agents/backend/fm-voice-relay.py +1256 -0
- package/.agents/backend/fm-wake-drain.sh +592 -0
- package/.agents/backend/fm-wake-grant.sh +127 -0
- package/.agents/backend/fm-wake-lib.sh +1849 -0
- package/.agents/backend/fm-watch-arm.sh +602 -0
- package/.agents/backend/fm-watch-checkpoint.sh +109 -0
- package/.agents/backend/fm-watch.sh +1962 -0
- package/.agents/backend/fm-x-dismiss.sh +116 -0
- package/.agents/backend/fm-x-followup.sh +286 -0
- package/.agents/backend/fm-x-lib.sh +1000 -0
- package/.agents/backend/fm-x-link.sh +234 -0
- package/.agents/backend/fm-x-poll.sh +185 -0
- package/.agents/backend/fm-x-reply.sh +385 -0
- package/.agents/backend/fm_voice_frame.py +166 -0
- package/.agents/backend/fm_voice_records.py +574 -0
- package/.agents/backend/model-bridge.py +290 -0
- package/.agents/backend/opencode-go-bridge.py +30 -0
- package/.agents/bus/README.md +12 -0
- package/.agents/bus/messages.json +1 -0
- package/.agents/config/agents.machine.example.yaml +16 -0
- package/.agents/config/agents.yaml +50 -0
- package/.agents/config/agents.yaml.example +72 -0
- package/.agents/config/crew-dispatch.json +22 -0
- package/.agents/config/cron.yaml +9 -0
- package/.agents/config/eindri-dispatch.json +67 -0
- package/.agents/config/eindri-harness +1 -0
- package/.agents/config/startup-memory-budget +1 -0
- package/.agents/config/tailscale-sync.yaml +27 -0
- package/.agents/filebrowser/.filebrowser.json +6 -0
- package/.agents/filebrowser/README.md +11 -0
- package/.agents/gateway/README.md +12 -0
- package/.agents/github/README.md +15 -0
- package/.agents/github/webhooks/.gitkeep +0 -0
- package/.agents/github/workflows/.gitkeep +0 -0
- package/.agents/harness/opencode/plugins/lib/rodd-operational-input.js +37 -0
- package/.agents/harness/opencode/plugins/package.json +4 -0
- package/.agents/harness/opencode/plugins/saga-sessionstart.js +77 -0
- package/.agents/harness/opencode/plugins/syn-cd-check.js +61 -0
- package/.agents/harness/opencode/plugins/syn-pretool-check.js +68 -0
- package/.agents/harness/opencode/plugins/syn-turnend-guard.js +105 -0
- package/.agents/harness/opencode/plugins/syn-watch-arm.js +521 -0
- package/.agents/memory/README.md +46 -0
- package/.agents/memory/kaia.engram +0 -0
- package/.agents/memory/kaia.engram-shm +0 -0
- package/.agents/memory/kaia.engram-wal +0 -0
- package/.agents/memory/runes_audit.md +5 -0
- package/.agents/memory/well/episodes.jsonl +367 -0
- package/.agents/memory/well/workspace.jsonl +27 -0
- package/.agents/migrations/0001-hodd-layout.sh +38 -0
- package/.agents/migrations/0002-a2a-mcp.sh +27 -0
- package/.agents/migrations/0003-private-data-separation.sh +111 -0
- package/.agents/migrations/0004-hoard-and-realms.sh +104 -0
- package/.agents/sandbox/Dockerfile.utgard +19 -0
- package/.agents/sandbox/README.md +14 -0
- package/.agents/sandbox/utgard.config.json +14 -0
- package/.agents/skills/README.md +59 -0
- package/.agents/skills/bragi-marketing/README.md +3 -0
- package/.agents/skills/bragi-marketing/SKILL.md +82 -0
- package/.agents/skills/eindri-homes/README.md +3 -0
- package/.agents/skills/eindri-homes/SKILL.md +291 -0
- package/.agents/skills/eindri-homes/assets/control-plane.md +122 -0
- package/.agents/skills/eindri-homes/assets/dispatch.md +80 -0
- package/.agents/skills/frigg-consent/README.md +3 -0
- package/.agents/skills/frigg-consent/SKILL.md +56 -0
- package/.agents/skills/galdr-ymirsystem/README.md +3 -0
- package/.agents/skills/galdr-ymirsystem/SKILL.md +158 -0
- package/.agents/skills/galdr-ymirsystem/assets/README.md +74 -0
- package/.agents/skills/galdr-ymirsystem/assets/brokk-distro-runtime.md +390 -0
- package/.agents/skills/galdr-ymirsystem/assets/build-method.md +113 -0
- package/.agents/skills/galdr-ymirsystem/assets/build-tool-categories.md +178 -0
- package/.agents/skills/galdr-ymirsystem/assets/eindri-orchestration.md +518 -0
- package/.agents/skills/galdr-ymirsystem/assets/eindri-profiles.md +136 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/README.md +673 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/claude-code.md +197 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/codex.md +191 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/cursor.md +193 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/opencode.md +262 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/pi.md +295 -0
- package/.agents/skills/galdr-ymirsystem/assets/hlidskjalf-ui.md +496 -0
- package/.agents/skills/galdr-ymirsystem/assets/installation.md +571 -0
- package/.agents/skills/galdr-ymirsystem/assets/local-models/HOST-DATA.example.md +72 -0
- package/.agents/skills/galdr-ymirsystem/assets/local-models.md +274 -0
- package/.agents/skills/galdr-ymirsystem/assets/memory-well.md +161 -0
- package/.agents/skills/galdr-ymirsystem/assets/nornir-jobs.md +377 -0
- package/.agents/skills/galdr-ymirsystem/assets/norse-naming.md +325 -0
- package/.agents/skills/galdr-ymirsystem/assets/odrerir-hall.md +129 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/einherjar-spawn.schema.json +81 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/herdr-profile.toml +75 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/pi-profile.yml +96 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/supervision-tree.yml +163 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot-guide.md +58 -0
- package/.agents/skills/galdr-ymirsystem/assets/porting-upstream-to-norse.md +301 -0
- package/.agents/skills/galdr-ymirsystem/assets/principles.md +385 -0
- package/.agents/skills/galdr-ymirsystem/assets/reference-adoption.md +99 -0
- package/.agents/skills/galdr-ymirsystem/assets/registry.md +379 -0
- package/.agents/skills/galdr-ymirsystem/assets/runtime-compliance.md +463 -0
- package/.agents/skills/galdr-ymirsystem/assets/runtime-components.md +553 -0
- package/.agents/skills/galdr-ymirsystem/assets/smidja.md +175 -0
- package/.agents/skills/galdr-ymirsystem/schemas/toon-schemas.md +190 -0
- package/.agents/skills/galdr-ymirsystem/scripts/README.md +45 -0
- package/.agents/skills/galdr-ymirsystem/scripts/bench-one.sh +248 -0
- package/.agents/skills/galdr-ymirsystem/scripts/compliance-check.sh +360 -0
- package/.agents/skills/galdr-ymirsystem/scripts/gpu-sample.sh +43 -0
- package/.agents/skills/galdr-ymirsystem/scripts/stop-all.sh +34 -0
- package/.agents/skills/galdr-ymirsystem/scripts/toon-check.py +188 -0
- package/.agents/skills/gjallarhorn-relay/README.md +3 -0
- package/.agents/skills/gjallarhorn-relay/SKILL.md +283 -0
- package/.agents/skills/groa-update/SKILL.md +70 -0
- package/.agents/skills/hamr-adapters/README.md +3 -0
- package/.agents/skills/hamr-adapters/SKILL.md +123 -0
- package/.agents/skills/hamr-adapters/references/common/control-and-recovery.md +37 -0
- package/.agents/skills/hamr-adapters/references/common/dispatch.md +32 -0
- package/.agents/skills/hamr-adapters/references/common/model-and-effort.md +42 -0
- package/.agents/skills/hamr-adapters/references/common/primary-hooks.md +40 -0
- package/.agents/skills/hamr-adapters/references/harness/claude.md +55 -0
- package/.agents/skills/hamr-adapters/references/harness/codex.md +43 -0
- package/.agents/skills/hamr-adapters/references/harness/cursor.md +75 -0
- package/.agents/skills/hamr-adapters/references/harness/grok.md +69 -0
- package/.agents/skills/hamr-adapters/references/harness/kimi.md +51 -0
- package/.agents/skills/hamr-adapters/references/harness/muse.md +70 -0
- package/.agents/skills/hamr-adapters/references/harness/opencode.md +42 -0
- package/.agents/skills/hamr-adapters/references/harness/pi.md +56 -0
- package/.agents/skills/herdr-panes/README.md +3 -0
- package/.agents/skills/herdr-panes/SKILL.md +92 -0
- package/.agents/skills/herdr-panes/assets/herdr-backend.md +346 -0
- package/.agents/skills/herdr-panes/assets/tmux-backend.md +115 -0
- package/.agents/skills/hnoss-design/DESIGN.md +19 -0
- package/.agents/skills/hnoss-design/README.md +3 -0
- package/.agents/skills/hnoss-design/SKILL.md +83 -0
- package/.agents/skills/hvild-afk/README.md +3 -0
- package/.agents/skills/hvild-afk/SKILL.md +241 -0
- package/.agents/skills/jord-projects/README.md +3 -0
- package/.agents/skills/jord-projects/SKILL.md +92 -0
- package/.agents/skills/lifecycle/SKILL.md +56 -0
- package/.agents/skills/lifecycle/smoke_test.sh +52 -0
- package/.agents/skills/lifecycle/start.sh +21 -0
- package/.agents/skills/lifecycle/status.sh +35 -0
- package/.agents/skills/lifecycle/stop.sh +16 -0
- package/.agents/skills/muninn-stow/README.md +3 -0
- package/.agents/skills/muninn-stow/SKILL.md +309 -0
- package/.agents/skills/no-mistakes/SKILL.md +379 -0
- package/.agents/skills/nornir-schedule/README.md +3 -0
- package/.agents/skills/nornir-schedule/SKILL.md +25 -0
- package/.agents/skills/nornir-schedule/assets/events.md +137 -0
- package/.agents/skills/nornir-schedule/assets/quota.md +131 -0
- package/.agents/skills/nsr-compliance/README.md +3 -0
- package/.agents/skills/nsr-compliance/SKILL.md +29 -0
- package/.agents/skills/nsr-compliance/assets/nsr/README.md +40 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/README.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/git-workflow.md +18 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/security.md +22 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/tech-stack.md +8 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/SKILL.md +71 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/config/core_four.yaml +16 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/check_danger.sh +102 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/check_wiring.sh +69 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/validate_code.sh +29 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/verify_docs.py +66 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/generate.sh +109 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/envelopes/result_envelope.json +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/envelopes/task_envelope.json +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/runner.py +303 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/telemetry/logger.py +112 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/README.md +18 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/config/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/README.md +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_env.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_paths.sh +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_platform.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/harness/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/harness/envelopes/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/installer/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/installer/install.sh +125 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/telemetry/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/README.md +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/features/README.md +36 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/features/SKILL-template.md +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/README.md +25 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/SKILL.md +13 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/create_branch.sh +6 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/safe_commit.sh +9 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/sync_upstream.sh +6 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/README.md +27 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/SKILL.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/smoke_test.sh +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/start.sh +19 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/status.sh +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/stop.sh +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/README.md +18 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/config/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/config/core_four.yaml +13 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/README.md +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_danger.sh +102 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_env.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_paths.sh +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_platform.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_wiring.sh +69 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/result_envelope.json +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/task_envelope.json +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/runner.py +303 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/installer/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/installer/install.sh +125 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/telemetry/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/telemetry/logger.py +112 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/README.md +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/api.md +17 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/compliance-wiring.md +155 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/frontend.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/README.md +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/clients/README.md +16 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/clients/template-README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/deploy.sh +49 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/README.md +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/development.env.example +17 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/production.env.example +17 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/staging.env.example +17 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/tenants/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/tenants/template.env.example +8 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/README.md +26 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/agent.md +7 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/developers/dev-1.md +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/linux.md +9 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/macos.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/shared.md +19 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/windows.md +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/README.md +25 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/_template.md +41 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/hosting-1.md +41 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/README.md +21 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/README.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/deployment.md +19 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/disaster-recovery.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/ops-tasks.md +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/features/README.md +16 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/project-skills.md +146 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/research/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/research/software-compliance-research.md +269 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/working-with-agents.md +260 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/AGENTS.md +38 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/ARCHITECTURE.md +36 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/BEST_PRACTICES.md +27 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/CI_CD.md +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/FEATURES.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/README.md +22 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/RULES.md +37 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/STRUCTURE.md +45 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/TECH_STACK.md +28 -0
- package/.agents/skills/nsr-compliance/assets/nsr/scaffold-spec.md +63 -0
- package/.agents/skills/nsr-compliance/assets/nsr/scripts/scaffold.sh +103 -0
- package/.agents/skills/nsr-compliance/assets/nsr/scripts/validate.sh +52 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/SKILL.md +71 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/config/core_four.yaml +16 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/check_danger.sh +102 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/check_wiring.sh +69 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/validate_code.sh +29 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/verify_docs.py +66 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/generate.sh +109 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/envelopes/result_envelope.json +14 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/envelopes/task_envelope.json +20 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/runner.py +303 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/telemetry/logger.py +112 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/README.md +18 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/config/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/README.md +12 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_env.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_paths.sh +20 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_platform.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/harness/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/harness/envelopes/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/installer/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/installer/install.sh +125 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/telemetry/README.md +11 -0
- package/.agents/skills/pr-ops/README.md +3 -0
- package/.agents/skills/pr-ops/SKILL.md +109 -0
- package/.agents/skills/ratatoskr-a2a/README.md +3 -0
- package/.agents/skills/ratatoskr-a2a/SKILL.md +148 -0
- package/.agents/skills/rules-check-drift/SKILL.md +81 -0
- package/.agents/skills/saga-bearings/README.md +3 -0
- package/.agents/skills/saga-bearings/SKILL.md +26 -0
- package/.agents/skills/saga-bearings/assets/bearings.md +161 -0
- package/.agents/skills/saga-bearings/assets/board-template.html +731 -0
- package/.agents/skills/saga-bearings/assets/recap.md +56 -0
- package/.agents/skills/syn-recovery/README.md +3 -0
- package/.agents/skills/syn-recovery/SKILL.md +54 -0
- package/.agents/skills/tyr-check/README.md +3 -0
- package/.agents/skills/tyr-check/SKILL.md +218 -0
- package/.agents/skills/urdh-hold/README.md +3 -0
- package/.agents/skills/urdh-hold/SKILL.md +25 -0
- package/.agents/skills/urdh-hold/assets/decisions.md +15 -0
- package/.agents/skills/urdh-hold/assets/hold.md +54 -0
- package/.agents/skills/vor-diagnostics/README.md +3 -0
- package/.agents/skills/vor-diagnostics/SKILL.md +68 -0
- package/.agents/skills/ymir-host/README.md +3 -0
- package/.agents/skills/ymir-host/SKILL.md +34 -0
- package/.agents/skills/ymir-host/assets/desktop.md +36 -0
- package/.agents/skills/ymir-host/assets/omarchy.md +297 -0
- package/.agents/skills/ymir-host/assets/runbooks.md +15 -0
- package/.agents/skills/ymir-host/assets/thjazi.md +220 -0
- package/.agents/skills/ymir-host/assets/update.md +64 -0
- package/.agents/tests/assets/board-render-harness.mjs +117 -0
- package/.agents/tests/cmux-test-safety.sh +51 -0
- package/.agents/tests/fixtures.sh +291 -0
- package/.agents/tests/fm-afk-inject-e2e.test.sh +428 -0
- package/.agents/tests/fm-afk-inject-herdr-e2e.test.sh +536 -0
- package/.agents/tests/fm-afk-launch.test.sh +961 -0
- package/.agents/tests/fm-afk-pi-herdr-return-e2e.test.sh +297 -0
- package/.agents/tests/fm-afk-return.test.sh +283 -0
- package/.agents/tests/fm-arm-pretool-check.test.sh +482 -0
- package/.agents/tests/fm-ask-user-authority.test.sh +42 -0
- package/.agents/tests/fm-backend-autodetect-smoke.test.sh +176 -0
- package/.agents/tests/fm-backend-cmux-smoke.test.sh +188 -0
- package/.agents/tests/fm-backend-cmux.test.sh +1166 -0
- package/.agents/tests/fm-backend-herdr-eventwait-smoke.test.sh +136 -0
- package/.agents/tests/fm-backend-herdr-eventwait.test.py +106 -0
- package/.agents/tests/fm-backend-herdr-focus-flash-e2e.test.sh +409 -0
- package/.agents/tests/fm-backend-herdr-launcher-workspace-e2e.test.sh +437 -0
- package/.agents/tests/fm-backend-herdr-presentation-e2e.test.sh +1424 -0
- package/.agents/tests/fm-backend-herdr-prune-safety-e2e.test.sh +180 -0
- package/.agents/tests/fm-backend-herdr-respawn-idem-e2e.test.sh +182 -0
- package/.agents/tests/fm-backend-herdr-smoke.test.sh +355 -0
- package/.agents/tests/fm-backend-herdr-workspace-per-home-e2e.test.sh +251 -0
- package/.agents/tests/fm-backend-herdr.test.sh +4606 -0
- package/.agents/tests/fm-backend-orca.test.sh +1357 -0
- package/.agents/tests/fm-backend-tmux-smoke.test.sh +173 -0
- package/.agents/tests/fm-backend-zellij-smoke.test.sh +205 -0
- package/.agents/tests/fm-backend-zellij.test.sh +1360 -0
- package/.agents/tests/fm-backend.test.sh +1142 -0
- package/.agents/tests/fm-backlog-atomicity.test.sh +2302 -0
- package/.agents/tests/fm-backlog-handoff.test.sh +1360 -0
- package/.agents/tests/fm-bearings-board-render.test.sh +135 -0
- package/.agents/tests/fm-bearings-board.test.sh +414 -0
- package/.agents/tests/fm-bearings-snapshot.test.sh +1990 -0
- package/.agents/tests/fm-bootstrap-network-parallel.test.sh +316 -0
- package/.agents/tests/fm-bootstrap.test.sh +1178 -0
- package/.agents/tests/fm-branch-supervision.test.sh +552 -0
- package/.agents/tests/fm-brief.test.sh +785 -0
- package/.agents/tests/fm-busy-adapter-wiring.test.sh +324 -0
- package/.agents/tests/fm-busy-state.test.sh +465 -0
- package/.agents/tests/fm-calm-pi-extension.test.sh +3979 -0
- package/.agents/tests/fm-captain-hold-lifecycle.test.sh +1187 -0
- package/.agents/tests/fm-cd-pretool-check.test.sh +400 -0
- package/.agents/tests/fm-check-unregister.test.sh +198 -0
- package/.agents/tests/fm-classify-corr-token.test.sh +543 -0
- package/.agents/tests/fm-classify-decision-key.test.sh +340 -0
- package/.agents/tests/fm-claude-stop-autoarm-live-e2e.test.sh +164 -0
- package/.agents/tests/fm-claude-stop-autoarm.test.sh +1190 -0
- package/.agents/tests/fm-cmux-claude-composer-live-e2e.test.sh +110 -0
- package/.agents/tests/fm-codex-continuity-live-e2e.test.sh +55 -0
- package/.agents/tests/fm-composer-ghost.test.sh +716 -0
- package/.agents/tests/fm-composer-lib.test.sh +666 -0
- package/.agents/tests/fm-composer-matrix-live-e2e.test.sh +220 -0
- package/.agents/tests/fm-control-herdr-smoke.test.sh +149 -0
- package/.agents/tests/fm-control-relaunch.test.sh +1530 -0
- package/.agents/tests/fm-control.test.sh +910 -0
- package/.agents/tests/fm-crew-state.test.sh +1610 -0
- package/.agents/tests/fm-cursor-harness.test.sh +404 -0
- package/.agents/tests/fm-cursor-primary-live-e2e.test.sh +217 -0
- package/.agents/tests/fm-cursor-primary.test.sh +708 -0
- package/.agents/tests/fm-daemon.test.sh +2740 -0
- package/.agents/tests/fm-documentation-audiences.test.sh +141 -0
- package/.agents/tests/fm-ensure-agents-md.test.sh +371 -0
- package/.agents/tests/fm-extension-binding.test.sh +2187 -0
- package/.agents/tests/fm-fleet-snapshot-view.test.sh +816 -0
- package/.agents/tests/fm-fleet-sync.test.sh +721 -0
- package/.agents/tests/fm-gate-refuse.test.sh +356 -0
- package/.agents/tests/fm-gitignore-config.test.sh +89 -0
- package/.agents/tests/fm-gotmp.test.sh +230 -0
- package/.agents/tests/fm-grok-continuity-live-e2e.test.sh +112 -0
- package/.agents/tests/fm-grok-harness.test.sh +117 -0
- package/.agents/tests/fm-grok-stop-live-e2e.test.sh +219 -0
- package/.agents/tests/fm-guard-stale-banner.test.sh +709 -0
- package/.agents/tests/fm-harness-adapter-instructions-live-e2e.test.sh +134 -0
- package/.agents/tests/fm-harness-adapter-references.test.sh +30 -0
- package/.agents/tests/fm-harness-liveness-drift-live-e2e.test.sh +151 -0
- package/.agents/tests/fm-herdr-lab.test.sh +243 -0
- package/.agents/tests/fm-herdr-session-cleanup-e2e.test.sh +146 -0
- package/.agents/tests/fm-herdr-session-cleanup.test.sh +329 -0
- package/.agents/tests/fm-herdr-submit-confirm-live-e2e.test.sh +125 -0
- package/.agents/tests/fm-herdr-version-floor-live-e2e.test.sh +144 -0
- package/.agents/tests/fm-home-summary-refresh.test.sh +971 -0
- package/.agents/tests/fm-inactive-reconcile.test.sh +485 -0
- package/.agents/tests/fm-kimi-harness.test.sh +687 -0
- package/.agents/tests/fm-lint-workflows.test.sh +532 -0
- package/.agents/tests/fm-lint.test.sh +1023 -0
- package/.agents/tests/fm-muse-harness.test.sh +932 -0
- package/.agents/tests/fm-muse-signals-live-e2e.test.sh +205 -0
- package/.agents/tests/fm-no-mistakes-required.test.sh +72 -0
- package/.agents/tests/fm-on.test.sh +507 -0
- package/.agents/tests/fm-opencode-primary-live-e2e.test.sh +357 -0
- package/.agents/tests/fm-operational-input.test.sh +160 -0
- package/.agents/tests/fm-peek-remote.test.sh +110 -0
- package/.agents/tests/fm-pending-reply.test.sh +1288 -0
- package/.agents/tests/fm-pi-branch-extension.test.sh +3182 -0
- package/.agents/tests/fm-pi-branch-live-e2e.test.sh +527 -0
- package/.agents/tests/fm-pi-primary-live-e2e.test.sh +345 -0
- package/.agents/tests/fm-pi-primary-types.test.sh +68 -0
- package/.agents/tests/fm-pi-watch-extension.test.sh +2843 -0
- package/.agents/tests/fm-pr-check-security.test.sh +2140 -0
- package/.agents/tests/fm-pr-merge.test.sh +2135 -0
- package/.agents/tests/fm-procevent-quota.test.sh +225 -0
- package/.agents/tests/fm-procevent-when.test.sh +406 -0
- package/.agents/tests/fm-procevent.test.sh +1745 -0
- package/.agents/tests/fm-project-origin.test.sh +110 -0
- package/.agents/tests/fm-public-followup.test.sh +2272 -0
- package/.agents/tests/fm-quota-array-dispatch-live-e2e.test.sh +526 -0
- package/.agents/tests/fm-quota-choose.test.sh +626 -0
- package/.agents/tests/fm-remote-backlog-handoff.test.sh +453 -0
- package/.agents/tests/fm-remote-doctor.test.sh +625 -0
- package/.agents/tests/fm-remote-entrypoint.test.sh +59 -0
- package/.agents/tests/fm-remote-job-orphan-reap.test.sh +205 -0
- package/.agents/tests/fm-remote-job.test.sh +768 -0
- package/.agents/tests/fm-remote-reply.test.sh +520 -0
- package/.agents/tests/fm-remote-secondmate-lifecycle-e2e.test.sh +1256 -0
- package/.agents/tests/fm-remote-secondmate-parent-binding.test.sh +326 -0
- package/.agents/tests/fm-remote-secondmate-trace-context.test.sh +310 -0
- package/.agents/tests/fm-remote-transport-lanes.test.sh +431 -0
- package/.agents/tests/fm-review-diff.test.sh +176 -0
- package/.agents/tests/fm-secondmate-harness.test.sh +2600 -0
- package/.agents/tests/fm-secondmate-lifecycle-e2e.test.sh +259 -0
- package/.agents/tests/fm-secondmate-liveness.test.sh +559 -0
- package/.agents/tests/fm-secondmate-reconcile.test.sh +732 -0
- package/.agents/tests/fm-secondmate-safety.test.sh +2972 -0
- package/.agents/tests/fm-secondmate-sync.test.sh +913 -0
- package/.agents/tests/fm-send-inbox-doorbell-live-e2e.test.sh +206 -0
- package/.agents/tests/fm-send-inbox.test.sh +352 -0
- package/.agents/tests/fm-send-popup-settle.test.sh +167 -0
- package/.agents/tests/fm-send-remote-delivery.test.sh +796 -0
- package/.agents/tests/fm-send-resolve-key.test.sh +551 -0
- package/.agents/tests/fm-send-secondmate-marker-herdr-e2e.test.sh +187 -0
- package/.agents/tests/fm-send-secondmate-marker.test.sh +278 -0
- package/.agents/tests/fm-send-settle.test.sh +147 -0
- package/.agents/tests/fm-send-strict.test.sh +241 -0
- package/.agents/tests/fm-session-lock-ancestry.test.sh +365 -0
- package/.agents/tests/fm-session-start.test.sh +2515 -0
- package/.agents/tests/fm-sessionstart-hook-live-e2e.test.sh +631 -0
- package/.agents/tests/fm-sessionstart-instruction-refresh-live-e2e.test.sh +230 -0
- package/.agents/tests/fm-sessionstart-nudge.test.sh +1039 -0
- package/.agents/tests/fm-shared-captain-inheritance.test.sh +404 -0
- package/.agents/tests/fm-spawn-batch.test.sh +148 -0
- package/.agents/tests/fm-spawn-dispatch-profile.test.sh +827 -0
- package/.agents/tests/fm-spawn-pool-base-freshen.test.sh +440 -0
- package/.agents/tests/fm-spawn-worktree-settle.test.sh +147 -0
- package/.agents/tests/fm-startup-memory-budget.test.sh +333 -0
- package/.agents/tests/fm-startup-network.test.sh +712 -0
- package/.agents/tests/fm-stow-cascade.test.sh +370 -0
- package/.agents/tests/fm-subagent-pretool-check.test.sh +291 -0
- package/.agents/tests/fm-supervision-events.test.sh +156 -0
- package/.agents/tests/fm-supervision-instructions.test.sh +189 -0
- package/.agents/tests/fm-tangle-guard.test.sh +277 -0
- package/.agents/tests/fm-task-delivery.test.sh +420 -0
- package/.agents/tests/fm-task-inbox.test.sh +513 -0
- package/.agents/tests/fm-teardown-endpoint-safety.test.sh +374 -0
- package/.agents/tests/fm-teardown.test.sh +2665 -0
- package/.agents/tests/fm-test-fixture-cleanup.test.sh +172 -0
- package/.agents/tests/fm-test-fixtures.test.sh +132 -0
- package/.agents/tests/fm-test-isolation-proof.test.sh +278 -0
- package/.agents/tests/fm-test-run.test.sh +1196 -0
- package/.agents/tests/fm-tmux-agent-liveness.test.sh +354 -0
- package/.agents/tests/fm-tmux-submit-busy.test.sh +340 -0
- package/.agents/tests/fm-tool-update-check.test.sh +1044 -0
- package/.agents/tests/fm-trace-context-lib.test.sh +253 -0
- package/.agents/tests/fm-trace-context-spawn.test.sh +581 -0
- package/.agents/tests/fm-transition-lib.test.sh +54 -0
- package/.agents/tests/fm-turnend-guard.test.sh +1822 -0
- package/.agents/tests/fm-update.test.sh +304 -0
- package/.agents/tests/fm-vendor-auth-probe.test.sh +395 -0
- package/.agents/tests/fm-voice-relay.test.sh +4741 -0
- package/.agents/tests/fm-wake-daemon-lifecycle-e2e.test.sh +171 -0
- package/.agents/tests/fm-wake-drain-open-decisions-cursor.test.sh +356 -0
- package/.agents/tests/fm-wake-drain-open-decisions.test.sh +226 -0
- package/.agents/tests/fm-wake-drain-unread-status.test.sh +379 -0
- package/.agents/tests/fm-wake-queue.test.sh +1224 -0
- package/.agents/tests/fm-watch-arm.test.sh +821 -0
- package/.agents/tests/fm-watch-checkpoint.test.sh +87 -0
- package/.agents/tests/fm-watch-recovery-loop.test.sh +223 -0
- package/.agents/tests/fm-watch-triage.test.sh +3889 -0
- package/.agents/tests/fm-watcher-lock.test.sh +1133 -0
- package/.agents/tests/fm-x-mode.test.sh +3042 -0
- package/.agents/tests/gleipnir-guard-pretool-check.test.sh +51 -0
- package/.agents/tests/gleipnir-machine-lock.test.sh +130 -0
- package/.agents/tests/herdr-test-safety.sh +42 -0
- package/.agents/tests/lib.sh +315 -0
- package/.agents/tests/remote-herdr-fixture.sh +125 -0
- package/.agents/tests/secondmate-helpers.sh +193 -0
- package/.agents/tests/smoke.test.sh +93 -0
- package/.agents/tests/wake-helpers.sh +338 -0
- package/.agents/tests/zellij-test-safety.sh +60 -0
- package/.agents/tools/README.md +10 -0
- package/.agents/tools/bin/tasks-cli +267 -0
- package/.agents/tools/tasks-cli.ts +216 -0
- package/AGENTS.md +454 -0
- package/CHANGELOG.md +881 -0
- package/LICENSE +1 -1
- package/NOTICE +63 -0
- package/README.md +113 -59
- package/RULES/01-domains.md +51 -0
- package/RULES/02-agents.md +78 -0
- package/RULES/03-houses.md +61 -0
- package/RULES/04-hoard.md +65 -0
- package/RULES/05-platforms.md +67 -0
- package/RULES/06-append-only.md +58 -0
- package/RULES/07-config.md +45 -0
- package/RULES/08-delivery-gate.md +75 -0
- package/RULES/README.md +20 -0
- package/bin/README.md +107 -0
- package/bin/a2a-mcp.sh +98 -0
- package/bin/a2a-serve.py +103 -0
- package/bin/a2a-serve.sh +8 -0
- package/bin/a2a-talk.sh +50 -0
- package/bin/a2abridge-ensure.sh +108 -0
- package/bin/agent-run.sh +43 -0
- package/bin/agents-config.sh +233 -0
- package/bin/apodex-smoke-test.sh +92 -0
- package/bin/bifrost-bridge.sh +112 -0
- package/bin/bifrost-ingress.sh +77 -0
- package/bin/bootstrap-macos.sh +107 -0
- package/bin/bootstrap-windows.ps1 +112 -0
- package/bin/branch-guard.sh +64 -0
- package/bin/brokk +73 -0
- package/bin/brokk-classify-lib.sh +1770 -0
- package/bin/brokk-lease-lib.sh +222 -0
- package/bin/brokk-lease.sh +193 -0
- package/bin/brokk-lint.sh +65 -0
- package/bin/brokk-send.sh +38 -0
- package/bin/brokk-update.sh +9 -0
- package/bin/brokk-wake-grant.sh +127 -0
- package/bin/brokk-wake-lib.sh +1849 -0
- package/bin/changelog-guard.sh +165 -0
- package/bin/crash-sense.sh +160 -0
- package/bin/desktop-place.sh +224 -0
- package/bin/docs-guard.sh +39 -0
- package/bin/editor-place.sh +207 -0
- package/bin/eindri-acclaim.sh +34 -0
- package/bin/eindri-control.sh +28 -0
- package/bin/eindri-role.sh +83 -0
- package/bin/eindri-seen.sh +41 -0
- package/bin/eindri-send.sh +15 -0
- package/bin/eindri-start.sh +85 -0
- package/bin/eindri-watch.sh +57 -0
- package/bin/einherjar-spawn.sh +576 -0
- package/bin/eir-doctor.sh +112 -0
- package/bin/erindi-brief.sh +271 -0
- package/bin/fleet-apply.sh +68 -0
- package/bin/github-deploy.sh +81 -0
- package/bin/gjallarhorn-expose.sh +102 -0
- package/bin/gjallarhorn-notify.sh +58 -0
- package/bin/gjallarhorn-purge.sh +54 -0
- package/bin/gjallarhorn-tunnel.sh +72 -0
- package/bin/gleipnir-lock-lib.sh +284 -0
- package/bin/groa-update.sh +122 -0
- package/bin/hall-snapshot.sh +92 -0
- package/bin/hamr-harness.sh +246 -0
- package/bin/heimdall-ssh-keys.sh +374 -0
- package/bin/herdr-agents.py +44 -0
- package/bin/herdr-ensure.sh +104 -0
- package/bin/herdr-run.sh +431 -0
- package/bin/hermes-ensure.sh +88 -0
- package/bin/hoard-lib.sh +25 -0
- package/bin/hodd.sh +78 -0
- package/bin/host-sense.sh +199 -0
- package/bin/huginn-research-worker.sh +108 -0
- package/bin/local-model-lock.sh +51 -0
- package/bin/mimir-bridge.py +226 -0
- package/bin/mimir-bridge.sh +87 -0
- package/bin/mimir-ingest.sh +131 -0
- package/bin/mimir.sh +113 -0
- package/bin/mjollnir-webhook.sh +59 -0
- package/bin/mjollnir.sh +85 -0
- package/bin/model-hardware.sh +82 -0
- package/bin/model-resolve.sh +147 -0
- package/bin/models-detect.sh +178 -0
- package/bin/nornir-cron-start.sh +162 -0
- package/bin/nornir-job-daily-briefing.sh +191 -0
- package/bin/nornir-job-git-sync.sh +152 -0
- package/bin/nornir-job-memory-housekeeping.sh +114 -0
- package/bin/nornir-job-observer.sh +166 -0
- package/bin/nornir-job-skillopt-sleep.sh +76 -0
- package/bin/omarchy-hook-install.sh +60 -0
- package/bin/omarchy-install.sh +148 -0
- package/bin/omarchy-plugins.sh +174 -0
- package/bin/omarchy-sense.sh +149 -0
- package/bin/perm-guard.sh +30 -0
- package/bin/pi-agent.sh +68 -0
- package/bin/pi-ensure.sh +77 -0
- package/bin/pi-local.sh +37 -0
- package/bin/pi-seat.sh +63 -0
- package/bin/prereq-ensure.sh +166 -0
- package/bin/private-guard.sh +38 -0
- package/bin/project-git.sh +55 -0
- package/bin/public-guard.sh +70 -0
- package/bin/ratatoskr.sh +49 -0
- package/bin/realm-lib.sh +32 -0
- package/bin/repo-scrub.sh +62 -0
- package/bin/rodd-operational-input.sh +250 -0
- package/bin/runes-append.sh +198 -0
- package/bin/saga-session-start.sh +172 -0
- package/bin/saga-sessionstart-run.sh +79 -0
- package/bin/saga-wake-drain.sh +41 -0
- package/bin/secret-guard.sh +63 -0
- package/bin/sessrumnir-ensure.sh +100 -0
- package/bin/sessrumnir-sync.sh +237 -0
- package/bin/sessrumnir.sh +91 -0
- package/bin/skillopt-setup.sh +76 -0
- package/bin/skuld-branch-outcome.sh +203 -0
- package/bin/skuld-branch-prompt.sh +101 -0
- package/bin/smidja-bootstrap.sh +90 -0
- package/bin/smidja-observe.sh +86 -0
- package/bin/syn-arm-pretool-check.sh +57 -0
- package/bin/syn-asset-pretool-check.sh +76 -0
- package/bin/syn-cd-pretool-check.sh +28 -0
- package/bin/syn-guard-pretool-check.sh +83 -0
- package/bin/syn-turnend-guard.sh +36 -0
- package/bin/syn-watch-arm.sh +99 -0
- package/bin/tailscale-sync.sh +190 -0
- package/bin/telegram-bot.sh +69 -0
- package/bin/toolchain.sh +74 -0
- package/bin/utgard.sh +111 -0
- package/bin/valhalla.sh +115 -0
- package/bin/valknut-load.sh +260 -0
- package/bin/vor-crew-state.sh +124 -0
- package/bin/wedge-notify.sh +47 -0
- package/bin/workspace-provision.sh +80 -0
- package/bin/workspace-rag.sh +150 -0
- package/bin/wyrd-db.sh +47 -0
- package/bin/yggdrasil.sh +152 -0
- package/bin/ymir-edit.sh +145 -0
- package/bin/ymir-install.sh +641 -0
- package/bin/ymir-invite.sh +93 -0
- package/bin/ymir-isolation.sh +88 -0
- package/bin/ymir-migrate.sh +61 -0
- package/bin/ymir-platform.sh +348 -0
- package/bin/ymir-say.sh +97 -0
- package/bin/ymir-setup-auth.sh +108 -0
- package/bin/ymir-validate.sh +173 -0
- package/bin/ymir.js +74 -16
- package/docs/Architecture.md +339 -0
- package/docs/design.md +351 -0
- package/docs/installations/README.md +63 -0
- package/docs/installations/ymir-home.md +93 -0
- package/docs/integration.md +105 -0
- package/docs/lore.md +1056 -0
- package/docs/research/agent-harnesses.md +290 -0
- package/docs/runbooks/README.md +19 -0
- package/docs/runbooks/a2a.md +91 -0
- package/docs/runbooks/agent-permissions.md +99 -0
- package/docs/runbooks/agents.md +57 -0
- package/docs/runbooks/models.md +69 -0
- package/docs/runbooks/realm-onboarding.md +60 -0
- package/docs/runbooks/secrets-and-hoard.md +60 -0
- package/docs/runbooks/updates-and-migrations.md +110 -0
- package/docs/runbooks/worktrees-isolation.md +72 -0
- package/docs/session-start.md +105 -0
- package/docs/skillopt-integration.md +321 -0
- package/docs/sync-system.md +66 -0
- package/docs/workspaces.md +104 -0
- package/docs/ymir-rut.md +260 -0
- package/package.json +44 -14
- package/packaging/build.sh +74 -0
- package/packaging/macos/Ymir Installer.command +43 -0
- package/packaging/windows/ymir-setup.nsi +74 -0
- package/scripts/README.md +22 -0
- package/scripts/electron.sh +210 -0
- package/scripts/start.sh +167 -0
- package/scripts/stop.sh +113 -0
- package/install.sh +0 -35
|
@@ -0,0 +1,709 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Regression tests for fm-guard's watcher-down banner deduplication.
|
|
3
|
+
#
|
|
4
|
+
# The first stale command in one FM_HOME must print the full actionable watcher
|
|
5
|
+
# banner.
|
|
6
|
+
# Repeated commands in that same stale episode should print only a concise
|
|
7
|
+
# reminder, while unrelated alarms such as queued wakes stay independent.
|
|
8
|
+
set -u
|
|
9
|
+
|
|
10
|
+
# shellcheck source=tests/lib.sh
|
|
11
|
+
. "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
|
|
12
|
+
|
|
13
|
+
TMP_ROOT=$(fm_test_tmproot fm-guard-stale-banner)
|
|
14
|
+
|
|
15
|
+
make_guard_case() {
|
|
16
|
+
local name=$1 dir home root
|
|
17
|
+
dir="$TMP_ROOT/$name"
|
|
18
|
+
home="$dir/home"
|
|
19
|
+
root="$dir/root"
|
|
20
|
+
mkdir -p "$home/state" "$home/config" "$root"
|
|
21
|
+
fm_write_meta "$home/state/task.meta" "window=firstmate:fm-task" "kind=ship"
|
|
22
|
+
printf '%s\n' "$dir"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
case_home() {
|
|
26
|
+
printf '%s/home\n' "$1"
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
case_root() {
|
|
30
|
+
printf '%s/root\n' "$1"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
record_live_watcher() {
|
|
34
|
+
local dir=$1 pid=$2 home identity
|
|
35
|
+
home=$(case_home "$dir")
|
|
36
|
+
identity=$(FM_STATE_OVERRIDE="$home/state" bash -c '. "$1"; fm_pid_identity "$2"' _ "$ROOT/bin/fm-wake-lib.sh" "$pid") || return 1
|
|
37
|
+
mkdir -p "$home/state/.watch.lock"
|
|
38
|
+
printf '%s\n' "$pid" > "$home/state/.watch.lock/pid"
|
|
39
|
+
printf '%s\n' "$home" > "$home/state/.watch.lock/fm-home"
|
|
40
|
+
printf '%s\n' "$ROOT/bin/fm-watch.sh" > "$home/state/.watch.lock/watcher-path"
|
|
41
|
+
printf '%s\n' "$identity" > "$home/state/.watch.lock/pid-identity"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# These cases exercise the persistent-watcher model (a live pid is the real
|
|
45
|
+
# liveness signal), so pin the model rather than letting the host test runner's
|
|
46
|
+
# ambient harness ancestry pick it.
|
|
47
|
+
run_guard_case() {
|
|
48
|
+
local dir=$1
|
|
49
|
+
FM_ROOT_OVERRIDE="$(case_root "$dir")" \
|
|
50
|
+
FM_HOME="$(case_home "$dir")" \
|
|
51
|
+
FM_GUARD_GRACE=999 \
|
|
52
|
+
FM_SUPERVISION_MODEL=persistent \
|
|
53
|
+
"$ROOT/bin/fm-guard.sh" 2>&1
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
run_guard_case_read_only() {
|
|
57
|
+
local dir=$1
|
|
58
|
+
FM_ROOT_OVERRIDE="$(case_root "$dir")" \
|
|
59
|
+
FM_HOME="$(case_home "$dir")" \
|
|
60
|
+
FM_GUARD_GRACE=999 \
|
|
61
|
+
FM_SUPERVISION_MODEL=persistent \
|
|
62
|
+
FM_GUARD_READ_ONLY=1 \
|
|
63
|
+
"$ROOT/bin/fm-guard.sh" 2>&1
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# The Claude Stop auto-arm model: the watcher runs only between turns, so a fresh
|
|
67
|
+
# beacon with no live watcher process is the healthy mid-turn state.
|
|
68
|
+
run_guard_case_autoarm() {
|
|
69
|
+
local dir=$1
|
|
70
|
+
FM_ROOT_OVERRIDE="$(case_root "$dir")" \
|
|
71
|
+
FM_HOME="$(case_home "$dir")" \
|
|
72
|
+
FM_GUARD_GRACE=999 \
|
|
73
|
+
FM_SUPERVISION_MODEL=autoarm \
|
|
74
|
+
"$ROOT/bin/fm-guard.sh" 2>&1
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
# The Pi extension model: .pi/extensions/fm-primary-pi-watch.ts tears the watcher
|
|
78
|
+
# down on every actionable wake and spawns the replacement itself, so the lock is
|
|
79
|
+
# legitimately unheld during a hand-off.
|
|
80
|
+
run_guard_case_extension() {
|
|
81
|
+
local dir=$1
|
|
82
|
+
FM_ROOT_OVERRIDE="$(case_root "$dir")" \
|
|
83
|
+
FM_HOME="$(case_home "$dir")" \
|
|
84
|
+
FM_GUARD_GRACE=999 \
|
|
85
|
+
FM_SUPERVISION_MODEL=extension \
|
|
86
|
+
"$ROOT/bin/fm-guard.sh" 2>&1
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# Stand up the durable evidence a live Pi session leaves behind: both primary
|
|
90
|
+
# extensions present under the case root, and a marker per extension recording
|
|
91
|
+
# that extension's current build plus the session pid in state/.lock.
|
|
92
|
+
# Each named part can be broken independently so a test can prove which one the
|
|
93
|
+
# verdict actually depends on.
|
|
94
|
+
# session_pid the pid state/.lock names (a live one unless the test wants a dead
|
|
95
|
+
# session); "" writes no session lock at all
|
|
96
|
+
# omit "" | watch | turnend - skip that extension's marker
|
|
97
|
+
# drift "" | watch | turnend - write a marker whose version is not the
|
|
98
|
+
# current build, i.e. the session loaded an older extension
|
|
99
|
+
record_pi_extension_session() {
|
|
100
|
+
local dir=$1 session_pid=${2:-} omit=${3:-} drift=${4:-} home root pair source marker version
|
|
101
|
+
home=$(case_home "$dir")
|
|
102
|
+
root=$(case_root "$dir")
|
|
103
|
+
mkdir -p "$root/.pi/extensions"
|
|
104
|
+
for pair in \
|
|
105
|
+
"fm-primary-pi-watch.ts:.pi-watch-extension-loaded:watch" \
|
|
106
|
+
"fm-primary-turnend-guard.ts:.pi-turnend-extension-loaded:turnend"; do
|
|
107
|
+
source=${pair%%:*}
|
|
108
|
+
marker=${pair#*:}; marker=${marker%%:*}
|
|
109
|
+
printf '// %s for %s\n' "${pair##*:}" "$(basename "$dir")" > "$root/.pi/extensions/$source"
|
|
110
|
+
[ "$omit" = "${pair##*:}" ] && continue
|
|
111
|
+
if [ "$drift" = "${pair##*:}" ]; then
|
|
112
|
+
version="sha256:0000000000000000000000000000000000000000000000000000000000000000"
|
|
113
|
+
else
|
|
114
|
+
version=$(FM_STATE_OVERRIDE="$home/state" bash -c '. "$1"; fm_pi_extension_version "$2"' \
|
|
115
|
+
_ "$ROOT/bin/fm-wake-lib.sh" "$root/.pi/extensions/$source") || return 1
|
|
116
|
+
fi
|
|
117
|
+
printf '%s\n%s\n' "$version" "$session_pid" > "$home/state/$marker"
|
|
118
|
+
done
|
|
119
|
+
[ -n "$session_pid" ] && printf '%s\n' "$session_pid" > "$home/state/.lock"
|
|
120
|
+
return 0
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
count_text() {
|
|
124
|
+
local haystack=$1 needle=$2
|
|
125
|
+
awk -v needle="$needle" 'index($0, needle) { c++ } END { print c + 0 }' <<EOF
|
|
126
|
+
$haystack
|
|
127
|
+
EOF
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
test_first_stale_call_prints_full_banner() {
|
|
131
|
+
local dir out
|
|
132
|
+
dir=$(make_guard_case first-stale)
|
|
133
|
+
out=$(run_guard_case "$dir")
|
|
134
|
+
[ "$(count_text "$out" "WATCHER DOWN - SUPERVISION IS OFF")" -eq 1 ] \
|
|
135
|
+
|| fail "first stale guard call did not print exactly one full banner: $out"
|
|
136
|
+
assert_contains "$out" "Trust the emitted supervision protocol" \
|
|
137
|
+
"full banner must keep the actionable watcher-repair instruction"
|
|
138
|
+
assert_contains "$out" "WILL still run" \
|
|
139
|
+
"full banner must keep the guarded-operation continuation line"
|
|
140
|
+
pass "fm-guard stale banner: first stale call prints the full actionable banner"
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
test_repeated_same_episode_prints_reminder_only() {
|
|
144
|
+
local dir out1 out2 marker lines
|
|
145
|
+
dir=$(make_guard_case repeated-stale)
|
|
146
|
+
out1=$(run_guard_case "$dir")
|
|
147
|
+
out2=$(run_guard_case "$dir")
|
|
148
|
+
[ "$(count_text "$out1" "WATCHER DOWN - SUPERVISION IS OFF")" -eq 1 ] \
|
|
149
|
+
|| fail "first stale call did not print the full banner: $out1"
|
|
150
|
+
[ "$(count_text "$out2" "WATCHER DOWN - SUPERVISION IS OFF")" -eq 0 ] \
|
|
151
|
+
|| fail "second stale call repeated the full banner: $out2"
|
|
152
|
+
assert_contains "$out2" "full banner already printed this episode" \
|
|
153
|
+
"second stale call did not print the concise reminder"
|
|
154
|
+
marker="$(case_home "$dir")/state/.guard-watcher-stale-banner"
|
|
155
|
+
assert_present "$marker" "stale banner marker was not written under the owning home"
|
|
156
|
+
lines=$(awk 'END { print NR + 0 }' "$marker")
|
|
157
|
+
[ "$lines" -le 1 ] || fail "stale banner marker must stay bounded to one line, got $lines"
|
|
158
|
+
pass "fm-guard stale banner: repeated same-episode calls print a concise reminder only"
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
test_fresh_beacon_without_live_watcher_stays_alarm() {
|
|
162
|
+
local dir out
|
|
163
|
+
dir=$(make_guard_case fresh-no-live)
|
|
164
|
+
touch "$(case_home "$dir")/state/.last-watcher-beat"
|
|
165
|
+
out=$(run_guard_case "$dir")
|
|
166
|
+
[ "$(count_text "$out" "WATCHER DOWN - SUPERVISION IS OFF")" -eq 1 ] \
|
|
167
|
+
|| fail "a fresh leftover beacon without a live watcher must still alarm: $out"
|
|
168
|
+
pass "fm-guard stale banner: a fresh beacon without a live watcher remains unhealthy"
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
test_x_mode_without_live_watcher_stays_alarm() {
|
|
172
|
+
local dir home out
|
|
173
|
+
dir=$(make_guard_case x-mode-no-live)
|
|
174
|
+
home=$(case_home "$dir")
|
|
175
|
+
rm -f "$home/state/task.meta"
|
|
176
|
+
: > "$home/state/x-watch.check.sh"
|
|
177
|
+
out=$(run_guard_case "$dir")
|
|
178
|
+
assert_contains "$out" "X-mode relay polling needs supervision" "X-mode-only need must remain guarded"
|
|
179
|
+
pass "fm-guard stale banner: X-mode polling without a live watcher remains unhealthy"
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
test_healthy_recovery_rearms_next_stale_episode() {
|
|
183
|
+
local dir home out1 healthy out2 pid
|
|
184
|
+
dir=$(make_guard_case healthy-recovery)
|
|
185
|
+
home=$(case_home "$dir")
|
|
186
|
+
out1=$(run_guard_case "$dir")
|
|
187
|
+
[ "$(count_text "$out1" "WATCHER DOWN - SUPERVISION IS OFF")" -eq 1 ] \
|
|
188
|
+
|| fail "first stale episode did not print the full banner: $out1"
|
|
189
|
+
|
|
190
|
+
sleep 60 &
|
|
191
|
+
pid=$!
|
|
192
|
+
record_live_watcher "$dir" "$pid" || fail "could not record the live watcher for recovery"
|
|
193
|
+
touch "$home/state/.last-watcher-beat"
|
|
194
|
+
healthy=$(run_guard_case "$dir")
|
|
195
|
+
kill "$pid" 2>/dev/null || true
|
|
196
|
+
wait "$pid" 2>/dev/null || true
|
|
197
|
+
[ -z "$healthy" ] || fail "guard should be silent after watcher recovery, got: $healthy"
|
|
198
|
+
assert_absent "$home/state/.guard-watcher-stale-banner" \
|
|
199
|
+
"healthy recovery must clear the stale-banner marker"
|
|
200
|
+
|
|
201
|
+
rm -f "$home/state/.last-watcher-beat"
|
|
202
|
+
rm -rf "$home/state/.watch.lock"
|
|
203
|
+
out2=$(run_guard_case "$dir")
|
|
204
|
+
[ "$(count_text "$out2" "WATCHER DOWN - SUPERVISION IS OFF")" -eq 1 ] \
|
|
205
|
+
|| fail "second stale episode did not re-print the full banner: $out2"
|
|
206
|
+
pass "fm-guard stale banner: healthy recovery rearms the next stale episode"
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
test_concurrent_same_episode_prints_one_full_banner() {
|
|
210
|
+
local dir out_dir i pids pid all full reminders
|
|
211
|
+
dir=$(make_guard_case concurrent-stale)
|
|
212
|
+
out_dir="$dir/outs"
|
|
213
|
+
mkdir -p "$out_dir"
|
|
214
|
+
pids=
|
|
215
|
+
i=1
|
|
216
|
+
while [ "$i" -le 30 ]; do
|
|
217
|
+
(
|
|
218
|
+
run_guard_case "$dir" > "$out_dir/$i.out" 2>&1
|
|
219
|
+
) &
|
|
220
|
+
pids="$pids $!"
|
|
221
|
+
i=$((i + 1))
|
|
222
|
+
done
|
|
223
|
+
for pid in $pids; do
|
|
224
|
+
wait "$pid" 2>/dev/null || fail "concurrent guard subprocess failed"
|
|
225
|
+
done
|
|
226
|
+
all=$(cat "$out_dir"/*.out)
|
|
227
|
+
full=$(count_text "$all" "WATCHER DOWN - SUPERVISION IS OFF")
|
|
228
|
+
reminders=$(count_text "$all" "full banner already printed this episode")
|
|
229
|
+
[ "$full" -eq 1 ] || fail "concurrent same-episode calls printed $full full banners"$'\n'"$all"
|
|
230
|
+
[ "$reminders" -eq 29 ] || fail "concurrent same-episode calls printed $reminders reminders, expected 29"$'\n'"$all"
|
|
231
|
+
pass "fm-guard stale banner: concurrent same-episode calls claim exactly one full banner"
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
test_home_isolation() {
|
|
235
|
+
local dir_a dir_b out_a1 out_a2 out_b1
|
|
236
|
+
dir_a=$(make_guard_case home-a)
|
|
237
|
+
dir_b=$(make_guard_case home-b)
|
|
238
|
+
out_a1=$(run_guard_case "$dir_a")
|
|
239
|
+
out_b1=$(run_guard_case "$dir_b")
|
|
240
|
+
out_a2=$(run_guard_case "$dir_a")
|
|
241
|
+
[ "$(count_text "$out_a1" "WATCHER DOWN - SUPERVISION IS OFF")" -eq 1 ] \
|
|
242
|
+
|| fail "home A first stale call did not print a full banner: $out_a1"
|
|
243
|
+
[ "$(count_text "$out_b1" "WATCHER DOWN - SUPERVISION IS OFF")" -eq 1 ] \
|
|
244
|
+
|| fail "home B first stale call was suppressed by home A: $out_b1"
|
|
245
|
+
assert_contains "$out_a2" "full banner already printed this episode" \
|
|
246
|
+
"home A repeated stale call did not remember its own episode"
|
|
247
|
+
pass "fm-guard stale banner: deduplication is isolated per FM_HOME"
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
test_queued_wake_warning_stays_independent() {
|
|
251
|
+
local dir home out1 out2
|
|
252
|
+
dir=$(make_guard_case queued-wake)
|
|
253
|
+
home=$(case_home "$dir")
|
|
254
|
+
out1=$(run_guard_case "$dir")
|
|
255
|
+
[ "$(count_text "$out1" "WATCHER DOWN - SUPERVISION IS OFF")" -eq 1 ] \
|
|
256
|
+
|| fail "first stale call did not print the full banner before queued wake case: $out1"
|
|
257
|
+
printf 'signal: %s/state/task.status\n' "$home" > "$home/state/.wake-queue"
|
|
258
|
+
out2=$(run_guard_case "$dir")
|
|
259
|
+
assert_contains "$out2" "full banner already printed this episode" \
|
|
260
|
+
"same-episode stale call should still print its concise reminder"
|
|
261
|
+
assert_contains "$out2" "queued wakes pending" \
|
|
262
|
+
"queued wake warning must not be suppressed by stale-banner deduplication"
|
|
263
|
+
pass "fm-guard stale banner: queued-wake warning remains independent"
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
test_read_only_before_writable_does_not_consume_full_banner() {
|
|
267
|
+
local dir home marker lock out_ro out_rw
|
|
268
|
+
dir=$(make_guard_case read-only-before-writable)
|
|
269
|
+
home=$(case_home "$dir")
|
|
270
|
+
marker="$home/state/.guard-watcher-stale-banner"
|
|
271
|
+
lock="$home/state/.guard-watcher-stale-banner.lock"
|
|
272
|
+
|
|
273
|
+
out_ro=$(run_guard_case_read_only "$dir")
|
|
274
|
+
[ "$(count_text "$out_ro" "WATCHER DOWN - SUPERVISION IS OFF")" -eq 1 ] \
|
|
275
|
+
|| fail "read-only stale call should print the advisory full banner: $out_ro"
|
|
276
|
+
assert_absent "$marker" "read-only stale call must not create the stale-banner marker"
|
|
277
|
+
assert_absent "$lock" "read-only stale call must not create the stale-banner lock"
|
|
278
|
+
|
|
279
|
+
out_rw=$(run_guard_case "$dir")
|
|
280
|
+
[ "$(count_text "$out_rw" "WATCHER DOWN - SUPERVISION IS OFF")" -eq 1 ] \
|
|
281
|
+
|| fail "writable stale call should still receive the full banner after read-only: $out_rw"
|
|
282
|
+
assert_present "$marker" "writable stale call should claim the stale-banner marker"
|
|
283
|
+
pass "fm-guard stale banner: read-only before writable does not consume full banner"
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
test_read_only_during_episode_observes_without_mutating_marker() {
|
|
287
|
+
local dir home marker before after out_ro
|
|
288
|
+
dir=$(make_guard_case read-only-during-episode)
|
|
289
|
+
home=$(case_home "$dir")
|
|
290
|
+
marker="$home/state/.guard-watcher-stale-banner"
|
|
291
|
+
|
|
292
|
+
run_guard_case "$dir" >/dev/null
|
|
293
|
+
before=$(cat "$marker")
|
|
294
|
+
out_ro=$(run_guard_case_read_only "$dir")
|
|
295
|
+
after=$(cat "$marker")
|
|
296
|
+
assert_contains "$out_ro" "full banner already printed this episode" \
|
|
297
|
+
"read-only stale call during a claimed episode should print the concise reminder"
|
|
298
|
+
[ "$after" = "$before" ] || fail "read-only stale call must not update an existing marker"
|
|
299
|
+
pass "fm-guard stale banner: read-only during episode observes without mutating marker"
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
test_healthy_read_only_does_not_clear_marker() {
|
|
303
|
+
local dir home marker before after healthy pid
|
|
304
|
+
dir=$(make_guard_case healthy-read-only)
|
|
305
|
+
home=$(case_home "$dir")
|
|
306
|
+
marker="$home/state/.guard-watcher-stale-banner"
|
|
307
|
+
|
|
308
|
+
run_guard_case "$dir" >/dev/null
|
|
309
|
+
before=$(cat "$marker")
|
|
310
|
+
sleep 60 &
|
|
311
|
+
pid=$!
|
|
312
|
+
record_live_watcher "$dir" "$pid" || fail "could not record the live watcher for read-only recovery"
|
|
313
|
+
touch "$home/state/.last-watcher-beat"
|
|
314
|
+
healthy=$(run_guard_case_read_only "$dir")
|
|
315
|
+
kill "$pid" 2>/dev/null || true
|
|
316
|
+
wait "$pid" 2>/dev/null || true
|
|
317
|
+
[ -z "$healthy" ] || fail "healthy read-only guard should stay silent, got: $healthy"
|
|
318
|
+
assert_present "$marker" "healthy read-only guard must not clear the stale-banner marker"
|
|
319
|
+
after=$(cat "$marker")
|
|
320
|
+
[ "$after" = "$before" ] || fail "healthy read-only guard must not update the marker"
|
|
321
|
+
pass "fm-guard stale banner: healthy read-only does not clear marker"
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
test_read_only_never_mutates_stale_banner_state_files() {
|
|
325
|
+
local dir home marker lock before after no_work
|
|
326
|
+
dir=$(make_guard_case read-only-state-nonmutation)
|
|
327
|
+
home=$(case_home "$dir")
|
|
328
|
+
marker="$home/state/.guard-watcher-stale-banner"
|
|
329
|
+
lock="$home/state/.guard-watcher-stale-banner.lock"
|
|
330
|
+
printf '%s\n' "sentinel-marker" > "$marker"
|
|
331
|
+
|
|
332
|
+
before=$(find "$home/state" -maxdepth 1 -mindepth 1 -name '.guard-watcher-stale-banner*' -print | sort)
|
|
333
|
+
run_guard_case_read_only "$dir" >/dev/null
|
|
334
|
+
after=$(find "$home/state" -maxdepth 1 -mindepth 1 -name '.guard-watcher-stale-banner*' -print | sort)
|
|
335
|
+
[ "$after" = "$before" ] || fail "stale read-only guard changed stale-banner state files"$'\n'"before: $before"$'\n'"after: $after"
|
|
336
|
+
[ "$(cat "$marker")" = "sentinel-marker" ] || fail "stale read-only guard updated the marker content"
|
|
337
|
+
assert_absent "$lock" "stale read-only guard must not create the stale-banner lock"
|
|
338
|
+
|
|
339
|
+
rm -f "$home/state/task.meta"
|
|
340
|
+
no_work=$(run_guard_case_read_only "$dir")
|
|
341
|
+
[ -z "$no_work" ] || fail "read-only guard with no in-flight work should stay silent, got: $no_work"
|
|
342
|
+
after=$(find "$home/state" -maxdepth 1 -mindepth 1 -name '.guard-watcher-stale-banner*' -print | sort)
|
|
343
|
+
[ "$after" = "$before" ] || fail "no-work read-only guard changed stale-banner state files"$'\n'"before: $before"$'\n'"after: $after"
|
|
344
|
+
[ "$(cat "$marker")" = "sentinel-marker" ] || fail "no-work read-only guard updated the marker content"
|
|
345
|
+
pass "fm-guard stale banner: read-only never mutates stale-banner state files"
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
test_autoarm_fresh_beacon_without_watcher_is_healthy() {
|
|
349
|
+
local dir out
|
|
350
|
+
dir=$(make_guard_case autoarm-fresh)
|
|
351
|
+
# A fresh beacon and NO live watcher: the healthy mid-turn state under the
|
|
352
|
+
# Claude Stop auto-arm model, where the watcher only runs between turns.
|
|
353
|
+
touch "$(case_home "$dir")/state/.last-watcher-beat"
|
|
354
|
+
out=$(run_guard_case_autoarm "$dir")
|
|
355
|
+
[ -z "$out" ] \
|
|
356
|
+
|| fail "auto-arm model with a fresh beacon and no live watcher must stay silent, got: $out"
|
|
357
|
+
pass "fm-guard stale banner: auto-arm fresh beacon without a live watcher is healthy"
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
test_autoarm_stale_beacon_alarms_with_correct_reason() {
|
|
361
|
+
local dir out
|
|
362
|
+
dir=$(make_guard_case autoarm-stale)
|
|
363
|
+
# No beacon at all -> a genuine supervision lapse even under the auto-arm model.
|
|
364
|
+
out=$(run_guard_case_autoarm "$dir")
|
|
365
|
+
[ "$(count_text "$out" "WATCHER DOWN - SUPERVISION IS OFF")" -eq 1 ] \
|
|
366
|
+
|| fail "auto-arm model with an absent/stale beacon must alarm: $out"
|
|
367
|
+
assert_contains "$out" "no watcher has a fresh beacon" \
|
|
368
|
+
"auto-arm stale-beacon banner must name the stale-beacon reason"
|
|
369
|
+
pass "fm-guard stale banner: auto-arm stale beacon alarms with the true reason"
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
test_autoarm_stale_episode_is_stable() {
|
|
373
|
+
local dir out1 out2
|
|
374
|
+
dir=$(make_guard_case autoarm-stable-episode)
|
|
375
|
+
out1=$(run_guard_case_autoarm "$dir")
|
|
376
|
+
out2=$(run_guard_case_autoarm "$dir")
|
|
377
|
+
[ "$(count_text "$out1" "WATCHER DOWN - SUPERVISION IS OFF")" -eq 1 ] \
|
|
378
|
+
|| fail "first auto-arm stale call did not print the full banner: $out1"
|
|
379
|
+
[ "$(count_text "$out2" "WATCHER DOWN - SUPERVISION IS OFF")" -eq 0 ] \
|
|
380
|
+
|| fail "auto-arm stale episode re-printed the full banner instead of deduping: $out2"
|
|
381
|
+
assert_contains "$out2" "full banner already printed this episode" \
|
|
382
|
+
"second auto-arm stale call did not print the concise reminder"
|
|
383
|
+
pass "fm-guard stale banner: auto-arm stale episode stays one episode across calls"
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
test_persistent_no_watcher_banner_names_missing_process() {
|
|
387
|
+
local dir out
|
|
388
|
+
dir=$(make_guard_case persistent-no-watcher-reason)
|
|
389
|
+
# A fresh beacon with no live watcher under the persistent model: the real
|
|
390
|
+
# failing condition is the missing process, not a stale beacon.
|
|
391
|
+
touch "$(case_home "$dir")/state/.last-watcher-beat"
|
|
392
|
+
out=$(run_guard_case "$dir")
|
|
393
|
+
assert_contains "$out" "no live watcher process holds this home lock" \
|
|
394
|
+
"persistent no-watcher banner must name the missing watcher process"
|
|
395
|
+
assert_not_contains "$out" "no watcher has a fresh beacon" \
|
|
396
|
+
"persistent no-watcher banner must not blame the fresh beacon"
|
|
397
|
+
pass "fm-guard stale banner: persistent no-watcher banner names the true reason"
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
test_persistent_no_watcher_episode_survives_beacon_touch() {
|
|
401
|
+
local dir home out1 out2
|
|
402
|
+
dir=$(make_guard_case persistent-no-watcher-episode)
|
|
403
|
+
home=$(case_home "$dir")
|
|
404
|
+
touch "$home/state/.last-watcher-beat"
|
|
405
|
+
out1=$(run_guard_case "$dir")
|
|
406
|
+
[ "$(count_text "$out1" "WATCHER DOWN - SUPERVISION IS OFF")" -eq 1 ] \
|
|
407
|
+
|| fail "first persistent no-watcher call did not print the full banner: $out1"
|
|
408
|
+
# The beacon mtime advancing with NO live watcher must not split the continuous
|
|
409
|
+
# down-episode. The old beacon-mtime episode key re-printed the full banner
|
|
410
|
+
# here; the reason-based key keeps it a single episode. Separate the touches by
|
|
411
|
+
# a second so the mtime genuinely changes at whole-second stat granularity.
|
|
412
|
+
sleep 1
|
|
413
|
+
touch "$home/state/.last-watcher-beat"
|
|
414
|
+
out2=$(run_guard_case "$dir")
|
|
415
|
+
[ "$(count_text "$out2" "WATCHER DOWN - SUPERVISION IS OFF")" -eq 0 ] \
|
|
416
|
+
|| fail "advancing the beacon mtime with no live watcher re-printed the banner: $out2"
|
|
417
|
+
assert_contains "$out2" "full banner already printed this episode" \
|
|
418
|
+
"same no-watcher episode did not print the concise reminder after a beacon touch"
|
|
419
|
+
pass "fm-guard stale banner: a no-watcher episode survives a beacon mtime change"
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
# The send-time false alarm this suite exists to pin: on a Pi primary the watcher
|
|
423
|
+
# process is torn down and respawned by the extension on every actionable wake, so
|
|
424
|
+
# a guarded command that lands in a hand-off sees a fresh beacon and an unheld lock
|
|
425
|
+
# - state the persistent model cannot tell apart from supervision being off.
|
|
426
|
+
test_extension_handoff_with_live_session_is_healthy() {
|
|
427
|
+
local dir home out pid
|
|
428
|
+
dir=$(make_guard_case extension-handoff)
|
|
429
|
+
home=$(case_home "$dir")
|
|
430
|
+
sleep 60 &
|
|
431
|
+
pid=$!
|
|
432
|
+
record_pi_extension_session "$dir" "$pid" || fail "could not record the Pi extension session"
|
|
433
|
+
touch "$home/state/.last-watcher-beat"
|
|
434
|
+
out=$(run_guard_case_extension "$dir")
|
|
435
|
+
kill "$pid" 2>/dev/null || true
|
|
436
|
+
wait "$pid" 2>/dev/null || true
|
|
437
|
+
[ -z "$out" ] \
|
|
438
|
+
|| fail "an extension-owned hand-off with a live Pi session must stay silent, got: $out"
|
|
439
|
+
assert_absent "$home/state/.guard-watcher-stale-banner" \
|
|
440
|
+
"a healthy extension-owned hand-off must not open a down-episode"
|
|
441
|
+
pass "fm-guard stale banner: extension-owned hand-off with a live session is healthy"
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
# A released owner may leave the lock directory briefly before cleanup. It is
|
|
445
|
+
# still genuinely unheld when it records no pid, so the hand-off stays benign.
|
|
446
|
+
test_extension_handoff_with_empty_lock_is_healthy() {
|
|
447
|
+
local dir home out pid
|
|
448
|
+
dir=$(make_guard_case extension-empty-lock)
|
|
449
|
+
home=$(case_home "$dir")
|
|
450
|
+
sleep 60 &
|
|
451
|
+
pid=$!
|
|
452
|
+
record_pi_extension_session "$dir" "$pid" || fail "could not record the Pi extension session"
|
|
453
|
+
mkdir -p "$home/state/.watch.lock"
|
|
454
|
+
touch "$home/state/.last-watcher-beat"
|
|
455
|
+
out=$(run_guard_case_extension "$dir")
|
|
456
|
+
kill "$pid" 2>/dev/null || true
|
|
457
|
+
wait "$pid" 2>/dev/null || true
|
|
458
|
+
[ -z "$out" ] \
|
|
459
|
+
|| fail "an extension-owned hand-off with an empty lock must stay silent, got: $out"
|
|
460
|
+
assert_absent "$home/state/.guard-watcher-stale-banner" \
|
|
461
|
+
"an empty lock during a healthy hand-off must not open a down-episode"
|
|
462
|
+
pass "fm-guard stale banner: extension-owned empty lock is genuinely unheld"
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
# Extension ownership tolerates only a released lock. Every non-empty recorded
|
|
466
|
+
# pid means the lock is held, so any strict watcher-health failure stays loud.
|
|
467
|
+
test_extension_held_unhealthy_locks_stay_alarm() {
|
|
468
|
+
local dir home out session_pid holder_pid case_name
|
|
469
|
+
for case_name in dead-pid malformed-pid wrong-home wrong-path identity-mismatch; do
|
|
470
|
+
dir=$(make_guard_case "extension-held-$case_name")
|
|
471
|
+
home=$(case_home "$dir")
|
|
472
|
+
sleep 60 &
|
|
473
|
+
session_pid=$!
|
|
474
|
+
record_pi_extension_session "$dir" "$session_pid" \
|
|
475
|
+
|| fail "could not record the Pi extension session for $case_name"
|
|
476
|
+
holder_pid=
|
|
477
|
+
case "$case_name" in
|
|
478
|
+
malformed-pid)
|
|
479
|
+
mkdir -p "$home/state/.watch.lock"
|
|
480
|
+
printf '%s\n' not-a-pid > "$home/state/.watch.lock/pid"
|
|
481
|
+
;;
|
|
482
|
+
*)
|
|
483
|
+
sleep 60 &
|
|
484
|
+
holder_pid=$!
|
|
485
|
+
record_live_watcher "$dir" "$holder_pid" \
|
|
486
|
+
|| fail "could not record the watcher lock for $case_name"
|
|
487
|
+
case "$case_name" in
|
|
488
|
+
dead-pid)
|
|
489
|
+
kill "$holder_pid" 2>/dev/null || true
|
|
490
|
+
wait "$holder_pid" 2>/dev/null || true
|
|
491
|
+
holder_pid=
|
|
492
|
+
;;
|
|
493
|
+
wrong-home)
|
|
494
|
+
printf '%s\n' "$home/other" > "$home/state/.watch.lock/fm-home"
|
|
495
|
+
;;
|
|
496
|
+
wrong-path)
|
|
497
|
+
printf '%s\n' "$home/bin/not-fm-watch.sh" > "$home/state/.watch.lock/watcher-path"
|
|
498
|
+
;;
|
|
499
|
+
identity-mismatch)
|
|
500
|
+
printf '%s\n' mismatched-identity > "$home/state/.watch.lock/pid-identity"
|
|
501
|
+
;;
|
|
502
|
+
esac
|
|
503
|
+
;;
|
|
504
|
+
esac
|
|
505
|
+
touch "$home/state/.last-watcher-beat"
|
|
506
|
+
out=$(run_guard_case_extension "$dir")
|
|
507
|
+
[ -z "$holder_pid" ] || kill "$holder_pid" 2>/dev/null || true
|
|
508
|
+
[ -z "$holder_pid" ] || wait "$holder_pid" 2>/dev/null || true
|
|
509
|
+
kill "$session_pid" 2>/dev/null || true
|
|
510
|
+
wait "$session_pid" 2>/dev/null || true
|
|
511
|
+
[ "$(count_text "$out" "WATCHER DOWN - SUPERVISION IS OFF")" -eq 1 ] \
|
|
512
|
+
|| fail "an extension-owned held lock with $case_name must alarm: $out"
|
|
513
|
+
assert_contains "$out" "no live watcher process holds this home lock" \
|
|
514
|
+
"a held unhealthy lock with $case_name must report no-watcher"
|
|
515
|
+
done
|
|
516
|
+
pass "fm-guard stale banner: held unhealthy extension locks stay loud"
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
# The same unheld lock and fresh beacon, with NO extension ownership to prove, is
|
|
520
|
+
# the genuinely-down cycle and must stay exactly as loud as before.
|
|
521
|
+
test_extension_without_ownership_evidence_stays_alarm() {
|
|
522
|
+
local dir home out
|
|
523
|
+
dir=$(make_guard_case extension-no-evidence)
|
|
524
|
+
home=$(case_home "$dir")
|
|
525
|
+
touch "$home/state/.last-watcher-beat"
|
|
526
|
+
out=$(run_guard_case_extension "$dir")
|
|
527
|
+
[ "$(count_text "$out" "WATCHER DOWN - SUPERVISION IS OFF")" -eq 1 ] \
|
|
528
|
+
|| fail "an unheld lock with no extension ownership evidence must alarm: $out"
|
|
529
|
+
assert_contains "$out" "no live watcher process holds this home lock" \
|
|
530
|
+
"the unowned extension-model banner must name the missing watcher process"
|
|
531
|
+
pass "fm-guard stale banner: extension model without ownership evidence stays loud"
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
# Drive the ownership signals apart one at a time. Each part is load-bearing on its
|
|
535
|
+
# own, so losing any single one restores the alarm rather than leaving the tolerance
|
|
536
|
+
# resting on whichever signal happens to survive.
|
|
537
|
+
test_extension_ownership_needs_every_signal() {
|
|
538
|
+
local dir home out pid case_name spec
|
|
539
|
+
for spec in \
|
|
540
|
+
"dead-session:dead::" \
|
|
541
|
+
"missing-watch-marker:live:watch:" \
|
|
542
|
+
"missing-turnend-marker:live:turnend:" \
|
|
543
|
+
"drifted-watch-build:live::watch" \
|
|
544
|
+
"drifted-turnend-build:live::turnend"; do
|
|
545
|
+
case_name=${spec%%:*}
|
|
546
|
+
dir=$(make_guard_case "extension-$case_name")
|
|
547
|
+
home=$(case_home "$dir")
|
|
548
|
+
sleep 60 &
|
|
549
|
+
pid=$!
|
|
550
|
+
if [ "$(printf '%s' "$spec" | cut -d: -f2)" = dead ]; then
|
|
551
|
+
kill "$pid" 2>/dev/null || true
|
|
552
|
+
wait "$pid" 2>/dev/null || true
|
|
553
|
+
fi
|
|
554
|
+
record_pi_extension_session "$dir" "$pid" \
|
|
555
|
+
"$(printf '%s' "$spec" | cut -d: -f3)" \
|
|
556
|
+
"$(printf '%s' "$spec" | cut -d: -f4)" \
|
|
557
|
+
|| fail "could not record the Pi extension session for $case_name"
|
|
558
|
+
touch "$home/state/.last-watcher-beat"
|
|
559
|
+
out=$(run_guard_case_extension "$dir")
|
|
560
|
+
kill "$pid" 2>/dev/null || true
|
|
561
|
+
wait "$pid" 2>/dev/null || true
|
|
562
|
+
[ "$(count_text "$out" "WATCHER DOWN - SUPERVISION IS OFF")" -eq 1 ] \
|
|
563
|
+
|| fail "extension ownership must not survive $case_name; guard output: $out"
|
|
564
|
+
done
|
|
565
|
+
pass "fm-guard stale banner: every extension-ownership signal is load-bearing"
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
# Ownership tolerates the hand-off, never a supervision lapse: once the beacon
|
|
569
|
+
# passes the grace window the extension has not restored the cycle and the banner
|
|
570
|
+
# must fire even with a fully live, correctly loaded Pi session.
|
|
571
|
+
test_extension_stale_beacon_alarms_despite_live_session() {
|
|
572
|
+
local dir home out pid
|
|
573
|
+
dir=$(make_guard_case extension-stale-beacon)
|
|
574
|
+
home=$(case_home "$dir")
|
|
575
|
+
sleep 60 &
|
|
576
|
+
pid=$!
|
|
577
|
+
record_pi_extension_session "$dir" "$pid" || fail "could not record the Pi extension session"
|
|
578
|
+
out=$(FM_ROOT_OVERRIDE="$(case_root "$dir")" \
|
|
579
|
+
FM_HOME="$home" \
|
|
580
|
+
FM_GUARD_GRACE=1 \
|
|
581
|
+
FM_SUPERVISION_MODEL=extension \
|
|
582
|
+
"$ROOT/bin/fm-guard.sh" 2>&1)
|
|
583
|
+
kill "$pid" 2>/dev/null || true
|
|
584
|
+
wait "$pid" 2>/dev/null || true
|
|
585
|
+
[ "$(count_text "$out" "WATCHER DOWN - SUPERVISION IS OFF")" -eq 1 ] \
|
|
586
|
+
|| fail "a beacon past grace must alarm even under a live Pi session: $out"
|
|
587
|
+
assert_contains "$out" "no watcher has a fresh beacon" \
|
|
588
|
+
"the extension-model stale-beacon banner must name the stale beacon"
|
|
589
|
+
pass "fm-guard stale banner: extension model still alarms on a genuinely stale beacon"
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
# The queued-wake hazard is independent of the watcher verdict and must survive the
|
|
593
|
+
# hand-off tolerance: a silenced banner must never take this warning down with it.
|
|
594
|
+
test_extension_handoff_keeps_queued_wake_warning() {
|
|
595
|
+
local dir home out pid
|
|
596
|
+
dir=$(make_guard_case extension-queued-wake)
|
|
597
|
+
home=$(case_home "$dir")
|
|
598
|
+
sleep 60 &
|
|
599
|
+
pid=$!
|
|
600
|
+
record_pi_extension_session "$dir" "$pid" || fail "could not record the Pi extension session"
|
|
601
|
+
touch "$home/state/.last-watcher-beat"
|
|
602
|
+
printf '%s\n' "1700000000 1 signal task signal: crewmate needs a decision" > "$home/state/.wake-queue"
|
|
603
|
+
out=$(run_guard_case_extension "$dir")
|
|
604
|
+
kill "$pid" 2>/dev/null || true
|
|
605
|
+
wait "$pid" 2>/dev/null || true
|
|
606
|
+
assert_contains "$out" "queued wakes pending" \
|
|
607
|
+
"the queued-wake warning must still fire during an extension-owned hand-off"
|
|
608
|
+
assert_not_contains "$out" "WATCHER DOWN - SUPERVISION IS OFF" \
|
|
609
|
+
"a queued wake must not resurrect the watcher-down banner for a healthy hand-off"
|
|
610
|
+
pass "fm-guard stale banner: queued-wake warning survives the extension hand-off tolerance"
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
# The tolerance is scoped to the extension model alone. Every persistent-watcher
|
|
614
|
+
# primary (codex, opencode, grok, kimi, tmux, unknown) must keep alarming on the
|
|
615
|
+
# same state, even when Pi extension markers happen to be present on disk.
|
|
616
|
+
test_persistent_model_ignores_pi_extension_evidence() {
|
|
617
|
+
local dir home out pid
|
|
618
|
+
dir=$(make_guard_case persistent-ignores-pi-evidence)
|
|
619
|
+
home=$(case_home "$dir")
|
|
620
|
+
sleep 60 &
|
|
621
|
+
pid=$!
|
|
622
|
+
record_pi_extension_session "$dir" "$pid" || fail "could not record the Pi extension session"
|
|
623
|
+
touch "$home/state/.last-watcher-beat"
|
|
624
|
+
out=$(run_guard_case "$dir")
|
|
625
|
+
kill "$pid" 2>/dev/null || true
|
|
626
|
+
wait "$pid" 2>/dev/null || true
|
|
627
|
+
[ "$(count_text "$out" "WATCHER DOWN - SUPERVISION IS OFF")" -eq 1 ] \
|
|
628
|
+
|| fail "a persistent-watcher primary must still alarm with Pi markers present: $out"
|
|
629
|
+
assert_contains "$out" "no live watcher process holds this home lock" \
|
|
630
|
+
"the persistent-model banner must still name the missing watcher process"
|
|
631
|
+
pass "fm-guard stale banner: persistent primaries ignore Pi extension evidence"
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
# An extension-owned home with a genuinely live watcher is the ordinary steady
|
|
635
|
+
# state and must stay silent through the strict path, not through the tolerance.
|
|
636
|
+
test_extension_live_watcher_is_healthy_without_ownership_evidence() {
|
|
637
|
+
local dir home out pid
|
|
638
|
+
dir=$(make_guard_case extension-live-watcher)
|
|
639
|
+
home=$(case_home "$dir")
|
|
640
|
+
sleep 60 &
|
|
641
|
+
pid=$!
|
|
642
|
+
record_live_watcher "$dir" "$pid" || fail "could not record the live watcher"
|
|
643
|
+
touch "$home/state/.last-watcher-beat"
|
|
644
|
+
out=$(run_guard_case_extension "$dir")
|
|
645
|
+
kill "$pid" 2>/dev/null || true
|
|
646
|
+
wait "$pid" 2>/dev/null || true
|
|
647
|
+
[ -z "$out" ] \
|
|
648
|
+
|| fail "a live identity-matched watcher must be healthy under the extension model, got: $out"
|
|
649
|
+
pass "fm-guard stale banner: extension model stays silent for a live watcher"
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
# The cases above pin the model. This one takes the end-user path instead: no
|
|
653
|
+
# FM_SUPERVISION_MODEL at all, so bin/fm-harness.sh must route a Pi primary to the
|
|
654
|
+
# extension model on its own. Without that routing the tolerance would never reach
|
|
655
|
+
# a real Pi home. The foreign markers are cleared because fm-harness.sh tests them
|
|
656
|
+
# ahead of Pi, and the host running this suite may carry one.
|
|
657
|
+
test_pi_harness_routes_itself_to_the_extension_model() {
|
|
658
|
+
local dir home out pid harness
|
|
659
|
+
local -a pi_env
|
|
660
|
+
for harness in pi pi-signed; do
|
|
661
|
+
pi_env=(PI_CODING_AGENT=true)
|
|
662
|
+
[ "$harness" = pi ] || pi_env+=(FM_PI_HARNESS=pi-signed)
|
|
663
|
+
dir=$(make_guard_case "harness-routing-$harness")
|
|
664
|
+
home=$(case_home "$dir")
|
|
665
|
+
sleep 60 &
|
|
666
|
+
pid=$!
|
|
667
|
+
record_pi_extension_session "$dir" "$pid" || fail "could not record the Pi extension session"
|
|
668
|
+
touch "$home/state/.last-watcher-beat"
|
|
669
|
+
out=$(env -u CLAUDECODE -u CURSOR_AGENT -u CURSOR_INVOKED_AS -u GROK_AGENT -u FM_SUPERVISION_MODEL \
|
|
670
|
+
"${pi_env[@]}" \
|
|
671
|
+
FM_ROOT_OVERRIDE="$(case_root "$dir")" \
|
|
672
|
+
FM_HOME="$home" \
|
|
673
|
+
FM_GUARD_GRACE=999 \
|
|
674
|
+
"$ROOT/bin/fm-guard.sh" 2>&1)
|
|
675
|
+
kill "$pid" 2>/dev/null || true
|
|
676
|
+
wait "$pid" 2>/dev/null || true
|
|
677
|
+
[ -z "$out" ] \
|
|
678
|
+
|| fail "a $harness primary must route itself to the extension model, got: $out"
|
|
679
|
+
done
|
|
680
|
+
pass "fm-guard stale banner: Pi and pi-signed primaries route themselves to the extension model"
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
test_first_stale_call_prints_full_banner
|
|
684
|
+
test_repeated_same_episode_prints_reminder_only
|
|
685
|
+
test_pi_harness_routes_itself_to_the_extension_model
|
|
686
|
+
test_extension_handoff_with_live_session_is_healthy
|
|
687
|
+
test_extension_handoff_with_empty_lock_is_healthy
|
|
688
|
+
test_extension_held_unhealthy_locks_stay_alarm
|
|
689
|
+
test_extension_without_ownership_evidence_stays_alarm
|
|
690
|
+
test_extension_ownership_needs_every_signal
|
|
691
|
+
test_extension_stale_beacon_alarms_despite_live_session
|
|
692
|
+
test_extension_handoff_keeps_queued_wake_warning
|
|
693
|
+
test_persistent_model_ignores_pi_extension_evidence
|
|
694
|
+
test_extension_live_watcher_is_healthy_without_ownership_evidence
|
|
695
|
+
test_autoarm_fresh_beacon_without_watcher_is_healthy
|
|
696
|
+
test_autoarm_stale_beacon_alarms_with_correct_reason
|
|
697
|
+
test_autoarm_stale_episode_is_stable
|
|
698
|
+
test_persistent_no_watcher_banner_names_missing_process
|
|
699
|
+
test_persistent_no_watcher_episode_survives_beacon_touch
|
|
700
|
+
test_fresh_beacon_without_live_watcher_stays_alarm
|
|
701
|
+
test_x_mode_without_live_watcher_stays_alarm
|
|
702
|
+
test_healthy_recovery_rearms_next_stale_episode
|
|
703
|
+
test_concurrent_same_episode_prints_one_full_banner
|
|
704
|
+
test_home_isolation
|
|
705
|
+
test_queued_wake_warning_stays_independent
|
|
706
|
+
test_read_only_before_writable_does_not_consume_full_banner
|
|
707
|
+
test_read_only_during_episode_observes_without_mutating_marker
|
|
708
|
+
test_healthy_read_only_does_not_clear_marker
|
|
709
|
+
test_read_only_never_mutates_stale_banner_state_files
|