@zerwiz/ymir 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (850) hide show
  1. package/.agents/README.md +291 -0
  2. package/.agents/agents/bragi-marketer.md +111 -0
  3. package/.agents/agents/brokk.md +352 -0
  4. package/.agents/agents/forseti-reviewer.md +93 -0
  5. package/.agents/agents/frigg-consent.md +77 -0
  6. package/.agents/agents/groa-update.md +77 -0
  7. package/.agents/agents/hnoss-designer.md +69 -0
  8. package/.agents/agents/huginn-researcher.md +99 -0
  9. package/.agents/agents/jord-projects.md +78 -0
  10. package/.agents/agents/kvasir-scout.md +91 -0
  11. package/.agents/agents/mimir-planner.md +92 -0
  12. package/.agents/agents/muninn-stow.md +77 -0
  13. package/.agents/agents/saga-bearings.md +78 -0
  14. package/.agents/agents/sindri-developer.md +114 -0
  15. package/.agents/agents/snotra-documenter.md +105 -0
  16. package/.agents/agents/syn-recovery.md +78 -0
  17. package/.agents/agents/tyr-check.md +78 -0
  18. package/.agents/agents/urdh-hold.md +77 -0
  19. package/.agents/agents/volundr-smith.md +80 -0
  20. package/.agents/agents/vor-diagnostics.md +77 -0
  21. package/.agents/assets/agents/naming.md +50 -0
  22. package/.agents/assets/agents/registry.md +93 -0
  23. package/.agents/assets/agents/runtime.md +36 -0
  24. package/.agents/assets/agents/toon-tasks-cli.md +42 -0
  25. package/.agents/assets/templates/company_entity.template.md +37 -0
  26. package/.agents/backend/backends/cmux.sh +649 -0
  27. package/.agents/backend/backends/herdr-eventwait.py +157 -0
  28. package/.agents/backend/backends/herdr-workspace-move.py +114 -0
  29. package/.agents/backend/backends/herdr.sh +3386 -0
  30. package/.agents/backend/backends/orca.sh +290 -0
  31. package/.agents/backend/backends/tmux.sh +357 -0
  32. package/.agents/backend/backends/zellij.sh +700 -0
  33. package/.agents/backend/fm-afk-launch.sh +654 -0
  34. package/.agents/backend/fm-afk-return.sh +241 -0
  35. package/.agents/backend/fm-afk-start.sh +172 -0
  36. package/.agents/backend/fm-arm-command-policy.mjs +960 -0
  37. package/.agents/backend/fm-arm-pretool-check.sh +200 -0
  38. package/.agents/backend/fm-backend-hometag-lib.sh +52 -0
  39. package/.agents/backend/fm-backend.sh +981 -0
  40. package/.agents/backend/fm-backlog-handoff.sh +909 -0
  41. package/.agents/backend/fm-backlog-receive.sh +187 -0
  42. package/.agents/backend/fm-backlog-transition-lib.sh +779 -0
  43. package/.agents/backend/fm-bearings-board.sh +204 -0
  44. package/.agents/backend/fm-bearings-snapshot.sh +546 -0
  45. package/.agents/backend/fm-bootstrap.sh +1568 -0
  46. package/.agents/backend/fm-branch-outcome.sh +203 -0
  47. package/.agents/backend/fm-branch-prompt.sh +101 -0
  48. package/.agents/backend/fm-brief.sh +452 -0
  49. package/.agents/backend/fm-busy-event.sh +234 -0
  50. package/.agents/backend/fm-busy-lib.sh +986 -0
  51. package/.agents/backend/fm-captain-hold.sh +1001 -0
  52. package/.agents/backend/fm-cd-command-policy.mjs +153 -0
  53. package/.agents/backend/fm-cd-pretool-check.sh +190 -0
  54. package/.agents/backend/fm-check-lib.sh +74 -0
  55. package/.agents/backend/fm-check-register.sh +42 -0
  56. package/.agents/backend/fm-check-unregister.sh +52 -0
  57. package/.agents/backend/fm-classify-lib.sh +1770 -0
  58. package/.agents/backend/fm-claude-stop-autoarm.sh +334 -0
  59. package/.agents/backend/fm-composer-lib.sh +1416 -0
  60. package/.agents/backend/fm-config-inherit-lib.sh +1202 -0
  61. package/.agents/backend/fm-config-push.sh +254 -0
  62. package/.agents/backend/fm-control-lib.sh +251 -0
  63. package/.agents/backend/fm-control.sh +878 -0
  64. package/.agents/backend/fm-crew-state.sh +625 -0
  65. package/.agents/backend/fm-cursor-lib.sh +243 -0
  66. package/.agents/backend/fm-decision-hold.sh +232 -0
  67. package/.agents/backend/fm-doc-audience-check.sh +269 -0
  68. package/.agents/backend/fm-dod-lib.sh +67 -0
  69. package/.agents/backend/fm-ensure-agents-md.sh +253 -0
  70. package/.agents/backend/fm-extension-launch-barrier.mjs +129 -0
  71. package/.agents/backend/fm-extension.mjs +2577 -0
  72. package/.agents/backend/fm-extension.sh +16 -0
  73. package/.agents/backend/fm-ff-lib.sh +420 -0
  74. package/.agents/backend/fm-fleet-snapshot.sh +1463 -0
  75. package/.agents/backend/fm-fleet-sync.sh +458 -0
  76. package/.agents/backend/fm-fleet-view.sh +96 -0
  77. package/.agents/backend/fm-gate-refuse-lib.sh +102 -0
  78. package/.agents/backend/fm-guard.sh +242 -0
  79. package/.agents/backend/fm-harness.sh +195 -0
  80. package/.agents/backend/fm-herdr-ci-cleanup.sh +115 -0
  81. package/.agents/backend/fm-herdr-lab.sh +346 -0
  82. package/.agents/backend/fm-herdr-session-cleanup.sh +337 -0
  83. package/.agents/backend/fm-home-seed.sh +984 -0
  84. package/.agents/backend/fm-home-summary-refresh.sh +255 -0
  85. package/.agents/backend/fm-hook-host-lib.sh +36 -0
  86. package/.agents/backend/fm-inactive-reconcile.sh +531 -0
  87. package/.agents/backend/fm-inbox.sh +399 -0
  88. package/.agents/backend/fm-install-actionlint.sh +84 -0
  89. package/.agents/backend/fm-install-herdr.sh +96 -0
  90. package/.agents/backend/fm-install-shellcheck.sh +84 -0
  91. package/.agents/backend/fm-install-treehouse.sh +95 -0
  92. package/.agents/backend/fm-kimi-turnend-hook.sh +276 -0
  93. package/.agents/backend/fm-lease-lib.sh +218 -0
  94. package/.agents/backend/fm-lease.sh +189 -0
  95. package/.agents/backend/fm-line-cap-lib.sh +51 -0
  96. package/.agents/backend/fm-lint-workflows.sh +137 -0
  97. package/.agents/backend/fm-lint.sh +591 -0
  98. package/.agents/backend/fm-lock-lib.sh +104 -0
  99. package/.agents/backend/fm-lock.sh +107 -0
  100. package/.agents/backend/fm-marker-lib.sh +12 -0
  101. package/.agents/backend/fm-merge-local.sh +74 -0
  102. package/.agents/backend/fm-merge-outcome-lib.sh +138 -0
  103. package/.agents/backend/fm-nm-run-lib.sh +124 -0
  104. package/.agents/backend/fm-on.sh +125 -0
  105. package/.agents/backend/fm-operational-input.sh +253 -0
  106. package/.agents/backend/fm-peek.sh +46 -0
  107. package/.agents/backend/fm-pending-reply-lib.sh +1409 -0
  108. package/.agents/backend/fm-pr-check.sh +135 -0
  109. package/.agents/backend/fm-pr-lib.sh +1016 -0
  110. package/.agents/backend/fm-pr-merge.sh +707 -0
  111. package/.agents/backend/fm-pr-poll.sh +110 -0
  112. package/.agents/backend/fm-primary-scope-lib.sh +33 -0
  113. package/.agents/backend/fm-procevent-extension-capture.pl +259 -0
  114. package/.agents/backend/fm-procevent-lavish.sh +628 -0
  115. package/.agents/backend/fm-procevent-lib.sh +892 -0
  116. package/.agents/backend/fm-procevent-quota.sh +290 -0
  117. package/.agents/backend/fm-procevent-remote-reply.sh +577 -0
  118. package/.agents/backend/fm-procevent-when.sh +504 -0
  119. package/.agents/backend/fm-procevent.sh +1466 -0
  120. package/.agents/backend/fm-project-mode.sh +92 -0
  121. package/.agents/backend/fm-project-origin-lib.sh +180 -0
  122. package/.agents/backend/fm-promote.sh +282 -0
  123. package/.agents/backend/fm-public-followup-emit.sh +260 -0
  124. package/.agents/backend/fm-public-followup-lib.sh +398 -0
  125. package/.agents/backend/fm-public-followup.sh +1330 -0
  126. package/.agents/backend/fm-push-transition-lib.sh +168 -0
  127. package/.agents/backend/fm-quota-axi-lib.sh +93 -0
  128. package/.agents/backend/fm-quota-choose.sh +384 -0
  129. package/.agents/backend/fm-remote-delta-read.sh +189 -0
  130. package/.agents/backend/fm-remote-doctor.sh +800 -0
  131. package/.agents/backend/fm-remote-entrypoint.sh +193 -0
  132. package/.agents/backend/fm-remote-file.sh +234 -0
  133. package/.agents/backend/fm-remote-home-provision.sh +259 -0
  134. package/.agents/backend/fm-remote-home-seed.sh +259 -0
  135. package/.agents/backend/fm-remote-inherit-push.sh +90 -0
  136. package/.agents/backend/fm-remote-inherit.sh +179 -0
  137. package/.agents/backend/fm-remote-job-lib.sh +1241 -0
  138. package/.agents/backend/fm-remote-job-reap-orphans.sh +137 -0
  139. package/.agents/backend/fm-remote-job-worker.sh +1124 -0
  140. package/.agents/backend/fm-remote-readiness-lib.sh +44 -0
  141. package/.agents/backend/fm-remote-secondmate-control.sh +340 -0
  142. package/.agents/backend/fm-review-diff.sh +158 -0
  143. package/.agents/backend/fm-secondmate-charter-lib.sh +44 -0
  144. package/.agents/backend/fm-secondmate-nudge-lib.sh +68 -0
  145. package/.agents/backend/fm-secondmate-parent-lib.sh +70 -0
  146. package/.agents/backend/fm-secondmate-reconcile.sh +371 -0
  147. package/.agents/backend/fm-secondmate-registry-lib.sh +311 -0
  148. package/.agents/backend/fm-secondmate-report.sh +88 -0
  149. package/.agents/backend/fm-send.sh +1059 -0
  150. package/.agents/backend/fm-session-lock-lib.sh +176 -0
  151. package/.agents/backend/fm-session-start.sh +970 -0
  152. package/.agents/backend/fm-sessionstart-cursor.sh +40 -0
  153. package/.agents/backend/fm-sessionstart-nudge.sh +45 -0
  154. package/.agents/backend/fm-sessionstart-run.sh +145 -0
  155. package/.agents/backend/fm-spawn.sh +3153 -0
  156. package/.agents/backend/fm-startup-memory-budget-lib.sh +224 -0
  157. package/.agents/backend/fm-startup-memory-budget.sh +94 -0
  158. package/.agents/backend/fm-startup-network.sh +642 -0
  159. package/.agents/backend/fm-stow-cascade.sh +251 -0
  160. package/.agents/backend/fm-subagent-pretool-check.sh +207 -0
  161. package/.agents/backend/fm-supervise-daemon.sh +1732 -0
  162. package/.agents/backend/fm-supervision-instructions.sh +215 -0
  163. package/.agents/backend/fm-supervision-lib.sh +90 -0
  164. package/.agents/backend/fm-supervisor-target-lib.sh +78 -0
  165. package/.agents/backend/fm-tangle-lib.sh +53 -0
  166. package/.agents/backend/fm-task-inbox-lib.sh +402 -0
  167. package/.agents/backend/fm-tasks-axi-lib.sh +123 -0
  168. package/.agents/backend/fm-teardown.sh +2922 -0
  169. package/.agents/backend/fm-test-isolation-proof.sh +588 -0
  170. package/.agents/backend/fm-test-run.sh +2191 -0
  171. package/.agents/backend/fm-timeout-lib.sh +141 -0
  172. package/.agents/backend/fm-timing-lib.sh +179 -0
  173. package/.agents/backend/fm-tmux-lib.sh +291 -0
  174. package/.agents/backend/fm-tool-update-check.sh +898 -0
  175. package/.agents/backend/fm-trace-context-lib.sh +227 -0
  176. package/.agents/backend/fm-transition-lib.sh +103 -0
  177. package/.agents/backend/fm-turnend-guard-cursor.sh +391 -0
  178. package/.agents/backend/fm-turnend-guard-grok.sh +90 -0
  179. package/.agents/backend/fm-turnend-guard.sh +432 -0
  180. package/.agents/backend/fm-update.sh +110 -0
  181. package/.agents/backend/fm-vendor-auth-probe.sh +190 -0
  182. package/.agents/backend/fm-voice-client.py +1373 -0
  183. package/.agents/backend/fm-voice-relay.py +1256 -0
  184. package/.agents/backend/fm-wake-drain.sh +592 -0
  185. package/.agents/backend/fm-wake-grant.sh +127 -0
  186. package/.agents/backend/fm-wake-lib.sh +1849 -0
  187. package/.agents/backend/fm-watch-arm.sh +602 -0
  188. package/.agents/backend/fm-watch-checkpoint.sh +109 -0
  189. package/.agents/backend/fm-watch.sh +1962 -0
  190. package/.agents/backend/fm-x-dismiss.sh +116 -0
  191. package/.agents/backend/fm-x-followup.sh +286 -0
  192. package/.agents/backend/fm-x-lib.sh +1000 -0
  193. package/.agents/backend/fm-x-link.sh +234 -0
  194. package/.agents/backend/fm-x-poll.sh +185 -0
  195. package/.agents/backend/fm-x-reply.sh +385 -0
  196. package/.agents/backend/fm_voice_frame.py +166 -0
  197. package/.agents/backend/fm_voice_records.py +574 -0
  198. package/.agents/backend/model-bridge.py +290 -0
  199. package/.agents/backend/opencode-go-bridge.py +30 -0
  200. package/.agents/bus/README.md +12 -0
  201. package/.agents/bus/messages.json +1 -0
  202. package/.agents/config/agents.machine.example.yaml +16 -0
  203. package/.agents/config/agents.yaml +50 -0
  204. package/.agents/config/agents.yaml.example +72 -0
  205. package/.agents/config/crew-dispatch.json +22 -0
  206. package/.agents/config/cron.yaml +9 -0
  207. package/.agents/config/eindri-dispatch.json +67 -0
  208. package/.agents/config/eindri-harness +1 -0
  209. package/.agents/config/startup-memory-budget +1 -0
  210. package/.agents/config/tailscale-sync.yaml +27 -0
  211. package/.agents/filebrowser/.filebrowser.json +6 -0
  212. package/.agents/filebrowser/README.md +11 -0
  213. package/.agents/gateway/README.md +12 -0
  214. package/.agents/github/README.md +15 -0
  215. package/.agents/github/webhooks/.gitkeep +0 -0
  216. package/.agents/github/workflows/.gitkeep +0 -0
  217. package/.agents/harness/opencode/plugins/lib/rodd-operational-input.js +37 -0
  218. package/.agents/harness/opencode/plugins/package.json +4 -0
  219. package/.agents/harness/opencode/plugins/saga-sessionstart.js +77 -0
  220. package/.agents/harness/opencode/plugins/syn-cd-check.js +61 -0
  221. package/.agents/harness/opencode/plugins/syn-pretool-check.js +68 -0
  222. package/.agents/harness/opencode/plugins/syn-turnend-guard.js +105 -0
  223. package/.agents/harness/opencode/plugins/syn-watch-arm.js +521 -0
  224. package/.agents/memory/README.md +46 -0
  225. package/.agents/memory/kaia.engram +0 -0
  226. package/.agents/memory/kaia.engram-shm +0 -0
  227. package/.agents/memory/kaia.engram-wal +0 -0
  228. package/.agents/memory/runes_audit.md +5 -0
  229. package/.agents/memory/well/episodes.jsonl +367 -0
  230. package/.agents/memory/well/workspace.jsonl +27 -0
  231. package/.agents/migrations/0001-hodd-layout.sh +38 -0
  232. package/.agents/migrations/0002-a2a-mcp.sh +27 -0
  233. package/.agents/migrations/0003-private-data-separation.sh +111 -0
  234. package/.agents/migrations/0004-hoard-and-realms.sh +104 -0
  235. package/.agents/sandbox/Dockerfile.utgard +19 -0
  236. package/.agents/sandbox/README.md +14 -0
  237. package/.agents/sandbox/utgard.config.json +14 -0
  238. package/.agents/skills/README.md +59 -0
  239. package/.agents/skills/bragi-marketing/README.md +3 -0
  240. package/.agents/skills/bragi-marketing/SKILL.md +82 -0
  241. package/.agents/skills/eindri-homes/README.md +3 -0
  242. package/.agents/skills/eindri-homes/SKILL.md +291 -0
  243. package/.agents/skills/eindri-homes/assets/control-plane.md +122 -0
  244. package/.agents/skills/eindri-homes/assets/dispatch.md +80 -0
  245. package/.agents/skills/frigg-consent/README.md +3 -0
  246. package/.agents/skills/frigg-consent/SKILL.md +56 -0
  247. package/.agents/skills/galdr-ymirsystem/README.md +3 -0
  248. package/.agents/skills/galdr-ymirsystem/SKILL.md +158 -0
  249. package/.agents/skills/galdr-ymirsystem/assets/README.md +74 -0
  250. package/.agents/skills/galdr-ymirsystem/assets/brokk-distro-runtime.md +390 -0
  251. package/.agents/skills/galdr-ymirsystem/assets/build-method.md +113 -0
  252. package/.agents/skills/galdr-ymirsystem/assets/build-tool-categories.md +178 -0
  253. package/.agents/skills/galdr-ymirsystem/assets/eindri-orchestration.md +518 -0
  254. package/.agents/skills/galdr-ymirsystem/assets/eindri-profiles.md +136 -0
  255. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/README.md +673 -0
  256. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/claude-code.md +197 -0
  257. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/codex.md +191 -0
  258. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/cursor.md +193 -0
  259. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/opencode.md +262 -0
  260. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/pi.md +295 -0
  261. package/.agents/skills/galdr-ymirsystem/assets/hlidskjalf-ui.md +496 -0
  262. package/.agents/skills/galdr-ymirsystem/assets/installation.md +571 -0
  263. package/.agents/skills/galdr-ymirsystem/assets/local-models/HOST-DATA.example.md +72 -0
  264. package/.agents/skills/galdr-ymirsystem/assets/local-models.md +274 -0
  265. package/.agents/skills/galdr-ymirsystem/assets/memory-well.md +161 -0
  266. package/.agents/skills/galdr-ymirsystem/assets/nornir-jobs.md +377 -0
  267. package/.agents/skills/galdr-ymirsystem/assets/norse-naming.md +325 -0
  268. package/.agents/skills/galdr-ymirsystem/assets/odrerir-hall.md +129 -0
  269. package/.agents/skills/galdr-ymirsystem/assets/pi-boot/einherjar-spawn.schema.json +81 -0
  270. package/.agents/skills/galdr-ymirsystem/assets/pi-boot/herdr-profile.toml +75 -0
  271. package/.agents/skills/galdr-ymirsystem/assets/pi-boot/pi-profile.yml +96 -0
  272. package/.agents/skills/galdr-ymirsystem/assets/pi-boot/supervision-tree.yml +163 -0
  273. package/.agents/skills/galdr-ymirsystem/assets/pi-boot-guide.md +58 -0
  274. package/.agents/skills/galdr-ymirsystem/assets/porting-upstream-to-norse.md +301 -0
  275. package/.agents/skills/galdr-ymirsystem/assets/principles.md +385 -0
  276. package/.agents/skills/galdr-ymirsystem/assets/reference-adoption.md +99 -0
  277. package/.agents/skills/galdr-ymirsystem/assets/registry.md +379 -0
  278. package/.agents/skills/galdr-ymirsystem/assets/runtime-compliance.md +463 -0
  279. package/.agents/skills/galdr-ymirsystem/assets/runtime-components.md +553 -0
  280. package/.agents/skills/galdr-ymirsystem/assets/smidja.md +175 -0
  281. package/.agents/skills/galdr-ymirsystem/schemas/toon-schemas.md +190 -0
  282. package/.agents/skills/galdr-ymirsystem/scripts/README.md +45 -0
  283. package/.agents/skills/galdr-ymirsystem/scripts/bench-one.sh +248 -0
  284. package/.agents/skills/galdr-ymirsystem/scripts/compliance-check.sh +360 -0
  285. package/.agents/skills/galdr-ymirsystem/scripts/gpu-sample.sh +43 -0
  286. package/.agents/skills/galdr-ymirsystem/scripts/stop-all.sh +34 -0
  287. package/.agents/skills/galdr-ymirsystem/scripts/toon-check.py +188 -0
  288. package/.agents/skills/gjallarhorn-relay/README.md +3 -0
  289. package/.agents/skills/gjallarhorn-relay/SKILL.md +283 -0
  290. package/.agents/skills/groa-update/SKILL.md +70 -0
  291. package/.agents/skills/hamr-adapters/README.md +3 -0
  292. package/.agents/skills/hamr-adapters/SKILL.md +123 -0
  293. package/.agents/skills/hamr-adapters/references/common/control-and-recovery.md +37 -0
  294. package/.agents/skills/hamr-adapters/references/common/dispatch.md +32 -0
  295. package/.agents/skills/hamr-adapters/references/common/model-and-effort.md +42 -0
  296. package/.agents/skills/hamr-adapters/references/common/primary-hooks.md +40 -0
  297. package/.agents/skills/hamr-adapters/references/harness/claude.md +55 -0
  298. package/.agents/skills/hamr-adapters/references/harness/codex.md +43 -0
  299. package/.agents/skills/hamr-adapters/references/harness/cursor.md +75 -0
  300. package/.agents/skills/hamr-adapters/references/harness/grok.md +69 -0
  301. package/.agents/skills/hamr-adapters/references/harness/kimi.md +51 -0
  302. package/.agents/skills/hamr-adapters/references/harness/muse.md +70 -0
  303. package/.agents/skills/hamr-adapters/references/harness/opencode.md +42 -0
  304. package/.agents/skills/hamr-adapters/references/harness/pi.md +56 -0
  305. package/.agents/skills/herdr-panes/README.md +3 -0
  306. package/.agents/skills/herdr-panes/SKILL.md +92 -0
  307. package/.agents/skills/herdr-panes/assets/herdr-backend.md +346 -0
  308. package/.agents/skills/herdr-panes/assets/tmux-backend.md +115 -0
  309. package/.agents/skills/hnoss-design/DESIGN.md +19 -0
  310. package/.agents/skills/hnoss-design/README.md +3 -0
  311. package/.agents/skills/hnoss-design/SKILL.md +83 -0
  312. package/.agents/skills/hvild-afk/README.md +3 -0
  313. package/.agents/skills/hvild-afk/SKILL.md +241 -0
  314. package/.agents/skills/jord-projects/README.md +3 -0
  315. package/.agents/skills/jord-projects/SKILL.md +92 -0
  316. package/.agents/skills/lifecycle/SKILL.md +56 -0
  317. package/.agents/skills/lifecycle/smoke_test.sh +52 -0
  318. package/.agents/skills/lifecycle/start.sh +21 -0
  319. package/.agents/skills/lifecycle/status.sh +35 -0
  320. package/.agents/skills/lifecycle/stop.sh +16 -0
  321. package/.agents/skills/muninn-stow/README.md +3 -0
  322. package/.agents/skills/muninn-stow/SKILL.md +309 -0
  323. package/.agents/skills/no-mistakes/SKILL.md +379 -0
  324. package/.agents/skills/nornir-schedule/README.md +3 -0
  325. package/.agents/skills/nornir-schedule/SKILL.md +25 -0
  326. package/.agents/skills/nornir-schedule/assets/events.md +137 -0
  327. package/.agents/skills/nornir-schedule/assets/quota.md +131 -0
  328. package/.agents/skills/nsr-compliance/README.md +3 -0
  329. package/.agents/skills/nsr-compliance/SKILL.md +29 -0
  330. package/.agents/skills/nsr-compliance/assets/nsr/README.md +40 -0
  331. package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/README.md +15 -0
  332. package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/git-workflow.md +18 -0
  333. package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/security.md +22 -0
  334. package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/tech-stack.md +8 -0
  335. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/SKILL.md +71 -0
  336. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/config/core_four.yaml +16 -0
  337. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/check_danger.sh +102 -0
  338. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/check_wiring.sh +69 -0
  339. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/validate_code.sh +29 -0
  340. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/verify_docs.py +66 -0
  341. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/generate.sh +109 -0
  342. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/envelopes/result_envelope.json +14 -0
  343. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/envelopes/task_envelope.json +20 -0
  344. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/runner.py +303 -0
  345. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/telemetry/logger.py +112 -0
  346. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/README.md +18 -0
  347. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/config/README.md +10 -0
  348. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/README.md +12 -0
  349. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_env.sh +23 -0
  350. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_paths.sh +20 -0
  351. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_platform.sh +23 -0
  352. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/harness/README.md +11 -0
  353. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/harness/envelopes/README.md +10 -0
  354. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/installer/README.md +10 -0
  355. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/installer/install.sh +125 -0
  356. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/telemetry/README.md +11 -0
  357. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/README.md +20 -0
  358. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/features/README.md +36 -0
  359. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/features/SKILL-template.md +14 -0
  360. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/README.md +25 -0
  361. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/SKILL.md +13 -0
  362. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/create_branch.sh +6 -0
  363. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/safe_commit.sh +9 -0
  364. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/sync_upstream.sh +6 -0
  365. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/README.md +27 -0
  366. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/SKILL.md +15 -0
  367. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/smoke_test.sh +12 -0
  368. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/start.sh +19 -0
  369. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/status.sh +12 -0
  370. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/stop.sh +15 -0
  371. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/README.md +18 -0
  372. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/config/README.md +10 -0
  373. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/config/core_four.yaml +13 -0
  374. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/README.md +12 -0
  375. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_danger.sh +102 -0
  376. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_env.sh +23 -0
  377. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_paths.sh +20 -0
  378. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_platform.sh +23 -0
  379. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_wiring.sh +69 -0
  380. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/README.md +11 -0
  381. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/README.md +10 -0
  382. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/result_envelope.json +14 -0
  383. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/task_envelope.json +20 -0
  384. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/runner.py +303 -0
  385. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/installer/README.md +10 -0
  386. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/installer/install.sh +125 -0
  387. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/telemetry/README.md +11 -0
  388. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/telemetry/logger.py +112 -0
  389. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/README.md +14 -0
  390. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/api.md +17 -0
  391. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/compliance-wiring.md +155 -0
  392. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/frontend.md +15 -0
  393. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/README.md +11 -0
  394. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/README.md +23 -0
  395. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/clients/README.md +16 -0
  396. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/clients/template-README.md +11 -0
  397. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/deploy.sh +49 -0
  398. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/README.md +12 -0
  399. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/development.env.example +17 -0
  400. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/production.env.example +17 -0
  401. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/staging.env.example +17 -0
  402. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/tenants/README.md +11 -0
  403. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/tenants/template.env.example +8 -0
  404. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/README.md +26 -0
  405. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/agent.md +7 -0
  406. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/developers/dev-1.md +20 -0
  407. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/linux.md +9 -0
  408. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/macos.md +10 -0
  409. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/shared.md +19 -0
  410. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/windows.md +14 -0
  411. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/README.md +25 -0
  412. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/_template.md +41 -0
  413. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/hosting-1.md +41 -0
  414. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/README.md +21 -0
  415. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/README.md +15 -0
  416. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/deployment.md +19 -0
  417. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/disaster-recovery.md +15 -0
  418. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/ops-tasks.md +14 -0
  419. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/features/README.md +16 -0
  420. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/project-skills.md +146 -0
  421. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/research/README.md +11 -0
  422. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/research/software-compliance-research.md +269 -0
  423. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/working-with-agents.md +260 -0
  424. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/AGENTS.md +38 -0
  425. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/ARCHITECTURE.md +36 -0
  426. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/BEST_PRACTICES.md +27 -0
  427. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/CI_CD.md +23 -0
  428. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/FEATURES.md +15 -0
  429. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/README.md +22 -0
  430. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/RULES.md +37 -0
  431. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/STRUCTURE.md +45 -0
  432. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/TECH_STACK.md +28 -0
  433. package/.agents/skills/nsr-compliance/assets/nsr/scaffold-spec.md +63 -0
  434. package/.agents/skills/nsr-compliance/assets/nsr/scripts/scaffold.sh +103 -0
  435. package/.agents/skills/nsr-compliance/assets/nsr/scripts/validate.sh +52 -0
  436. package/.agents/skills/nsr-compliance/assets/nsrcompliance/SKILL.md +71 -0
  437. package/.agents/skills/nsr-compliance/assets/nsrcompliance/config/core_four.yaml +16 -0
  438. package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/check_danger.sh +102 -0
  439. package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/check_wiring.sh +69 -0
  440. package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/validate_code.sh +29 -0
  441. package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/verify_docs.py +66 -0
  442. package/.agents/skills/nsr-compliance/assets/nsrcompliance/generate.sh +109 -0
  443. package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/envelopes/result_envelope.json +14 -0
  444. package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/envelopes/task_envelope.json +20 -0
  445. package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/runner.py +303 -0
  446. package/.agents/skills/nsr-compliance/assets/nsrcompliance/telemetry/logger.py +112 -0
  447. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/README.md +18 -0
  448. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/config/README.md +10 -0
  449. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/README.md +12 -0
  450. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_env.sh +23 -0
  451. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_paths.sh +20 -0
  452. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_platform.sh +23 -0
  453. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/harness/README.md +11 -0
  454. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/harness/envelopes/README.md +10 -0
  455. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/installer/README.md +10 -0
  456. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/installer/install.sh +125 -0
  457. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/telemetry/README.md +11 -0
  458. package/.agents/skills/pr-ops/README.md +3 -0
  459. package/.agents/skills/pr-ops/SKILL.md +109 -0
  460. package/.agents/skills/ratatoskr-a2a/README.md +3 -0
  461. package/.agents/skills/ratatoskr-a2a/SKILL.md +148 -0
  462. package/.agents/skills/rules-check-drift/SKILL.md +81 -0
  463. package/.agents/skills/saga-bearings/README.md +3 -0
  464. package/.agents/skills/saga-bearings/SKILL.md +26 -0
  465. package/.agents/skills/saga-bearings/assets/bearings.md +161 -0
  466. package/.agents/skills/saga-bearings/assets/board-template.html +731 -0
  467. package/.agents/skills/saga-bearings/assets/recap.md +56 -0
  468. package/.agents/skills/syn-recovery/README.md +3 -0
  469. package/.agents/skills/syn-recovery/SKILL.md +54 -0
  470. package/.agents/skills/tyr-check/README.md +3 -0
  471. package/.agents/skills/tyr-check/SKILL.md +218 -0
  472. package/.agents/skills/urdh-hold/README.md +3 -0
  473. package/.agents/skills/urdh-hold/SKILL.md +25 -0
  474. package/.agents/skills/urdh-hold/assets/decisions.md +15 -0
  475. package/.agents/skills/urdh-hold/assets/hold.md +54 -0
  476. package/.agents/skills/vor-diagnostics/README.md +3 -0
  477. package/.agents/skills/vor-diagnostics/SKILL.md +68 -0
  478. package/.agents/skills/ymir-host/README.md +3 -0
  479. package/.agents/skills/ymir-host/SKILL.md +34 -0
  480. package/.agents/skills/ymir-host/assets/desktop.md +36 -0
  481. package/.agents/skills/ymir-host/assets/omarchy.md +297 -0
  482. package/.agents/skills/ymir-host/assets/runbooks.md +15 -0
  483. package/.agents/skills/ymir-host/assets/thjazi.md +220 -0
  484. package/.agents/skills/ymir-host/assets/update.md +64 -0
  485. package/.agents/tests/assets/board-render-harness.mjs +117 -0
  486. package/.agents/tests/cmux-test-safety.sh +51 -0
  487. package/.agents/tests/fixtures.sh +291 -0
  488. package/.agents/tests/fm-afk-inject-e2e.test.sh +428 -0
  489. package/.agents/tests/fm-afk-inject-herdr-e2e.test.sh +536 -0
  490. package/.agents/tests/fm-afk-launch.test.sh +961 -0
  491. package/.agents/tests/fm-afk-pi-herdr-return-e2e.test.sh +297 -0
  492. package/.agents/tests/fm-afk-return.test.sh +283 -0
  493. package/.agents/tests/fm-arm-pretool-check.test.sh +482 -0
  494. package/.agents/tests/fm-ask-user-authority.test.sh +42 -0
  495. package/.agents/tests/fm-backend-autodetect-smoke.test.sh +176 -0
  496. package/.agents/tests/fm-backend-cmux-smoke.test.sh +188 -0
  497. package/.agents/tests/fm-backend-cmux.test.sh +1166 -0
  498. package/.agents/tests/fm-backend-herdr-eventwait-smoke.test.sh +136 -0
  499. package/.agents/tests/fm-backend-herdr-eventwait.test.py +106 -0
  500. package/.agents/tests/fm-backend-herdr-focus-flash-e2e.test.sh +409 -0
  501. package/.agents/tests/fm-backend-herdr-launcher-workspace-e2e.test.sh +437 -0
  502. package/.agents/tests/fm-backend-herdr-presentation-e2e.test.sh +1424 -0
  503. package/.agents/tests/fm-backend-herdr-prune-safety-e2e.test.sh +180 -0
  504. package/.agents/tests/fm-backend-herdr-respawn-idem-e2e.test.sh +182 -0
  505. package/.agents/tests/fm-backend-herdr-smoke.test.sh +355 -0
  506. package/.agents/tests/fm-backend-herdr-workspace-per-home-e2e.test.sh +251 -0
  507. package/.agents/tests/fm-backend-herdr.test.sh +4606 -0
  508. package/.agents/tests/fm-backend-orca.test.sh +1357 -0
  509. package/.agents/tests/fm-backend-tmux-smoke.test.sh +173 -0
  510. package/.agents/tests/fm-backend-zellij-smoke.test.sh +205 -0
  511. package/.agents/tests/fm-backend-zellij.test.sh +1360 -0
  512. package/.agents/tests/fm-backend.test.sh +1142 -0
  513. package/.agents/tests/fm-backlog-atomicity.test.sh +2302 -0
  514. package/.agents/tests/fm-backlog-handoff.test.sh +1360 -0
  515. package/.agents/tests/fm-bearings-board-render.test.sh +135 -0
  516. package/.agents/tests/fm-bearings-board.test.sh +414 -0
  517. package/.agents/tests/fm-bearings-snapshot.test.sh +1990 -0
  518. package/.agents/tests/fm-bootstrap-network-parallel.test.sh +316 -0
  519. package/.agents/tests/fm-bootstrap.test.sh +1178 -0
  520. package/.agents/tests/fm-branch-supervision.test.sh +552 -0
  521. package/.agents/tests/fm-brief.test.sh +785 -0
  522. package/.agents/tests/fm-busy-adapter-wiring.test.sh +324 -0
  523. package/.agents/tests/fm-busy-state.test.sh +465 -0
  524. package/.agents/tests/fm-calm-pi-extension.test.sh +3979 -0
  525. package/.agents/tests/fm-captain-hold-lifecycle.test.sh +1187 -0
  526. package/.agents/tests/fm-cd-pretool-check.test.sh +400 -0
  527. package/.agents/tests/fm-check-unregister.test.sh +198 -0
  528. package/.agents/tests/fm-classify-corr-token.test.sh +543 -0
  529. package/.agents/tests/fm-classify-decision-key.test.sh +340 -0
  530. package/.agents/tests/fm-claude-stop-autoarm-live-e2e.test.sh +164 -0
  531. package/.agents/tests/fm-claude-stop-autoarm.test.sh +1190 -0
  532. package/.agents/tests/fm-cmux-claude-composer-live-e2e.test.sh +110 -0
  533. package/.agents/tests/fm-codex-continuity-live-e2e.test.sh +55 -0
  534. package/.agents/tests/fm-composer-ghost.test.sh +716 -0
  535. package/.agents/tests/fm-composer-lib.test.sh +666 -0
  536. package/.agents/tests/fm-composer-matrix-live-e2e.test.sh +220 -0
  537. package/.agents/tests/fm-control-herdr-smoke.test.sh +149 -0
  538. package/.agents/tests/fm-control-relaunch.test.sh +1530 -0
  539. package/.agents/tests/fm-control.test.sh +910 -0
  540. package/.agents/tests/fm-crew-state.test.sh +1610 -0
  541. package/.agents/tests/fm-cursor-harness.test.sh +404 -0
  542. package/.agents/tests/fm-cursor-primary-live-e2e.test.sh +217 -0
  543. package/.agents/tests/fm-cursor-primary.test.sh +708 -0
  544. package/.agents/tests/fm-daemon.test.sh +2740 -0
  545. package/.agents/tests/fm-documentation-audiences.test.sh +141 -0
  546. package/.agents/tests/fm-ensure-agents-md.test.sh +371 -0
  547. package/.agents/tests/fm-extension-binding.test.sh +2187 -0
  548. package/.agents/tests/fm-fleet-snapshot-view.test.sh +816 -0
  549. package/.agents/tests/fm-fleet-sync.test.sh +721 -0
  550. package/.agents/tests/fm-gate-refuse.test.sh +356 -0
  551. package/.agents/tests/fm-gitignore-config.test.sh +89 -0
  552. package/.agents/tests/fm-gotmp.test.sh +230 -0
  553. package/.agents/tests/fm-grok-continuity-live-e2e.test.sh +112 -0
  554. package/.agents/tests/fm-grok-harness.test.sh +117 -0
  555. package/.agents/tests/fm-grok-stop-live-e2e.test.sh +219 -0
  556. package/.agents/tests/fm-guard-stale-banner.test.sh +709 -0
  557. package/.agents/tests/fm-harness-adapter-instructions-live-e2e.test.sh +134 -0
  558. package/.agents/tests/fm-harness-adapter-references.test.sh +30 -0
  559. package/.agents/tests/fm-harness-liveness-drift-live-e2e.test.sh +151 -0
  560. package/.agents/tests/fm-herdr-lab.test.sh +243 -0
  561. package/.agents/tests/fm-herdr-session-cleanup-e2e.test.sh +146 -0
  562. package/.agents/tests/fm-herdr-session-cleanup.test.sh +329 -0
  563. package/.agents/tests/fm-herdr-submit-confirm-live-e2e.test.sh +125 -0
  564. package/.agents/tests/fm-herdr-version-floor-live-e2e.test.sh +144 -0
  565. package/.agents/tests/fm-home-summary-refresh.test.sh +971 -0
  566. package/.agents/tests/fm-inactive-reconcile.test.sh +485 -0
  567. package/.agents/tests/fm-kimi-harness.test.sh +687 -0
  568. package/.agents/tests/fm-lint-workflows.test.sh +532 -0
  569. package/.agents/tests/fm-lint.test.sh +1023 -0
  570. package/.agents/tests/fm-muse-harness.test.sh +932 -0
  571. package/.agents/tests/fm-muse-signals-live-e2e.test.sh +205 -0
  572. package/.agents/tests/fm-no-mistakes-required.test.sh +72 -0
  573. package/.agents/tests/fm-on.test.sh +507 -0
  574. package/.agents/tests/fm-opencode-primary-live-e2e.test.sh +357 -0
  575. package/.agents/tests/fm-operational-input.test.sh +160 -0
  576. package/.agents/tests/fm-peek-remote.test.sh +110 -0
  577. package/.agents/tests/fm-pending-reply.test.sh +1288 -0
  578. package/.agents/tests/fm-pi-branch-extension.test.sh +3182 -0
  579. package/.agents/tests/fm-pi-branch-live-e2e.test.sh +527 -0
  580. package/.agents/tests/fm-pi-primary-live-e2e.test.sh +345 -0
  581. package/.agents/tests/fm-pi-primary-types.test.sh +68 -0
  582. package/.agents/tests/fm-pi-watch-extension.test.sh +2843 -0
  583. package/.agents/tests/fm-pr-check-security.test.sh +2140 -0
  584. package/.agents/tests/fm-pr-merge.test.sh +2135 -0
  585. package/.agents/tests/fm-procevent-quota.test.sh +225 -0
  586. package/.agents/tests/fm-procevent-when.test.sh +406 -0
  587. package/.agents/tests/fm-procevent.test.sh +1745 -0
  588. package/.agents/tests/fm-project-origin.test.sh +110 -0
  589. package/.agents/tests/fm-public-followup.test.sh +2272 -0
  590. package/.agents/tests/fm-quota-array-dispatch-live-e2e.test.sh +526 -0
  591. package/.agents/tests/fm-quota-choose.test.sh +626 -0
  592. package/.agents/tests/fm-remote-backlog-handoff.test.sh +453 -0
  593. package/.agents/tests/fm-remote-doctor.test.sh +625 -0
  594. package/.agents/tests/fm-remote-entrypoint.test.sh +59 -0
  595. package/.agents/tests/fm-remote-job-orphan-reap.test.sh +205 -0
  596. package/.agents/tests/fm-remote-job.test.sh +768 -0
  597. package/.agents/tests/fm-remote-reply.test.sh +520 -0
  598. package/.agents/tests/fm-remote-secondmate-lifecycle-e2e.test.sh +1256 -0
  599. package/.agents/tests/fm-remote-secondmate-parent-binding.test.sh +326 -0
  600. package/.agents/tests/fm-remote-secondmate-trace-context.test.sh +310 -0
  601. package/.agents/tests/fm-remote-transport-lanes.test.sh +431 -0
  602. package/.agents/tests/fm-review-diff.test.sh +176 -0
  603. package/.agents/tests/fm-secondmate-harness.test.sh +2600 -0
  604. package/.agents/tests/fm-secondmate-lifecycle-e2e.test.sh +259 -0
  605. package/.agents/tests/fm-secondmate-liveness.test.sh +559 -0
  606. package/.agents/tests/fm-secondmate-reconcile.test.sh +732 -0
  607. package/.agents/tests/fm-secondmate-safety.test.sh +2972 -0
  608. package/.agents/tests/fm-secondmate-sync.test.sh +913 -0
  609. package/.agents/tests/fm-send-inbox-doorbell-live-e2e.test.sh +206 -0
  610. package/.agents/tests/fm-send-inbox.test.sh +352 -0
  611. package/.agents/tests/fm-send-popup-settle.test.sh +167 -0
  612. package/.agents/tests/fm-send-remote-delivery.test.sh +796 -0
  613. package/.agents/tests/fm-send-resolve-key.test.sh +551 -0
  614. package/.agents/tests/fm-send-secondmate-marker-herdr-e2e.test.sh +187 -0
  615. package/.agents/tests/fm-send-secondmate-marker.test.sh +278 -0
  616. package/.agents/tests/fm-send-settle.test.sh +147 -0
  617. package/.agents/tests/fm-send-strict.test.sh +241 -0
  618. package/.agents/tests/fm-session-lock-ancestry.test.sh +365 -0
  619. package/.agents/tests/fm-session-start.test.sh +2515 -0
  620. package/.agents/tests/fm-sessionstart-hook-live-e2e.test.sh +631 -0
  621. package/.agents/tests/fm-sessionstart-instruction-refresh-live-e2e.test.sh +230 -0
  622. package/.agents/tests/fm-sessionstart-nudge.test.sh +1039 -0
  623. package/.agents/tests/fm-shared-captain-inheritance.test.sh +404 -0
  624. package/.agents/tests/fm-spawn-batch.test.sh +148 -0
  625. package/.agents/tests/fm-spawn-dispatch-profile.test.sh +827 -0
  626. package/.agents/tests/fm-spawn-pool-base-freshen.test.sh +440 -0
  627. package/.agents/tests/fm-spawn-worktree-settle.test.sh +147 -0
  628. package/.agents/tests/fm-startup-memory-budget.test.sh +333 -0
  629. package/.agents/tests/fm-startup-network.test.sh +712 -0
  630. package/.agents/tests/fm-stow-cascade.test.sh +370 -0
  631. package/.agents/tests/fm-subagent-pretool-check.test.sh +291 -0
  632. package/.agents/tests/fm-supervision-events.test.sh +156 -0
  633. package/.agents/tests/fm-supervision-instructions.test.sh +189 -0
  634. package/.agents/tests/fm-tangle-guard.test.sh +277 -0
  635. package/.agents/tests/fm-task-delivery.test.sh +420 -0
  636. package/.agents/tests/fm-task-inbox.test.sh +513 -0
  637. package/.agents/tests/fm-teardown-endpoint-safety.test.sh +374 -0
  638. package/.agents/tests/fm-teardown.test.sh +2665 -0
  639. package/.agents/tests/fm-test-fixture-cleanup.test.sh +172 -0
  640. package/.agents/tests/fm-test-fixtures.test.sh +132 -0
  641. package/.agents/tests/fm-test-isolation-proof.test.sh +278 -0
  642. package/.agents/tests/fm-test-run.test.sh +1196 -0
  643. package/.agents/tests/fm-tmux-agent-liveness.test.sh +354 -0
  644. package/.agents/tests/fm-tmux-submit-busy.test.sh +340 -0
  645. package/.agents/tests/fm-tool-update-check.test.sh +1044 -0
  646. package/.agents/tests/fm-trace-context-lib.test.sh +253 -0
  647. package/.agents/tests/fm-trace-context-spawn.test.sh +581 -0
  648. package/.agents/tests/fm-transition-lib.test.sh +54 -0
  649. package/.agents/tests/fm-turnend-guard.test.sh +1822 -0
  650. package/.agents/tests/fm-update.test.sh +304 -0
  651. package/.agents/tests/fm-vendor-auth-probe.test.sh +395 -0
  652. package/.agents/tests/fm-voice-relay.test.sh +4741 -0
  653. package/.agents/tests/fm-wake-daemon-lifecycle-e2e.test.sh +171 -0
  654. package/.agents/tests/fm-wake-drain-open-decisions-cursor.test.sh +356 -0
  655. package/.agents/tests/fm-wake-drain-open-decisions.test.sh +226 -0
  656. package/.agents/tests/fm-wake-drain-unread-status.test.sh +379 -0
  657. package/.agents/tests/fm-wake-queue.test.sh +1224 -0
  658. package/.agents/tests/fm-watch-arm.test.sh +821 -0
  659. package/.agents/tests/fm-watch-checkpoint.test.sh +87 -0
  660. package/.agents/tests/fm-watch-recovery-loop.test.sh +223 -0
  661. package/.agents/tests/fm-watch-triage.test.sh +3889 -0
  662. package/.agents/tests/fm-watcher-lock.test.sh +1133 -0
  663. package/.agents/tests/fm-x-mode.test.sh +3042 -0
  664. package/.agents/tests/gleipnir-guard-pretool-check.test.sh +51 -0
  665. package/.agents/tests/gleipnir-machine-lock.test.sh +130 -0
  666. package/.agents/tests/herdr-test-safety.sh +42 -0
  667. package/.agents/tests/lib.sh +315 -0
  668. package/.agents/tests/remote-herdr-fixture.sh +125 -0
  669. package/.agents/tests/secondmate-helpers.sh +193 -0
  670. package/.agents/tests/smoke.test.sh +93 -0
  671. package/.agents/tests/wake-helpers.sh +338 -0
  672. package/.agents/tests/zellij-test-safety.sh +60 -0
  673. package/.agents/tools/README.md +10 -0
  674. package/.agents/tools/bin/tasks-cli +267 -0
  675. package/.agents/tools/tasks-cli.ts +216 -0
  676. package/AGENTS.md +454 -0
  677. package/CHANGELOG.md +881 -0
  678. package/LICENSE +1 -1
  679. package/NOTICE +63 -0
  680. package/README.md +113 -59
  681. package/RULES/01-domains.md +51 -0
  682. package/RULES/02-agents.md +78 -0
  683. package/RULES/03-houses.md +61 -0
  684. package/RULES/04-hoard.md +65 -0
  685. package/RULES/05-platforms.md +67 -0
  686. package/RULES/06-append-only.md +58 -0
  687. package/RULES/07-config.md +45 -0
  688. package/RULES/08-delivery-gate.md +75 -0
  689. package/RULES/README.md +20 -0
  690. package/bin/README.md +107 -0
  691. package/bin/a2a-mcp.sh +98 -0
  692. package/bin/a2a-serve.py +103 -0
  693. package/bin/a2a-serve.sh +8 -0
  694. package/bin/a2a-talk.sh +50 -0
  695. package/bin/a2abridge-ensure.sh +108 -0
  696. package/bin/agent-run.sh +43 -0
  697. package/bin/agents-config.sh +233 -0
  698. package/bin/apodex-smoke-test.sh +92 -0
  699. package/bin/bifrost-bridge.sh +112 -0
  700. package/bin/bifrost-ingress.sh +77 -0
  701. package/bin/bootstrap-macos.sh +107 -0
  702. package/bin/bootstrap-windows.ps1 +112 -0
  703. package/bin/branch-guard.sh +64 -0
  704. package/bin/brokk +73 -0
  705. package/bin/brokk-classify-lib.sh +1770 -0
  706. package/bin/brokk-lease-lib.sh +222 -0
  707. package/bin/brokk-lease.sh +193 -0
  708. package/bin/brokk-lint.sh +65 -0
  709. package/bin/brokk-send.sh +38 -0
  710. package/bin/brokk-update.sh +9 -0
  711. package/bin/brokk-wake-grant.sh +127 -0
  712. package/bin/brokk-wake-lib.sh +1849 -0
  713. package/bin/changelog-guard.sh +165 -0
  714. package/bin/crash-sense.sh +160 -0
  715. package/bin/desktop-place.sh +224 -0
  716. package/bin/docs-guard.sh +39 -0
  717. package/bin/editor-place.sh +207 -0
  718. package/bin/eindri-acclaim.sh +34 -0
  719. package/bin/eindri-control.sh +28 -0
  720. package/bin/eindri-role.sh +83 -0
  721. package/bin/eindri-seen.sh +41 -0
  722. package/bin/eindri-send.sh +15 -0
  723. package/bin/eindri-start.sh +85 -0
  724. package/bin/eindri-watch.sh +57 -0
  725. package/bin/einherjar-spawn.sh +576 -0
  726. package/bin/eir-doctor.sh +112 -0
  727. package/bin/erindi-brief.sh +271 -0
  728. package/bin/fleet-apply.sh +68 -0
  729. package/bin/github-deploy.sh +81 -0
  730. package/bin/gjallarhorn-expose.sh +102 -0
  731. package/bin/gjallarhorn-notify.sh +58 -0
  732. package/bin/gjallarhorn-purge.sh +54 -0
  733. package/bin/gjallarhorn-tunnel.sh +72 -0
  734. package/bin/gleipnir-lock-lib.sh +284 -0
  735. package/bin/groa-update.sh +122 -0
  736. package/bin/hall-snapshot.sh +92 -0
  737. package/bin/hamr-harness.sh +246 -0
  738. package/bin/heimdall-ssh-keys.sh +374 -0
  739. package/bin/herdr-agents.py +44 -0
  740. package/bin/herdr-ensure.sh +104 -0
  741. package/bin/herdr-run.sh +431 -0
  742. package/bin/hermes-ensure.sh +88 -0
  743. package/bin/hoard-lib.sh +25 -0
  744. package/bin/hodd.sh +78 -0
  745. package/bin/host-sense.sh +199 -0
  746. package/bin/huginn-research-worker.sh +108 -0
  747. package/bin/local-model-lock.sh +51 -0
  748. package/bin/mimir-bridge.py +226 -0
  749. package/bin/mimir-bridge.sh +87 -0
  750. package/bin/mimir-ingest.sh +131 -0
  751. package/bin/mimir.sh +113 -0
  752. package/bin/mjollnir-webhook.sh +59 -0
  753. package/bin/mjollnir.sh +85 -0
  754. package/bin/model-hardware.sh +82 -0
  755. package/bin/model-resolve.sh +147 -0
  756. package/bin/models-detect.sh +178 -0
  757. package/bin/nornir-cron-start.sh +162 -0
  758. package/bin/nornir-job-daily-briefing.sh +191 -0
  759. package/bin/nornir-job-git-sync.sh +152 -0
  760. package/bin/nornir-job-memory-housekeeping.sh +114 -0
  761. package/bin/nornir-job-observer.sh +166 -0
  762. package/bin/nornir-job-skillopt-sleep.sh +76 -0
  763. package/bin/omarchy-hook-install.sh +60 -0
  764. package/bin/omarchy-install.sh +148 -0
  765. package/bin/omarchy-plugins.sh +174 -0
  766. package/bin/omarchy-sense.sh +149 -0
  767. package/bin/perm-guard.sh +30 -0
  768. package/bin/pi-agent.sh +68 -0
  769. package/bin/pi-ensure.sh +77 -0
  770. package/bin/pi-local.sh +37 -0
  771. package/bin/pi-seat.sh +63 -0
  772. package/bin/prereq-ensure.sh +166 -0
  773. package/bin/private-guard.sh +38 -0
  774. package/bin/project-git.sh +55 -0
  775. package/bin/public-guard.sh +70 -0
  776. package/bin/ratatoskr.sh +49 -0
  777. package/bin/realm-lib.sh +32 -0
  778. package/bin/repo-scrub.sh +62 -0
  779. package/bin/rodd-operational-input.sh +250 -0
  780. package/bin/runes-append.sh +198 -0
  781. package/bin/saga-session-start.sh +172 -0
  782. package/bin/saga-sessionstart-run.sh +79 -0
  783. package/bin/saga-wake-drain.sh +41 -0
  784. package/bin/secret-guard.sh +63 -0
  785. package/bin/sessrumnir-ensure.sh +100 -0
  786. package/bin/sessrumnir-sync.sh +237 -0
  787. package/bin/sessrumnir.sh +91 -0
  788. package/bin/skillopt-setup.sh +76 -0
  789. package/bin/skuld-branch-outcome.sh +203 -0
  790. package/bin/skuld-branch-prompt.sh +101 -0
  791. package/bin/smidja-bootstrap.sh +90 -0
  792. package/bin/smidja-observe.sh +86 -0
  793. package/bin/syn-arm-pretool-check.sh +57 -0
  794. package/bin/syn-asset-pretool-check.sh +76 -0
  795. package/bin/syn-cd-pretool-check.sh +28 -0
  796. package/bin/syn-guard-pretool-check.sh +83 -0
  797. package/bin/syn-turnend-guard.sh +36 -0
  798. package/bin/syn-watch-arm.sh +99 -0
  799. package/bin/tailscale-sync.sh +190 -0
  800. package/bin/telegram-bot.sh +69 -0
  801. package/bin/toolchain.sh +74 -0
  802. package/bin/utgard.sh +111 -0
  803. package/bin/valhalla.sh +115 -0
  804. package/bin/valknut-load.sh +260 -0
  805. package/bin/vor-crew-state.sh +124 -0
  806. package/bin/wedge-notify.sh +47 -0
  807. package/bin/workspace-provision.sh +80 -0
  808. package/bin/workspace-rag.sh +150 -0
  809. package/bin/wyrd-db.sh +47 -0
  810. package/bin/yggdrasil.sh +152 -0
  811. package/bin/ymir-edit.sh +145 -0
  812. package/bin/ymir-install.sh +641 -0
  813. package/bin/ymir-invite.sh +93 -0
  814. package/bin/ymir-isolation.sh +88 -0
  815. package/bin/ymir-migrate.sh +61 -0
  816. package/bin/ymir-platform.sh +348 -0
  817. package/bin/ymir-say.sh +97 -0
  818. package/bin/ymir-setup-auth.sh +108 -0
  819. package/bin/ymir-validate.sh +173 -0
  820. package/bin/ymir.js +74 -16
  821. package/docs/Architecture.md +339 -0
  822. package/docs/design.md +351 -0
  823. package/docs/installations/README.md +63 -0
  824. package/docs/installations/ymir-home.md +93 -0
  825. package/docs/integration.md +105 -0
  826. package/docs/lore.md +1056 -0
  827. package/docs/research/agent-harnesses.md +290 -0
  828. package/docs/runbooks/README.md +19 -0
  829. package/docs/runbooks/a2a.md +91 -0
  830. package/docs/runbooks/agent-permissions.md +99 -0
  831. package/docs/runbooks/agents.md +57 -0
  832. package/docs/runbooks/models.md +69 -0
  833. package/docs/runbooks/realm-onboarding.md +60 -0
  834. package/docs/runbooks/secrets-and-hoard.md +60 -0
  835. package/docs/runbooks/updates-and-migrations.md +110 -0
  836. package/docs/runbooks/worktrees-isolation.md +72 -0
  837. package/docs/session-start.md +105 -0
  838. package/docs/skillopt-integration.md +321 -0
  839. package/docs/sync-system.md +66 -0
  840. package/docs/workspaces.md +104 -0
  841. package/docs/ymir-rut.md +260 -0
  842. package/package.json +44 -14
  843. package/packaging/build.sh +74 -0
  844. package/packaging/macos/Ymir Installer.command +43 -0
  845. package/packaging/windows/ymir-setup.nsi +74 -0
  846. package/scripts/README.md +22 -0
  847. package/scripts/electron.sh +210 -0
  848. package/scripts/start.sh +167 -0
  849. package/scripts/stop.sh +113 -0
  850. 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[@]}"