@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,95 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# fm-install-treehouse.sh - install CI's pinned, verified Treehouse build.
|
|
3
|
+
#
|
|
4
|
+
# Used only by the required real-Herdr CI lane for E2E scripts that genuinely
|
|
5
|
+
# need treehouse (spawn worktree acquisition). Same pin/checksum discipline as
|
|
6
|
+
# fm-install-herdr.sh: official release URL, exact asset, SHA-256, bounded
|
|
7
|
+
# download, post-install version check. Never a floating package-manager latest.
|
|
8
|
+
#
|
|
9
|
+
# Usage:
|
|
10
|
+
# fm-install-treehouse.sh <destination-directory>
|
|
11
|
+
#
|
|
12
|
+
# Pins Treehouse v2.0.1, the version exercised by the local real-Herdr suite.
|
|
13
|
+
set -eu
|
|
14
|
+
|
|
15
|
+
FM_TREEHOUSE_CI_VERSION=2.0.1
|
|
16
|
+
FM_TREEHOUSE_CI_TAG="v${FM_TREEHOUSE_CI_VERSION}"
|
|
17
|
+
# Bounded download ceiling (bytes). Official 2.0.1 archives are under 8 MiB.
|
|
18
|
+
FM_TREEHOUSE_CI_MAX_BYTES=15000000
|
|
19
|
+
FM_TREEHOUSE_CI_REPO=kunchenguid/treehouse
|
|
20
|
+
|
|
21
|
+
die() {
|
|
22
|
+
printf 'fm-install-treehouse.sh: %s\n' "$*" >&2
|
|
23
|
+
exit 1
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
DESTINATION=${1:?usage: fm-install-treehouse.sh <destination-directory>}
|
|
27
|
+
|
|
28
|
+
os=$(uname -s)
|
|
29
|
+
arch=$(uname -m)
|
|
30
|
+
case "${os}-${arch}" in
|
|
31
|
+
Linux-x86_64)
|
|
32
|
+
ARCHIVE=treehouse-v${FM_TREEHOUSE_CI_VERSION}-linux-amd64.tar.gz
|
|
33
|
+
SHA256=1d5a32751ab921670103fd201ddb2b91b47338cb13976f45642b827cf8976af2
|
|
34
|
+
;;
|
|
35
|
+
Linux-aarch64|Linux-arm64)
|
|
36
|
+
ARCHIVE=treehouse-v${FM_TREEHOUSE_CI_VERSION}-linux-arm64.tar.gz
|
|
37
|
+
SHA256=eaccc9c5b98125df8bd77425598eeecee66cb0371db4eb1cf75f0d813c18fab9
|
|
38
|
+
;;
|
|
39
|
+
Darwin-arm64)
|
|
40
|
+
ARCHIVE=treehouse-v${FM_TREEHOUSE_CI_VERSION}-darwin-arm64.tar.gz
|
|
41
|
+
SHA256=7ee5078f3d1f33c01196548797fce65408e459d53530b77d4ba56e074fa1c1a2
|
|
42
|
+
;;
|
|
43
|
+
Darwin-x86_64)
|
|
44
|
+
ARCHIVE=treehouse-v${FM_TREEHOUSE_CI_VERSION}-darwin-amd64.tar.gz
|
|
45
|
+
SHA256=1cf44580a5837f995e1d3bb74f4fbd3112b642acd20406087d9735a8106112fd
|
|
46
|
+
;;
|
|
47
|
+
*)
|
|
48
|
+
die "unsupported platform ${os}-${arch}; official Treehouse assets are linux/darwin amd64 and arm64"
|
|
49
|
+
;;
|
|
50
|
+
esac
|
|
51
|
+
|
|
52
|
+
URL="https://github.com/${FM_TREEHOUSE_CI_REPO}/releases/download/${FM_TREEHOUSE_CI_TAG}/${ARCHIVE}"
|
|
53
|
+
TMP=$(mktemp -d "${RUNNER_TEMP:-${TMPDIR:-/tmp}}/fm-treehouse.XXXXXX")
|
|
54
|
+
trap 'rm -rf "$TMP"' EXIT
|
|
55
|
+
|
|
56
|
+
printf 'fm-install-treehouse.sh: downloading %s from %s\n' "$ARCHIVE" "$URL" >&2
|
|
57
|
+
curl -fsSL --max-filesize "$FM_TREEHOUSE_CI_MAX_BYTES" "$URL" -o "$TMP/$ARCHIVE" \
|
|
58
|
+
|| die "download failed for $URL (bounded at $FM_TREEHOUSE_CI_MAX_BYTES bytes)"
|
|
59
|
+
|
|
60
|
+
if command -v sha256sum >/dev/null 2>&1; then
|
|
61
|
+
ACTUAL_SHA256=$(sha256sum "$TMP/$ARCHIVE" | awk '{print $1}')
|
|
62
|
+
elif command -v shasum >/dev/null 2>&1; then
|
|
63
|
+
ACTUAL_SHA256=$(shasum -a 256 "$TMP/$ARCHIVE" | awk '{print $1}')
|
|
64
|
+
else
|
|
65
|
+
die "need sha256sum or shasum to verify the Treehouse archive"
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
[ "$ACTUAL_SHA256" = "$SHA256" ] || die "checksum mismatch for $ARCHIVE (expected $SHA256, got $ACTUAL_SHA256)"
|
|
69
|
+
|
|
70
|
+
tar -xzf "$TMP/$ARCHIVE" -C "$TMP"
|
|
71
|
+
# Archive layout: a single `treehouse` binary at the archive root (verified for v2.0.1).
|
|
72
|
+
if [ -f "$TMP/treehouse" ]; then
|
|
73
|
+
BIN="$TMP/treehouse"
|
|
74
|
+
elif [ -f "$TMP/treehouse-v${FM_TREEHOUSE_CI_VERSION}/treehouse" ]; then
|
|
75
|
+
BIN="$TMP/treehouse-v${FM_TREEHOUSE_CI_VERSION}/treehouse"
|
|
76
|
+
else
|
|
77
|
+
BIN=$(find "$TMP" -type f -name treehouse | head -n 1)
|
|
78
|
+
[ -n "$BIN" ] || die "archive $ARCHIVE did not contain a treehouse binary"
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
mkdir -p "$DESTINATION"
|
|
82
|
+
install -m 0755 "$BIN" "$DESTINATION/treehouse"
|
|
83
|
+
|
|
84
|
+
installed_version=$("$DESTINATION/treehouse" --version 2>/dev/null | tr -d '[:space:]')
|
|
85
|
+
# treehouse prints "v2.0.1" (leading v) on --version.
|
|
86
|
+
case "$installed_version" in
|
|
87
|
+
"v${FM_TREEHOUSE_CI_VERSION}"|"${FM_TREEHOUSE_CI_VERSION}") ;;
|
|
88
|
+
*)
|
|
89
|
+
die "installed treehouse version is '${installed_version:-<empty>}', expected exact pin v${FM_TREEHOUSE_CI_VERSION}"
|
|
90
|
+
;;
|
|
91
|
+
esac
|
|
92
|
+
|
|
93
|
+
printf 'fm-install-treehouse.sh: installed treehouse %s to %s\n' \
|
|
94
|
+
"$installed_version" "$DESTINATION/treehouse" >&2
|
|
95
|
+
"$DESTINATION/treehouse" --version
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Install or remove Firstmate's guarded Kimi crew turn-end hook.
|
|
3
|
+
#
|
|
4
|
+
# This command is the sole owner of the text-level edit to
|
|
5
|
+
# $HOME/.kimi-code/config.toml. It validates the existing TOML but never
|
|
6
|
+
# serializes it: install adds or replaces one marker-delimited Firstmate region,
|
|
7
|
+
# and remove excises only that region. Missing, malformed, symlinked, partially
|
|
8
|
+
# marked, or otherwise surprising config is refused without a config write.
|
|
9
|
+
#
|
|
10
|
+
# The installed Stop hook always exits 0 and stays silent. It reads cwd from the
|
|
11
|
+
# hook payload, checks for a .fm-kimi-turnend pointer before registry work, and
|
|
12
|
+
# touches a task turn-end marker only when the pointer names a Firstmate-created
|
|
13
|
+
# token in $HOME/.kimi-code/fm-turn-end.d/.
|
|
14
|
+
#
|
|
15
|
+
# Usage:
|
|
16
|
+
# fm-kimi-turnend-hook.sh install
|
|
17
|
+
# fm-kimi-turnend-hook.sh remove
|
|
18
|
+
set -u
|
|
19
|
+
|
|
20
|
+
case "${1:-}" in
|
|
21
|
+
install|remove) ACTION=$1 ;;
|
|
22
|
+
-h|--help)
|
|
23
|
+
sed -n '2,18{s/^# \{0,1\}//;p;}' "$0"
|
|
24
|
+
exit 0
|
|
25
|
+
;;
|
|
26
|
+
*)
|
|
27
|
+
printf 'usage: %s install|remove\n' "${0##*/}" >&2
|
|
28
|
+
exit 2
|
|
29
|
+
;;
|
|
30
|
+
esac
|
|
31
|
+
|
|
32
|
+
if [ -z "${HOME:-}" ]; then
|
|
33
|
+
printf 'fm-kimi-turnend-hook: refused: HOME is unset.\n' >&2
|
|
34
|
+
exit 1
|
|
35
|
+
fi
|
|
36
|
+
if ! command -v python3 >/dev/null 2>&1; then
|
|
37
|
+
printf 'fm-kimi-turnend-hook: refused: python3 with tomllib is required to validate config.toml.\n' >&2
|
|
38
|
+
exit 1
|
|
39
|
+
fi
|
|
40
|
+
if [ "$ACTION" = install ] && ! command -v jq >/dev/null 2>&1; then
|
|
41
|
+
printf 'fm-kimi-turnend-hook: refused: jq is required by the installed Kimi turn-end hook.\n' >&2
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
python3 - "$ACTION" "$HOME/.kimi-code" <<'PY'
|
|
46
|
+
import os
|
|
47
|
+
import re
|
|
48
|
+
import shutil
|
|
49
|
+
import stat
|
|
50
|
+
import sys
|
|
51
|
+
import tempfile
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
import tomllib
|
|
55
|
+
except ImportError:
|
|
56
|
+
print(
|
|
57
|
+
"fm-kimi-turnend-hook: refused: python3 with tomllib is required to validate config.toml.",
|
|
58
|
+
file=sys.stderr,
|
|
59
|
+
)
|
|
60
|
+
raise SystemExit(1)
|
|
61
|
+
|
|
62
|
+
ACTION = sys.argv[1]
|
|
63
|
+
CONFIG_DIR = sys.argv[2]
|
|
64
|
+
CONFIG = os.path.join(CONFIG_DIR, "config.toml")
|
|
65
|
+
HOOK = os.path.join(CONFIG_DIR, "fm-turn-end.sh")
|
|
66
|
+
REGISTRY = os.path.join(CONFIG_DIR, "fm-turn-end.d")
|
|
67
|
+
BEGIN = b"# BEGIN FIRSTMATE KIMI TURN-END HOOK"
|
|
68
|
+
BEGIN_OWNS_NEWLINE = BEGIN + b" (OWNS PRECEDING NEWLINE)"
|
|
69
|
+
END = b"# END FIRSTMATE KIMI TURN-END HOOK"
|
|
70
|
+
IDENTIFIER = b"FIRSTMATE KIMI TURN-END HOOK"
|
|
71
|
+
HOOK_NAME = b"fm-turn-end.sh"
|
|
72
|
+
TOKEN_NAME = re.compile(r"fm\.[A-Za-z0-9]{12}\Z")
|
|
73
|
+
|
|
74
|
+
HOOK_BYTES = b'''#!/usr/bin/env bash
|
|
75
|
+
# Firstmate Kimi turn-end hook. Managed by fm-kimi-turnend-hook.sh.
|
|
76
|
+
# This hook is deliberately passive: every path is silent and exits zero.
|
|
77
|
+
set +e
|
|
78
|
+
exec >/dev/null 2>&1
|
|
79
|
+
payload=
|
|
80
|
+
IFS= read -r payload || [ -n "$payload" ] || exit 0
|
|
81
|
+
command -v jq >/dev/null 2>&1 || exit 0
|
|
82
|
+
workspace=$(jq -er 'select(.hook_event_name == "Stop") | .cwd | strings | select(length > 0)' <<< "$payload" 2>/dev/null) || exit 0
|
|
83
|
+
pointer="$workspace/.fm-kimi-turnend"
|
|
84
|
+
[ -f "$pointer" ] || exit 0
|
|
85
|
+
first=
|
|
86
|
+
IFS= read -r -n 256 first < "$pointer" 2>/dev/null || [ -n "$first" ] || exit 0
|
|
87
|
+
case "$first" in token=*) token=${first#token=} ;; *) exit 0 ;; esac
|
|
88
|
+
case "$token" in fm.????????????) : ;; *) exit 0 ;; esac
|
|
89
|
+
case "$token" in *[!A-Za-z0-9._-]*) exit 0 ;; esac
|
|
90
|
+
auth_dir=${HOME:-}/.kimi-code/fm-turn-end.d
|
|
91
|
+
[ -n "${HOME:-}" ] || exit 0
|
|
92
|
+
target=$(cat "$auth_dir/$token" 2>/dev/null) || exit 0
|
|
93
|
+
case "$target" in /*.turn-ended) : ;; *) exit 0 ;; esac
|
|
94
|
+
touch -- "$target" 2>/dev/null || true
|
|
95
|
+
exit 0
|
|
96
|
+
'''
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def refuse(reason: str) -> None:
|
|
100
|
+
print(f"fm-kimi-turnend-hook: refused: {reason}", file=sys.stderr)
|
|
101
|
+
raise SystemExit(1)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def regular_not_symlink(path: str, label: str) -> os.stat_result:
|
|
105
|
+
try:
|
|
106
|
+
info = os.lstat(path)
|
|
107
|
+
except FileNotFoundError:
|
|
108
|
+
refuse(f"{label} is missing at {path}.")
|
|
109
|
+
if stat.S_ISLNK(info.st_mode) or not stat.S_ISREG(info.st_mode):
|
|
110
|
+
refuse(f"{label} is not a regular non-symlink file at {path}.")
|
|
111
|
+
return info
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def parse_toml(data: bytes, label: str):
|
|
115
|
+
try:
|
|
116
|
+
text = data.decode("utf-8")
|
|
117
|
+
except UnicodeDecodeError as error:
|
|
118
|
+
refuse(f"{label} is not UTF-8: {error}.")
|
|
119
|
+
try:
|
|
120
|
+
parsed = tomllib.loads(text)
|
|
121
|
+
except tomllib.TOMLDecodeError as error:
|
|
122
|
+
refuse(f"{label} is malformed TOML: {error}.")
|
|
123
|
+
hooks = parsed.get("hooks")
|
|
124
|
+
if hooks is not None and not isinstance(hooks, list):
|
|
125
|
+
refuse(f"{label} has an unexpected non-array 'hooks' value.")
|
|
126
|
+
return parsed
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def locate_region(data: bytes):
|
|
130
|
+
normal_count = data.count(BEGIN + b"\n")
|
|
131
|
+
owned_count = data.count(BEGIN_OWNS_NEWLINE + b"\n")
|
|
132
|
+
end_count = data.count(END)
|
|
133
|
+
identifier_count = data.count(IDENTIFIER)
|
|
134
|
+
if normal_count + owned_count == 0 and end_count == 0 and identifier_count == 0:
|
|
135
|
+
return None
|
|
136
|
+
if normal_count + owned_count != 1 or end_count != 1 or identifier_count != 2:
|
|
137
|
+
refuse("config.toml has partial, duplicated, or altered Firstmate region markers.")
|
|
138
|
+
marker = BEGIN_OWNS_NEWLINE if owned_count else BEGIN
|
|
139
|
+
marker_at = data.find(marker)
|
|
140
|
+
if marker_at != 0 and data[marker_at - 1 : marker_at] != b"\n":
|
|
141
|
+
refuse("the Firstmate begin marker is not at a line boundary.")
|
|
142
|
+
start = marker_at
|
|
143
|
+
if owned_count:
|
|
144
|
+
if marker_at == 0 or data[marker_at - 1 : marker_at] != b"\n":
|
|
145
|
+
refuse("the Firstmate region claims a preceding newline that is absent.")
|
|
146
|
+
start -= 1
|
|
147
|
+
end_at = data.find(END, marker_at + len(marker))
|
|
148
|
+
if end_at < 0:
|
|
149
|
+
refuse("the Firstmate end marker is missing.")
|
|
150
|
+
after = end_at + len(END)
|
|
151
|
+
if after < len(data):
|
|
152
|
+
if data[after : after + 1] != b"\n":
|
|
153
|
+
refuse("the Firstmate end marker is not a complete line.")
|
|
154
|
+
after += 1
|
|
155
|
+
return start, after, marker
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def block(marker: bytes) -> bytes:
|
|
159
|
+
return b"\n".join(
|
|
160
|
+
(
|
|
161
|
+
marker,
|
|
162
|
+
b"[[hooks]]",
|
|
163
|
+
b'event = "Stop"',
|
|
164
|
+
b'matcher = "^$"',
|
|
165
|
+
b'command = "bash \\"$HOME/.kimi-code/fm-turn-end.sh\\" >/dev/null 2>&1 || true"',
|
|
166
|
+
b"timeout = 1",
|
|
167
|
+
END,
|
|
168
|
+
b"",
|
|
169
|
+
)
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def without_region(data: bytes, region) -> bytes:
|
|
174
|
+
prefix = data[: region[0]]
|
|
175
|
+
suffix = data[region[1] :]
|
|
176
|
+
# Retain a newline so removal cannot join the captain's preceding line to content appended after installation.
|
|
177
|
+
separator = b"\n" if region[2] == BEGIN_OWNS_NEWLINE and suffix else b""
|
|
178
|
+
return prefix + separator + suffix
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def atomic_write(path: str, data: bytes, mode: int) -> None:
|
|
182
|
+
fd, temporary = tempfile.mkstemp(prefix=f".{os.path.basename(path)}.", dir=os.path.dirname(path))
|
|
183
|
+
try:
|
|
184
|
+
os.fchmod(fd, mode)
|
|
185
|
+
with os.fdopen(fd, "wb") as stream:
|
|
186
|
+
fd = -1
|
|
187
|
+
stream.write(data)
|
|
188
|
+
stream.flush()
|
|
189
|
+
os.fsync(stream.fileno())
|
|
190
|
+
os.replace(temporary, path)
|
|
191
|
+
except Exception:
|
|
192
|
+
if fd >= 0:
|
|
193
|
+
os.close(fd)
|
|
194
|
+
try:
|
|
195
|
+
os.unlink(temporary)
|
|
196
|
+
except FileNotFoundError:
|
|
197
|
+
pass
|
|
198
|
+
raise
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def validate_firstmate_files_for_remove() -> None:
|
|
202
|
+
if os.path.lexists(HOOK):
|
|
203
|
+
info = regular_not_symlink(HOOK, "Firstmate hook script")
|
|
204
|
+
with open(HOOK, "rb") as stream:
|
|
205
|
+
if stream.read() != HOOK_BYTES:
|
|
206
|
+
refuse(f"Firstmate hook script has unexpected content at {HOOK}.")
|
|
207
|
+
if stat.S_IMODE(info.st_mode) & 0o077:
|
|
208
|
+
refuse(f"Firstmate hook script has unexpectedly broad permissions at {HOOK}.")
|
|
209
|
+
if os.path.lexists(REGISTRY):
|
|
210
|
+
info = os.lstat(REGISTRY)
|
|
211
|
+
if stat.S_ISLNK(info.st_mode) or not stat.S_ISDIR(info.st_mode):
|
|
212
|
+
refuse(f"Firstmate registry is not a regular directory at {REGISTRY}.")
|
|
213
|
+
for name in os.listdir(REGISTRY):
|
|
214
|
+
path = os.path.join(REGISTRY, name)
|
|
215
|
+
child = os.lstat(path)
|
|
216
|
+
if not TOKEN_NAME.fullmatch(name) or stat.S_ISLNK(child.st_mode) or not stat.S_ISREG(child.st_mode):
|
|
217
|
+
refuse(f"Firstmate registry contains an unexpected entry at {path}.")
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
try:
|
|
221
|
+
if not os.path.isdir(CONFIG_DIR) or os.path.islink(CONFIG_DIR):
|
|
222
|
+
refuse(f"Kimi config directory is missing or unexpected at {CONFIG_DIR}.")
|
|
223
|
+
config_info = regular_not_symlink(CONFIG, "Kimi config")
|
|
224
|
+
with open(CONFIG, "rb") as stream:
|
|
225
|
+
original = stream.read()
|
|
226
|
+
parse_toml(original, "config.toml")
|
|
227
|
+
region = locate_region(original)
|
|
228
|
+
outside = original if region is None else without_region(original, region)
|
|
229
|
+
if HOOK_NAME in outside:
|
|
230
|
+
refuse("config.toml references fm-turn-end.sh outside the Firstmate-owned region.")
|
|
231
|
+
|
|
232
|
+
if ACTION == "install":
|
|
233
|
+
if os.path.lexists(REGISTRY):
|
|
234
|
+
info = os.lstat(REGISTRY)
|
|
235
|
+
if stat.S_ISLNK(info.st_mode) or not stat.S_ISDIR(info.st_mode):
|
|
236
|
+
refuse(f"Firstmate registry is not a regular directory at {REGISTRY}.")
|
|
237
|
+
if os.path.lexists(HOOK):
|
|
238
|
+
regular_not_symlink(HOOK, "Firstmate hook script")
|
|
239
|
+
with open(HOOK, "rb") as stream:
|
|
240
|
+
existing_hook = stream.read()
|
|
241
|
+
if existing_hook != HOOK_BYTES and not existing_hook.startswith(
|
|
242
|
+
b"#!/usr/bin/env bash\n# Firstmate Kimi turn-end hook."
|
|
243
|
+
):
|
|
244
|
+
refuse(f"Firstmate hook path has unexpected content at {HOOK}.")
|
|
245
|
+
if region is None:
|
|
246
|
+
marker = BEGIN if original.endswith(b"\n") else BEGIN_OWNS_NEWLINE
|
|
247
|
+
addition = block(marker)
|
|
248
|
+
candidate = original + (b"" if original.endswith(b"\n") else b"\n") + addition
|
|
249
|
+
else:
|
|
250
|
+
candidate = original[: region[0]] + (
|
|
251
|
+
(b"\n" if region[2] == BEGIN_OWNS_NEWLINE else b"") + block(region[2])
|
|
252
|
+
) + original[region[1] :]
|
|
253
|
+
parse_toml(candidate, "updated config.toml")
|
|
254
|
+
os.makedirs(REGISTRY, mode=0o700, exist_ok=True)
|
|
255
|
+
os.chmod(REGISTRY, 0o700)
|
|
256
|
+
installed_hook = None
|
|
257
|
+
if os.path.exists(HOOK):
|
|
258
|
+
with open(HOOK, "rb") as stream:
|
|
259
|
+
installed_hook = stream.read()
|
|
260
|
+
if installed_hook != HOOK_BYTES or stat.S_IMODE(os.stat(HOOK).st_mode) != 0o700:
|
|
261
|
+
atomic_write(HOOK, HOOK_BYTES, 0o700)
|
|
262
|
+
if candidate != original:
|
|
263
|
+
atomic_write(CONFIG, candidate, stat.S_IMODE(config_info.st_mode))
|
|
264
|
+
else:
|
|
265
|
+
validate_firstmate_files_for_remove()
|
|
266
|
+
candidate = outside
|
|
267
|
+
parse_toml(candidate, "config.toml after Firstmate region removal")
|
|
268
|
+
if candidate != original:
|
|
269
|
+
atomic_write(CONFIG, candidate, stat.S_IMODE(config_info.st_mode))
|
|
270
|
+
if os.path.lexists(HOOK):
|
|
271
|
+
os.unlink(HOOK)
|
|
272
|
+
if os.path.lexists(REGISTRY):
|
|
273
|
+
shutil.rmtree(REGISTRY)
|
|
274
|
+
except OSError as error:
|
|
275
|
+
refuse(f"filesystem operation failed: {error}.")
|
|
276
|
+
PY
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# fm-lease-lib.sh - the per-task supervision lease contract (one owner).
|
|
3
|
+
#
|
|
4
|
+
# WHY. On the Pi supervision branch (docs/pi-supervision-branch.md), two LLM
|
|
5
|
+
# actors share one firstmate home inside one pi process: MAIN (the captain's
|
|
6
|
+
# chat) and BRANCH (the persistent supervision conversation). Most records have
|
|
7
|
+
# exactly one natural owner, but the overlap set - steering or stopping a
|
|
8
|
+
# worker, post-landing cleanup, backlog status for a task, stuck-worker
|
|
9
|
+
# recovery - could otherwise be mutated by both actors at once. The lease is
|
|
10
|
+
# the merge-conflict analog: a small per-task file saying which actor is
|
|
11
|
+
# changing that task right now, and the mutating entrypoints refuse the other
|
|
12
|
+
# actor while it exists.
|
|
13
|
+
#
|
|
14
|
+
# CONTRACT.
|
|
15
|
+
# - Lease file: $STATE/.lease-<task>, one line "<actor>\t<pid>\t<epoch>".
|
|
16
|
+
# Written atomically (temp + ln for claim, temp + mv for a same-actor
|
|
17
|
+
# refresh), with inspection and mutation serialized by the home-local
|
|
18
|
+
# lease-command lock; leases never coordinate across firstmate homes.
|
|
19
|
+
# - Actors: exactly "main" and "branch". The current actor is
|
|
20
|
+
# $FM_SUPERVISION_ACTOR when set, else "main". The branch's shell gets
|
|
21
|
+
# FM_SUPERVISION_ACTOR=branch injected deterministically by the Pi branch
|
|
22
|
+
# extension's bash tool, not by agent memory. Any other value is refused
|
|
23
|
+
# loudly - an unknown actor is a wiring bug, not a third role.
|
|
24
|
+
# - Staleness: the recorded pid is the long-lived supervising process (the
|
|
25
|
+
# session-lock holder, or FM_LEASE_HOLDER_PID - see bin/fm-lease.sh), and
|
|
26
|
+
# both actors live inside that one pi process, so a dead recorded pid
|
|
27
|
+
# means the process died; the lease is cleared at the next claim, guard,
|
|
28
|
+
# or sweep. Liveness requires a Pi calling context plus state/.lock, and
|
|
29
|
+
# the recorded pid must BE its current holder, so a lease left by an exited
|
|
30
|
+
# Pi session goes stale even if its pid was recycled by an unrelated
|
|
31
|
+
# process, and a non-Pi home never honors a leftover Pi lease. A lease held by the
|
|
32
|
+
# live current session but an abandoned branch conversation is recovered
|
|
33
|
+
# by the branch extension's generation-activation cleanup.
|
|
34
|
+
#
|
|
35
|
+
# THREAT MODEL (deliberate, captain-decided): these guards are
|
|
36
|
+
# CONFUSED-AGENT-GRADE, the same grade bin/fm-gate-refuse-lib.sh documents
|
|
37
|
+
# for the gate refusal. They stop non-deliberate misuse - the injected actor
|
|
38
|
+
# identity, the loud refusals, and the session-bound staleness make every
|
|
39
|
+
# accidental cross-actor mutation fail loudly. A deliberately forging shell
|
|
40
|
+
# running as the same uid inside the same pi process can evade any in-process
|
|
41
|
+
# discriminator (it can rewrite env, spawn fresh shells, and edit state
|
|
42
|
+
# files), so adversarial-grade separation is explicitly out of scope here and
|
|
43
|
+
# tracked as separate follow-up design work. The branch's shell prelude makes
|
|
44
|
+
# the actor variables readonly (see the Pi branch extension), so an
|
|
45
|
+
# ACCIDENTAL override fails loudly inside the branch's own shell as well.
|
|
46
|
+
# - Guard semantics (fm_lease_guard): no lease, a same-actor lease, or a
|
|
47
|
+
# provably stale lease passes; a live lease held by the OTHER actor
|
|
48
|
+
# refuses with exit FM_LEASE_REFUSE_EXIT. In a Pi supervision context the
|
|
49
|
+
# guard retains the lease-command lock until fm_lease_guard_release, so the
|
|
50
|
+
# other actor cannot claim between the check and the guarded mutation. A
|
|
51
|
+
# home without the current Pi session lock cannot have a live lease, so
|
|
52
|
+
# the guard is a no-op there - non-Pi behavior is unchanged by construction.
|
|
53
|
+
# - Role partition (fm_lease_forbid_branch): actions MAIN alone owns -
|
|
54
|
+
# merging a PR, landing local-only work, spawning workers - refuse the
|
|
55
|
+
# branch actor outright, lease or no lease.
|
|
56
|
+
# - "backlog" is a reserved claimable resource name used by the branch
|
|
57
|
+
# prompt around its own data/backlog.md writes. This is deliberately
|
|
58
|
+
# branch-side containment only; main's tasks-axi path has no executable
|
|
59
|
+
# backlog lease guard in this scope.
|
|
60
|
+
#
|
|
61
|
+
# Sourced by bin/fm-send.sh, bin/fm-control.sh, bin/fm-teardown.sh,
|
|
62
|
+
# bin/fm-pr-merge.sh, bin/fm-merge-local.sh, bin/fm-spawn.sh, and
|
|
63
|
+
# bin/fm-lease.sh. Callers must have $STATE resolved before calling. No side
|
|
64
|
+
# effects on source. set -u / set -e safe.
|
|
65
|
+
|
|
66
|
+
# Distinct from usage errors (2), the gate refusal (3), and fm-send's
|
|
67
|
+
# unconfirmed submit (3): recognizable as "the other supervision actor holds
|
|
68
|
+
# this task right now - retry after the lease clears".
|
|
69
|
+
FM_LEASE_REFUSE_EXIT=6
|
|
70
|
+
FM_LEASE_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
71
|
+
FM_LEASE_GUARD_LOCK=
|
|
72
|
+
|
|
73
|
+
fm_lease_lock_helpers() {
|
|
74
|
+
command -v fm_lock_acquire_wait >/dev/null 2>&1 && return 0
|
|
75
|
+
# fm-wake-lib.sh is a canonical lint root in its own right and is already
|
|
76
|
+
# sourced directly by every caller of this lazy fallback; keep this an
|
|
77
|
+
# analysis boundary so ShellCheck's external-source traversal does not
|
|
78
|
+
# recursively duplicate that large graph for every lease-lib consumer.
|
|
79
|
+
# shellcheck source=/dev/null
|
|
80
|
+
. "$FM_LEASE_LIB_DIR/fm-wake-lib.sh"
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
# fm_lease_actor: print the current actor after validating it. Returns 1 (with
|
|
84
|
+
# stderr) for an unknown FM_SUPERVISION_ACTOR value.
|
|
85
|
+
fm_lease_actor() {
|
|
86
|
+
local actor=${FM_SUPERVISION_ACTOR:-main}
|
|
87
|
+
case "$actor" in
|
|
88
|
+
main|branch) printf '%s\n' "$actor" ;;
|
|
89
|
+
*)
|
|
90
|
+
echo "error: unknown FM_SUPERVISION_ACTOR '$actor' (expected main or branch)" >&2
|
|
91
|
+
return 1
|
|
92
|
+
;;
|
|
93
|
+
esac
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
# fm_lease_valid_id <id>: 0 iff the task/resource id is safe to embed in a
|
|
97
|
+
# state filename.
|
|
98
|
+
fm_lease_valid_id() {
|
|
99
|
+
case "${1:-}" in
|
|
100
|
+
'' | *[!A-Za-z0-9._-]*) return 1 ;;
|
|
101
|
+
*) return 0 ;;
|
|
102
|
+
esac
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
fm_lease_path() {
|
|
106
|
+
printf '%s/.lease-%s\n' "$STATE" "$1"
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
# fm_lease_read <task>: read the lease into FM_LEASE_ACTOR/FM_LEASE_PID/
|
|
110
|
+
# FM_LEASE_EPOCH. Returns 1 when no lease file exists. A malformed lease
|
|
111
|
+
# (unreadable actor or pid) reads as actor "" so callers treat it as stale
|
|
112
|
+
# rather than blocking forever on a torn record.
|
|
113
|
+
fm_lease_read() {
|
|
114
|
+
local file line
|
|
115
|
+
file=$(fm_lease_path "$1")
|
|
116
|
+
FM_LEASE_ACTOR=
|
|
117
|
+
FM_LEASE_PID=
|
|
118
|
+
FM_LEASE_EPOCH=
|
|
119
|
+
[ -e "$file" ] || return 1
|
|
120
|
+
IFS= read -r line < "$file" 2>/dev/null || line=
|
|
121
|
+
FM_LEASE_ACTOR=$(printf '%s' "$line" | cut -f1)
|
|
122
|
+
FM_LEASE_PID=$(printf '%s' "$line" | cut -f2)
|
|
123
|
+
# shellcheck disable=SC2034 # Consumed by sourcing callers (bin/fm-lease.sh check).
|
|
124
|
+
FM_LEASE_EPOCH=$(printf '%s' "$line" | cut -f3)
|
|
125
|
+
case "$FM_LEASE_ACTOR" in
|
|
126
|
+
main|branch) ;;
|
|
127
|
+
*) FM_LEASE_ACTOR= ;;
|
|
128
|
+
esac
|
|
129
|
+
case "$FM_LEASE_PID" in
|
|
130
|
+
'' | *[!0-9]*) FM_LEASE_PID= ;;
|
|
131
|
+
esac
|
|
132
|
+
return 0
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
# fm_lease_live <task>: 0 iff a well-formed lease exists in a Pi context, its
|
|
136
|
+
# recorded pid is alive, and that pid IS the current session-lock holder (see
|
|
137
|
+
# the staleness contract above).
|
|
138
|
+
fm_lease_live() {
|
|
139
|
+
local lock_pid
|
|
140
|
+
case "${PI_CODING_AGENT:-}:${FM_SUPERVISION_ACTOR:-}" in
|
|
141
|
+
true:*|*:main|*:branch) ;;
|
|
142
|
+
*) return 1 ;;
|
|
143
|
+
esac
|
|
144
|
+
fm_lease_read "$1" || return 1
|
|
145
|
+
[ -n "$FM_LEASE_ACTOR" ] || return 1
|
|
146
|
+
[ -n "$FM_LEASE_PID" ] || return 1
|
|
147
|
+
kill -0 "$FM_LEASE_PID" 2>/dev/null || return 1
|
|
148
|
+
lock_pid=$(head -n 1 "$STATE/.lock" 2>/dev/null || true)
|
|
149
|
+
case "$lock_pid" in ''|0|1|*[!0-9]*) return 1 ;; esac
|
|
150
|
+
[ "$FM_LEASE_PID" = "$lock_pid" ]
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
# fm_lease_clear_stale <task>: remove the lease file when it exists but is not
|
|
154
|
+
# live. Silent; never touches a live lease.
|
|
155
|
+
fm_lease_clear_stale() {
|
|
156
|
+
local file
|
|
157
|
+
file=$(fm_lease_path "$1")
|
|
158
|
+
[ -e "$file" ] || return 0
|
|
159
|
+
fm_lease_live "$1" && return 0
|
|
160
|
+
rm -f -- "$file"
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
# fm_lease_guard <task> <action-label>: refuse (exit FM_LEASE_REFUSE_EXIT) when
|
|
164
|
+
# a live lease held by the OTHER actor exists for <task>. In a Pi supervision
|
|
165
|
+
# context, a successful guard retains the command lock across the caller's
|
|
166
|
+
# mutation; the caller must invoke fm_lease_guard_release from its EXIT cleanup.
|
|
167
|
+
# This closes the check/use race with a concurrent claim. Outside Pi, stale
|
|
168
|
+
# records are still cleaned but the lock is released before returning.
|
|
169
|
+
fm_lease_guard() {
|
|
170
|
+
local task=$1 action=$2 actor lock lease_actor active=0
|
|
171
|
+
fm_lease_valid_id "$task" || return 0
|
|
172
|
+
actor=$(fm_lease_actor) || exit "$FM_LEASE_REFUSE_EXIT"
|
|
173
|
+
case "${PI_CODING_AGENT:-}:${FM_SUPERVISION_ACTOR:-}" in
|
|
174
|
+
true:*|*:main|*:branch) active=1 ;;
|
|
175
|
+
esac
|
|
176
|
+
[ "$active" = 1 ] || [ -e "$(fm_lease_path "$task")" ] || return 0
|
|
177
|
+
fm_lease_lock_helpers
|
|
178
|
+
lock="$STATE/.fm-lease-command.lock"
|
|
179
|
+
# A caller with more than one guarded phase already excludes claims until
|
|
180
|
+
# its shared cleanup; do not recursively acquire the non-reentrant lock.
|
|
181
|
+
if [ "$FM_LEASE_GUARD_LOCK" != "$lock" ]; then
|
|
182
|
+
fm_lock_acquire_wait "$lock"
|
|
183
|
+
FM_LEASE_GUARD_LOCK=$lock
|
|
184
|
+
fi
|
|
185
|
+
if ! fm_lease_live "$task"; then
|
|
186
|
+
fm_lease_clear_stale "$task" || { fm_lease_guard_release; return 1; }
|
|
187
|
+
if [ "$active" != 1 ]; then
|
|
188
|
+
fm_lease_guard_release
|
|
189
|
+
fi
|
|
190
|
+
return 0
|
|
191
|
+
fi
|
|
192
|
+
lease_actor=$FM_LEASE_ACTOR
|
|
193
|
+
if [ "$lease_actor" != "$actor" ]; then
|
|
194
|
+
fm_lease_guard_release
|
|
195
|
+
echo "error: $action refused - task '$task' is leased to the $lease_actor supervision actor (state/.lease-$task); retry after that actor releases it" >&2
|
|
196
|
+
exit "$FM_LEASE_REFUSE_EXIT"
|
|
197
|
+
fi
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
# Release the claim/guard serialization lock retained by fm_lease_guard.
|
|
201
|
+
# Idempotent so callers can use it unconditionally from existing EXIT cleanup.
|
|
202
|
+
fm_lease_guard_release() {
|
|
203
|
+
local lock=$FM_LEASE_GUARD_LOCK
|
|
204
|
+
[ -n "$lock" ] || return 0
|
|
205
|
+
FM_LEASE_GUARD_LOCK=
|
|
206
|
+
fm_lock_release "$lock"
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
# fm_lease_forbid_branch <action-label>: refuse (exit FM_LEASE_REFUSE_EXIT)
|
|
210
|
+
# when the current actor is the supervision branch. Guards the main-owned role
|
|
211
|
+
# partition; a home with no branch never sets the actor and always passes.
|
|
212
|
+
fm_lease_forbid_branch() {
|
|
213
|
+
local action=$1 actor
|
|
214
|
+
actor=$(fm_lease_actor) || exit "$FM_LEASE_REFUSE_EXIT"
|
|
215
|
+
[ "$actor" = branch ] || return 0
|
|
216
|
+
echo "error: $action refused - the supervision branch never performs this action; report the outcome and leave it to main (role partition: docs/pi-supervision-branch.md)" >&2
|
|
217
|
+
exit "$FM_LEASE_REFUSE_EXIT"
|
|
218
|
+
}
|