@zerwiz/ymir 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/README.md +291 -0
- package/.agents/agents/bragi-marketer.md +111 -0
- package/.agents/agents/brokk.md +352 -0
- package/.agents/agents/forseti-reviewer.md +93 -0
- package/.agents/agents/frigg-consent.md +77 -0
- package/.agents/agents/groa-update.md +77 -0
- package/.agents/agents/hnoss-designer.md +69 -0
- package/.agents/agents/huginn-researcher.md +99 -0
- package/.agents/agents/jord-projects.md +78 -0
- package/.agents/agents/kvasir-scout.md +91 -0
- package/.agents/agents/mimir-planner.md +92 -0
- package/.agents/agents/muninn-stow.md +77 -0
- package/.agents/agents/saga-bearings.md +78 -0
- package/.agents/agents/sindri-developer.md +114 -0
- package/.agents/agents/snotra-documenter.md +105 -0
- package/.agents/agents/syn-recovery.md +78 -0
- package/.agents/agents/tyr-check.md +78 -0
- package/.agents/agents/urdh-hold.md +77 -0
- package/.agents/agents/volundr-smith.md +80 -0
- package/.agents/agents/vor-diagnostics.md +77 -0
- package/.agents/assets/agents/naming.md +50 -0
- package/.agents/assets/agents/registry.md +93 -0
- package/.agents/assets/agents/runtime.md +36 -0
- package/.agents/assets/agents/toon-tasks-cli.md +42 -0
- package/.agents/assets/templates/company_entity.template.md +37 -0
- package/.agents/backend/backends/cmux.sh +649 -0
- package/.agents/backend/backends/herdr-eventwait.py +157 -0
- package/.agents/backend/backends/herdr-workspace-move.py +114 -0
- package/.agents/backend/backends/herdr.sh +3386 -0
- package/.agents/backend/backends/orca.sh +290 -0
- package/.agents/backend/backends/tmux.sh +357 -0
- package/.agents/backend/backends/zellij.sh +700 -0
- package/.agents/backend/fm-afk-launch.sh +654 -0
- package/.agents/backend/fm-afk-return.sh +241 -0
- package/.agents/backend/fm-afk-start.sh +172 -0
- package/.agents/backend/fm-arm-command-policy.mjs +960 -0
- package/.agents/backend/fm-arm-pretool-check.sh +200 -0
- package/.agents/backend/fm-backend-hometag-lib.sh +52 -0
- package/.agents/backend/fm-backend.sh +981 -0
- package/.agents/backend/fm-backlog-handoff.sh +909 -0
- package/.agents/backend/fm-backlog-receive.sh +187 -0
- package/.agents/backend/fm-backlog-transition-lib.sh +779 -0
- package/.agents/backend/fm-bearings-board.sh +204 -0
- package/.agents/backend/fm-bearings-snapshot.sh +546 -0
- package/.agents/backend/fm-bootstrap.sh +1568 -0
- package/.agents/backend/fm-branch-outcome.sh +203 -0
- package/.agents/backend/fm-branch-prompt.sh +101 -0
- package/.agents/backend/fm-brief.sh +452 -0
- package/.agents/backend/fm-busy-event.sh +234 -0
- package/.agents/backend/fm-busy-lib.sh +986 -0
- package/.agents/backend/fm-captain-hold.sh +1001 -0
- package/.agents/backend/fm-cd-command-policy.mjs +153 -0
- package/.agents/backend/fm-cd-pretool-check.sh +190 -0
- package/.agents/backend/fm-check-lib.sh +74 -0
- package/.agents/backend/fm-check-register.sh +42 -0
- package/.agents/backend/fm-check-unregister.sh +52 -0
- package/.agents/backend/fm-classify-lib.sh +1770 -0
- package/.agents/backend/fm-claude-stop-autoarm.sh +334 -0
- package/.agents/backend/fm-composer-lib.sh +1416 -0
- package/.agents/backend/fm-config-inherit-lib.sh +1202 -0
- package/.agents/backend/fm-config-push.sh +254 -0
- package/.agents/backend/fm-control-lib.sh +251 -0
- package/.agents/backend/fm-control.sh +878 -0
- package/.agents/backend/fm-crew-state.sh +625 -0
- package/.agents/backend/fm-cursor-lib.sh +243 -0
- package/.agents/backend/fm-decision-hold.sh +232 -0
- package/.agents/backend/fm-doc-audience-check.sh +269 -0
- package/.agents/backend/fm-dod-lib.sh +67 -0
- package/.agents/backend/fm-ensure-agents-md.sh +253 -0
- package/.agents/backend/fm-extension-launch-barrier.mjs +129 -0
- package/.agents/backend/fm-extension.mjs +2577 -0
- package/.agents/backend/fm-extension.sh +16 -0
- package/.agents/backend/fm-ff-lib.sh +420 -0
- package/.agents/backend/fm-fleet-snapshot.sh +1463 -0
- package/.agents/backend/fm-fleet-sync.sh +458 -0
- package/.agents/backend/fm-fleet-view.sh +96 -0
- package/.agents/backend/fm-gate-refuse-lib.sh +102 -0
- package/.agents/backend/fm-guard.sh +242 -0
- package/.agents/backend/fm-harness.sh +195 -0
- package/.agents/backend/fm-herdr-ci-cleanup.sh +115 -0
- package/.agents/backend/fm-herdr-lab.sh +346 -0
- package/.agents/backend/fm-herdr-session-cleanup.sh +337 -0
- package/.agents/backend/fm-home-seed.sh +984 -0
- package/.agents/backend/fm-home-summary-refresh.sh +255 -0
- package/.agents/backend/fm-hook-host-lib.sh +36 -0
- package/.agents/backend/fm-inactive-reconcile.sh +531 -0
- package/.agents/backend/fm-inbox.sh +399 -0
- package/.agents/backend/fm-install-actionlint.sh +84 -0
- package/.agents/backend/fm-install-herdr.sh +96 -0
- package/.agents/backend/fm-install-shellcheck.sh +84 -0
- package/.agents/backend/fm-install-treehouse.sh +95 -0
- package/.agents/backend/fm-kimi-turnend-hook.sh +276 -0
- package/.agents/backend/fm-lease-lib.sh +218 -0
- package/.agents/backend/fm-lease.sh +189 -0
- package/.agents/backend/fm-line-cap-lib.sh +51 -0
- package/.agents/backend/fm-lint-workflows.sh +137 -0
- package/.agents/backend/fm-lint.sh +591 -0
- package/.agents/backend/fm-lock-lib.sh +104 -0
- package/.agents/backend/fm-lock.sh +107 -0
- package/.agents/backend/fm-marker-lib.sh +12 -0
- package/.agents/backend/fm-merge-local.sh +74 -0
- package/.agents/backend/fm-merge-outcome-lib.sh +138 -0
- package/.agents/backend/fm-nm-run-lib.sh +124 -0
- package/.agents/backend/fm-on.sh +125 -0
- package/.agents/backend/fm-operational-input.sh +253 -0
- package/.agents/backend/fm-peek.sh +46 -0
- package/.agents/backend/fm-pending-reply-lib.sh +1409 -0
- package/.agents/backend/fm-pr-check.sh +135 -0
- package/.agents/backend/fm-pr-lib.sh +1016 -0
- package/.agents/backend/fm-pr-merge.sh +707 -0
- package/.agents/backend/fm-pr-poll.sh +110 -0
- package/.agents/backend/fm-primary-scope-lib.sh +33 -0
- package/.agents/backend/fm-procevent-extension-capture.pl +259 -0
- package/.agents/backend/fm-procevent-lavish.sh +628 -0
- package/.agents/backend/fm-procevent-lib.sh +892 -0
- package/.agents/backend/fm-procevent-quota.sh +290 -0
- package/.agents/backend/fm-procevent-remote-reply.sh +577 -0
- package/.agents/backend/fm-procevent-when.sh +504 -0
- package/.agents/backend/fm-procevent.sh +1466 -0
- package/.agents/backend/fm-project-mode.sh +92 -0
- package/.agents/backend/fm-project-origin-lib.sh +180 -0
- package/.agents/backend/fm-promote.sh +282 -0
- package/.agents/backend/fm-public-followup-emit.sh +260 -0
- package/.agents/backend/fm-public-followup-lib.sh +398 -0
- package/.agents/backend/fm-public-followup.sh +1330 -0
- package/.agents/backend/fm-push-transition-lib.sh +168 -0
- package/.agents/backend/fm-quota-axi-lib.sh +93 -0
- package/.agents/backend/fm-quota-choose.sh +384 -0
- package/.agents/backend/fm-remote-delta-read.sh +189 -0
- package/.agents/backend/fm-remote-doctor.sh +800 -0
- package/.agents/backend/fm-remote-entrypoint.sh +193 -0
- package/.agents/backend/fm-remote-file.sh +234 -0
- package/.agents/backend/fm-remote-home-provision.sh +259 -0
- package/.agents/backend/fm-remote-home-seed.sh +259 -0
- package/.agents/backend/fm-remote-inherit-push.sh +90 -0
- package/.agents/backend/fm-remote-inherit.sh +179 -0
- package/.agents/backend/fm-remote-job-lib.sh +1241 -0
- package/.agents/backend/fm-remote-job-reap-orphans.sh +137 -0
- package/.agents/backend/fm-remote-job-worker.sh +1124 -0
- package/.agents/backend/fm-remote-readiness-lib.sh +44 -0
- package/.agents/backend/fm-remote-secondmate-control.sh +340 -0
- package/.agents/backend/fm-review-diff.sh +158 -0
- package/.agents/backend/fm-secondmate-charter-lib.sh +44 -0
- package/.agents/backend/fm-secondmate-nudge-lib.sh +68 -0
- package/.agents/backend/fm-secondmate-parent-lib.sh +70 -0
- package/.agents/backend/fm-secondmate-reconcile.sh +371 -0
- package/.agents/backend/fm-secondmate-registry-lib.sh +311 -0
- package/.agents/backend/fm-secondmate-report.sh +88 -0
- package/.agents/backend/fm-send.sh +1059 -0
- package/.agents/backend/fm-session-lock-lib.sh +176 -0
- package/.agents/backend/fm-session-start.sh +970 -0
- package/.agents/backend/fm-sessionstart-cursor.sh +40 -0
- package/.agents/backend/fm-sessionstart-nudge.sh +45 -0
- package/.agents/backend/fm-sessionstart-run.sh +145 -0
- package/.agents/backend/fm-spawn.sh +3153 -0
- package/.agents/backend/fm-startup-memory-budget-lib.sh +224 -0
- package/.agents/backend/fm-startup-memory-budget.sh +94 -0
- package/.agents/backend/fm-startup-network.sh +642 -0
- package/.agents/backend/fm-stow-cascade.sh +251 -0
- package/.agents/backend/fm-subagent-pretool-check.sh +207 -0
- package/.agents/backend/fm-supervise-daemon.sh +1732 -0
- package/.agents/backend/fm-supervision-instructions.sh +215 -0
- package/.agents/backend/fm-supervision-lib.sh +90 -0
- package/.agents/backend/fm-supervisor-target-lib.sh +78 -0
- package/.agents/backend/fm-tangle-lib.sh +53 -0
- package/.agents/backend/fm-task-inbox-lib.sh +402 -0
- package/.agents/backend/fm-tasks-axi-lib.sh +123 -0
- package/.agents/backend/fm-teardown.sh +2922 -0
- package/.agents/backend/fm-test-isolation-proof.sh +588 -0
- package/.agents/backend/fm-test-run.sh +2191 -0
- package/.agents/backend/fm-timeout-lib.sh +141 -0
- package/.agents/backend/fm-timing-lib.sh +179 -0
- package/.agents/backend/fm-tmux-lib.sh +291 -0
- package/.agents/backend/fm-tool-update-check.sh +898 -0
- package/.agents/backend/fm-trace-context-lib.sh +227 -0
- package/.agents/backend/fm-transition-lib.sh +103 -0
- package/.agents/backend/fm-turnend-guard-cursor.sh +391 -0
- package/.agents/backend/fm-turnend-guard-grok.sh +90 -0
- package/.agents/backend/fm-turnend-guard.sh +432 -0
- package/.agents/backend/fm-update.sh +110 -0
- package/.agents/backend/fm-vendor-auth-probe.sh +190 -0
- package/.agents/backend/fm-voice-client.py +1373 -0
- package/.agents/backend/fm-voice-relay.py +1256 -0
- package/.agents/backend/fm-wake-drain.sh +592 -0
- package/.agents/backend/fm-wake-grant.sh +127 -0
- package/.agents/backend/fm-wake-lib.sh +1849 -0
- package/.agents/backend/fm-watch-arm.sh +602 -0
- package/.agents/backend/fm-watch-checkpoint.sh +109 -0
- package/.agents/backend/fm-watch.sh +1962 -0
- package/.agents/backend/fm-x-dismiss.sh +116 -0
- package/.agents/backend/fm-x-followup.sh +286 -0
- package/.agents/backend/fm-x-lib.sh +1000 -0
- package/.agents/backend/fm-x-link.sh +234 -0
- package/.agents/backend/fm-x-poll.sh +185 -0
- package/.agents/backend/fm-x-reply.sh +385 -0
- package/.agents/backend/fm_voice_frame.py +166 -0
- package/.agents/backend/fm_voice_records.py +574 -0
- package/.agents/backend/model-bridge.py +290 -0
- package/.agents/backend/opencode-go-bridge.py +30 -0
- package/.agents/bus/README.md +12 -0
- package/.agents/bus/messages.json +1 -0
- package/.agents/config/agents.machine.example.yaml +16 -0
- package/.agents/config/agents.yaml +50 -0
- package/.agents/config/agents.yaml.example +72 -0
- package/.agents/config/crew-dispatch.json +22 -0
- package/.agents/config/cron.yaml +9 -0
- package/.agents/config/eindri-dispatch.json +67 -0
- package/.agents/config/eindri-harness +1 -0
- package/.agents/config/startup-memory-budget +1 -0
- package/.agents/config/tailscale-sync.yaml +27 -0
- package/.agents/filebrowser/.filebrowser.json +6 -0
- package/.agents/filebrowser/README.md +11 -0
- package/.agents/gateway/README.md +12 -0
- package/.agents/github/README.md +15 -0
- package/.agents/github/webhooks/.gitkeep +0 -0
- package/.agents/github/workflows/.gitkeep +0 -0
- package/.agents/harness/opencode/plugins/lib/rodd-operational-input.js +37 -0
- package/.agents/harness/opencode/plugins/package.json +4 -0
- package/.agents/harness/opencode/plugins/saga-sessionstart.js +77 -0
- package/.agents/harness/opencode/plugins/syn-cd-check.js +61 -0
- package/.agents/harness/opencode/plugins/syn-pretool-check.js +68 -0
- package/.agents/harness/opencode/plugins/syn-turnend-guard.js +105 -0
- package/.agents/harness/opencode/plugins/syn-watch-arm.js +521 -0
- package/.agents/memory/README.md +46 -0
- package/.agents/memory/kaia.engram +0 -0
- package/.agents/memory/kaia.engram-shm +0 -0
- package/.agents/memory/kaia.engram-wal +0 -0
- package/.agents/memory/runes_audit.md +5 -0
- package/.agents/memory/well/episodes.jsonl +367 -0
- package/.agents/memory/well/workspace.jsonl +27 -0
- package/.agents/migrations/0001-hodd-layout.sh +38 -0
- package/.agents/migrations/0002-a2a-mcp.sh +27 -0
- package/.agents/migrations/0003-private-data-separation.sh +111 -0
- package/.agents/migrations/0004-hoard-and-realms.sh +104 -0
- package/.agents/sandbox/Dockerfile.utgard +19 -0
- package/.agents/sandbox/README.md +14 -0
- package/.agents/sandbox/utgard.config.json +14 -0
- package/.agents/skills/README.md +59 -0
- package/.agents/skills/bragi-marketing/README.md +3 -0
- package/.agents/skills/bragi-marketing/SKILL.md +82 -0
- package/.agents/skills/eindri-homes/README.md +3 -0
- package/.agents/skills/eindri-homes/SKILL.md +291 -0
- package/.agents/skills/eindri-homes/assets/control-plane.md +122 -0
- package/.agents/skills/eindri-homes/assets/dispatch.md +80 -0
- package/.agents/skills/frigg-consent/README.md +3 -0
- package/.agents/skills/frigg-consent/SKILL.md +56 -0
- package/.agents/skills/galdr-ymirsystem/README.md +3 -0
- package/.agents/skills/galdr-ymirsystem/SKILL.md +158 -0
- package/.agents/skills/galdr-ymirsystem/assets/README.md +74 -0
- package/.agents/skills/galdr-ymirsystem/assets/brokk-distro-runtime.md +390 -0
- package/.agents/skills/galdr-ymirsystem/assets/build-method.md +113 -0
- package/.agents/skills/galdr-ymirsystem/assets/build-tool-categories.md +178 -0
- package/.agents/skills/galdr-ymirsystem/assets/eindri-orchestration.md +518 -0
- package/.agents/skills/galdr-ymirsystem/assets/eindri-profiles.md +136 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/README.md +673 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/claude-code.md +197 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/codex.md +191 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/cursor.md +193 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/opencode.md +262 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/pi.md +295 -0
- package/.agents/skills/galdr-ymirsystem/assets/hlidskjalf-ui.md +496 -0
- package/.agents/skills/galdr-ymirsystem/assets/installation.md +571 -0
- package/.agents/skills/galdr-ymirsystem/assets/local-models/HOST-DATA.example.md +72 -0
- package/.agents/skills/galdr-ymirsystem/assets/local-models.md +274 -0
- package/.agents/skills/galdr-ymirsystem/assets/memory-well.md +161 -0
- package/.agents/skills/galdr-ymirsystem/assets/nornir-jobs.md +377 -0
- package/.agents/skills/galdr-ymirsystem/assets/norse-naming.md +325 -0
- package/.agents/skills/galdr-ymirsystem/assets/odrerir-hall.md +129 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/einherjar-spawn.schema.json +81 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/herdr-profile.toml +75 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/pi-profile.yml +96 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/supervision-tree.yml +163 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot-guide.md +58 -0
- package/.agents/skills/galdr-ymirsystem/assets/porting-upstream-to-norse.md +301 -0
- package/.agents/skills/galdr-ymirsystem/assets/principles.md +385 -0
- package/.agents/skills/galdr-ymirsystem/assets/reference-adoption.md +99 -0
- package/.agents/skills/galdr-ymirsystem/assets/registry.md +379 -0
- package/.agents/skills/galdr-ymirsystem/assets/runtime-compliance.md +463 -0
- package/.agents/skills/galdr-ymirsystem/assets/runtime-components.md +553 -0
- package/.agents/skills/galdr-ymirsystem/assets/smidja.md +175 -0
- package/.agents/skills/galdr-ymirsystem/schemas/toon-schemas.md +190 -0
- package/.agents/skills/galdr-ymirsystem/scripts/README.md +45 -0
- package/.agents/skills/galdr-ymirsystem/scripts/bench-one.sh +248 -0
- package/.agents/skills/galdr-ymirsystem/scripts/compliance-check.sh +360 -0
- package/.agents/skills/galdr-ymirsystem/scripts/gpu-sample.sh +43 -0
- package/.agents/skills/galdr-ymirsystem/scripts/stop-all.sh +34 -0
- package/.agents/skills/galdr-ymirsystem/scripts/toon-check.py +188 -0
- package/.agents/skills/gjallarhorn-relay/README.md +3 -0
- package/.agents/skills/gjallarhorn-relay/SKILL.md +283 -0
- package/.agents/skills/groa-update/SKILL.md +70 -0
- package/.agents/skills/hamr-adapters/README.md +3 -0
- package/.agents/skills/hamr-adapters/SKILL.md +123 -0
- package/.agents/skills/hamr-adapters/references/common/control-and-recovery.md +37 -0
- package/.agents/skills/hamr-adapters/references/common/dispatch.md +32 -0
- package/.agents/skills/hamr-adapters/references/common/model-and-effort.md +42 -0
- package/.agents/skills/hamr-adapters/references/common/primary-hooks.md +40 -0
- package/.agents/skills/hamr-adapters/references/harness/claude.md +55 -0
- package/.agents/skills/hamr-adapters/references/harness/codex.md +43 -0
- package/.agents/skills/hamr-adapters/references/harness/cursor.md +75 -0
- package/.agents/skills/hamr-adapters/references/harness/grok.md +69 -0
- package/.agents/skills/hamr-adapters/references/harness/kimi.md +51 -0
- package/.agents/skills/hamr-adapters/references/harness/muse.md +70 -0
- package/.agents/skills/hamr-adapters/references/harness/opencode.md +42 -0
- package/.agents/skills/hamr-adapters/references/harness/pi.md +56 -0
- package/.agents/skills/herdr-panes/README.md +3 -0
- package/.agents/skills/herdr-panes/SKILL.md +92 -0
- package/.agents/skills/herdr-panes/assets/herdr-backend.md +346 -0
- package/.agents/skills/herdr-panes/assets/tmux-backend.md +115 -0
- package/.agents/skills/hnoss-design/DESIGN.md +19 -0
- package/.agents/skills/hnoss-design/README.md +3 -0
- package/.agents/skills/hnoss-design/SKILL.md +83 -0
- package/.agents/skills/hvild-afk/README.md +3 -0
- package/.agents/skills/hvild-afk/SKILL.md +241 -0
- package/.agents/skills/jord-projects/README.md +3 -0
- package/.agents/skills/jord-projects/SKILL.md +92 -0
- package/.agents/skills/lifecycle/SKILL.md +56 -0
- package/.agents/skills/lifecycle/smoke_test.sh +52 -0
- package/.agents/skills/lifecycle/start.sh +21 -0
- package/.agents/skills/lifecycle/status.sh +35 -0
- package/.agents/skills/lifecycle/stop.sh +16 -0
- package/.agents/skills/muninn-stow/README.md +3 -0
- package/.agents/skills/muninn-stow/SKILL.md +309 -0
- package/.agents/skills/no-mistakes/SKILL.md +379 -0
- package/.agents/skills/nornir-schedule/README.md +3 -0
- package/.agents/skills/nornir-schedule/SKILL.md +25 -0
- package/.agents/skills/nornir-schedule/assets/events.md +137 -0
- package/.agents/skills/nornir-schedule/assets/quota.md +131 -0
- package/.agents/skills/nsr-compliance/README.md +3 -0
- package/.agents/skills/nsr-compliance/SKILL.md +29 -0
- package/.agents/skills/nsr-compliance/assets/nsr/README.md +40 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/README.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/git-workflow.md +18 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/security.md +22 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/tech-stack.md +8 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/SKILL.md +71 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/config/core_four.yaml +16 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/check_danger.sh +102 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/check_wiring.sh +69 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/validate_code.sh +29 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/verify_docs.py +66 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/generate.sh +109 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/envelopes/result_envelope.json +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/envelopes/task_envelope.json +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/runner.py +303 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/telemetry/logger.py +112 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/README.md +18 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/config/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/README.md +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_env.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_paths.sh +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_platform.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/harness/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/harness/envelopes/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/installer/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/installer/install.sh +125 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/telemetry/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/README.md +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/features/README.md +36 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/features/SKILL-template.md +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/README.md +25 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/SKILL.md +13 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/create_branch.sh +6 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/safe_commit.sh +9 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/sync_upstream.sh +6 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/README.md +27 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/SKILL.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/smoke_test.sh +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/start.sh +19 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/status.sh +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/stop.sh +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/README.md +18 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/config/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/config/core_four.yaml +13 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/README.md +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_danger.sh +102 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_env.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_paths.sh +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_platform.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_wiring.sh +69 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/result_envelope.json +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/task_envelope.json +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/runner.py +303 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/installer/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/installer/install.sh +125 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/telemetry/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/telemetry/logger.py +112 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/README.md +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/api.md +17 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/compliance-wiring.md +155 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/frontend.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/README.md +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/clients/README.md +16 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/clients/template-README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/deploy.sh +49 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/README.md +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/development.env.example +17 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/production.env.example +17 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/staging.env.example +17 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/tenants/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/tenants/template.env.example +8 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/README.md +26 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/agent.md +7 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/developers/dev-1.md +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/linux.md +9 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/macos.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/shared.md +19 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/windows.md +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/README.md +25 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/_template.md +41 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/hosting-1.md +41 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/README.md +21 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/README.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/deployment.md +19 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/disaster-recovery.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/ops-tasks.md +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/features/README.md +16 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/project-skills.md +146 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/research/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/research/software-compliance-research.md +269 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/working-with-agents.md +260 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/AGENTS.md +38 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/ARCHITECTURE.md +36 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/BEST_PRACTICES.md +27 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/CI_CD.md +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/FEATURES.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/README.md +22 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/RULES.md +37 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/STRUCTURE.md +45 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/TECH_STACK.md +28 -0
- package/.agents/skills/nsr-compliance/assets/nsr/scaffold-spec.md +63 -0
- package/.agents/skills/nsr-compliance/assets/nsr/scripts/scaffold.sh +103 -0
- package/.agents/skills/nsr-compliance/assets/nsr/scripts/validate.sh +52 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/SKILL.md +71 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/config/core_four.yaml +16 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/check_danger.sh +102 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/check_wiring.sh +69 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/validate_code.sh +29 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/verify_docs.py +66 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/generate.sh +109 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/envelopes/result_envelope.json +14 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/envelopes/task_envelope.json +20 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/runner.py +303 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/telemetry/logger.py +112 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/README.md +18 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/config/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/README.md +12 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_env.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_paths.sh +20 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_platform.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/harness/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/harness/envelopes/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/installer/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/installer/install.sh +125 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/telemetry/README.md +11 -0
- package/.agents/skills/pr-ops/README.md +3 -0
- package/.agents/skills/pr-ops/SKILL.md +109 -0
- package/.agents/skills/ratatoskr-a2a/README.md +3 -0
- package/.agents/skills/ratatoskr-a2a/SKILL.md +148 -0
- package/.agents/skills/rules-check-drift/SKILL.md +81 -0
- package/.agents/skills/saga-bearings/README.md +3 -0
- package/.agents/skills/saga-bearings/SKILL.md +26 -0
- package/.agents/skills/saga-bearings/assets/bearings.md +161 -0
- package/.agents/skills/saga-bearings/assets/board-template.html +731 -0
- package/.agents/skills/saga-bearings/assets/recap.md +56 -0
- package/.agents/skills/syn-recovery/README.md +3 -0
- package/.agents/skills/syn-recovery/SKILL.md +54 -0
- package/.agents/skills/tyr-check/README.md +3 -0
- package/.agents/skills/tyr-check/SKILL.md +218 -0
- package/.agents/skills/urdh-hold/README.md +3 -0
- package/.agents/skills/urdh-hold/SKILL.md +25 -0
- package/.agents/skills/urdh-hold/assets/decisions.md +15 -0
- package/.agents/skills/urdh-hold/assets/hold.md +54 -0
- package/.agents/skills/vor-diagnostics/README.md +3 -0
- package/.agents/skills/vor-diagnostics/SKILL.md +68 -0
- package/.agents/skills/ymir-host/README.md +3 -0
- package/.agents/skills/ymir-host/SKILL.md +34 -0
- package/.agents/skills/ymir-host/assets/desktop.md +36 -0
- package/.agents/skills/ymir-host/assets/omarchy.md +297 -0
- package/.agents/skills/ymir-host/assets/runbooks.md +15 -0
- package/.agents/skills/ymir-host/assets/thjazi.md +220 -0
- package/.agents/skills/ymir-host/assets/update.md +64 -0
- package/.agents/tests/assets/board-render-harness.mjs +117 -0
- package/.agents/tests/cmux-test-safety.sh +51 -0
- package/.agents/tests/fixtures.sh +291 -0
- package/.agents/tests/fm-afk-inject-e2e.test.sh +428 -0
- package/.agents/tests/fm-afk-inject-herdr-e2e.test.sh +536 -0
- package/.agents/tests/fm-afk-launch.test.sh +961 -0
- package/.agents/tests/fm-afk-pi-herdr-return-e2e.test.sh +297 -0
- package/.agents/tests/fm-afk-return.test.sh +283 -0
- package/.agents/tests/fm-arm-pretool-check.test.sh +482 -0
- package/.agents/tests/fm-ask-user-authority.test.sh +42 -0
- package/.agents/tests/fm-backend-autodetect-smoke.test.sh +176 -0
- package/.agents/tests/fm-backend-cmux-smoke.test.sh +188 -0
- package/.agents/tests/fm-backend-cmux.test.sh +1166 -0
- package/.agents/tests/fm-backend-herdr-eventwait-smoke.test.sh +136 -0
- package/.agents/tests/fm-backend-herdr-eventwait.test.py +106 -0
- package/.agents/tests/fm-backend-herdr-focus-flash-e2e.test.sh +409 -0
- package/.agents/tests/fm-backend-herdr-launcher-workspace-e2e.test.sh +437 -0
- package/.agents/tests/fm-backend-herdr-presentation-e2e.test.sh +1424 -0
- package/.agents/tests/fm-backend-herdr-prune-safety-e2e.test.sh +180 -0
- package/.agents/tests/fm-backend-herdr-respawn-idem-e2e.test.sh +182 -0
- package/.agents/tests/fm-backend-herdr-smoke.test.sh +355 -0
- package/.agents/tests/fm-backend-herdr-workspace-per-home-e2e.test.sh +251 -0
- package/.agents/tests/fm-backend-herdr.test.sh +4606 -0
- package/.agents/tests/fm-backend-orca.test.sh +1357 -0
- package/.agents/tests/fm-backend-tmux-smoke.test.sh +173 -0
- package/.agents/tests/fm-backend-zellij-smoke.test.sh +205 -0
- package/.agents/tests/fm-backend-zellij.test.sh +1360 -0
- package/.agents/tests/fm-backend.test.sh +1142 -0
- package/.agents/tests/fm-backlog-atomicity.test.sh +2302 -0
- package/.agents/tests/fm-backlog-handoff.test.sh +1360 -0
- package/.agents/tests/fm-bearings-board-render.test.sh +135 -0
- package/.agents/tests/fm-bearings-board.test.sh +414 -0
- package/.agents/tests/fm-bearings-snapshot.test.sh +1990 -0
- package/.agents/tests/fm-bootstrap-network-parallel.test.sh +316 -0
- package/.agents/tests/fm-bootstrap.test.sh +1178 -0
- package/.agents/tests/fm-branch-supervision.test.sh +552 -0
- package/.agents/tests/fm-brief.test.sh +785 -0
- package/.agents/tests/fm-busy-adapter-wiring.test.sh +324 -0
- package/.agents/tests/fm-busy-state.test.sh +465 -0
- package/.agents/tests/fm-calm-pi-extension.test.sh +3979 -0
- package/.agents/tests/fm-captain-hold-lifecycle.test.sh +1187 -0
- package/.agents/tests/fm-cd-pretool-check.test.sh +400 -0
- package/.agents/tests/fm-check-unregister.test.sh +198 -0
- package/.agents/tests/fm-classify-corr-token.test.sh +543 -0
- package/.agents/tests/fm-classify-decision-key.test.sh +340 -0
- package/.agents/tests/fm-claude-stop-autoarm-live-e2e.test.sh +164 -0
- package/.agents/tests/fm-claude-stop-autoarm.test.sh +1190 -0
- package/.agents/tests/fm-cmux-claude-composer-live-e2e.test.sh +110 -0
- package/.agents/tests/fm-codex-continuity-live-e2e.test.sh +55 -0
- package/.agents/tests/fm-composer-ghost.test.sh +716 -0
- package/.agents/tests/fm-composer-lib.test.sh +666 -0
- package/.agents/tests/fm-composer-matrix-live-e2e.test.sh +220 -0
- package/.agents/tests/fm-control-herdr-smoke.test.sh +149 -0
- package/.agents/tests/fm-control-relaunch.test.sh +1530 -0
- package/.agents/tests/fm-control.test.sh +910 -0
- package/.agents/tests/fm-crew-state.test.sh +1610 -0
- package/.agents/tests/fm-cursor-harness.test.sh +404 -0
- package/.agents/tests/fm-cursor-primary-live-e2e.test.sh +217 -0
- package/.agents/tests/fm-cursor-primary.test.sh +708 -0
- package/.agents/tests/fm-daemon.test.sh +2740 -0
- package/.agents/tests/fm-documentation-audiences.test.sh +141 -0
- package/.agents/tests/fm-ensure-agents-md.test.sh +371 -0
- package/.agents/tests/fm-extension-binding.test.sh +2187 -0
- package/.agents/tests/fm-fleet-snapshot-view.test.sh +816 -0
- package/.agents/tests/fm-fleet-sync.test.sh +721 -0
- package/.agents/tests/fm-gate-refuse.test.sh +356 -0
- package/.agents/tests/fm-gitignore-config.test.sh +89 -0
- package/.agents/tests/fm-gotmp.test.sh +230 -0
- package/.agents/tests/fm-grok-continuity-live-e2e.test.sh +112 -0
- package/.agents/tests/fm-grok-harness.test.sh +117 -0
- package/.agents/tests/fm-grok-stop-live-e2e.test.sh +219 -0
- package/.agents/tests/fm-guard-stale-banner.test.sh +709 -0
- package/.agents/tests/fm-harness-adapter-instructions-live-e2e.test.sh +134 -0
- package/.agents/tests/fm-harness-adapter-references.test.sh +30 -0
- package/.agents/tests/fm-harness-liveness-drift-live-e2e.test.sh +151 -0
- package/.agents/tests/fm-herdr-lab.test.sh +243 -0
- package/.agents/tests/fm-herdr-session-cleanup-e2e.test.sh +146 -0
- package/.agents/tests/fm-herdr-session-cleanup.test.sh +329 -0
- package/.agents/tests/fm-herdr-submit-confirm-live-e2e.test.sh +125 -0
- package/.agents/tests/fm-herdr-version-floor-live-e2e.test.sh +144 -0
- package/.agents/tests/fm-home-summary-refresh.test.sh +971 -0
- package/.agents/tests/fm-inactive-reconcile.test.sh +485 -0
- package/.agents/tests/fm-kimi-harness.test.sh +687 -0
- package/.agents/tests/fm-lint-workflows.test.sh +532 -0
- package/.agents/tests/fm-lint.test.sh +1023 -0
- package/.agents/tests/fm-muse-harness.test.sh +932 -0
- package/.agents/tests/fm-muse-signals-live-e2e.test.sh +205 -0
- package/.agents/tests/fm-no-mistakes-required.test.sh +72 -0
- package/.agents/tests/fm-on.test.sh +507 -0
- package/.agents/tests/fm-opencode-primary-live-e2e.test.sh +357 -0
- package/.agents/tests/fm-operational-input.test.sh +160 -0
- package/.agents/tests/fm-peek-remote.test.sh +110 -0
- package/.agents/tests/fm-pending-reply.test.sh +1288 -0
- package/.agents/tests/fm-pi-branch-extension.test.sh +3182 -0
- package/.agents/tests/fm-pi-branch-live-e2e.test.sh +527 -0
- package/.agents/tests/fm-pi-primary-live-e2e.test.sh +345 -0
- package/.agents/tests/fm-pi-primary-types.test.sh +68 -0
- package/.agents/tests/fm-pi-watch-extension.test.sh +2843 -0
- package/.agents/tests/fm-pr-check-security.test.sh +2140 -0
- package/.agents/tests/fm-pr-merge.test.sh +2135 -0
- package/.agents/tests/fm-procevent-quota.test.sh +225 -0
- package/.agents/tests/fm-procevent-when.test.sh +406 -0
- package/.agents/tests/fm-procevent.test.sh +1745 -0
- package/.agents/tests/fm-project-origin.test.sh +110 -0
- package/.agents/tests/fm-public-followup.test.sh +2272 -0
- package/.agents/tests/fm-quota-array-dispatch-live-e2e.test.sh +526 -0
- package/.agents/tests/fm-quota-choose.test.sh +626 -0
- package/.agents/tests/fm-remote-backlog-handoff.test.sh +453 -0
- package/.agents/tests/fm-remote-doctor.test.sh +625 -0
- package/.agents/tests/fm-remote-entrypoint.test.sh +59 -0
- package/.agents/tests/fm-remote-job-orphan-reap.test.sh +205 -0
- package/.agents/tests/fm-remote-job.test.sh +768 -0
- package/.agents/tests/fm-remote-reply.test.sh +520 -0
- package/.agents/tests/fm-remote-secondmate-lifecycle-e2e.test.sh +1256 -0
- package/.agents/tests/fm-remote-secondmate-parent-binding.test.sh +326 -0
- package/.agents/tests/fm-remote-secondmate-trace-context.test.sh +310 -0
- package/.agents/tests/fm-remote-transport-lanes.test.sh +431 -0
- package/.agents/tests/fm-review-diff.test.sh +176 -0
- package/.agents/tests/fm-secondmate-harness.test.sh +2600 -0
- package/.agents/tests/fm-secondmate-lifecycle-e2e.test.sh +259 -0
- package/.agents/tests/fm-secondmate-liveness.test.sh +559 -0
- package/.agents/tests/fm-secondmate-reconcile.test.sh +732 -0
- package/.agents/tests/fm-secondmate-safety.test.sh +2972 -0
- package/.agents/tests/fm-secondmate-sync.test.sh +913 -0
- package/.agents/tests/fm-send-inbox-doorbell-live-e2e.test.sh +206 -0
- package/.agents/tests/fm-send-inbox.test.sh +352 -0
- package/.agents/tests/fm-send-popup-settle.test.sh +167 -0
- package/.agents/tests/fm-send-remote-delivery.test.sh +796 -0
- package/.agents/tests/fm-send-resolve-key.test.sh +551 -0
- package/.agents/tests/fm-send-secondmate-marker-herdr-e2e.test.sh +187 -0
- package/.agents/tests/fm-send-secondmate-marker.test.sh +278 -0
- package/.agents/tests/fm-send-settle.test.sh +147 -0
- package/.agents/tests/fm-send-strict.test.sh +241 -0
- package/.agents/tests/fm-session-lock-ancestry.test.sh +365 -0
- package/.agents/tests/fm-session-start.test.sh +2515 -0
- package/.agents/tests/fm-sessionstart-hook-live-e2e.test.sh +631 -0
- package/.agents/tests/fm-sessionstart-instruction-refresh-live-e2e.test.sh +230 -0
- package/.agents/tests/fm-sessionstart-nudge.test.sh +1039 -0
- package/.agents/tests/fm-shared-captain-inheritance.test.sh +404 -0
- package/.agents/tests/fm-spawn-batch.test.sh +148 -0
- package/.agents/tests/fm-spawn-dispatch-profile.test.sh +827 -0
- package/.agents/tests/fm-spawn-pool-base-freshen.test.sh +440 -0
- package/.agents/tests/fm-spawn-worktree-settle.test.sh +147 -0
- package/.agents/tests/fm-startup-memory-budget.test.sh +333 -0
- package/.agents/tests/fm-startup-network.test.sh +712 -0
- package/.agents/tests/fm-stow-cascade.test.sh +370 -0
- package/.agents/tests/fm-subagent-pretool-check.test.sh +291 -0
- package/.agents/tests/fm-supervision-events.test.sh +156 -0
- package/.agents/tests/fm-supervision-instructions.test.sh +189 -0
- package/.agents/tests/fm-tangle-guard.test.sh +277 -0
- package/.agents/tests/fm-task-delivery.test.sh +420 -0
- package/.agents/tests/fm-task-inbox.test.sh +513 -0
- package/.agents/tests/fm-teardown-endpoint-safety.test.sh +374 -0
- package/.agents/tests/fm-teardown.test.sh +2665 -0
- package/.agents/tests/fm-test-fixture-cleanup.test.sh +172 -0
- package/.agents/tests/fm-test-fixtures.test.sh +132 -0
- package/.agents/tests/fm-test-isolation-proof.test.sh +278 -0
- package/.agents/tests/fm-test-run.test.sh +1196 -0
- package/.agents/tests/fm-tmux-agent-liveness.test.sh +354 -0
- package/.agents/tests/fm-tmux-submit-busy.test.sh +340 -0
- package/.agents/tests/fm-tool-update-check.test.sh +1044 -0
- package/.agents/tests/fm-trace-context-lib.test.sh +253 -0
- package/.agents/tests/fm-trace-context-spawn.test.sh +581 -0
- package/.agents/tests/fm-transition-lib.test.sh +54 -0
- package/.agents/tests/fm-turnend-guard.test.sh +1822 -0
- package/.agents/tests/fm-update.test.sh +304 -0
- package/.agents/tests/fm-vendor-auth-probe.test.sh +395 -0
- package/.agents/tests/fm-voice-relay.test.sh +4741 -0
- package/.agents/tests/fm-wake-daemon-lifecycle-e2e.test.sh +171 -0
- package/.agents/tests/fm-wake-drain-open-decisions-cursor.test.sh +356 -0
- package/.agents/tests/fm-wake-drain-open-decisions.test.sh +226 -0
- package/.agents/tests/fm-wake-drain-unread-status.test.sh +379 -0
- package/.agents/tests/fm-wake-queue.test.sh +1224 -0
- package/.agents/tests/fm-watch-arm.test.sh +821 -0
- package/.agents/tests/fm-watch-checkpoint.test.sh +87 -0
- package/.agents/tests/fm-watch-recovery-loop.test.sh +223 -0
- package/.agents/tests/fm-watch-triage.test.sh +3889 -0
- package/.agents/tests/fm-watcher-lock.test.sh +1133 -0
- package/.agents/tests/fm-x-mode.test.sh +3042 -0
- package/.agents/tests/gleipnir-guard-pretool-check.test.sh +51 -0
- package/.agents/tests/gleipnir-machine-lock.test.sh +130 -0
- package/.agents/tests/herdr-test-safety.sh +42 -0
- package/.agents/tests/lib.sh +315 -0
- package/.agents/tests/remote-herdr-fixture.sh +125 -0
- package/.agents/tests/secondmate-helpers.sh +193 -0
- package/.agents/tests/smoke.test.sh +93 -0
- package/.agents/tests/wake-helpers.sh +338 -0
- package/.agents/tests/zellij-test-safety.sh +60 -0
- package/.agents/tools/README.md +10 -0
- package/.agents/tools/bin/tasks-cli +267 -0
- package/.agents/tools/tasks-cli.ts +216 -0
- package/AGENTS.md +454 -0
- package/CHANGELOG.md +881 -0
- package/LICENSE +1 -1
- package/NOTICE +63 -0
- package/README.md +113 -39
- package/RULES/01-domains.md +51 -0
- package/RULES/02-agents.md +78 -0
- package/RULES/03-houses.md +61 -0
- package/RULES/04-hoard.md +65 -0
- package/RULES/05-platforms.md +67 -0
- package/RULES/06-append-only.md +58 -0
- package/RULES/07-config.md +45 -0
- package/RULES/08-delivery-gate.md +75 -0
- package/RULES/README.md +20 -0
- package/bin/README.md +107 -0
- package/bin/a2a-mcp.sh +98 -0
- package/bin/a2a-serve.py +103 -0
- package/bin/a2a-serve.sh +8 -0
- package/bin/a2a-talk.sh +50 -0
- package/bin/a2abridge-ensure.sh +108 -0
- package/bin/agent-run.sh +43 -0
- package/bin/agents-config.sh +233 -0
- package/bin/apodex-smoke-test.sh +92 -0
- package/bin/bifrost-bridge.sh +112 -0
- package/bin/bifrost-ingress.sh +77 -0
- package/bin/bootstrap-macos.sh +107 -0
- package/bin/bootstrap-windows.ps1 +112 -0
- package/bin/branch-guard.sh +64 -0
- package/bin/brokk +73 -0
- package/bin/brokk-classify-lib.sh +1770 -0
- package/bin/brokk-lease-lib.sh +222 -0
- package/bin/brokk-lease.sh +193 -0
- package/bin/brokk-lint.sh +65 -0
- package/bin/brokk-send.sh +38 -0
- package/bin/brokk-update.sh +9 -0
- package/bin/brokk-wake-grant.sh +127 -0
- package/bin/brokk-wake-lib.sh +1849 -0
- package/bin/changelog-guard.sh +165 -0
- package/bin/crash-sense.sh +160 -0
- package/bin/desktop-place.sh +224 -0
- package/bin/docs-guard.sh +39 -0
- package/bin/editor-place.sh +207 -0
- package/bin/eindri-acclaim.sh +34 -0
- package/bin/eindri-control.sh +28 -0
- package/bin/eindri-role.sh +83 -0
- package/bin/eindri-seen.sh +41 -0
- package/bin/eindri-send.sh +15 -0
- package/bin/eindri-start.sh +85 -0
- package/bin/eindri-watch.sh +57 -0
- package/bin/einherjar-spawn.sh +576 -0
- package/bin/eir-doctor.sh +112 -0
- package/bin/erindi-brief.sh +271 -0
- package/bin/fleet-apply.sh +68 -0
- package/bin/github-deploy.sh +81 -0
- package/bin/gjallarhorn-expose.sh +102 -0
- package/bin/gjallarhorn-notify.sh +58 -0
- package/bin/gjallarhorn-purge.sh +54 -0
- package/bin/gjallarhorn-tunnel.sh +72 -0
- package/bin/gleipnir-lock-lib.sh +284 -0
- package/bin/groa-update.sh +122 -0
- package/bin/hall-snapshot.sh +92 -0
- package/bin/hamr-harness.sh +246 -0
- package/bin/heimdall-ssh-keys.sh +374 -0
- package/bin/herdr-agents.py +44 -0
- package/bin/herdr-ensure.sh +104 -0
- package/bin/herdr-run.sh +431 -0
- package/bin/hermes-ensure.sh +88 -0
- package/bin/hoard-lib.sh +25 -0
- package/bin/hodd.sh +78 -0
- package/bin/host-sense.sh +199 -0
- package/bin/huginn-research-worker.sh +108 -0
- package/bin/local-model-lock.sh +51 -0
- package/bin/mimir-bridge.py +226 -0
- package/bin/mimir-bridge.sh +87 -0
- package/bin/mimir-ingest.sh +131 -0
- package/bin/mimir.sh +113 -0
- package/bin/mjollnir-webhook.sh +59 -0
- package/bin/mjollnir.sh +85 -0
- package/bin/model-hardware.sh +82 -0
- package/bin/model-resolve.sh +147 -0
- package/bin/models-detect.sh +178 -0
- package/bin/nornir-cron-start.sh +162 -0
- package/bin/nornir-job-daily-briefing.sh +191 -0
- package/bin/nornir-job-git-sync.sh +152 -0
- package/bin/nornir-job-memory-housekeeping.sh +114 -0
- package/bin/nornir-job-observer.sh +166 -0
- package/bin/nornir-job-skillopt-sleep.sh +76 -0
- package/bin/omarchy-hook-install.sh +60 -0
- package/bin/omarchy-install.sh +148 -0
- package/bin/omarchy-plugins.sh +174 -0
- package/bin/omarchy-sense.sh +149 -0
- package/bin/perm-guard.sh +30 -0
- package/bin/pi-agent.sh +68 -0
- package/bin/pi-ensure.sh +77 -0
- package/bin/pi-local.sh +37 -0
- package/bin/pi-seat.sh +63 -0
- package/bin/prereq-ensure.sh +166 -0
- package/bin/private-guard.sh +38 -0
- package/bin/project-git.sh +55 -0
- package/bin/public-guard.sh +70 -0
- package/bin/ratatoskr.sh +49 -0
- package/bin/realm-lib.sh +32 -0
- package/bin/repo-scrub.sh +62 -0
- package/bin/rodd-operational-input.sh +250 -0
- package/bin/runes-append.sh +198 -0
- package/bin/saga-session-start.sh +172 -0
- package/bin/saga-sessionstart-run.sh +79 -0
- package/bin/saga-wake-drain.sh +41 -0
- package/bin/secret-guard.sh +63 -0
- package/bin/sessrumnir-ensure.sh +100 -0
- package/bin/sessrumnir-sync.sh +237 -0
- package/bin/sessrumnir.sh +91 -0
- package/bin/skillopt-setup.sh +76 -0
- package/bin/skuld-branch-outcome.sh +203 -0
- package/bin/skuld-branch-prompt.sh +101 -0
- package/bin/smidja-bootstrap.sh +90 -0
- package/bin/smidja-observe.sh +86 -0
- package/bin/syn-arm-pretool-check.sh +57 -0
- package/bin/syn-asset-pretool-check.sh +76 -0
- package/bin/syn-cd-pretool-check.sh +28 -0
- package/bin/syn-guard-pretool-check.sh +83 -0
- package/bin/syn-turnend-guard.sh +36 -0
- package/bin/syn-watch-arm.sh +99 -0
- package/bin/tailscale-sync.sh +190 -0
- package/bin/telegram-bot.sh +69 -0
- package/bin/toolchain.sh +74 -0
- package/bin/utgard.sh +111 -0
- package/bin/valhalla.sh +115 -0
- package/bin/valknut-load.sh +260 -0
- package/bin/vor-crew-state.sh +124 -0
- package/bin/wedge-notify.sh +47 -0
- package/bin/workspace-provision.sh +80 -0
- package/bin/workspace-rag.sh +150 -0
- package/bin/wyrd-db.sh +47 -0
- package/bin/yggdrasil.sh +152 -0
- package/bin/ymir-edit.sh +145 -0
- package/bin/ymir-install.sh +641 -0
- package/bin/ymir-invite.sh +93 -0
- package/bin/ymir-isolation.sh +88 -0
- package/bin/ymir-migrate.sh +61 -0
- package/bin/ymir-platform.sh +348 -0
- package/bin/ymir-say.sh +97 -0
- package/bin/ymir-setup-auth.sh +108 -0
- package/bin/ymir-validate.sh +173 -0
- package/bin/ymir.js +74 -16
- package/docs/Architecture.md +339 -0
- package/docs/design.md +351 -0
- package/docs/installations/README.md +63 -0
- package/docs/installations/ymir-home.md +93 -0
- package/docs/integration.md +105 -0
- package/docs/lore.md +1056 -0
- package/docs/research/agent-harnesses.md +290 -0
- package/docs/runbooks/README.md +19 -0
- package/docs/runbooks/a2a.md +91 -0
- package/docs/runbooks/agent-permissions.md +99 -0
- package/docs/runbooks/agents.md +57 -0
- package/docs/runbooks/models.md +69 -0
- package/docs/runbooks/realm-onboarding.md +60 -0
- package/docs/runbooks/secrets-and-hoard.md +60 -0
- package/docs/runbooks/updates-and-migrations.md +110 -0
- package/docs/runbooks/worktrees-isolation.md +72 -0
- package/docs/session-start.md +105 -0
- package/docs/skillopt-integration.md +321 -0
- package/docs/sync-system.md +66 -0
- package/docs/workspaces.md +104 -0
- package/docs/ymir-rut.md +260 -0
- package/package.json +44 -14
- package/packaging/build.sh +74 -0
- package/packaging/macos/Ymir Installer.command +43 -0
- package/packaging/windows/ymir-setup.nsi +74 -0
- package/scripts/README.md +22 -0
- package/scripts/electron.sh +210 -0
- package/scripts/start.sh +167 -0
- package/scripts/stop.sh +113 -0
- package/install.sh +0 -35
|
@@ -0,0 +1,909 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Hand already-identified, in-scope backlog items off from the main firstmate
|
|
3
|
+
# backlog to a secondmate's own home backlog. Use this when a secondmate is
|
|
4
|
+
# created (or whenever an existing queued item should become its domain's work)
|
|
5
|
+
# so the secondmate owns its queue from day one instead of the item staying
|
|
6
|
+
# stranded in the main backlog.
|
|
7
|
+
#
|
|
8
|
+
# Scope-matching is firstmate's JUDGMENT: you pass the task-id keys you have
|
|
9
|
+
# already judged in-scope for the secondmate. This script performs only the
|
|
10
|
+
# fleet-level validation that the backlog backend cannot know, then DELEGATES
|
|
11
|
+
# the actual item move to `tasks-axi mv`, the single owner of the backlog
|
|
12
|
+
# format. Delegating the move is the durability end-state: it removes the awk
|
|
13
|
+
# that used to re-implement block extraction and insertion here, so the format
|
|
14
|
+
# has exactly one parser and cannot drift out of sync (the body-orphaning class
|
|
15
|
+
# of bug fixed in PR #401 was exactly that drift).
|
|
16
|
+
#
|
|
17
|
+
# What this script still owns (never delegated):
|
|
18
|
+
# - resolving the secondmate home from data/secondmates.md;
|
|
19
|
+
# - proving the destination is a genuine seeded secondmate home
|
|
20
|
+
# (.fm-secondmate-home marker, AGENTS.md + bin/), never a project clone, the
|
|
21
|
+
# active home, or the firstmate repo;
|
|
22
|
+
# - moving only `## Queued` items, refusing `## In flight` and historical
|
|
23
|
+
# `## Done` records, which must stay with their home for pruning or
|
|
24
|
+
# archiving;
|
|
25
|
+
# - the multi-key classification and idempotent per-key reporting: a key
|
|
26
|
+
# already present in the secondmate backlog is reported and skipped, and if
|
|
27
|
+
# any key matches neither backlog nothing is moved;
|
|
28
|
+
# - warning, after a successful move, when a moved key still owes a public
|
|
29
|
+
# relay reply bound to main/<key>, or when this home has an open public loop
|
|
30
|
+
# with nothing owed, because routing work out does not close that loop. The
|
|
31
|
+
# move is not blocked: rebinding or rechain is a relay-side decision the
|
|
32
|
+
# caller makes.
|
|
33
|
+
#
|
|
34
|
+
# What `tasks-axi mv <id>... --to <dest>` owns: moving each full item BLOCK
|
|
35
|
+
# byte-exact (header, body lines, blank separators, and indented pseudo-headings
|
|
36
|
+
# such as ` ## Intent`), preserving destination section placement, and moving a
|
|
37
|
+
# whole connected set (a blocker and its dependents) atomically with blocked-by
|
|
38
|
+
# links preserved. It refuses a move that would strand a dependency across the
|
|
39
|
+
# two files; that error is surfaced verbatim and nothing is moved.
|
|
40
|
+
#
|
|
41
|
+
# Item bodies must use at least two leading spaces. The helper refuses a selected
|
|
42
|
+
# item with a single-space or tab-indented continuation rather than risk leaving
|
|
43
|
+
# it orphaned, because tasks-axi treats only two-or-more-space lines as body.
|
|
44
|
+
# The move needs compatible `tasks-axi` on PATH, including atomic multi-ID `mv`
|
|
45
|
+
# support. Bootstrap requires a compatible build fleet-wide, so this works
|
|
46
|
+
# everywhere; the `config/backlog-backend=manual` knob only governs firstmate's
|
|
47
|
+
# own hand-editing of its own backlog, not this validated helper. Idempotent:
|
|
48
|
+
# re-running converges. Atomic: on any move failure nothing moves.
|
|
49
|
+
# See AGENTS.md project management and task lifecycle.
|
|
50
|
+
# Remote routes use an outbox handoff: one atomic local tasks-axi mv removes the
|
|
51
|
+
# selected set from the dispatchable backlog into data/handoff/<id>.outbox.md,
|
|
52
|
+
# then an idempotent confined transfer and fm-backlog-receive.sh deliver it.
|
|
53
|
+
# A present outbox remains the remote retry trigger until backlog receipt and
|
|
54
|
+
# receiver wake are both confirmed; a companion pending-reply correlation makes
|
|
55
|
+
# crash recovery reconcile an attempted or confirmed wake instead of blindly
|
|
56
|
+
# resending it. A prepared local wake is bound to the exact sorted
|
|
57
|
+
# requested-key batch; an unrelated handoff to that mate refuses until the
|
|
58
|
+
# original batch is retried, so it cannot discard wake intent for work that
|
|
59
|
+
# already moved. No two-phase journal exists.
|
|
60
|
+
# Every newly durable backlog delivery also sends one marked wake to the
|
|
61
|
+
# receiving endpoint. A missing endpoint or a live endpoint that rejects the
|
|
62
|
+
# wake makes the handoff fail with the delivered backlog intact.
|
|
63
|
+
# Usage: fm-backlog-handoff.sh <secondmate-id> <item-key>...
|
|
64
|
+
# fm-backlog-handoff.sh --resume-pending
|
|
65
|
+
set -eu
|
|
66
|
+
|
|
67
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
68
|
+
FM_ROOT="${FM_ROOT_OVERRIDE:-$(cd "$SCRIPT_DIR/.." && pwd)}"
|
|
69
|
+
FM_HOME="${FM_HOME:-${FM_ROOT_OVERRIDE:-$FM_ROOT}}"
|
|
70
|
+
DATA="${FM_DATA_OVERRIDE:-$FM_HOME/data}"
|
|
71
|
+
STATE="${FM_STATE_OVERRIDE:-$FM_HOME/state}"
|
|
72
|
+
REG="$DATA/secondmates.md"
|
|
73
|
+
MAIN_BACKLOG="$DATA/backlog.md"
|
|
74
|
+
# shellcheck source=bin/fm-tasks-axi-lib.sh disable=SC1091
|
|
75
|
+
. "$SCRIPT_DIR/fm-tasks-axi-lib.sh"
|
|
76
|
+
# shellcheck source=bin/fm-secondmate-registry-lib.sh
|
|
77
|
+
. "$SCRIPT_DIR/fm-secondmate-registry-lib.sh"
|
|
78
|
+
# shellcheck source=bin/fm-wake-lib.sh
|
|
79
|
+
. "$SCRIPT_DIR/fm-wake-lib.sh"
|
|
80
|
+
# shellcheck source=bin/fm-public-followup-lib.sh
|
|
81
|
+
. "$SCRIPT_DIR/fm-public-followup-lib.sh"
|
|
82
|
+
# shellcheck source=bin/fm-pending-reply-lib.sh
|
|
83
|
+
. "$SCRIPT_DIR/fm-pending-reply-lib.sh"
|
|
84
|
+
|
|
85
|
+
RECEIVER_WAKE_MESSAGE='New routed work is in your backlog. Run bin/fm-session-start.sh now, then act on the routed task.'
|
|
86
|
+
|
|
87
|
+
ACTIVE_HANDOFF_LOCK=
|
|
88
|
+
ACTIVE_REGISTRY_LOCK=
|
|
89
|
+
release_remote_locks() {
|
|
90
|
+
if [ -n "$ACTIVE_HANDOFF_LOCK" ]; then
|
|
91
|
+
fm_lock_release "$ACTIVE_HANDOFF_LOCK"
|
|
92
|
+
ACTIVE_HANDOFF_LOCK=
|
|
93
|
+
fi
|
|
94
|
+
if [ -n "$ACTIVE_REGISTRY_LOCK" ]; then
|
|
95
|
+
fm_lock_release "$ACTIVE_REGISTRY_LOCK"
|
|
96
|
+
ACTIVE_REGISTRY_LOCK=
|
|
97
|
+
fi
|
|
98
|
+
}
|
|
99
|
+
trap release_remote_locks EXIT
|
|
100
|
+
trap 'exit 1' HUP INT TERM
|
|
101
|
+
|
|
102
|
+
sha256_file() {
|
|
103
|
+
if command -v shasum >/dev/null 2>&1; then shasum -a 256 "$1" | awk '{print $1}'; else sha256sum "$1" | awk '{print $1}'; fi
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
RESUME_PENDING=0
|
|
107
|
+
if [ "${1:-}" = --resume-pending ]; then
|
|
108
|
+
[ "$#" -eq 1 ] || { echo "usage: fm-backlog-handoff.sh --resume-pending" >&2; exit 1; }
|
|
109
|
+
RESUME_PENDING=1
|
|
110
|
+
ID=
|
|
111
|
+
shift
|
|
112
|
+
else
|
|
113
|
+
[ "$#" -ge 2 ] || { echo "usage: fm-backlog-handoff.sh <secondmate-id> <item-key>..." >&2; exit 1; }
|
|
114
|
+
ID=$1
|
|
115
|
+
case "$ID" in ''|*[!A-Za-z0-9._-]*) echo "error: unsafe secondmate id: $ID" >&2; exit 1 ;; esac
|
|
116
|
+
shift
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
secondmate_home() {
|
|
120
|
+
local id=$1 home
|
|
121
|
+
[ -f "$REG" ] || { echo "error: no secondmate registry at $REG" >&2; return 1; }
|
|
122
|
+
home=$(secondmate_registry_field "$REG" "$id" home || true)
|
|
123
|
+
[ -n "$home" ] || { echo "error: secondmate $id has no home in $REG" >&2; return 1; }
|
|
124
|
+
printf '%s\n' "$home"
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
path_is_ancestor_of() {
|
|
128
|
+
local ancestor=$1 path=$2
|
|
129
|
+
[ -n "$ancestor" ] || return 1
|
|
130
|
+
[ -n "$path" ] || return 1
|
|
131
|
+
[ "$ancestor" != "$path" ] || return 1
|
|
132
|
+
case "$path" in
|
|
133
|
+
"$ancestor"/*) return 0 ;;
|
|
134
|
+
esac
|
|
135
|
+
return 1
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
resolved_existing_dir() {
|
|
139
|
+
local path=$1
|
|
140
|
+
[ -d "$path" ] || { echo "error: firstmate home does not exist or is not a directory: $path" >&2; return 1; }
|
|
141
|
+
cd "$path" && pwd -P
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
validate_operational_dirs() {
|
|
145
|
+
local abs_home=$1 abs_active_home=$2 abs_root=$3 name dir abs_dir
|
|
146
|
+
for name in data state config projects; do
|
|
147
|
+
dir="$abs_home/$name"
|
|
148
|
+
if [ -L "$dir" ] && [ ! -e "$dir" ]; then
|
|
149
|
+
echo "error: secondmate $name directory must resolve inside the secondmate home: $dir" >&2
|
|
150
|
+
return 1
|
|
151
|
+
fi
|
|
152
|
+
if [ -d "$dir" ]; then
|
|
153
|
+
abs_dir=$(cd "$dir" && pwd -P)
|
|
154
|
+
elif [ -e "$dir" ]; then
|
|
155
|
+
echo "error: secondmate $name path is not a directory: $dir" >&2
|
|
156
|
+
return 1
|
|
157
|
+
else
|
|
158
|
+
abs_dir="$abs_home/$name"
|
|
159
|
+
fi
|
|
160
|
+
if ! path_is_ancestor_of "$abs_home" "$abs_dir"; then
|
|
161
|
+
echo "error: secondmate $name directory must resolve inside the secondmate home: $dir" >&2
|
|
162
|
+
return 1
|
|
163
|
+
fi
|
|
164
|
+
if [ "$abs_dir" = "$abs_active_home" ] || path_is_ancestor_of "$abs_active_home" "$abs_dir"; then
|
|
165
|
+
echo "error: secondmate $name directory cannot be inside the active firstmate home: $dir" >&2
|
|
166
|
+
return 1
|
|
167
|
+
fi
|
|
168
|
+
if [ "$abs_dir" = "$abs_root" ] || path_is_ancestor_of "$abs_root" "$abs_dir"; then
|
|
169
|
+
echo "error: secondmate $name directory cannot be inside the firstmate repo: $dir" >&2
|
|
170
|
+
return 1
|
|
171
|
+
fi
|
|
172
|
+
done
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
validate_secondmate_home() {
|
|
176
|
+
local id=$1 home=$2 abs_home abs_active_home abs_root marker_id
|
|
177
|
+
abs_home=$(resolved_existing_dir "$home") || return 1
|
|
178
|
+
abs_active_home=$(resolved_existing_dir "$FM_HOME")
|
|
179
|
+
abs_root=$(resolved_existing_dir "$FM_ROOT")
|
|
180
|
+
if [ "$abs_home" = "/" ]; then
|
|
181
|
+
echo "error: secondmate home cannot be the filesystem root: $home" >&2
|
|
182
|
+
return 1
|
|
183
|
+
fi
|
|
184
|
+
if [ "$abs_home" = "$abs_active_home" ]; then
|
|
185
|
+
echo "error: secondmate home cannot be the active firstmate home: $home" >&2
|
|
186
|
+
return 1
|
|
187
|
+
fi
|
|
188
|
+
if [ "$abs_home" = "$abs_root" ]; then
|
|
189
|
+
echo "error: secondmate home cannot be the firstmate repo: $home" >&2
|
|
190
|
+
return 1
|
|
191
|
+
fi
|
|
192
|
+
if path_is_ancestor_of "$abs_active_home" "$abs_home"; then
|
|
193
|
+
echo "error: secondmate home cannot be inside the active firstmate home: $home" >&2
|
|
194
|
+
return 1
|
|
195
|
+
fi
|
|
196
|
+
if path_is_ancestor_of "$abs_root" "$abs_home"; then
|
|
197
|
+
echo "error: secondmate home cannot be inside the firstmate repo: $home" >&2
|
|
198
|
+
return 1
|
|
199
|
+
fi
|
|
200
|
+
if path_is_ancestor_of "$abs_home" "$abs_active_home"; then
|
|
201
|
+
echo "error: secondmate home cannot be an ancestor of the active firstmate home: $home" >&2
|
|
202
|
+
return 1
|
|
203
|
+
fi
|
|
204
|
+
if path_is_ancestor_of "$abs_home" "$abs_root"; then
|
|
205
|
+
echo "error: secondmate home cannot be an ancestor of the firstmate repo: $home" >&2
|
|
206
|
+
return 1
|
|
207
|
+
fi
|
|
208
|
+
validate_operational_dirs "$abs_home" "$abs_active_home" "$abs_root" || return 1
|
|
209
|
+
if [ ! -f "$abs_home/.fm-secondmate-home" ]; then
|
|
210
|
+
echo "error: firstmate home $home is not a seeded secondmate home" >&2
|
|
211
|
+
return 1
|
|
212
|
+
fi
|
|
213
|
+
marker_id=$(cat "$abs_home/.fm-secondmate-home" 2>/dev/null || true)
|
|
214
|
+
if [ "$marker_id" != "$id" ]; then
|
|
215
|
+
echo "error: firstmate home $home is marked for secondmate ${marker_id:-unknown}, expected $id" >&2
|
|
216
|
+
return 1
|
|
217
|
+
fi
|
|
218
|
+
if [ ! -f "$abs_home/AGENTS.md" ]; then
|
|
219
|
+
echo "error: $home is not a firstmate home (missing AGENTS.md)" >&2
|
|
220
|
+
return 1
|
|
221
|
+
fi
|
|
222
|
+
if [ ! -d "$abs_home/bin" ]; then
|
|
223
|
+
echo "error: $home is not a firstmate home (missing bin/)" >&2
|
|
224
|
+
return 1
|
|
225
|
+
fi
|
|
226
|
+
printf '%s\n' "$abs_home"
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
validate_backlog_file() {
|
|
230
|
+
local label=$1 path=$2
|
|
231
|
+
if [ -L "$path" ]; then
|
|
232
|
+
echo "error: $label must not be a symlink: $path" >&2
|
|
233
|
+
return 1
|
|
234
|
+
fi
|
|
235
|
+
if [ -e "$path" ] && [ ! -f "$path" ]; then
|
|
236
|
+
echo "error: $label is not a regular file: $path" >&2
|
|
237
|
+
return 1
|
|
238
|
+
fi
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
# Classify a single key by the section it lives under (## In flight /
|
|
242
|
+
# ## Queued / ## Done), or return non-zero if no `- [ ] <key>` / `- [x] <key>`
|
|
243
|
+
# header exists in the file. This reads only section headings and item header
|
|
244
|
+
# lines - never item bodies - so it drives the fleet-level classification (in-
|
|
245
|
+
# flight refusal, already-present idempotency, missing-key abort) without
|
|
246
|
+
# re-implementing the block/body move semantics that tasks-axi mv owns.
|
|
247
|
+
backlog_key_section() {
|
|
248
|
+
local file=$1 key=$2
|
|
249
|
+
[ -f "$file" ] || return 1
|
|
250
|
+
awk -v key="$key" '
|
|
251
|
+
BEGIN { section = "## Queued" }
|
|
252
|
+
/^##[[:space:]]+/ {
|
|
253
|
+
section = $0
|
|
254
|
+
sub(/^##[[:space:]]+/, "## ", section)
|
|
255
|
+
sub(/[[:space:]]+$/, "", section)
|
|
256
|
+
next
|
|
257
|
+
}
|
|
258
|
+
/^- \[[ x]\] / {
|
|
259
|
+
rest = $0
|
|
260
|
+
sub(/^- \[[ x]\] +/, "", rest)
|
|
261
|
+
id = rest
|
|
262
|
+
sub(/[ \t].*/, "", id)
|
|
263
|
+
if (id == key) { print section; found = 1; exit }
|
|
264
|
+
}
|
|
265
|
+
END { exit found ? 0 : 1 }
|
|
266
|
+
' "$file"
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
backlog_key_noncanonical_body_lines() {
|
|
270
|
+
local file=$1 key=$2
|
|
271
|
+
awk -v key="$key" '
|
|
272
|
+
/^- \[[ x]\] / {
|
|
273
|
+
rest = $0
|
|
274
|
+
sub(/^- \[[ x]\] +/, "", rest)
|
|
275
|
+
id = rest
|
|
276
|
+
sub(/[ \t].*/, "", id)
|
|
277
|
+
if (capturing) exit
|
|
278
|
+
if (id == key) { capturing = 1 }
|
|
279
|
+
next
|
|
280
|
+
}
|
|
281
|
+
capturing && /^##[[:space:]]+/ { exit }
|
|
282
|
+
capturing && /^[[:space:]]/ && !/^ / && /[^[:space:]]/ { print }
|
|
283
|
+
' "$file"
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
seed_backlog_scaffold() { # <path>
|
|
287
|
+
mkdir -p "$(dirname "$1")"
|
|
288
|
+
[ -f "$1" ] || printf '## In flight\n\n## Queued\n\n## Done\n' > "$1"
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
# A public commitment made through the relay binds its work by home AND id, so an
|
|
292
|
+
# item that leaves this home takes that binding out of sync: reconciliation would
|
|
293
|
+
# still look for main/<key> while the work now lives in the secondmate's home.
|
|
294
|
+
# The move itself stays safe and is never blocked - rebinding is a relay-side
|
|
295
|
+
# decision the caller owns - but this is the one moment the staleness is
|
|
296
|
+
# detectable, so report it loudly instead of letting the promise go quiet.
|
|
297
|
+
# A home that never opted into the relay pays one presence check per key here.
|
|
298
|
+
warn_stale_public_commitments() { # <secondmate-id> <moved-key>...
|
|
299
|
+
local id=$1 key out rc
|
|
300
|
+
shift
|
|
301
|
+
for key in "$@"; do
|
|
302
|
+
rc=0
|
|
303
|
+
out=$("$SCRIPT_DIR/fm-public-followup.sh" guard-work main "$key" 2>/dev/null) || rc=$?
|
|
304
|
+
[ "$rc" -ne 0 ] || continue
|
|
305
|
+
[ -z "$out" ] || printf '%s\n' "$out" >&2
|
|
306
|
+
printf 'warning: %s still owes a public reply bound to main/%s; rebind it to secondmate:%s (tasks-axi public-followup bind-work, then bin/fm-public-followup.sh register <obligation-id> --relation <relation-id> --work-home secondmate:%s --work-id %s --generation <n>) or the promised reply will be reconciled against work this home no longer owns.\n' \
|
|
307
|
+
"$key" "$key" "$id" "$id" "$key" >&2
|
|
308
|
+
done
|
|
309
|
+
if fm_pf_relay_active "$FM_HOME" && fm_pf_has_delivered_open_loops "$STATE"; then
|
|
310
|
+
printf 'warning: this home has an open public loop with nothing owed; routing work to secondmate:%s does not close it. Hand it on with bin/fm-public-followup.sh rechain or close it with retire --reason.\n' \
|
|
311
|
+
"$id" >&2
|
|
312
|
+
fi
|
|
313
|
+
# Reporting never changes the handoff's own success: the move already landed.
|
|
314
|
+
return 0
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
# Wake a live receiver after its backlog has become durable. The marked message
|
|
318
|
+
# uses the normal endpoint route, so local and remote secondmates share the same
|
|
319
|
+
# verified submit and failure semantics. A seeded but not-yet-spawned home is a
|
|
320
|
+
# valid handoff destination, but its missing endpoint is reported rather than
|
|
321
|
+
# pretending the task was started.
|
|
322
|
+
receiver_wake_batch_id() { # <item-key>...
|
|
323
|
+
local digest
|
|
324
|
+
if command -v shasum >/dev/null 2>&1; then
|
|
325
|
+
digest=$(printf '%s\n' "$@" | LC_ALL=C sort | shasum -a 256 2>/dev/null | awk '{print $1}')
|
|
326
|
+
else
|
|
327
|
+
digest=$(printf '%s\n' "$@" | LC_ALL=C sort | sha256sum 2>/dev/null | awk '{print $1}')
|
|
328
|
+
fi
|
|
329
|
+
printf '%s' "$digest" | grep -Eq '^[a-f0-9]{64}$' || return 1
|
|
330
|
+
printf '%s' "${digest:0:16}"
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
receiver_wake_state_write() { # <secondmate-id> <state>
|
|
334
|
+
local id=$1 value=$2 marker="$STATE/.backlog-handoff-$1.wake-pending" tmp
|
|
335
|
+
case "$id" in ''|*[!A-Za-z0-9._-]*) return 1 ;; esac
|
|
336
|
+
case "$value" in
|
|
337
|
+
pending|confirmed) ;;
|
|
338
|
+
prepared:*) printf '%s' "$value" | grep -Eq '^prepared:[a-f0-9]{16}:[a-f0-9]{16}$' || return 1 ;;
|
|
339
|
+
pending:*) printf '%s' "$value" | grep -Eq '^pending:[a-f0-9]{16}$' || return 1 ;;
|
|
340
|
+
confirmed:*) printf '%s' "$value" | grep -Eq '^confirmed:[a-f0-9]{16}$' || return 1 ;;
|
|
341
|
+
*) return 1 ;;
|
|
342
|
+
esac
|
|
343
|
+
tmp=$(umask 077; mktemp "$STATE/.backlog-handoff-wake.XXXXXX") || return 1
|
|
344
|
+
if ! printf '%s\n' "$value" > "$tmp" || ! chmod 600 "$tmp" || ! mv -f -- "$tmp" "$marker"; then
|
|
345
|
+
rm -f -- "$tmp"
|
|
346
|
+
return 1
|
|
347
|
+
fi
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
receiver_wake_mark() { # <secondmate-id> <prepared|pending> [batch-id]
|
|
351
|
+
local id=$1 wake_phase=$2 batch=${3:-} marker="$STATE/.backlog-handoff-$1.wake-pending" value corr rec
|
|
352
|
+
local wake_state
|
|
353
|
+
case "$wake_phase" in prepared|pending) ;; *) return 1 ;; esac
|
|
354
|
+
if [ -e "$marker" ] || [ -L "$marker" ]; then
|
|
355
|
+
[ -f "$marker" ] && [ ! -L "$marker" ] || return 1
|
|
356
|
+
value=$(cat "$marker" 2>/dev/null || true)
|
|
357
|
+
case "$value" in
|
|
358
|
+
prepared:*|pending:*)
|
|
359
|
+
corr=${value#*:}
|
|
360
|
+
corr=${corr%%:*}
|
|
361
|
+
rec=$(fm_pending_reply_path "$STATE" "$corr")
|
|
362
|
+
[ -f "$rec" ] && [ ! -L "$rec" ] \
|
|
363
|
+
&& [ "$(fm_pending_reply_get "$rec" task_id)" = "$id" ]
|
|
364
|
+
return $?
|
|
365
|
+
;;
|
|
366
|
+
pending) ;;
|
|
367
|
+
*) return 1 ;;
|
|
368
|
+
esac
|
|
369
|
+
fi
|
|
370
|
+
corr=$(fm_pending_reply_create "$FM_HOME" "$STATE" "$id" "$RECEIVER_WAKE_MESSAGE") || return 1
|
|
371
|
+
wake_state="$wake_phase:$corr"
|
|
372
|
+
if [ "$wake_phase" = prepared ]; then
|
|
373
|
+
printf '%s' "$batch" | grep -Eq '^[a-f0-9]{16}$' || return 1
|
|
374
|
+
wake_state="$wake_state:$batch"
|
|
375
|
+
fi
|
|
376
|
+
if ! receiver_wake_state_write "$id" "$wake_state"; then
|
|
377
|
+
fm_pending_reply_discard_undelivered "$STATE" "$corr" || true
|
|
378
|
+
return 1
|
|
379
|
+
fi
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
receiver_wake_mark_pending() { # <secondmate-id>
|
|
383
|
+
receiver_wake_mark "$1" pending
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
receiver_wake_mark_prepared() { # <secondmate-id> <batch-id>
|
|
387
|
+
receiver_wake_mark "$1" prepared "$2"
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
receiver_wake_discard_prepared() { # <secondmate-id>
|
|
391
|
+
local id=$1 marker="$STATE/.backlog-handoff-$1.wake-pending" value corr
|
|
392
|
+
[ -f "$marker" ] && [ ! -L "$marker" ] || return 1
|
|
393
|
+
value=$(cat "$marker" 2>/dev/null || true)
|
|
394
|
+
case "$value" in
|
|
395
|
+
prepared:*)
|
|
396
|
+
corr=${value#prepared:}
|
|
397
|
+
corr=${corr%%:*}
|
|
398
|
+
;;
|
|
399
|
+
*) return 1 ;;
|
|
400
|
+
esac
|
|
401
|
+
fm_pending_reply_discard_undelivered "$STATE" "$corr" || return 1
|
|
402
|
+
rm -f -- "$marker"
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
receiver_wake_promote_prepared() { # <secondmate-id> <batch-id>
|
|
406
|
+
local id=$1 batch=$2 marker="$STATE/.backlog-handoff-$1.wake-pending" value corr
|
|
407
|
+
[ -f "$marker" ] && [ ! -L "$marker" ] || return 1
|
|
408
|
+
value=$(cat "$marker" 2>/dev/null || true)
|
|
409
|
+
case "$value" in
|
|
410
|
+
prepared:*:"$batch")
|
|
411
|
+
corr=${value#prepared:}
|
|
412
|
+
corr=${corr%%:*}
|
|
413
|
+
;;
|
|
414
|
+
pending:*) return 0 ;;
|
|
415
|
+
*) return 1 ;;
|
|
416
|
+
esac
|
|
417
|
+
receiver_wake_state_write "$id" "pending:$corr"
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
receiver_wake_discard_pending() { # <secondmate-id>
|
|
421
|
+
local id=$1 marker="$STATE/.backlog-handoff-$1.wake-pending" value corr
|
|
422
|
+
[ -f "$marker" ] && [ ! -L "$marker" ] || return 1
|
|
423
|
+
value=$(cat "$marker" 2>/dev/null || true)
|
|
424
|
+
case "$value" in
|
|
425
|
+
pending:*)
|
|
426
|
+
corr=${value#pending:}
|
|
427
|
+
fm_pending_reply_discard_undelivered "$STATE" "$corr" || return 1
|
|
428
|
+
;;
|
|
429
|
+
pending) ;;
|
|
430
|
+
*) return 1 ;;
|
|
431
|
+
esac
|
|
432
|
+
rm -f -- "$marker"
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
receiver_wake_clear_confirmed() { # <secondmate-id>
|
|
436
|
+
local id=$1 marker="$STATE/.backlog-handoff-$1.wake-pending" value
|
|
437
|
+
[ -e "$marker" ] || [ -L "$marker" ] || return 0
|
|
438
|
+
[ -f "$marker" ] && [ ! -L "$marker" ] || return 1
|
|
439
|
+
value=$(cat "$marker" 2>/dev/null || true)
|
|
440
|
+
case "$value" in
|
|
441
|
+
pending|pending:*) return 0 ;;
|
|
442
|
+
confirmed|confirmed:*) rm -f -- "$marker" ;;
|
|
443
|
+
*) return 1 ;;
|
|
444
|
+
esac
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
wake_secondmate_receiver() { # <secondmate-id> <correlation-id>
|
|
448
|
+
local id=$1 corr=$2 meta="$STATE/$1.meta" out rc=0
|
|
449
|
+
if [ ! -f "$meta" ] || [ -L "$meta" ]; then
|
|
450
|
+
printf 'error: handed off work to secondmate %s, but no live receiver endpoint is recorded; the destination backlog is durable and the receiver was not woken\n' "$id" >&2
|
|
451
|
+
return 1
|
|
452
|
+
fi
|
|
453
|
+
[ "$(grep '^kind=' "$meta" | cut -d= -f2-)" = secondmate ] || {
|
|
454
|
+
printf 'error: secondmate %s has non-secondmate endpoint metadata; backlog is durable but the receiver was not woken\n' "$id" >&2
|
|
455
|
+
return 1
|
|
456
|
+
}
|
|
457
|
+
out=$(FM_HOME="$FM_HOME" FM_STATE_OVERRIDE="$STATE" FM_ROOT_OVERRIDE="$FM_ROOT" \
|
|
458
|
+
FM_PENDING_REPLY_EXISTING_CORR="$corr" \
|
|
459
|
+
"$SCRIPT_DIR/fm-send.sh" "$id" "$RECEIVER_WAKE_MESSAGE" 2>&1) || rc=$?
|
|
460
|
+
if [ "$rc" -ne 0 ]; then
|
|
461
|
+
[ -z "$out" ] || printf '%s\n' "$out" >&2
|
|
462
|
+
printf 'error: backlog delivery to secondmate %s succeeded, but its receiver wake failed; rerun this handoff to retry the wake\n' "$id" >&2
|
|
463
|
+
return 1
|
|
464
|
+
fi
|
|
465
|
+
[ -z "$out" ] || printf '%s\n' "$out"
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
wake_pending_secondmate_receiver() { # <secondmate-id> [retain-confirmed]
|
|
469
|
+
local id=$1 retain=${2:-0} marker="$STATE/.backlog-handoff-$1.wake-pending" value corr rec delivered
|
|
470
|
+
[ -e "$marker" ] || [ -L "$marker" ] || return 0
|
|
471
|
+
if [ ! -f "$marker" ] || [ -L "$marker" ]; then
|
|
472
|
+
printf 'error: receiver wake state for secondmate %s is unsafe or invalid\n' "$id" >&2
|
|
473
|
+
return 1
|
|
474
|
+
fi
|
|
475
|
+
value=$(cat "$marker" 2>/dev/null || true)
|
|
476
|
+
case "$value" in
|
|
477
|
+
confirmed|confirmed:*) return 0 ;;
|
|
478
|
+
prepared|prepared:*)
|
|
479
|
+
printf 'error: receiver wake for secondmate %s was prepared before its backlog became durable\n' "$id" >&2
|
|
480
|
+
return 1
|
|
481
|
+
;;
|
|
482
|
+
pending)
|
|
483
|
+
receiver_wake_mark_pending "$id" || return 1
|
|
484
|
+
value=$(cat "$marker" 2>/dev/null || true)
|
|
485
|
+
;;
|
|
486
|
+
esac
|
|
487
|
+
case "$value" in pending:*) corr=${value#pending:} ;; *)
|
|
488
|
+
printf 'error: receiver wake state for secondmate %s is unsafe or invalid\n' "$id" >&2
|
|
489
|
+
return 1
|
|
490
|
+
;;
|
|
491
|
+
esac
|
|
492
|
+
rec=$(fm_pending_reply_path "$STATE" "$corr")
|
|
493
|
+
[ -f "$rec" ] && [ ! -L "$rec" ] \
|
|
494
|
+
&& [ "$(fm_pending_reply_get "$rec" task_id)" = "$id" ] || return 1
|
|
495
|
+
fm_pending_reply_reconcile_delivery "$STATE" "$corr" >/dev/null 2>&1 || true
|
|
496
|
+
delivered=$(fm_pending_reply_get "$rec" delivered_epoch)
|
|
497
|
+
if [ -z "$delivered" ]; then
|
|
498
|
+
fm_pending_reply_corr_reusable "$STATE" "$corr" "$id" || {
|
|
499
|
+
printf 'error: receiver wake delivery for secondmate %s is unresolved; refusing to resend correlation %s\n' "$id" "$corr" >&2
|
|
500
|
+
return 1
|
|
501
|
+
}
|
|
502
|
+
wake_secondmate_receiver "$id" "$corr" || return 1
|
|
503
|
+
fi
|
|
504
|
+
if [ "$retain" = 1 ]; then
|
|
505
|
+
receiver_wake_state_write "$id" "confirmed:$corr" || {
|
|
506
|
+
printf 'error: receiver wake for secondmate %s was confirmed, but confirmed state could not be recorded\n' "$id" >&2
|
|
507
|
+
return 1
|
|
508
|
+
}
|
|
509
|
+
else
|
|
510
|
+
rm -f -- "$marker" || {
|
|
511
|
+
printf 'error: receiver wake for secondmate %s was confirmed, but pending state could not be cleared\n' "$id" >&2
|
|
512
|
+
return 1
|
|
513
|
+
}
|
|
514
|
+
fi
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
outbox_item_count() { # <path>
|
|
518
|
+
awk '/^- \[[ x]\] / { count++ } END { print count + 0 }' "$1"
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
remote_deliver_outbox() { # <secondmate-id> <outbox-path>
|
|
522
|
+
local id=$1 outbox=$2 remote_rel receive_out snapshot bytes hash generation counter counter_tmp current marker
|
|
523
|
+
[ -f "$outbox" ] && [ ! -L "$outbox" ] || {
|
|
524
|
+
echo "error: pending outbox is unavailable or unsafe: $outbox" >&2
|
|
525
|
+
return 1
|
|
526
|
+
}
|
|
527
|
+
snapshot=$(umask 077; mktemp "${TMPDIR:-/tmp}/fm-handoff-payload.XXXXXX") || return 1
|
|
528
|
+
if ! cp -p -- "$outbox" "$snapshot"; then
|
|
529
|
+
rm -f -- "$snapshot"
|
|
530
|
+
return 1
|
|
531
|
+
fi
|
|
532
|
+
bytes=$(LC_ALL=C wc -c < "$snapshot" | tr -d ' ')
|
|
533
|
+
hash=$(sha256_file "$snapshot") || { rm -f -- "$snapshot"; return 1; }
|
|
534
|
+
counter="$STATE/.remote-handoff-$id.generation"
|
|
535
|
+
current=0
|
|
536
|
+
if [ -e "$counter" ] || [ -L "$counter" ]; then
|
|
537
|
+
[ -f "$counter" ] && [ ! -L "$counter" ] || { rm -f -- "$snapshot"; return 1; }
|
|
538
|
+
IFS= read -r current < "$counter" || { rm -f -- "$snapshot"; return 1; }
|
|
539
|
+
case "$current" in ''|*[!0-9]*) rm -f -- "$snapshot"; return 1 ;; esac
|
|
540
|
+
[ "${#current}" -le 17 ] || { rm -f -- "$snapshot"; return 1; }
|
|
541
|
+
fi
|
|
542
|
+
generation=$((current + 1))
|
|
543
|
+
counter_tmp=$(umask 077; mktemp "$STATE/.remote-handoff-generation.XXXXXX") \
|
|
544
|
+
|| { rm -f -- "$snapshot"; return 1; }
|
|
545
|
+
printf '%s\n' "$generation" > "$counter_tmp" \
|
|
546
|
+
|| { rm -f -- "$snapshot" "$counter_tmp"; return 1; }
|
|
547
|
+
chmod 600 "$counter_tmp" \
|
|
548
|
+
|| { rm -f -- "$snapshot" "$counter_tmp"; return 1; }
|
|
549
|
+
mv -f -- "$counter_tmp" "$counter" \
|
|
550
|
+
|| { rm -f -- "$snapshot" "$counter_tmp"; return 1; }
|
|
551
|
+
remote_rel="state/handoff/$id.outbox.md"
|
|
552
|
+
if ! "$SCRIPT_DIR/fm-on.sh" --stdin "$id" fm-remote-file.sh put "$remote_rel" 1048576 \
|
|
553
|
+
"$bytes" "$hash" "$generation" < "$snapshot"; then
|
|
554
|
+
rm -f -- "$snapshot"
|
|
555
|
+
echo "error: handoff transfer to $id was unavailable or completion is unknown; outbox preserved at $outbox" >&2
|
|
556
|
+
return 1
|
|
557
|
+
fi
|
|
558
|
+
rm -f -- "$snapshot"
|
|
559
|
+
if ! receive_out=$("$SCRIPT_DIR/fm-on.sh" "$id" fm-backlog-receive.sh \
|
|
560
|
+
"$remote_rel" "$bytes" "$hash" "$generation" < /dev/null 2>&1); then
|
|
561
|
+
[ -z "$receive_out" ] || printf '%s\n' "$receive_out" >&2
|
|
562
|
+
echo "error: handoff receipt by $id was unavailable or completion is unknown; outbox preserved at $outbox" >&2
|
|
563
|
+
return 1
|
|
564
|
+
fi
|
|
565
|
+
marker="$STATE/.backlog-handoff-$id.wake-pending"
|
|
566
|
+
case "$(cat "$marker" 2>/dev/null || true)" in
|
|
567
|
+
pending:*|confirmed|confirmed:*) ;;
|
|
568
|
+
*) receiver_wake_mark_pending "$id" || {
|
|
569
|
+
echo "error: remote backlog is durable at $id, but receiver wake state could not be recorded; outbox preserved at $outbox" >&2
|
|
570
|
+
return 1
|
|
571
|
+
} ;;
|
|
572
|
+
esac
|
|
573
|
+
if ! wake_pending_secondmate_receiver "$id" 1; then
|
|
574
|
+
echo "error: remote backlog is durable at $id; outbox preserved at $outbox for wake retry" >&2
|
|
575
|
+
return 1
|
|
576
|
+
fi
|
|
577
|
+
rm -f -- "$outbox" || {
|
|
578
|
+
echo "error: receiver wake was confirmed but local outbox cleanup failed: $outbox" >&2
|
|
579
|
+
return 1
|
|
580
|
+
}
|
|
581
|
+
rm -f -- "$marker" || {
|
|
582
|
+
echo "error: remote outbox cleanup succeeded but confirmed receiver wake state could not be cleared: $marker" >&2
|
|
583
|
+
return 1
|
|
584
|
+
}
|
|
585
|
+
printf '%s\n' "$receive_out"
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
remove_interrupted_source_duplicates() { # <outbox> <keys...>
|
|
589
|
+
local outbox=$1 key progress remaining pass=0
|
|
590
|
+
shift
|
|
591
|
+
while :; do
|
|
592
|
+
remaining=0
|
|
593
|
+
progress=0
|
|
594
|
+
for key in "$@"; do
|
|
595
|
+
backlog_key_section "$outbox" "$key" >/dev/null 2>&1 || continue
|
|
596
|
+
if backlog_key_section "$MAIN_BACKLOG" "$key" >/dev/null 2>&1; then
|
|
597
|
+
remaining=$((remaining + 1))
|
|
598
|
+
if tasks-axi rm "$key" --file "$MAIN_BACKLOG" >/dev/null 2>&1; then
|
|
599
|
+
progress=$((progress + 1))
|
|
600
|
+
fi
|
|
601
|
+
fi
|
|
602
|
+
done
|
|
603
|
+
[ "$remaining" -gt 0 ] || return 0
|
|
604
|
+
[ "$progress" -gt 0 ] || {
|
|
605
|
+
echo "error: could not complete interrupted source removal; outbox remains authoritative at $outbox" >&2
|
|
606
|
+
return 1
|
|
607
|
+
}
|
|
608
|
+
pass=$((pass + 1))
|
|
609
|
+
[ "$pass" -le "$#" ] || return 1
|
|
610
|
+
done
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
remote_handoff() { # <secondmate-id> <keys...>
|
|
614
|
+
local id=$1 outbox section main_section out_section key mv_out
|
|
615
|
+
local -a requested to_move already missing in_flight done_items not_queued
|
|
616
|
+
shift
|
|
617
|
+
requested=("$@")
|
|
618
|
+
outbox="$DATA/handoff/$id.outbox.md"
|
|
619
|
+
validate_backlog_file "main backlog" "$MAIN_BACKLOG" || return 1
|
|
620
|
+
validate_backlog_file "remote handoff outbox" "$outbox" || return 1
|
|
621
|
+
if [ ! -e "$outbox" ] && [ ! -L "$outbox" ]; then
|
|
622
|
+
receiver_wake_clear_confirmed "$id" || {
|
|
623
|
+
echo "error: stale receiver wake state for secondmate $id could not be cleared" >&2
|
|
624
|
+
return 1
|
|
625
|
+
}
|
|
626
|
+
fi
|
|
627
|
+
fm_tasks_axi_compatible || {
|
|
628
|
+
echo "error: a compatible tasks-axi with atomic multi-ID mv support is required to stage remote handoffs; run bin/fm-bootstrap.sh for the required version" >&2
|
|
629
|
+
return 1
|
|
630
|
+
}
|
|
631
|
+
to_move=()
|
|
632
|
+
already=()
|
|
633
|
+
missing=()
|
|
634
|
+
in_flight=()
|
|
635
|
+
done_items=()
|
|
636
|
+
not_queued=()
|
|
637
|
+
for key in "${requested[@]}"; do
|
|
638
|
+
out_section=$(backlog_key_section "$outbox" "$key" 2>/dev/null || true)
|
|
639
|
+
main_section=$(backlog_key_section "$MAIN_BACKLOG" "$key" 2>/dev/null || true)
|
|
640
|
+
if [ -n "$out_section" ]; then
|
|
641
|
+
[ "$out_section" = '## Queued' ] || not_queued+=("$key")
|
|
642
|
+
already+=("$key")
|
|
643
|
+
continue
|
|
644
|
+
fi
|
|
645
|
+
case "$main_section" in
|
|
646
|
+
'## Queued') to_move+=("$key") ;;
|
|
647
|
+
'## In flight') in_flight+=("$key") ;;
|
|
648
|
+
'## Done') done_items+=("$key") ;;
|
|
649
|
+
'') missing+=("$key") ;;
|
|
650
|
+
*) not_queued+=("$key") ;;
|
|
651
|
+
esac
|
|
652
|
+
done
|
|
653
|
+
if [ "${#in_flight[@]}" -gt 0 ] || [ "${#done_items[@]}" -gt 0 ] \
|
|
654
|
+
|| [ "${#not_queued[@]}" -gt 0 ] || [ "${#missing[@]}" -gt 0 ]; then
|
|
655
|
+
[ "${#in_flight[@]}" -eq 0 ] || echo "error: refusing to hand off in-flight backlog items: ${in_flight[*]}" >&2
|
|
656
|
+
[ "${#done_items[@]}" -eq 0 ] || echo "error: refusing to hand off Done backlog items: ${done_items[*]}" >&2
|
|
657
|
+
[ "${#not_queued[@]}" -eq 0 ] || echo "error: refusing to hand off non-Queued outbox or backlog items: ${not_queued[*]}" >&2
|
|
658
|
+
[ "${#missing[@]}" -eq 0 ] || echo "error: no backlog or pending outbox item matched: ${missing[*]}" >&2
|
|
659
|
+
echo " nothing new was staged." >&2
|
|
660
|
+
return 1
|
|
661
|
+
fi
|
|
662
|
+
for key in "${to_move[@]}"; do
|
|
663
|
+
while IFS= read -r line; do
|
|
664
|
+
printf 'error: refusing to hand off %s: non-2-space continuation line: %s\n' "$key" "$line" >&2
|
|
665
|
+
return 1
|
|
666
|
+
done < <(backlog_key_noncanonical_body_lines "$MAIN_BACKLOG" "$key")
|
|
667
|
+
done
|
|
668
|
+
# Do not append a fresh handoff to an older recovery batch. In particular, a
|
|
669
|
+
# confirmed wake can survive when outbox cleanup fails; if new work were
|
|
670
|
+
# staged into that outbox, the old confirmation would suppress the wake for
|
|
671
|
+
# the new work. Finish receipt, wake reconciliation, and cleanup for the old
|
|
672
|
+
# batch first. A failure leaves the fresh items dispatchable in main.
|
|
673
|
+
if [ "${#to_move[@]}" -gt 0 ] && [ -f "$outbox" ] \
|
|
674
|
+
&& [ "$(outbox_item_count "$outbox")" -gt 0 ]; then
|
|
675
|
+
remote_deliver_outbox "$id" "$outbox" || {
|
|
676
|
+
echo "error: previous remote handoff for secondmate $id could not be completed; nothing new was staged" >&2
|
|
677
|
+
return 1
|
|
678
|
+
}
|
|
679
|
+
fi
|
|
680
|
+
seed_backlog_scaffold "$outbox"
|
|
681
|
+
if [ "${#to_move[@]}" -gt 0 ]; then
|
|
682
|
+
if ! mv_out=$(tasks-axi mv "${to_move[@]}" --file "$MAIN_BACKLOG" --to "$outbox" 2>&1); then
|
|
683
|
+
[ -z "$mv_out" ] || printf '%s\n' "$mv_out" >&2
|
|
684
|
+
echo "error: atomic outbox staging failed; nothing new was handed off" >&2
|
|
685
|
+
return 1
|
|
686
|
+
fi
|
|
687
|
+
fi
|
|
688
|
+
# A hard local kill can land tasks-axi's target persist before its source
|
|
689
|
+
# persist. The outbox is already authoritative in that state, so converge by
|
|
690
|
+
# deleting only duplicates that tasks-axi itself confirms are dependency-safe.
|
|
691
|
+
remove_interrupted_source_duplicates "$outbox" "${requested[@]}" || return 1
|
|
692
|
+
remote_deliver_outbox "$id" "$outbox" || return 1
|
|
693
|
+
echo "handed off ${#requested[@]} item(s) to remote secondmate $id: ${requested[*]}"
|
|
694
|
+
[ "${#already[@]}" -eq 0 ] || echo " already staged (recovered): ${already[*]}"
|
|
695
|
+
warn_stale_public_commitments "$id" "${requested[@]}"
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
with_remote_route_locks() { # <secondmate-id> <function> <args...>
|
|
699
|
+
local id=$1 operation=$2 rc
|
|
700
|
+
shift 2
|
|
701
|
+
case "$id" in ''|*[!A-Za-z0-9._-]*) echo "error: unsafe remote handoff id: $id" >&2; return 1 ;; esac
|
|
702
|
+
ACTIVE_REGISTRY_LOCK=$(secondmate_registry_lock_path "$STATE")
|
|
703
|
+
fm_lock_acquire_wait "$ACTIVE_REGISTRY_LOCK"
|
|
704
|
+
if [ "$(secondmate_registry_field "$REG" "$id" remote 2>/dev/null || true)" != 1 ]; then
|
|
705
|
+
echo "error: pending outbox has no matching remote secondmate route: $id" >&2
|
|
706
|
+
release_remote_locks
|
|
707
|
+
return 1
|
|
708
|
+
fi
|
|
709
|
+
ACTIVE_HANDOFF_LOCK="$STATE/.backlog-handoff-$id.lock"
|
|
710
|
+
fm_lock_acquire_wait "$ACTIVE_HANDOFF_LOCK"
|
|
711
|
+
if "$operation" "$@"; then rc=0; else rc=$?; fi
|
|
712
|
+
release_remote_locks
|
|
713
|
+
return "$rc"
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
resume_remote_outbox() { # <secondmate-id> <outbox-path>
|
|
717
|
+
local id=$1 outbox=$2
|
|
718
|
+
[ -e "$outbox" ] || [ -L "$outbox" ] || return 0
|
|
719
|
+
if [ ! -f "$outbox" ] || [ -L "$outbox" ]; then
|
|
720
|
+
echo "error: unsafe pending handoff outbox: $outbox" >&2
|
|
721
|
+
return 1
|
|
722
|
+
fi
|
|
723
|
+
remote_deliver_outbox "$id" "$outbox"
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
resume_pending_outboxes() {
|
|
727
|
+
local outbox id failed=0
|
|
728
|
+
[ -d "$DATA/handoff" ] || return 0
|
|
729
|
+
for outbox in "$DATA/handoff"/*.outbox.md; do
|
|
730
|
+
[ -e "$outbox" ] || [ -L "$outbox" ] || continue
|
|
731
|
+
id=$(basename "$outbox" .outbox.md)
|
|
732
|
+
case "$id" in ''|*[!A-Za-z0-9._-]*) echo "error: unsafe pending handoff id: $id" >&2; failed=1; continue ;; esac
|
|
733
|
+
with_remote_route_locks "$id" resume_remote_outbox "$id" "$outbox" || failed=1
|
|
734
|
+
done
|
|
735
|
+
return "$failed"
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
if [ "$RESUME_PENDING" -eq 1 ]; then
|
|
739
|
+
resume_pending_outboxes
|
|
740
|
+
exit $?
|
|
741
|
+
fi
|
|
742
|
+
|
|
743
|
+
ACTIVE_REGISTRY_LOCK=$(secondmate_registry_lock_path "$STATE")
|
|
744
|
+
fm_lock_acquire_wait "$ACTIVE_REGISTRY_LOCK"
|
|
745
|
+
REMOTE=$(secondmate_registry_field "$REG" "$ID" remote 2>/dev/null || true)
|
|
746
|
+
if [ "$REMOTE" = 1 ]; then
|
|
747
|
+
ACTIVE_HANDOFF_LOCK="$STATE/.backlog-handoff-$ID.lock"
|
|
748
|
+
fm_lock_acquire_wait "$ACTIVE_HANDOFF_LOCK"
|
|
749
|
+
if remote_handoff "$ID" "$@"; then rc=0; else rc=$?; fi
|
|
750
|
+
release_remote_locks
|
|
751
|
+
exit "$rc"
|
|
752
|
+
fi
|
|
753
|
+
ACTIVE_HANDOFF_LOCK="$STATE/.backlog-handoff-$ID.lock"
|
|
754
|
+
fm_lock_acquire_wait "$ACTIVE_HANDOFF_LOCK"
|
|
755
|
+
fm_lock_release "$ACTIVE_REGISTRY_LOCK"
|
|
756
|
+
ACTIVE_REGISTRY_LOCK=
|
|
757
|
+
|
|
758
|
+
RAW_HOME=$(secondmate_home "$ID") || exit 1
|
|
759
|
+
[ -n "$RAW_HOME" ] || { echo "error: secondmate $ID has no home in $REG" >&2; exit 1; }
|
|
760
|
+
SUB_HOME=$(validate_secondmate_home "$ID" "$RAW_HOME") || exit 1
|
|
761
|
+
SUB_BACKLOG="$SUB_HOME/data/backlog.md"
|
|
762
|
+
validate_backlog_file "main backlog" "$MAIN_BACKLOG" || exit 1
|
|
763
|
+
validate_backlog_file "secondmate backlog" "$SUB_BACKLOG" || exit 1
|
|
764
|
+
|
|
765
|
+
# Classify every key before changing anything: move-from-main, already-in-sub, or
|
|
766
|
+
# missing. Abort with no changes if any key matches neither backlog.
|
|
767
|
+
TO_MOVE=()
|
|
768
|
+
ALREADY=()
|
|
769
|
+
MISSING=()
|
|
770
|
+
IN_FLIGHT=()
|
|
771
|
+
DONE=()
|
|
772
|
+
NOT_QUEUED=()
|
|
773
|
+
for key in "$@"; do
|
|
774
|
+
if backlog_key_section "$SUB_BACKLOG" "$key" >/dev/null; then
|
|
775
|
+
ALREADY+=("$key")
|
|
776
|
+
elif section=$(backlog_key_section "$MAIN_BACKLOG" "$key"); then
|
|
777
|
+
case "$section" in
|
|
778
|
+
"## Queued") TO_MOVE+=("$key") ;;
|
|
779
|
+
"## In flight") IN_FLIGHT+=("$key") ;;
|
|
780
|
+
"## Done") DONE+=("$key") ;;
|
|
781
|
+
*) NOT_QUEUED+=("$key") ;;
|
|
782
|
+
esac
|
|
783
|
+
else
|
|
784
|
+
MISSING+=("$key")
|
|
785
|
+
fi
|
|
786
|
+
done
|
|
787
|
+
|
|
788
|
+
FAILED=0
|
|
789
|
+
if [ "${#IN_FLIGHT[@]}" -gt 0 ]; then
|
|
790
|
+
echo "error: refusing to hand off in-flight backlog items: ${IN_FLIGHT[*]}" >&2
|
|
791
|
+
FAILED=1
|
|
792
|
+
fi
|
|
793
|
+
if [ "${#DONE[@]}" -gt 0 ]; then
|
|
794
|
+
echo "error: refusing to hand off Done (historical) backlog items: ${DONE[*]}; handoffs move in-scope queued work only - Done records stay with their home and are pruned/archived." >&2
|
|
795
|
+
FAILED=1
|
|
796
|
+
fi
|
|
797
|
+
if [ "${#NOT_QUEUED[@]}" -gt 0 ]; then
|
|
798
|
+
echo "error: refusing to hand off non-queued backlog items: ${NOT_QUEUED[*]}; handoffs move in-scope queued work only." >&2
|
|
799
|
+
FAILED=1
|
|
800
|
+
fi
|
|
801
|
+
if [ "${#MISSING[@]}" -gt 0 ]; then
|
|
802
|
+
echo "error: no backlog item matched these keys in $MAIN_BACKLOG: ${MISSING[*]}" >&2
|
|
803
|
+
FAILED=1
|
|
804
|
+
fi
|
|
805
|
+
if [ "$FAILED" -ne 0 ]; then
|
|
806
|
+
echo " nothing was moved." >&2
|
|
807
|
+
exit 1
|
|
808
|
+
fi
|
|
809
|
+
|
|
810
|
+
REQUESTED_BATCH=$(receiver_wake_batch_id "$@") || {
|
|
811
|
+
echo "error: receiver wake batch identity could not be recorded; nothing was moved" >&2
|
|
812
|
+
exit 1
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
if [ "${#TO_MOVE[@]}" -eq 0 ]; then
|
|
816
|
+
WAKE_PENDING_MARKER="$STATE/.backlog-handoff-$ID.wake-pending"
|
|
817
|
+
case "$(cat "$WAKE_PENDING_MARKER" 2>/dev/null || true)" in
|
|
818
|
+
prepared:*:"$REQUESTED_BATCH") receiver_wake_promote_prepared "$ID" "$REQUESTED_BATCH" || exit 1 ;;
|
|
819
|
+
prepared:*)
|
|
820
|
+
echo "error: a prepared receiver wake for secondmate $ID belongs to a different routed batch; retry that original handoff before handling ${ALREADY[*]}" >&2
|
|
821
|
+
exit 1
|
|
822
|
+
;;
|
|
823
|
+
esac
|
|
824
|
+
echo "nothing to move: ${ALREADY[*]:-no keys} already present in $SUB_BACKLOG"
|
|
825
|
+
wake_pending_secondmate_receiver "$ID" || exit 1
|
|
826
|
+
exit 0
|
|
827
|
+
fi
|
|
828
|
+
|
|
829
|
+
FAILED=0
|
|
830
|
+
for key in "${TO_MOVE[@]}"; do
|
|
831
|
+
while IFS= read -r line; do
|
|
832
|
+
printf 'error: refusing to hand off %s: non-2-space continuation line: %s\n' \
|
|
833
|
+
"$key" "$line" >&2
|
|
834
|
+
FAILED=1
|
|
835
|
+
done < <(backlog_key_noncanonical_body_lines "$MAIN_BACKLOG" "$key")
|
|
836
|
+
done
|
|
837
|
+
if [ "$FAILED" -ne 0 ]; then
|
|
838
|
+
echo " nothing was moved." >&2
|
|
839
|
+
exit 1
|
|
840
|
+
fi
|
|
841
|
+
|
|
842
|
+
if ! fm_tasks_axi_compatible; then
|
|
843
|
+
echo "error: a compatible tasks-axi with atomic multi-ID mv support is required to move backlog items; run bin/fm-bootstrap.sh for the required version" >&2
|
|
844
|
+
exit 1
|
|
845
|
+
fi
|
|
846
|
+
|
|
847
|
+
WAKE_PENDING_MARKER="$STATE/.backlog-handoff-$ID.wake-pending"
|
|
848
|
+
if [ -e "$WAKE_PENDING_MARKER" ] || [ -L "$WAKE_PENDING_MARKER" ]; then
|
|
849
|
+
case "$(cat "$WAKE_PENDING_MARKER" 2>/dev/null || true)" in
|
|
850
|
+
prepared:*:"$REQUESTED_BATCH") receiver_wake_discard_prepared "$ID" || exit 1 ;;
|
|
851
|
+
prepared:*)
|
|
852
|
+
echo "error: a prepared receiver wake for secondmate $ID belongs to a different routed batch; retry that original handoff before moving ${TO_MOVE[*]}" >&2
|
|
853
|
+
exit 1
|
|
854
|
+
;;
|
|
855
|
+
*)
|
|
856
|
+
wake_pending_secondmate_receiver "$ID" || {
|
|
857
|
+
echo "error: previous receiver wake for secondmate $ID is unresolved; nothing new was moved" >&2
|
|
858
|
+
exit 1
|
|
859
|
+
}
|
|
860
|
+
;;
|
|
861
|
+
esac
|
|
862
|
+
fi
|
|
863
|
+
receiver_wake_mark_prepared "$ID" "$REQUESTED_BATCH" || {
|
|
864
|
+
echo "error: receiver wake state for secondmate $ID could not be recorded; nothing was moved" >&2
|
|
865
|
+
exit 1
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
# Seed the destination with firstmate's standard three-section scaffold when it
|
|
869
|
+
# does not exist yet, so the moved item lands under the right section. (Left to
|
|
870
|
+
# create the file itself, tasks-axi mv writes its own `# Backlog` title format,
|
|
871
|
+
# which is not firstmate's home-backlog convention.)
|
|
872
|
+
mkdir -p "$SUB_HOME/data"
|
|
873
|
+
SUB_CREATED=0
|
|
874
|
+
if [ ! -f "$SUB_BACKLOG" ]; then
|
|
875
|
+
printf '## In flight\n\n## Queued\n\n## Done\n' > "$SUB_BACKLOG"
|
|
876
|
+
SUB_CREATED=1
|
|
877
|
+
fi
|
|
878
|
+
|
|
879
|
+
# Delegate the move to tasks-axi. Passing the whole in-scope set to one call is a
|
|
880
|
+
# single atomic transaction, so a connected set (blocker + dependents) moves
|
|
881
|
+
# together and, on any failure, neither backlog's content changes - the only
|
|
882
|
+
# cleanup is a scaffold we just created. tasks-axi writes both its success and
|
|
883
|
+
# error output to stdout, so capture it and surface it only on failure.
|
|
884
|
+
if ! MV_OUT=$(tasks-axi mv "${TO_MOVE[@]}" --file "$MAIN_BACKLOG" --to "$SUB_BACKLOG" 2>&1); then
|
|
885
|
+
if [ "$SUB_CREATED" -eq 1 ]; then
|
|
886
|
+
rm -f "$SUB_BACKLOG"
|
|
887
|
+
fi
|
|
888
|
+
receiver_wake_discard_prepared "$ID" || {
|
|
889
|
+
echo "error: tasks-axi mv failed and receiver wake state could not be cleared" >&2
|
|
890
|
+
exit 1
|
|
891
|
+
}
|
|
892
|
+
if [ -n "$MV_OUT" ]; then
|
|
893
|
+
printf '%s\n' "$MV_OUT" >&2
|
|
894
|
+
fi
|
|
895
|
+
echo "error: tasks-axi mv failed; nothing was moved." >&2
|
|
896
|
+
exit 1
|
|
897
|
+
fi
|
|
898
|
+
|
|
899
|
+
echo "handed off ${#TO_MOVE[@]} item(s) to $ID: ${TO_MOVE[*]}"
|
|
900
|
+
echo " into $SUB_BACKLOG"
|
|
901
|
+
receiver_wake_promote_prepared "$ID" "$REQUESTED_BATCH" || {
|
|
902
|
+
echo "error: handed off work to secondmate $ID, but durable receiver wake state could not be recorded" >&2
|
|
903
|
+
exit 1
|
|
904
|
+
}
|
|
905
|
+
wake_pending_secondmate_receiver "$ID" || exit 1
|
|
906
|
+
if [ "${#ALREADY[@]}" -gt 0 ]; then
|
|
907
|
+
echo " already present (skipped): ${ALREADY[*]}"
|
|
908
|
+
fi
|
|
909
|
+
warn_stale_public_commitments "$ID" "${TO_MOVE[@]}"
|