@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,458 @@
1
+ #!/usr/bin/env bash
2
+ # Refresh project clones: fast-forward the checked-out local default branch to
3
+ # origin/<default> when safe, and prune local branches whose upstream tracking
4
+ # branch is gone (the remote branch was deleted, i.e. its PR merged) and that no
5
+ # worktree still needs.
6
+ # Self-heals the one unambiguously safe drift: a clean, detached HEAD that holds
7
+ # no unique commits (it is an ancestor of origin/<default>) and whose <default>
8
+ # branch is free to check out is re-attached and then fast-forwarded ("recovered:").
9
+ # Every other off-default state - a non-default named branch, a detached HEAD with
10
+ # unique commits, a dirty tree, or a diverged default - may hold real work, so it
11
+ # is left untouched and reported as a quantified, loud "STUCK: ... N commits behind
12
+ # ... - needs attention" warning rather than a quiet drift. Nothing is ever forced,
13
+ # stashed, or discarded.
14
+ # Still skips (benignly) local-only/no-origin projects, missing remotes/branches,
15
+ # and fetch failures.
16
+ # A candidate under projects/ must be the root of its own work tree: git discovery
17
+ # walks up, so a plain nested directory would otherwise resolve to the enclosing
18
+ # repository (the firstmate checkout) and be synced under that directory's label.
19
+ # Anything else is reported as "skipped: not a clone root" naming the repository
20
+ # that would have been touched.
21
+ # Pruning never deletes the checked-out branch or a branch that still has a
22
+ # worktree, so it cannot discard unlanded work; set FM_FLEET_PRUNE=0 to disable it.
23
+ # When the fetch fails on an orphaned .git/packed-refs.lock (left by a ref rewrite
24
+ # killed mid-write - e.g. a timed-out bootstrap sync or a teardown process kill),
25
+ # it is retried with a bounded wait and removed only when provably stale; see
26
+ # fetch_with_packed_refs_lock_guard and the FM_FLEET_SYNC_PACKED_REFS_LOCK_* knobs.
27
+ # Usage: fm-fleet-sync.sh [<project-dir-or-name>]
28
+ # The single-project form accepts either a path (absolute, or relative to the
29
+ # caller's cwd) or a bare "<name>"/"projects/<name>" form, resolved against
30
+ # this home's projects dir ($FM_HOME/projects, or $FM_PROJECTS_OVERRIDE).
31
+ # Bare names and "projects/<name>" forms prefer this home's projects dir before
32
+ # falling back to an explicit path. Example: from anywhere,
33
+ # `fm-fleet-sync.sh dotfiles-private` syncs just that one clone, same as
34
+ # passing its full projects/dotfiles-private path.
35
+ set -eu
36
+
37
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
38
+ FM_ROOT="${FM_ROOT_OVERRIDE:-$(cd "$SCRIPT_DIR/.." && pwd)}"
39
+ FM_HOME="${FM_HOME:-${FM_ROOT_OVERRIDE:-$FM_ROOT}}"
40
+ PROJECTS="${FM_PROJECTS_OVERRIDE:-$FM_HOME/projects}"
41
+ # shellcheck source=bin/fm-lock-lib.sh
42
+ . "$SCRIPT_DIR/fm-lock-lib.sh"
43
+ # Inert unless FM_TIMING_LOG names a file; only the deferred network stage sets it.
44
+ # shellcheck source=bin/fm-timing-lib.sh
45
+ . "$SCRIPT_DIR/fm-timing-lib.sh"
46
+ FM_LOCK_LOG_PREFIX=fleet-sync
47
+ "$FM_ROOT/bin/fm-guard.sh" || true
48
+
49
+ # Bounded recovery for an orphaned .git/packed-refs.lock. A git ref rewrite
50
+ # (fetch --prune, branch -D, pack-refs) killed after creating the lock but before
51
+ # renaming it - e.g. bootstrap's fleet-sync timeout kill, or teardown's process
52
+ # kills - leaves a lock that makes the next sync's fetch fail with Git's
53
+ # "Unable to create '...packed-refs.lock': File exists". These knobs bound the
54
+ # patience-then-provably-stale-clear recovery; see fetch_with_packed_refs_lock_guard.
55
+ FLEET_SYNC_PACKED_REFS_LOCK_RETRIES=${FM_FLEET_SYNC_PACKED_REFS_LOCK_RETRIES:-3}
56
+ FLEET_SYNC_PACKED_REFS_LOCK_RETRY_WAIT_SECS=${FM_FLEET_SYNC_PACKED_REFS_LOCK_RETRY_WAIT_SECS:-1}
57
+ FLEET_SYNC_PACKED_REFS_LOCK_AGE_SECS=${FM_FLEET_SYNC_PACKED_REFS_LOCK_AGE_SECS:-30}
58
+ case "$FLEET_SYNC_PACKED_REFS_LOCK_RETRIES" in ''|*[!0-9]*) FLEET_SYNC_PACKED_REFS_LOCK_RETRIES=3 ;; esac
59
+ case "$FLEET_SYNC_PACKED_REFS_LOCK_AGE_SECS" in ''|*[!0-9]*) FLEET_SYNC_PACKED_REFS_LOCK_AGE_SECS=30 ;; esac
60
+ if ! [[ "$FLEET_SYNC_PACKED_REFS_LOCK_RETRY_WAIT_SECS" =~ ^([0-9]+([.][0-9]*)?|[.][0-9]+)$ ]]; then
61
+ echo "fleet-sync: invalid packed-refs lock retry wait '$FLEET_SYNC_PACKED_REFS_LOCK_RETRY_WAIT_SECS'; using 1s" >&2
62
+ FLEET_SYNC_PACKED_REFS_LOCK_RETRY_WAIT_SECS=1
63
+ fi
64
+
65
+ usage() {
66
+ echo "usage: fm-fleet-sync.sh [<project-dir-or-name>]" >&2
67
+ }
68
+
69
+ if [ "${1:-}" = "--help" ] || [ "${1:-}" = "-h" ]; then
70
+ usage
71
+ exit 0
72
+ fi
73
+ [ $# -le 1 ] || { usage; exit 1; }
74
+
75
+ project_label() {
76
+ case "$PROJ" in
77
+ "$PROJECTS"/*) basename "$PROJ" ;;
78
+ projects/*) basename "$PROJ" ;;
79
+ *) printf '%s\n' "$PROJ" ;;
80
+ esac
81
+ }
82
+
83
+ # resolve_project_arg <arg>: accept a path (used as-is when it already exists)
84
+ # or a bare/"projects/<name>" project name, resolved against $PROJECTS. Falls
85
+ # back to the original argument unresolved so a genuinely bad path still hits
86
+ # sync_project's existing "not a directory" skip.
87
+ resolve_project_arg() {
88
+ local arg=$1 candidate
89
+ case "$arg" in
90
+ projects/*)
91
+ candidate="$PROJECTS/${arg#projects/}"
92
+ if [ -d "$candidate" ]; then
93
+ printf '%s\n' "$candidate"
94
+ return 0
95
+ fi
96
+ ;;
97
+ */*)
98
+ if [ -d "$arg" ]; then
99
+ printf '%s\n' "$arg"
100
+ return 0
101
+ fi
102
+ ;;
103
+ *)
104
+ candidate="$PROJECTS/$arg"
105
+ if [ -d "$candidate" ]; then
106
+ printf '%s\n' "$candidate"
107
+ return 0
108
+ fi
109
+ if [ -d "$arg" ]; then
110
+ printf '%s\n' "$arg"
111
+ return 0
112
+ fi
113
+ ;;
114
+ esac
115
+ printf '%s\n' "$arg"
116
+ }
117
+
118
+ default_branch() {
119
+ local ref branch
120
+ ref=$(git -C "$PROJ" symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null || true)
121
+ if [ -n "$ref" ]; then
122
+ echo "${ref#origin/}"
123
+ return 0
124
+ fi
125
+ for branch in main master; do
126
+ if git -C "$PROJ" show-ref --verify --quiet "refs/heads/$branch"; then
127
+ echo "$branch"
128
+ return 0
129
+ fi
130
+ done
131
+ return 1
132
+ }
133
+
134
+ first_line() {
135
+ printf '%s\n' "$1" | sed -n '1s/[[:space:]]\{1,\}/ /g;1p'
136
+ }
137
+
138
+ # True when git stderr shows the packed-refs.lock "File exists" race. The lock
139
+ # path can appear anywhere in the message (git prefixes it with the failed ref op,
140
+ # e.g. "could not delete reference ...:"). Other "File exists" errors must not match.
141
+ is_packed_refs_lock_error() {
142
+ printf '%s\n' "$1" | grep -Eq "Unable to create ['\"].*packed-refs\\.lock['\"]: File exists"
143
+ }
144
+
145
+ # Absolute path to $PROJ's packed-refs.lock, or empty when it cannot be resolved.
146
+ packed_refs_lock_path() {
147
+ local lock abs
148
+ lock=$(git -C "$PROJ" rev-parse --git-path packed-refs.lock 2>/dev/null) || return 1
149
+ [ -n "$lock" ] || return 1
150
+ case "$lock" in
151
+ /*) printf '%s\n' "$lock" ;;
152
+ *)
153
+ abs=$(cd "$PROJ" && pwd -P) || return 1
154
+ printf '%s/%s\n' "$abs" "$lock"
155
+ ;;
156
+ esac
157
+ }
158
+
159
+ # Run `git -C "$PROJ" fetch origin --prune --quiet`, tolerating an orphaned
160
+ # packed-refs.lock left by a killed ref rewrite. Sets FETCH_OUTPUT to the git
161
+ # command's combined output and returns its exit status. On the packed-refs.lock
162
+ # signature ONLY: retry up to FLEET_SYNC_PACKED_REFS_LOCK_RETRIES times (a
163
+ # transient lock self-clears as the owning process exits), then - only if the lock
164
+ # is provably stale per fm-lock-lib.sh (still present, mtime age past the
165
+ # threshold, no lsof holder of the lock or the clone worktree $PROJ) - remove it
166
+ # and retry once more. A live lock, an unprovable one, or any other failure keeps
167
+ # today's behavior. Every wait, retry, and removal prints to stderr, and a
168
+ # successful recovery also prints one "$label: recovered: ..." summary to stdout so
169
+ # a session-start refresh (which discards fleet-sync stderr) still surfaces it.
170
+ fetch_with_packed_refs_lock_guard() {
171
+ local rc attempt=0 lock lock_desc
172
+ FETCH_OUTPUT=$(git -C "$PROJ" fetch origin --prune --quiet 2>&1); rc=$?
173
+ [ "$rc" -eq 0 ] && return 0
174
+ is_packed_refs_lock_error "$FETCH_OUTPUT" || return "$rc"
175
+
176
+ lock=$(packed_refs_lock_path) || lock=""
177
+ lock_desc=${lock:-packed-refs.lock}
178
+ while [ "$attempt" -lt "$FLEET_SYNC_PACKED_REFS_LOCK_RETRIES" ]; do
179
+ attempt=$(( attempt + 1 ))
180
+ echo "$label: fetch blocked by packed-refs lock ($lock_desc); waiting ${FLEET_SYNC_PACKED_REFS_LOCK_RETRY_WAIT_SECS}s and retrying ($attempt/${FLEET_SYNC_PACKED_REFS_LOCK_RETRIES}) (owning process may be exiting)" >&2
181
+ sleep "$FLEET_SYNC_PACKED_REFS_LOCK_RETRY_WAIT_SECS"
182
+ FETCH_OUTPUT=$(git -C "$PROJ" fetch origin --prune --quiet 2>&1); rc=$?
183
+ if [ "$rc" -eq 0 ]; then
184
+ echo "$label: fetch succeeded on retry; packed-refs lock cleared on its own" >&2
185
+ # One stdout summary so a session-start refresh (which discards fleet-sync
186
+ # stderr and relays only stdout) still surfaces the recovery.
187
+ echo "$label: recovered: packed-refs lock cleared on its own during retry"
188
+ return 0
189
+ fi
190
+ is_packed_refs_lock_error "$FETCH_OUTPUT" || return "$rc"
191
+ done
192
+
193
+ # Retries exhausted and still the lock signature. Clear ONLY if provably stale.
194
+ # The companion liveness dir is $PROJ (the clone worktree): a live `git -C "$PROJ"`
195
+ # keeps its cwd there even in the narrow window after it closes packed-refs.lock
196
+ # and before it exits, so lsof on $PROJ still catches a holder the lock-file check
197
+ # alone would miss.
198
+ lock=$(packed_refs_lock_path) || lock=""
199
+ if [ -n "$lock" ] && [ -e "$lock" ]; then
200
+ if fm_lock_is_provably_stale "$lock" "$PROJ" "$FLEET_SYNC_PACKED_REFS_LOCK_AGE_SECS"; then
201
+ if ! rm -f "$lock"; then
202
+ echo "$label: failed to remove provably-stale packed-refs lock $lock; leaving it in place" >&2
203
+ return "$rc"
204
+ fi
205
+ echo "$label: removed provably-stale packed-refs lock $lock (age >= ${FLEET_SYNC_PACKED_REFS_LOCK_AGE_SECS}s, no live holder) and retrying fetch" >&2
206
+ FETCH_OUTPUT=$(git -C "$PROJ" fetch origin --prune --quiet 2>&1); rc=$?
207
+ if [ "$rc" -eq 0 ]; then
208
+ echo "$label: fetch succeeded after stale packed-refs lock cleanup" >&2
209
+ echo "$label: recovered: removed a stale packed-refs lock (no live holder)"
210
+ return 0
211
+ fi
212
+ return "$rc"
213
+ fi
214
+ echo "$label: fetch blocked by packed-refs lock $lock that persisted across ${FLEET_SYNC_PACKED_REFS_LOCK_RETRIES} retries and is not provably stale (may belong to a live process); leaving it in place" >&2
215
+ return "$rc"
216
+ fi
217
+ echo "$label: fetch packed-refs lock signature persisted across ${FLEET_SYNC_PACKED_REFS_LOCK_RETRIES} retries even after the lock file disappeared" >&2
218
+ return "$rc"
219
+ }
220
+
221
+ prune_gone_branches() {
222
+ # Delete local branches whose upstream tracking branch is gone - the remote
223
+ # branch was deleted, which in this fleet means its PR merged - as long as
224
+ # nothing still needs them. Never the checked-out branch, and never a branch
225
+ # that still has a worktree (a live or not-yet-torn-down task). "Gone" plus
226
+ # "no worktree" already proves the work landed: teardown removes a branch's
227
+ # worktree only after confirming the work reached the remote. We deliberately
228
+ # do NOT also require the branch to be an ancestor of origin/<default> - PRs in
229
+ # this fleet are squash-merged, so a merged branch is never an ancestor and
230
+ # such a check would prune nothing. The no-worktree guard is the real safety
231
+ # net. Set FM_FLEET_PRUNE=0 to skip pruning entirely.
232
+ [ "${FM_FLEET_PRUNE:-1}" != "0" ] || return 0
233
+
234
+ local worktree_branches current refline branch track
235
+ worktree_branches=$(git -C "$PROJ" worktree list --porcelain 2>/dev/null \
236
+ | sed -n 's#^branch refs/heads/##p')
237
+ current=$(git -C "$PROJ" symbolic-ref --quiet --short HEAD 2>/dev/null || true)
238
+
239
+ while IFS= read -r refline; do
240
+ branch=${refline%% *}
241
+ track=${refline#* }
242
+ [ "$track" = "[gone]" ] || continue
243
+ [ -n "$branch" ] || continue
244
+ [ "$branch" != "$current" ] || continue
245
+ if printf '%s\n' "$worktree_branches" | grep -Fxq -- "$branch"; then
246
+ continue
247
+ fi
248
+ if git -C "$PROJ" branch -D -- "$branch" >/dev/null 2>&1; then
249
+ echo "$label: pruned $branch"
250
+ fi
251
+ done < <(git -C "$PROJ" for-each-ref \
252
+ --format='%(refname:short) %(upstream:track)' refs/heads 2>/dev/null)
253
+ }
254
+
255
+ # True when some worktree of $PROJ has $DEFAULT checked out (so we cannot attach
256
+ # to it here). The current worktree is detached when this is consulted, so any
257
+ # match is necessarily another worktree.
258
+ default_checked_out_elsewhere() {
259
+ git -C "$PROJ" worktree list --porcelain 2>/dev/null \
260
+ | sed -n 's#^branch refs/heads/##p' \
261
+ | grep -Fxq -- "$DEFAULT"
262
+ }
263
+
264
+ local_default_safe_for_recovery() {
265
+ ! git -C "$PROJ" rev-parse --verify --quiet "$DEFAULT^{commit}" >/dev/null \
266
+ || git -C "$PROJ" merge-base --is-ancestor "$DEFAULT" "$BASE" 2>/dev/null
267
+ }
268
+
269
+ # Human-readable name for the unsafe state the clone is in, used in the STUCK
270
+ # warning. Reads $cur (current branch, empty when detached), $dirty, and the
271
+ # HEAD-vs-$BASE ancestry to pick the most informative description.
272
+ stuck_state() {
273
+ local s
274
+ if [ -n "$cur" ]; then
275
+ s="branch $cur"
276
+ elif [ "$dirty" = yes ]; then
277
+ s="detached HEAD"
278
+ elif ! git -C "$PROJ" merge-base --is-ancestor HEAD "$BASE" 2>/dev/null; then
279
+ s="detached HEAD with unique commits"
280
+ elif default_checked_out_elsewhere; then
281
+ s="detached HEAD ($DEFAULT checked out in another worktree)"
282
+ elif ! local_default_safe_for_recovery; then
283
+ s="detached HEAD (local $DEFAULT diverged from $BASE)"
284
+ else
285
+ s="detached HEAD"
286
+ fi
287
+ [ "$dirty" = no ] || s="$s with uncommitted changes"
288
+ printf '%s\n' "$s"
289
+ }
290
+
291
+ # Loud, quantified report for a clone we deliberately leave untouched. Includes
292
+ # how far behind origin/<default> it is, so a chronically-stuck clone is visibly
293
+ # distinct from a benign one-off skip.
294
+ report_stuck() {
295
+ local state=$1 behind
296
+ behind=$(git -C "$PROJ" rev-list --count "HEAD..$BASE" 2>/dev/null) || behind="?"
297
+ echo "$label: STUCK: on $state, $behind commits behind $BASE - needs attention"
298
+ }
299
+
300
+ sync_project() {
301
+ PROJ=$1
302
+ label=$(project_label)
303
+
304
+ if [ ! -d "$PROJ" ]; then
305
+ echo "$label: skipped: not a directory"
306
+ return 0
307
+ fi
308
+ # Git repository discovery walks UP from $PROJ, so a plain directory merely
309
+ # nested inside a repository - a worktree container left under projects/, say -
310
+ # resolves to the ENCLOSING repository, which in a firstmate home is the
311
+ # firstmate checkout itself. Every later `git -C "$PROJ"` would then read, prune
312
+ # and fast-forward that repository under this project's label, turning a routine
313
+ # refresh into an unrequested self-update reported as a project sync. Require
314
+ # $PROJ to be the root of its own work tree before any other git command runs.
315
+ proj_top=$(git -C "$PROJ" rev-parse --show-toplevel 2>/dev/null) || proj_top=""
316
+ if [ -z "$proj_top" ]; then
317
+ echo "$label: skipped: not a git repo"
318
+ return 0
319
+ fi
320
+ # Both sides are physical paths (git resolves --show-toplevel through symlinks),
321
+ # so a symlinked clone dir still compares equal to its own root.
322
+ proj_abs=$(cd "$PROJ" && pwd -P) || proj_abs=""
323
+ if [ "$proj_top" != "$proj_abs" ]; then
324
+ echo "$label: skipped: not a clone root (git would act on $proj_top)"
325
+ return 0
326
+ fi
327
+ mode_line=$("$FM_ROOT/bin/fm-project-mode.sh" "$label" 2>/dev/null || echo "no-mistakes off")
328
+ mode=${mode_line%% *}
329
+ if [ "$mode" = "local-only" ]; then
330
+ echo "$label: skipped: local-only project"
331
+ return 0
332
+ fi
333
+ if ! git -C "$PROJ" remote get-url origin >/dev/null 2>&1; then
334
+ echo "$label: skipped: no origin remote"
335
+ return 0
336
+ fi
337
+
338
+ if ! fetch_with_packed_refs_lock_guard; then
339
+ reason="fetch failed"
340
+ if [ -n "$FETCH_OUTPUT" ]; then
341
+ reason="$reason: $(first_line "$FETCH_OUTPUT")"
342
+ fi
343
+ echo "$label: skipped: $reason"
344
+ return 0
345
+ fi
346
+
347
+ prune_gone_branches || true
348
+
349
+ DEFAULT=$(default_branch) || {
350
+ echo "$label: skipped: cannot determine default branch"
351
+ return 0
352
+ }
353
+ BASE="origin/$DEFAULT"
354
+ if ! git -C "$PROJ" rev-parse --verify --quiet "$BASE^{commit}" >/dev/null; then
355
+ echo "$label: skipped: $BASE does not exist"
356
+ return 0
357
+ fi
358
+
359
+ cur=$(git -C "$PROJ" symbolic-ref --short HEAD 2>/dev/null || echo "")
360
+ dirty=no
361
+ [ -z "$(git -C "$PROJ" status --porcelain 2>/dev/null | head -1)" ] || dirty=yes
362
+ recovered=no
363
+
364
+ if [ "$cur" != "$DEFAULT" ]; then
365
+ # Off the default branch. Auto-recover only the one unambiguously safe drift:
366
+ # a clean, detached HEAD that holds no unique commits (it is an ancestor of
367
+ # origin/<default>) and whose <default> branch is free to check out here.
368
+ # Re-attaching to an already-published commit strands nothing, and the
369
+ # fast-forward path below then catches the clone up. Anything else - a
370
+ # non-default named branch, a detached HEAD with unique commits, a dirty tree,
371
+ # or <default> already checked out elsewhere - may hold real work, so it is
372
+ # reported loudly and left untouched.
373
+ if [ -z "$cur" ] && [ "$dirty" = no ] \
374
+ && git -C "$PROJ" merge-base --is-ancestor HEAD "$BASE" 2>/dev/null \
375
+ && ! default_checked_out_elsewhere \
376
+ && local_default_safe_for_recovery; then
377
+ if ! git -C "$PROJ" checkout --quiet "$DEFAULT" 2>/dev/null; then
378
+ report_stuck "$(stuck_state)"
379
+ return 0
380
+ fi
381
+ recovered=yes
382
+ cur=$DEFAULT
383
+ else
384
+ report_stuck "$(stuck_state)"
385
+ return 0
386
+ fi
387
+ elif [ "$dirty" = yes ]; then
388
+ # On the default branch but with uncommitted changes we must not disturb.
389
+ report_stuck "$(stuck_state)"
390
+ return 0
391
+ fi
392
+
393
+ if ! git -C "$PROJ" rev-parse --verify --quiet "$DEFAULT^{commit}" >/dev/null; then
394
+ echo "$label: skipped: local $DEFAULT does not exist"
395
+ return 0
396
+ fi
397
+
398
+ local_rev=$(git -C "$PROJ" rev-parse "$DEFAULT") || {
399
+ echo "$label: skipped: cannot read local $DEFAULT"
400
+ return 0
401
+ }
402
+ remote_rev=$(git -C "$PROJ" rev-parse "$BASE") || {
403
+ echo "$label: skipped: cannot read $BASE"
404
+ return 0
405
+ }
406
+ if [ "$local_rev" = "$remote_rev" ]; then
407
+ if [ "$recovered" = yes ]; then
408
+ echo "$label: recovered: re-attached $DEFAULT (already current)"
409
+ else
410
+ echo "$label: already current"
411
+ fi
412
+ return 0
413
+ fi
414
+ if ! git -C "$PROJ" merge-base --is-ancestor "$DEFAULT" "$BASE"; then
415
+ report_stuck "diverged $DEFAULT"
416
+ return 0
417
+ fi
418
+
419
+ before=$(git -C "$PROJ" rev-parse --short "$DEFAULT") || {
420
+ echo "$label: skipped: cannot read local $DEFAULT"
421
+ return 0
422
+ }
423
+ if ! merge_output=$(git -C "$PROJ" merge --ff-only "$BASE" 2>&1); then
424
+ reason="fast-forward failed"
425
+ if [ -n "$merge_output" ]; then
426
+ reason="$reason: $(first_line "$merge_output")"
427
+ fi
428
+ echo "$label: skipped: $reason"
429
+ return 0
430
+ fi
431
+ after=$(git -C "$PROJ" rev-parse --short "$DEFAULT") || {
432
+ echo "$label: skipped: fast-forward completed but cannot read local $DEFAULT"
433
+ return 0
434
+ }
435
+ if [ "$recovered" = yes ]; then
436
+ echo "$label: recovered: re-attached $DEFAULT, synced $before..$after"
437
+ else
438
+ echo "$label: synced $before..$after"
439
+ fi
440
+ return 0
441
+ }
442
+
443
+ if [ $# -eq 1 ]; then
444
+ sync_project "$(resolve_project_arg "$1")"
445
+ exit 0
446
+ fi
447
+
448
+ [ -d "$PROJECTS" ] || exit 0
449
+ for proj in "$PROJECTS"/*; do
450
+ [ -e "$proj" ] || continue
451
+ [ -d "$proj" ] || continue
452
+ # Per-clone elapsed, so a fleet refresh that runs long names WHICH clone cost
453
+ # the time instead of only its total. Recording is a no-op unless the deferred
454
+ # network stage asked for it.
455
+ __fm_timing_stamp=$(fm_timing_now_ms)
456
+ sync_project "$proj"
457
+ fm_timing_record clone sync "$__fm_timing_stamp" "$(basename "$proj")"
458
+ done
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env bash
2
+ # fm-fleet-view.sh - human renderer over fm-fleet-snapshot.sh.
3
+ #
4
+ # This command intentionally does not parse fleet state itself.
5
+ # It shells out to fm-fleet-snapshot.sh --json and renders that stable
6
+ # structured contract for humans.
7
+ set -u
8
+
9
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10
+
11
+ usage() {
12
+ cat <<'EOF'
13
+ usage: fm-fleet-view.sh [--json]
14
+
15
+ Render a human fleet view from fm-fleet-snapshot.sh.
16
+ Use --json to print the underlying snapshot.
17
+ EOF
18
+ }
19
+
20
+ case "${1:-}" in
21
+ -h|--help) usage; exit 0 ;;
22
+ --json) "$SCRIPT_DIR/fm-fleet-snapshot.sh" --json; exit $? ;;
23
+ "") ;;
24
+ *) usage >&2; exit 2 ;;
25
+ esac
26
+
27
+ command -v jq >/dev/null 2>&1 || { echo "fm-fleet-view: jq not found" >&2; exit 1; }
28
+
29
+ SNAPSHOT=$("$SCRIPT_DIR/fm-fleet-snapshot.sh" --json) || exit $?
30
+
31
+ printf '%s\n' "$SNAPSHOT" | jq -r '
32
+ def dash($v): if $v == null or $v == "" then "-" else $v end;
33
+ def endpoint_exists($t):
34
+ if $t.endpoint.exists == null then "unknown"
35
+ elif $t.endpoint.exists then "present"
36
+ else "absent" end;
37
+ def endpoint_of($t):
38
+ if $t.kind == "secondmate" then "\(endpoint_exists($t)) / \($t.endpoint.agent_alive)"
39
+ else endpoint_exists($t) end;
40
+ def artifact($t):
41
+ if $t.pr.url != null then $t.pr.url
42
+ elif $t.paths.report.present then $t.paths.report.path
43
+ else "-" end;
44
+ def path_of($t):
45
+ if $t.paths.home.present then $t.paths.home.path
46
+ elif $t.paths.home.path != null then $t.paths.home.path + " (absent)"
47
+ elif $t.paths.worktree.present then $t.paths.worktree.path
48
+ elif $t.paths.worktree.path != null then $t.paths.worktree.path + " (absent)"
49
+ else "-" end;
50
+ def action_of($t):
51
+ if $t.kind == "secondmate" then "\($t.actions.send) - \($t.actions.watch)"
52
+ else $t.actions.watch end;
53
+ def task_row($t):
54
+ "| \($t.id) | \($t.current_state.state) / \($t.current_state.source) | \($t.kind) | \(dash($t.backlog.repo // $t.project)) | \($t.backend) | \(endpoint_of($t)) | \(artifact($t)) | \(path_of($t)) | \(action_of($t)) |";
55
+ def blocker($r):
56
+ if ($r.blocked_by // "") == "" then "-"
57
+ elif ($r.blocked_reason // "") == "" then $r.blocked_by
58
+ else "\($r.blocked_by) - \($r.blocked_reason)" end;
59
+ def backlog_row($r):
60
+ "| \($r.id // "-") | \(dash($r.title // $r.raw)) | \(dash($r.repo)) | \(dash($r.kind)) | \(blocker($r)) | \(dash($r.pr_url // $r.report_path // $r.local_note)) |";
61
+
62
+ "# Fleet View",
63
+ "",
64
+ "Schema: \(.schema)",
65
+ "Home: \(.fm_home)",
66
+ "",
67
+ "## Under Way",
68
+ (if (.tasks | length) == 0 then
69
+ "No live task metadata found."
70
+ else
71
+ "| ID | Current | Kind | Repo/Project | Backend | Endpoint | Artifact | Path | Watch / return channel |",
72
+ "| --- | --- | --- | --- | --- | --- | --- | --- | --- |",
73
+ (.tasks[] | task_row(.))
74
+ end),
75
+ "",
76
+ "## Queued",
77
+ (if ([.backlog.records[]? | select(.state == "queued")] | length) == 0 then
78
+ "No queued backlog records found."
79
+ else
80
+ "| ID | Title | Repo | Kind | Blocked By | Artifact |",
81
+ "| --- | --- | --- | --- | --- | --- |",
82
+ (.backlog.records[] | select(.state == "queued") | backlog_row(.))
83
+ end),
84
+ "",
85
+ "## Done",
86
+ (if ([.backlog.records[]? | select(.state == "done")] | length) == 0 then
87
+ "No done backlog records found."
88
+ else
89
+ "| ID | Title | Repo | Kind | Blocked By | Artifact |",
90
+ "| --- | --- | --- | --- | --- | --- |",
91
+ (.backlog.records[] | select(.state == "done") | backlog_row(.))
92
+ end),
93
+ "",
94
+ "## Secondmates",
95
+ .secondmate_guidance.note
96
+ '
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env bash
2
+ # fm-gate-refuse-lib.sh - fail-closed refusal that keeps a no-mistakes GATE agent
3
+ # out of firstmate's fleet lifecycle.
4
+ #
5
+ # The hazard (data/nm-gate-ambient-authority-containment-c3/report.md): a
6
+ # no-mistakes gate agent runs inside a firstmate checkout with a free shell, so
7
+ # it auto-loads firstmate's AGENTS.md, adopts the captain identity, and - seeing
8
+ # crew "in flight" - reaches for fm-spawn.sh/fm-send.sh/fm-teardown.sh to
9
+ # "delegate" and "reconcile" the shared worktree. It has real capability because
10
+ # those entrypoints self-locate their home and never knew a gate context existed.
11
+ #
12
+ # no-mistakes owns the authority-removal half (it neutralizes the project
13
+ # instructions and stamps NO_MISTAKES_GATE into the gate agent's environment).
14
+ # THIS is the firstmate capability-removal half: an enforceable script refusal,
15
+ # not a prose rule the neutralized agent would never read. It is sourced at the
16
+ # top of the three fleet-lifecycle entrypoints and called before any fleet
17
+ # mutation, so a gate agent that still reaches for the fleet is stopped cold.
18
+ #
19
+ # Two independent signals, either of which refuses (fail closed):
20
+ #
21
+ # 1. NO_MISTAKES_GATE set - the durable env marker no-mistakes stamps into every
22
+ # gate agent. This is the primary signal and covers a relocated NM_HOME.
23
+ # 2. The current worktree's git-common-dir resolves under a no-mistakes gate
24
+ # repo (.../.no-mistakes/repos/*.git) - the UNSPOOFABLE backstop. It derives
25
+ # from the checkout's real filesystem location, which the agent cannot
26
+ # relocate without breaking the gate's own git operations, so it still
27
+ # refuses even if the agent tampered NO_MISTAKES_GATE away. Its limit: the
28
+ # literal-path match only fires for the default NM_HOME (~/.no-mistakes); a
29
+ # relocated NM_HOME is covered by signal 1.
30
+ #
31
+ # A NORMAL firstmate session - a real primary checkout, a real treehouse/Orca
32
+ # crew worktree - has NEITHER signal and is COMPLETELY unaffected: the function
33
+ # returns 0 and the lifecycle proceeds exactly as before.
34
+ #
35
+ # This mirrors the unspoofable-marker precedent in bin/fm-marker-lib.sh: a signal
36
+ # the agent cannot forge, keyed on at a chokepoint, keeping the pattern familiar
37
+ # to firstmate maintainers. It layers ABOVE no-mistakes' separately-shipping
38
+ # HEAD-continuity guard, which remains the adversarial/residual backstop.
39
+ #
40
+ # TEST-HARNESS ESCAPE HATCH (FM_GATE_REFUSE_BYPASS=1): firstmate's own test suite
41
+ # must exercise the REAL fm-spawn/fm-send/fm-teardown, but the no-mistakes gate
42
+ # runs that suite FROM a gate worktree (cwd git-common-dir under
43
+ # .no-mistakes/repos/*.git, and possibly NO_MISTAKES_GATE set) - the exact
44
+ # environment this guard refuses. So both signals would fire during firstmate's
45
+ # own validation and break unrelated tests. FM_GATE_REFUSE_BYPASS=1 makes the
46
+ # guard a no-op; firstmate's shared test helpers (tests/lib.sh and the backend
47
+ # safety helpers) export it, so every test that drives these scripts against its
48
+ # temp-sandbox fleet is exempt. This does NOT weaken the boundary against the
49
+ # real hazard: the threat is a CONFUSED-not-adversarial gate agent that runs
50
+ # bin/fm-spawn.sh directly after adopting firstmate's identity - it never sources
51
+ # firstmate's test helpers, so it never carries the bypass; and the adversarial
52
+ # case (an agent that would deliberately set it) is covered by no-mistakes'
53
+ # neutral-execution-context and the HEAD-continuity guard. The dedicated
54
+ # tests/fm-gate-refuse.test.sh strips the bypass so it still verifies real refusal.
55
+ #
56
+ # Sourced by bin/fm-spawn.sh, bin/fm-send.sh, bin/fm-teardown.sh,
57
+ # bin/fm-sessionstart-nudge.sh, and the tests.
58
+ # No side effects on source. set -u / set -e safe. The refusal is a hard exit,
59
+ # not a return, because there is no safe way to continue a fleet mutation from a
60
+ # gate context.
61
+
62
+ # The exit code every refusal uses, distinct enough to recognize in a caller or
63
+ # test as "the gate refusal fired" rather than an ordinary usage error.
64
+ FM_GATE_REFUSE_EXIT=3
65
+
66
+ # fm_is_gate_agent: return 0 without output when this process looks like a
67
+ # no-mistakes gate agent. An optional root anchors the git-common-dir check;
68
+ # callers that omit it retain the historical current-worktree behavior.
69
+ fm_is_gate_agent() {
70
+ local anchor=${1:-.} common
71
+ if [ "${FM_GATE_REFUSE_BYPASS:-}" = 1 ]; then
72
+ return 1
73
+ fi
74
+ if [ "${NO_MISTAKES_GATE+x}" = x ]; then
75
+ FM_GATE_REFUSE_REASON='env'
76
+ return 0
77
+ fi
78
+ common=$(cd "$anchor" 2>/dev/null \
79
+ && cd "$(git rev-parse --git-common-dir 2>/dev/null || echo /nonexistent)" 2>/dev/null \
80
+ && pwd -P || true)
81
+ case "$common" in
82
+ */.no-mistakes/repos/*.git)
83
+ FM_GATE_REFUSE_REASON='path'
84
+ FM_GATE_REFUSE_COMMON=$common
85
+ return 0 ;;
86
+ esac
87
+ return 1
88
+ }
89
+
90
+ # fm_refuse_if_gate_agent: exit FM_GATE_REFUSE_EXIT with a clear stderr message if
91
+ # this process looks like a no-mistakes gate agent. Call before any fleet
92
+ # mutation. No-ops (returns 0) for a normal firstmate session, or when firstmate's
93
+ # own test harness sets FM_GATE_REFUSE_BYPASS=1 (see the header).
94
+ fm_refuse_if_gate_agent() {
95
+ fm_is_gate_agent "${1:-.}" || return 0
96
+ if [ "$FM_GATE_REFUSE_REASON" = env ]; then
97
+ echo "error: no-mistakes gate agent must not drive the fleet (NO_MISTAKES_GATE set)" >&2
98
+ else
99
+ echo "error: refusing fleet lifecycle from inside a no-mistakes gate worktree ($FM_GATE_REFUSE_COMMON)" >&2
100
+ fi
101
+ exit "$FM_GATE_REFUSE_EXIT"
102
+ }