@zerwiz/ymir 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 -39
  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,984 @@
1
+ #!/usr/bin/env bash
2
+ # Provision and route persistent secondmate homes.
3
+ #
4
+ # Usage:
5
+ # fm-home-seed.sh <id> <home|-> {<project>...|--no-projects}
6
+ # Provision <home> as an isolated firstmate home. If <home> is "-", acquire
7
+ # a fresh firstmate worktree via "treehouse get --lease", which durably
8
+ # leases the worktree under the secondmate <id> so the home survives with
9
+ # no live process and is never recycled until the lease is released with
10
+ # "treehouse return". Projects are cloned
11
+ # from the active home into the secondmate home's projects/ directory.
12
+ # That project list is non-exclusive provisioning data. Pass --no-projects
13
+ # instead of a project list to seed a project-less home for a domain whose
14
+ # subject is the firstmate repo itself; it is mutually exclusive with a
15
+ # project list, and omitting both still fails loudly. A project-less seed
16
+ # refuses a home with project clones or project-registry entries, so it
17
+ # never converts populated homes in place. The charter brief
18
+ # is copied to data/charter.md, newly cloned no-mistakes projects are
19
+ # initialized, an ignored .fm-secondmate-parent binding is published before
20
+ # the .fm-secondmate-home identity marker, and data/secondmates.md is updated.
21
+ # Seeding is transactional: on validation, clone, init, or registry failure,
22
+ # generated briefs, new homes, new project clones, and registry edits are
23
+ # rolled back. Treehouse-acquired homes are returned only when the rollback
24
+ # target is safe; a failed return warns because the lease may still be held.
25
+ # Set FM_SECONDMATE_CHARTER='<charter>' to seed from inline charter text
26
+ # when no filled charter brief exists. Set FM_SECONDMATE_SCOPE='<scope>'
27
+ # to override the registry routing scope. Otherwise the registry summary
28
+ # and scope are derived from the filled charter brief.
29
+ # fm-home-seed.sh validate
30
+ # Refuse records that operational consumers cannot parse, unavailable or
31
+ # unsafe registry files when present, non-absolute or unresolvable homes,
32
+ # duplicate ids or homes, and nested or overlapping homes.
33
+ set -eu
34
+
35
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
36
+ FM_ROOT="${FM_ROOT_OVERRIDE:-$(cd "$SCRIPT_DIR/.." && pwd)}"
37
+ FM_HOME="${FM_HOME:-${FM_ROOT_OVERRIDE:-$FM_ROOT}}"
38
+ DATA="${FM_DATA_OVERRIDE:-$FM_HOME/data}"
39
+ PROJECTS="${FM_PROJECTS_OVERRIDE:-$FM_HOME/projects}"
40
+ STATE="${FM_STATE_OVERRIDE:-$FM_HOME/state}"
41
+ REG="$DATA/secondmates.md"
42
+ SUB_HOME_MARKER=".fm-secondmate-home"
43
+ SUB_HOME_PARENT_MARKER=".fm-secondmate-parent"
44
+ # shellcheck source=bin/fm-secondmate-registry-lib.sh
45
+ . "$SCRIPT_DIR/fm-secondmate-registry-lib.sh"
46
+ # shellcheck source=bin/fm-secondmate-parent-lib.sh
47
+ . "$SCRIPT_DIR/fm-secondmate-parent-lib.sh"
48
+ # shellcheck source=bin/fm-secondmate-charter-lib.sh
49
+ . "$SCRIPT_DIR/fm-secondmate-charter-lib.sh"
50
+ # shellcheck source=bin/fm-wake-lib.sh
51
+ . "$SCRIPT_DIR/fm-wake-lib.sh"
52
+
53
+ usage() {
54
+ echo "usage: fm-home-seed.sh <id> <home|-> {<project>...|--no-projects}" >&2
55
+ echo " fm-home-seed.sh validate" >&2
56
+ }
57
+
58
+ validate_registry_home_text() {
59
+ local home=$1
60
+ case "$home" in
61
+ *';'*|*')'*|*$'\n'*)
62
+ echo "error: secondmate home path contains registry delimiters: $home" >&2
63
+ return 1
64
+ ;;
65
+ esac
66
+ }
67
+
68
+ normalize_joined_path() {
69
+ local prefix=$1 tail=$2 component out old_ifs
70
+ out=${prefix%/}
71
+ [ -n "$out" ] || out=/
72
+ old_ifs=$IFS
73
+ IFS=/
74
+ for component in $tail; do
75
+ case "$component" in
76
+ ''|.) ;;
77
+ ..)
78
+ if [ "$out" != "/" ]; then
79
+ out=${out%/*}
80
+ [ -n "$out" ] || out=/
81
+ fi
82
+ ;;
83
+ *)
84
+ if [ "$out" = "/" ]; then
85
+ out="/$component"
86
+ else
87
+ out="$out/$component"
88
+ fi
89
+ ;;
90
+ esac
91
+ done
92
+ IFS=$old_ifs
93
+ printf '%s\n' "$out"
94
+ }
95
+
96
+ canonical_path_for_check() {
97
+ local path=$1 probe tail prefix parent base
98
+ case "$path" in
99
+ /*) probe=$path ;;
100
+ *) probe="$(pwd -P)/$path" ;;
101
+ esac
102
+ while [ "$probe" != "/" ] && [ "${probe%/}" != "$probe" ]; do
103
+ probe=${probe%/}
104
+ done
105
+ if [ -e "$probe" ]; then
106
+ if [ -d "$probe" ]; then
107
+ cd "$probe" && pwd -P
108
+ else
109
+ parent=$(dirname "$probe")
110
+ base=$(basename "$probe")
111
+ cd "$parent" && printf '%s/%s\n' "$(pwd -P)" "$base"
112
+ fi
113
+ return
114
+ fi
115
+ tail=
116
+ while [ ! -e "$probe" ] && [ "$probe" != "/" ]; do
117
+ tail="$(basename "$probe")${tail:+/$tail}"
118
+ probe=$(dirname "$probe")
119
+ done
120
+ if [ -d "$probe" ]; then
121
+ prefix=$(cd "$probe" && pwd -P)
122
+ elif [ -e "$probe" ]; then
123
+ parent=$(dirname "$probe")
124
+ base=$(basename "$probe")
125
+ prefix=$(cd "$parent" && printf '%s/%s\n' "$(pwd -P)" "$base")
126
+ else
127
+ prefix=/
128
+ fi
129
+ normalize_joined_path "$prefix" "$tail"
130
+ }
131
+
132
+ path_is_ancestor_of() {
133
+ local ancestor=$1 path=$2
134
+ [ -n "$ancestor" ] || return 1
135
+ [ -n "$path" ] || return 1
136
+ [ "$ancestor" != "$path" ] || return 1
137
+ case "$path" in
138
+ "$ancestor"/*) return 0 ;;
139
+ esac
140
+ return 1
141
+ }
142
+
143
+ registry_home_conflict_for_assignment() {
144
+ local id=$1 home=$2 target line registered_id registered_home registered_key
145
+ [ -f "$REG" ] || return 1
146
+ target=$(resolved_path "$home")
147
+ while IFS= read -r line || [ -n "$line" ]; do
148
+ case "$line" in
149
+ "- "*)
150
+ if ! secondmate_registry_parse_line "$line"; then
151
+ echo "error: malformed secondmate registry entry: $line" >&2
152
+ return 1
153
+ fi
154
+ registered_id=$SECONDMATE_REGISTRY_ID
155
+ registered_home=$SECONDMATE_REGISTRY_HOME
156
+ registered_key=$(resolved_path "$registered_home")
157
+ if [ "$registered_key" = "$target" ]; then
158
+ [ "$registered_id" = "$id" ] && continue
159
+ printf 'exact\t%s\t%s\n' "$registered_id" "$registered_key"
160
+ return 0
161
+ fi
162
+ if path_is_ancestor_of "$registered_key" "$target" || path_is_ancestor_of "$target" "$registered_key"; then
163
+ printf 'overlap\t%s\t%s\n' "$registered_id" "$registered_key"
164
+ return 0
165
+ fi
166
+ ;;
167
+ esac
168
+ done < "$REG"
169
+ return 1
170
+ }
171
+
172
+ registry_id_conflict_for_assignment() {
173
+ local id=$1 home=$2 target line registered_id registered_home registered_key
174
+ [ -f "$REG" ] || return 1
175
+ target=$(resolved_path "$home")
176
+ while IFS= read -r line || [ -n "$line" ]; do
177
+ case "$line" in
178
+ "- "*)
179
+ secondmate_registry_parse_line "$line" || {
180
+ echo "error: malformed secondmate registry entry: $line" >&2
181
+ return 1
182
+ }
183
+ registered_id=$SECONDMATE_REGISTRY_ID
184
+ [ "$registered_id" = "$id" ] || continue
185
+ registered_home=$SECONDMATE_REGISTRY_HOME
186
+ registered_key=$(resolved_path "$registered_home")
187
+ [ "$registered_key" = "$target" ] && continue
188
+ printf '%s\n' "$registered_key"
189
+ return 0
190
+ ;;
191
+ esac
192
+ done < "$REG"
193
+ return 1
194
+ }
195
+
196
+ validate_registry() {
197
+ [ -e "$REG" ] || [ -L "$REG" ] || return 0
198
+ secondmate_registry_validate_bindings "$REG" resolved_path || {
199
+ printf 'error: %s\n' "$SECONDMATE_REGISTRY_ERROR" >&2
200
+ return 1
201
+ }
202
+ }
203
+
204
+ join_projects() {
205
+ local out="" project
206
+ for project in "$@"; do
207
+ out="${out}${out:+, }$project"
208
+ done
209
+ printf '%s\n' "$out"
210
+ }
211
+
212
+ abs_path_for_new() {
213
+ canonical_path_for_check "$1"
214
+ }
215
+
216
+ resolved_path() {
217
+ canonical_path_for_check "$1"
218
+ }
219
+
220
+ refuse_active_home_path() {
221
+ local home=$1 abs_home abs_active_home abs_root
222
+ abs_home=$(resolved_path "$home")
223
+ abs_active_home=$(resolved_path "$FM_HOME")
224
+ abs_root=$(resolved_path "$FM_ROOT")
225
+ if [ "$abs_home" = "/" ]; then
226
+ echo "error: secondmate home cannot be the filesystem root: $home" >&2
227
+ return 1
228
+ fi
229
+ if [ "$abs_home" = "$abs_active_home" ]; then
230
+ echo "error: secondmate home cannot be the active firstmate home: $home" >&2
231
+ return 1
232
+ fi
233
+ if [ "$abs_home" = "$abs_root" ]; then
234
+ echo "error: secondmate home cannot be the firstmate repo: $home" >&2
235
+ return 1
236
+ fi
237
+ if path_is_ancestor_of "$abs_active_home" "$abs_home"; then
238
+ echo "error: secondmate home cannot be inside the active firstmate home: $home" >&2
239
+ return 1
240
+ fi
241
+ if path_is_ancestor_of "$abs_root" "$abs_home"; then
242
+ echo "error: secondmate home cannot be inside the firstmate repo: $home" >&2
243
+ return 1
244
+ fi
245
+ if path_is_ancestor_of "$abs_home" "$abs_active_home"; then
246
+ echo "error: secondmate home cannot be an ancestor of the active firstmate home: $home" >&2
247
+ return 1
248
+ fi
249
+ if path_is_ancestor_of "$abs_home" "$abs_root"; then
250
+ echo "error: secondmate home cannot be an ancestor of the firstmate repo: $home" >&2
251
+ return 1
252
+ fi
253
+ }
254
+
255
+ validate_operational_dir() {
256
+ local home=$1 name=$2 dir abs_home abs_dir abs_active_home abs_root
257
+ dir="$home/$name"
258
+ if [ -L "$dir" ] && [ ! -e "$dir" ]; then
259
+ echo "error: secondmate $name directory must resolve inside the secondmate home: $dir" >&2
260
+ return 1
261
+ fi
262
+ abs_home=$(resolved_path "$home")
263
+ abs_dir=$(resolved_path "$dir")
264
+ abs_active_home=$(resolved_path "$FM_HOME")
265
+ abs_root=$(resolved_path "$FM_ROOT")
266
+ if ! path_is_ancestor_of "$abs_home" "$abs_dir"; then
267
+ echo "error: secondmate $name directory must resolve inside the secondmate home: $dir" >&2
268
+ return 1
269
+ fi
270
+ if [ "$abs_dir" = "$abs_active_home" ] || path_is_ancestor_of "$abs_active_home" "$abs_dir"; then
271
+ echo "error: secondmate $name directory cannot be inside the active firstmate home: $dir" >&2
272
+ return 1
273
+ fi
274
+ if [ "$abs_dir" = "$abs_root" ] || path_is_ancestor_of "$abs_root" "$abs_dir"; then
275
+ echo "error: secondmate $name directory cannot be inside the firstmate repo: $dir" >&2
276
+ return 1
277
+ fi
278
+ }
279
+
280
+ validate_operational_dirs() {
281
+ local home=$1 name
282
+ for name in data state config projects; do
283
+ validate_operational_dir "$home" "$name" || return 1
284
+ done
285
+ }
286
+
287
+ validate_seed_leaf_files() {
288
+ local home=$1 label path abs_home abs_path
289
+ abs_home=$(resolved_path "$home")
290
+ for label in "data/projects.md" "data/charter.md" "$SUB_HOME_MARKER" "$SUB_HOME_PARENT_MARKER"; do
291
+ path="$home/$label"
292
+ if [ -L "$path" ]; then
293
+ echo "error: secondmate leaf file must not be a symlink: $path" >&2
294
+ return 1
295
+ fi
296
+ [ -e "$path" ] || continue
297
+ if [ ! -f "$path" ]; then
298
+ echo "error: secondmate leaf file must be a regular file: $path" >&2
299
+ return 1
300
+ fi
301
+ abs_path=$(resolved_path "$path")
302
+ case "$abs_path" in
303
+ "$abs_home"/*) ;;
304
+ *)
305
+ echo "error: secondmate leaf file must resolve inside the secondmate home: $path" >&2
306
+ return 1
307
+ ;;
308
+ esac
309
+ done
310
+ }
311
+
312
+ validate_existing_parent_binding() {
313
+ local home=$1 record recorded_parent requested_parent
314
+ record="$home/$SUB_HOME_PARENT_MARKER"
315
+ [ -f "$record" ] && [ ! -L "$record" ] || return 0
316
+ fm_secondmate_parent_record_parse "$record" || return 0
317
+ [ "$FM_SECONDMATE_PARENT_ROUTE" = local ] || return 0
318
+
319
+ recorded_parent=$(resolved_path "$FM_SECONDMATE_PARENT_HOME")
320
+ requested_parent=$(resolved_path "$FM_HOME")
321
+ [ "$recorded_parent" = "$requested_parent" ] && return 0
322
+ printf 'error: secondmate home is bound to parent %s, not requested parent %s\n' \
323
+ "$recorded_parent" "$requested_parent" >&2
324
+ return 1
325
+ }
326
+
327
+ validate_project_destination() {
328
+ local home=$1 project=$2 dst projects_dir abs_home abs_projects abs_dst abs_active_home abs_root
329
+ projects_dir="$home/projects"
330
+ dst="$projects_dir/$project"
331
+ abs_home=$(resolved_path "$home")
332
+ abs_projects=$(resolved_path "$projects_dir")
333
+ abs_dst=$(resolved_path "$dst")
334
+ abs_active_home=$(resolved_path "$FM_HOME")
335
+ abs_root=$(resolved_path "$FM_ROOT")
336
+ if ! path_is_ancestor_of "$abs_home" "$abs_projects"; then
337
+ echo "error: secondmate projects directory must resolve inside the secondmate home: $projects_dir" >&2
338
+ return 1
339
+ fi
340
+ if ! path_is_ancestor_of "$abs_projects" "$abs_dst"; then
341
+ echo "error: seeded project $project destination must resolve inside the secondmate projects directory: $dst" >&2
342
+ return 1
343
+ fi
344
+ if [ "$abs_dst" = "$abs_active_home" ] || path_is_ancestor_of "$abs_active_home" "$abs_dst"; then
345
+ echo "error: seeded project $project destination cannot be inside the active firstmate home: $dst" >&2
346
+ return 1
347
+ fi
348
+ if [ "$abs_dst" = "$abs_root" ] || path_is_ancestor_of "$abs_root" "$abs_dst"; then
349
+ echo "error: seeded project $project destination cannot be inside the firstmate repo: $dst" >&2
350
+ return 1
351
+ fi
352
+ printf '%s\n' "$abs_dst"
353
+ }
354
+
355
+ normalize_origin_url() {
356
+ local repo=$1 url=$2 prefix
357
+ case "$url" in
358
+ file://*|*://*)
359
+ printf '%s\n' "$url"
360
+ return
361
+ ;;
362
+ *:*)
363
+ prefix=${url%%:*}
364
+ case "$prefix" in
365
+ */*) ;;
366
+ *)
367
+ printf '%s\n' "$url"
368
+ return
369
+ ;;
370
+ esac
371
+ ;;
372
+ esac
373
+ ( cd "$repo" && canonical_path_for_check "$url" )
374
+ }
375
+
376
+ source_origin_url() {
377
+ local project=$1 mode=$2 src=$3 url
378
+ url=$(git -C "$src" remote get-url origin 2>/dev/null || true)
379
+ [ -n "$url" ] || { echo "error: project $project is $mode but has no origin remote" >&2; return 1; }
380
+ normalize_origin_url "$src" "$url"
381
+ }
382
+
383
+ seeded_origin_url() {
384
+ local project=$1 dst=$2 expected=$3 url
385
+ url=$(git -C "$dst" remote get-url origin 2>/dev/null || true)
386
+ [ -n "$url" ] || { echo "error: seeded project $project at $dst has no origin remote; expected $expected" >&2; return 1; }
387
+ normalize_origin_url "$dst" "$url"
388
+ }
389
+
390
+ acquire_treehouse_home() {
391
+ local id=$1 home
392
+ # Durably lease a firstmate worktree from the pool. The lease persists with no
393
+ # live process and is skipped by later get/prune, so the home survives restarts
394
+ # until teardown or rollback returns it. treehouse prints only the worktree path
395
+ # to stdout (banners go to stderr), so command substitution captures the path.
396
+ home=$(cd "$FM_ROOT" && treehouse get --lease --lease-holder "$id") || {
397
+ echo "error: treehouse get --lease failed to lease a firstmate home" >&2
398
+ return 1
399
+ }
400
+ [ -n "$home" ] || { echo "error: treehouse get --lease did not report a firstmate home" >&2; return 1; }
401
+ printf '%s\n' "$home"
402
+ }
403
+
404
+ ensure_home() {
405
+ local id=$1 requested=$2 home
406
+ if [ "$requested" = "-" ]; then
407
+ home=$(acquire_treehouse_home "$id")
408
+ verify_firstmate_home "$home"
409
+ return
410
+ fi
411
+
412
+ home=$(abs_path_for_new "$requested")
413
+ refuse_active_home_path "$home" || return 1
414
+ if [ -e "$home" ]; then
415
+ [ -d "$home" ] || { echo "error: $home exists and is not a directory" >&2; return 1; }
416
+ else
417
+ mkdir -p "$(dirname "$home")"
418
+ git clone --quiet "$FM_ROOT" "$home"
419
+ fi
420
+ verify_firstmate_home "$home"
421
+ }
422
+
423
+ verify_firstmate_home() {
424
+ local home=$1
425
+ refuse_active_home_path "$home" || return 1
426
+ [ -f "$home/AGENTS.md" ] || { echo "error: $home is not a firstmate home (missing AGENTS.md)" >&2; return 1; }
427
+ [ -d "$home/bin" ] || { echo "error: $home is not a firstmate home (missing bin/)" >&2; return 1; }
428
+ validate_operational_dirs "$home" || return 1
429
+ printf '%s\n' "$(cd "$home" && pwd -P)"
430
+ }
431
+
432
+ validate_home_assignment() {
433
+ local id=$1 home=$2 marker_id id_conflict conflict conflict_type owner registered_home
434
+ if [ -f "$home/$SUB_HOME_MARKER" ]; then
435
+ marker_id=$(cat "$home/$SUB_HOME_MARKER" 2>/dev/null || true)
436
+ if [ "$marker_id" != "$id" ]; then
437
+ echo "error: secondmate home $home is already marked for ${marker_id:-unknown}" >&2
438
+ return 1
439
+ fi
440
+ fi
441
+ id_conflict=$(registry_id_conflict_for_assignment "$id" "$home" || true)
442
+ if [ -n "$id_conflict" ]; then
443
+ echo "error: secondmate id $id is already registered to home $id_conflict; retire it before assigning $home" >&2
444
+ return 1
445
+ fi
446
+ conflict=$(registry_home_conflict_for_assignment "$id" "$home" || true)
447
+ [ -n "$conflict" ] || return 0
448
+ IFS=$'\t' read -r conflict_type owner registered_home <<EOF
449
+ $conflict
450
+ EOF
451
+ if [ "$conflict_type" = exact ]; then
452
+ echo "error: secondmate home $home is already registered to $owner" >&2
453
+ return 1
454
+ fi
455
+ echo "error: secondmate home $home overlaps registered secondmate home $registered_home for $owner" >&2
456
+ return 1
457
+ }
458
+
459
+ clone_project() {
460
+ local project=$1 home=$2 src dst url dst_url mode
461
+ src="$PROJECTS/$project"
462
+ dst=$(validate_project_destination "$home" "$project") || return 1
463
+ [ -d "$src" ] || { echo "error: project $project not found at $src" >&2; return 1; }
464
+ git -C "$src" rev-parse --is-inside-work-tree >/dev/null 2>&1 || { echo "error: project $project is not a git repo" >&2; return 1; }
465
+ read -r mode _ <<EOF
466
+ $(FM_HOME="$FM_HOME" FM_DATA_OVERRIDE="$DATA" "$FM_ROOT/bin/fm-project-mode.sh" "$project")
467
+ EOF
468
+ if [ "$mode" = local-only ]; then
469
+ echo "error: project $project is local-only; secondmate routes support only no-mistakes and direct-PR projects" >&2
470
+ return 1
471
+ fi
472
+ if [ -e "$dst" ]; then
473
+ [ -d "$dst" ] || { echo "error: seeded project $project exists at $dst but is not a directory" >&2; return 1; }
474
+ git -C "$dst" rev-parse --is-inside-work-tree >/dev/null 2>&1 || { echo "error: seeded project $project at $dst is not a git repo" >&2; return 1; }
475
+ url=$(source_origin_url "$project" "$mode" "$src") || return 1
476
+ dst_url=$(seeded_origin_url "$project" "$dst" "$url") || return 1
477
+ [ "$dst_url" = "$url" ] || {
478
+ echo "error: seeded project $project at $dst has origin $dst_url; expected $url" >&2
479
+ return 1
480
+ }
481
+ return 0
482
+ fi
483
+ url=$(source_origin_url "$project" "$mode" "$src") || return 1
484
+ git clone --quiet "$url" "$dst"
485
+ }
486
+
487
+ validate_seed_project() {
488
+ local project=$1 src mode url
489
+ src="$PROJECTS/$project"
490
+ [ -d "$src" ] || { echo "error: project $project not found at $src" >&2; return 1; }
491
+ git -C "$src" rev-parse --is-inside-work-tree >/dev/null 2>&1 || { echo "error: project $project is not a git repo" >&2; return 1; }
492
+ read -r mode _ <<EOF
493
+ $(FM_HOME="$FM_HOME" FM_DATA_OVERRIDE="$DATA" "$FM_ROOT/bin/fm-project-mode.sh" "$project")
494
+ EOF
495
+ if [ "$mode" = local-only ]; then
496
+ echo "error: project $project is local-only; secondmate routes support only no-mistakes and direct-PR projects" >&2
497
+ return 1
498
+ fi
499
+ url=$(git -C "$src" remote get-url origin 2>/dev/null || true)
500
+ [ -n "$url" ] || { echo "error: project $project is $mode but has no origin remote" >&2; return 1; }
501
+ }
502
+
503
+ SEED_ROLLBACK_ACTIVE=0
504
+ SEED_COMMITTED=0
505
+ SEED_REGISTRY_LOCK=
506
+ SEED_REGISTRY_LOCK_HELD=0
507
+
508
+ seed_registry_lock_release() {
509
+ if [ "$SEED_REGISTRY_LOCK_HELD" -eq 1 ]; then
510
+ fm_lock_release "$SEED_REGISTRY_LOCK"
511
+ SEED_REGISTRY_LOCK_HELD=0
512
+ fi
513
+ }
514
+
515
+ seed_exit_cleanup() {
516
+ seed_rollback
517
+ seed_registry_lock_release
518
+ }
519
+ SEED_HOME=
520
+ SEED_HOME_ACQUIRED=0
521
+ SEED_HOME_CREATED=0
522
+ SEED_HOME_BACKED_UP=0
523
+ SEED_BACKUP_DIR=
524
+ SEED_CREATED_PROJECTS_FILE=
525
+ SEED_PARENT_REG_EXISTED=0
526
+ SEED_PARENT_BRIEF=
527
+ SEED_PARENT_BRIEF_CREATED=0
528
+ SEED_PARENT_BRIEF_DIR_CREATED=0
529
+ SEED_SUB_REG_EXISTED=0
530
+ SEED_CHARTER_EXISTED=0
531
+ SEED_MARKER_EXISTED=0
532
+ SEED_PARENT_MARKER_EXISTED=0
533
+
534
+ restore_seed_file() {
535
+ local existed=$1 backup=$2 path=$3
536
+ if [ "$existed" = 1 ]; then
537
+ mkdir -p "$(dirname "$path")"
538
+ cp "$backup" "$path" 2>/dev/null || true
539
+ else
540
+ rm -f "$path" 2>/dev/null || true
541
+ fi
542
+ }
543
+
544
+ seed_rollback_target() {
545
+ local target=$1 label=$2 abs_target abs_home abs_root
546
+ [ -n "$target" ] || return 1
547
+ [ "$target" != "/" ] || { echo "REFUSED: unsafe $label rollback target $target" >&2; return 1; }
548
+ abs_target=$(resolved_path "$target")
549
+ abs_home=$(resolved_path "$FM_HOME")
550
+ abs_root=$(resolved_path "$FM_ROOT")
551
+ if [ "$abs_target" = "$abs_home" ]; then
552
+ echo "REFUSED: unsafe $label rollback target $target is the active firstmate home" >&2
553
+ return 1
554
+ fi
555
+ if [ "$abs_target" = "$abs_root" ]; then
556
+ echo "REFUSED: unsafe $label rollback target $target is the firstmate repo" >&2
557
+ return 1
558
+ fi
559
+ if path_is_ancestor_of "$abs_target" "$abs_home"; then
560
+ echo "REFUSED: unsafe $label rollback target $target is an ancestor of the active firstmate home" >&2
561
+ return 1
562
+ fi
563
+ if path_is_ancestor_of "$abs_target" "$abs_root"; then
564
+ echo "REFUSED: unsafe $label rollback target $target is an ancestor of the firstmate repo" >&2
565
+ return 1
566
+ fi
567
+ if path_is_ancestor_of "$abs_home" "$abs_target"; then
568
+ echo "REFUSED: unsafe $label rollback target $target is inside the active firstmate home" >&2
569
+ return 1
570
+ fi
571
+ if path_is_ancestor_of "$abs_root" "$abs_target"; then
572
+ echo "REFUSED: unsafe $label rollback target $target is inside the firstmate repo" >&2
573
+ return 1
574
+ fi
575
+ printf '%s\n' "$abs_target"
576
+ }
577
+
578
+ seed_return_treehouse_home() {
579
+ local home=$1 abs_home
580
+ abs_home=$(seed_rollback_target "$home" "treehouse-acquired home") || return 0
581
+ if ! command -v treehouse >/dev/null 2>&1; then
582
+ echo "warning: failed to return treehouse-acquired home $abs_home during seed rollback; treehouse command not found" >&2
583
+ return 0
584
+ fi
585
+ ( cd "$FM_ROOT" && treehouse return --force "$abs_home" >/dev/null ) || {
586
+ echo "warning: failed to return treehouse-acquired home $abs_home during seed rollback; lease may still be held" >&2
587
+ return 0
588
+ }
589
+ }
590
+
591
+ seed_remove_created_home() {
592
+ local home=$1 abs_home
593
+ abs_home=$(seed_rollback_target "$home" "created home") || return 0
594
+ rm -rf -- "$abs_home" 2>/dev/null || true
595
+ }
596
+
597
+ seed_project_rollback_target() {
598
+ local target=$1 abs_target abs_home abs_projects
599
+ abs_target=$(seed_rollback_target "$target" "created project") || return 1
600
+ abs_home=$(resolved_path "$SEED_HOME")
601
+ abs_projects=$(resolved_path "$SEED_HOME/projects")
602
+ if ! path_is_ancestor_of "$abs_home" "$abs_projects"; then
603
+ echo "REFUSED: unsafe created project rollback target $target has projects directory outside the secondmate home" >&2
604
+ return 1
605
+ fi
606
+ if ! path_is_ancestor_of "$abs_projects" "$abs_target"; then
607
+ echo "REFUSED: unsafe created project rollback target $target is outside the secondmate projects directory" >&2
608
+ return 1
609
+ fi
610
+ printf '%s\n' "$abs_target"
611
+ }
612
+
613
+ seed_remove_created_project() {
614
+ local project_path=$1 abs_project
615
+ abs_project=$(seed_project_rollback_target "$project_path") || return 0
616
+ rm -rf -- "$abs_project" 2>/dev/null || true
617
+ }
618
+
619
+ seed_project_was_created() {
620
+ local project_path=$1
621
+ [ -n "${SEED_CREATED_PROJECTS_FILE:-}" ] || return 1
622
+ [ -f "$SEED_CREATED_PROJECTS_FILE" ] || return 1
623
+ grep -Fx -- "$project_path" "$SEED_CREATED_PROJECTS_FILE" >/dev/null 2>&1
624
+ }
625
+
626
+ seed_rollback() {
627
+ local project_path
628
+ [ "${SEED_ROLLBACK_ACTIVE:-0}" = 1 ] || return 0
629
+ [ "${SEED_COMMITTED:-0}" = 0 ] || return 0
630
+
631
+ if [ -n "${SEED_PARENT_BRIEF:-}" ] && [ "$SEED_PARENT_BRIEF_CREATED" = 1 ]; then
632
+ rm -f "$SEED_PARENT_BRIEF" 2>/dev/null || true
633
+ fi
634
+ if [ -n "${SEED_PARENT_BRIEF:-}" ] && [ "$SEED_PARENT_BRIEF_DIR_CREATED" = 1 ]; then
635
+ rmdir "$(dirname "$SEED_PARENT_BRIEF")" 2>/dev/null || true
636
+ fi
637
+
638
+ if [ -n "${SEED_HOME:-}" ] && [ "$SEED_HOME" != "/" ]; then
639
+ if [ "$SEED_HOME_ACQUIRED" = 1 ]; then
640
+ seed_return_treehouse_home "$SEED_HOME"
641
+ elif [ "$SEED_HOME_CREATED" = 1 ]; then
642
+ seed_remove_created_home "$SEED_HOME"
643
+ else
644
+ if [ -n "${SEED_CREATED_PROJECTS_FILE:-}" ] && [ -f "$SEED_CREATED_PROJECTS_FILE" ]; then
645
+ while IFS= read -r project_path; do
646
+ [ -n "$project_path" ] || continue
647
+ seed_remove_created_project "$project_path"
648
+ done < "$SEED_CREATED_PROJECTS_FILE"
649
+ fi
650
+ if [ -n "${SEED_BACKUP_DIR:-}" ] && [ "${SEED_HOME_BACKED_UP:-0}" = 1 ]; then
651
+ restore_seed_file "$SEED_MARKER_EXISTED" "$SEED_BACKUP_DIR/marker" "$SEED_HOME/$SUB_HOME_MARKER"
652
+ restore_seed_file "$SEED_PARENT_MARKER_EXISTED" "$SEED_BACKUP_DIR/parent-marker" "$SEED_HOME/$SUB_HOME_PARENT_MARKER"
653
+ restore_seed_file "$SEED_CHARTER_EXISTED" "$SEED_BACKUP_DIR/charter.md" "$SEED_HOME/data/charter.md"
654
+ restore_seed_file "$SEED_SUB_REG_EXISTED" "$SEED_BACKUP_DIR/sub-projects.md" "$SEED_HOME/data/projects.md"
655
+ fi
656
+ fi
657
+ fi
658
+
659
+ if [ -n "${SEED_BACKUP_DIR:-}" ]; then
660
+ restore_seed_file "$SEED_PARENT_REG_EXISTED" "$SEED_BACKUP_DIR/parent-secondmates.md" "$REG"
661
+ rm -rf -- "$SEED_BACKUP_DIR" 2>/dev/null || true
662
+ fi
663
+ }
664
+
665
+ registry_line_for_project() {
666
+ local project=$1 line
667
+ [ -f "$DATA/projects.md" ] || return 1
668
+ line=$(awk -v n="$project" '$1=="-" && $2==n { print; exit }' "$DATA/projects.md")
669
+ [ -n "$line" ] || return 1
670
+ printf '%s\n' "$line"
671
+ }
672
+
673
+ project_mode_in_home() {
674
+ local home=$1 project=$2 mode
675
+ read -r mode _ <<EOF
676
+ $(FM_ROOT_OVERRIDE='' FM_STATE_OVERRIDE='' FM_DATA_OVERRIDE='' FM_PROJECTS_OVERRIDE='' FM_CONFIG_OVERRIDE='' FM_HOME="$home" "$FM_ROOT/bin/fm-project-mode.sh" "$project")
677
+ EOF
678
+ printf '%s\n' "$mode"
679
+ }
680
+
681
+ sync_project_registry() {
682
+ local home=$1 sub_reg tmp project line today names
683
+ shift
684
+ sub_reg="$home/data/projects.md"
685
+ tmp="$sub_reg.tmp.$$"
686
+ names=$(printf '%s\n' "$@" | awk '{ printf "%s%s", sep, $0; sep="\034" }')
687
+ if [ -f "$sub_reg" ]; then
688
+ awk -v names="$names" '
689
+ BEGIN {
690
+ split(names, a, "\034")
691
+ for (i in a) selected[a[i]]=1
692
+ }
693
+ !($1=="-" && ($2 in selected)) { print }
694
+ ' "$sub_reg" > "$tmp"
695
+ else
696
+ : > "$tmp"
697
+ fi
698
+ today=$(date +%F)
699
+ for project in "$@"; do
700
+ line=$(registry_line_for_project "$project" || true)
701
+ if [ -z "$line" ]; then
702
+ line="- $project - cloned project (added $today)"
703
+ fi
704
+ printf '%s\n' "$line" >> "$tmp"
705
+ done
706
+ mv "$tmp" "$sub_reg"
707
+ }
708
+
709
+ initialize_no_mistakes_project() {
710
+ local home=$1 project=$2 created=$3 mode dst
711
+ mode=$(project_mode_in_home "$home" "$project")
712
+ [ "$mode" = no-mistakes ] || return 0
713
+ dst=$(validate_project_destination "$home" "$project") || return 1
714
+ if git -C "$dst" remote get-url no-mistakes >/dev/null 2>&1; then
715
+ return 0
716
+ fi
717
+ if [ "$created" != 1 ]; then
718
+ echo "error: seeded project $project at $dst is not initialized for no-mistakes; refusing to mutate preexisting clone" >&2
719
+ return 1
720
+ fi
721
+ command -v no-mistakes >/dev/null 2>&1 || {
722
+ echo "error: no-mistakes command not found; cannot initialize $project in $home" >&2
723
+ return 1
724
+ }
725
+ ( cd "$dst" && no-mistakes init && no-mistakes doctor ) || {
726
+ echo "error: failed to initialize no-mistakes for $project at $dst" >&2
727
+ return 1
728
+ }
729
+ }
730
+
731
+ write_registry() {
732
+ local id=$1 home=$2 projects_csv=$3 brief=$4 scope summary tmp today
733
+ mkdir -p "$DATA"
734
+ scope=$(registry_scope_for_brief "$brief")
735
+ summary=$(registry_summary_for_brief "$brief")
736
+ today=$(date +%F)
737
+ tmp="$REG.tmp.$$"
738
+ if [ -f "$REG" ]; then
739
+ grep -vE "^- $id( |$)" "$REG" > "$tmp" || true
740
+ else
741
+ : > "$tmp"
742
+ fi
743
+ printf -- '- %s - %s (home: %s; scope: %s; projects: %s; added %s)\n' "$id" "$summary" "$home" "$scope" "$projects_csv" "$today" >> "$tmp"
744
+ mv "$tmp" "$REG"
745
+ }
746
+
747
+ refuse_populated_projectless_home() {
748
+ local home=$1 project_path project registry_entries
749
+ local clones=()
750
+ local registry_projects=()
751
+ if [ -L "$home/projects" ]; then
752
+ echo "error: cannot inspect existing projects directory at $home/projects because it is a symlink; resolve the symlink or retire or clean this home before seeding with --no-projects" >&2
753
+ return 1
754
+ fi
755
+ if [ -e "$home/projects" ] && [ ! -d "$home/projects" ]; then
756
+ echo "error: cannot inspect existing projects directory at $home/projects because it is not a directory; resolve its path or retire or clean this home before seeding with --no-projects" >&2
757
+ return 1
758
+ fi
759
+ if [ -d "$home/projects" ] && ! find -P "$home/projects" -mindepth 1 -maxdepth 1 -print >/dev/null 2>&1; then
760
+ echo "error: cannot inspect existing projects directory at $home/projects; resolve its access permissions or retire or clean this home before seeding with --no-projects" >&2
761
+ return 1
762
+ fi
763
+ for project_path in "$home/projects"/* "$home/projects"/.[!.]* "$home/projects"/..?*; do
764
+ [ -e "$project_path" ] || [ -L "$project_path" ] || continue
765
+ clones+=("$(basename "$project_path")")
766
+ done
767
+ if [ -f "$home/data/projects.md" ]; then
768
+ registry_entries=$(awk '$1 == "-" && $2 != "" { print $2 }' "$home/data/projects.md") || {
769
+ echo "error: cannot inspect existing project registry at $home/data/projects.md; resolve its access permissions or retire or clean this home before seeding with --no-projects" >&2
770
+ return 1
771
+ }
772
+ while IFS= read -r project; do
773
+ [ -n "$project" ] && registry_projects+=("$project")
774
+ done <<< "$registry_entries"
775
+ fi
776
+ [ "${#clones[@]}" -eq 0 ] && [ "${#registry_projects[@]}" -eq 0 ] && return 0
777
+
778
+ echo "error: cannot seed project-less secondmate home $home because it contains project data" >&2
779
+ if [ "${#clones[@]}" -gt 0 ]; then
780
+ printf 'error: projects/ entries: %s\n' "$(join_projects "${clones[@]}")" >&2
781
+ fi
782
+ if [ "${#registry_projects[@]}" -gt 0 ]; then
783
+ printf 'error: data/projects.md entries: %s\n' "$(join_projects "${registry_projects[@]}")" >&2
784
+ fi
785
+ echo "error: retire or clean this home first before seeding with --no-projects" >&2
786
+ return 1
787
+ }
788
+
789
+ refuse_projectful_projectless_charter() {
790
+ local id=$1 brief=$2 project_clones
791
+ project_clones=$(brief_section_text "$brief" "Project clones")
792
+ if printf '%s\n' "$project_clones" | grep -F 'None. This is a project-less domain' >/dev/null 2>&1 \
793
+ && ! printf '%s\n' "$project_clones" | grep -Eq '^[[:space:]]*-[[:space:]]+'; then
794
+ return 0
795
+ fi
796
+ printf 'error: cannot seed project-less secondmate home because existing charter brief at %s conflicts with --no-projects\n' "$brief" >&2
797
+ printf 'error: re-scaffold it with fm-brief.sh %s --secondmate --no-projects or remove the stale brief before seeding\n' "$id" >&2
798
+ return 1
799
+ }
800
+
801
+ seed_home() {
802
+ local id=$1 requested_home=$2 requested_abs home projects_csv project project_dst charter_summary charter_scope
803
+ local no_projects=0 arg
804
+ local filtered=()
805
+ shift 2
806
+ # A deliberate --no-projects signal (anywhere in the project position) seeds a
807
+ # project-less home; an accidental omission with no signal still fails loudly.
808
+ for arg in "$@"; do
809
+ if [ "$arg" = "--no-projects" ]; then
810
+ no_projects=1
811
+ else
812
+ filtered+=("$arg")
813
+ fi
814
+ done
815
+ if [ "${#filtered[@]}" -gt 0 ]; then
816
+ set -- "${filtered[@]}"
817
+ else
818
+ set --
819
+ fi
820
+ if [ "$no_projects" -eq 1 ]; then
821
+ [ $# -eq 0 ] || { echo "error: --no-projects cannot be combined with a project list" >&2; return 1; }
822
+ else
823
+ [ $# -gt 0 ] || { echo "error: secondmate needs at least one project, or --no-projects for a project-less home" >&2; return 1; }
824
+ fi
825
+
826
+ mkdir -p "$STATE" || return 1
827
+ SEED_REGISTRY_LOCK=$(secondmate_registry_lock_path "$STATE")
828
+ fm_lock_acquire_wait "$SEED_REGISTRY_LOCK" || return 1
829
+ SEED_REGISTRY_LOCK_HELD=1
830
+ trap seed_exit_cleanup EXIT
831
+
832
+ validate_registry
833
+ for project in "$@"; do
834
+ validate_seed_project "$project"
835
+ done
836
+
837
+ SEED_ROLLBACK_ACTIVE=1
838
+ SEED_COMMITTED=0
839
+ SEED_HOME=
840
+ SEED_HOME_ACQUIRED=0
841
+ SEED_HOME_CREATED=0
842
+ SEED_HOME_ACQUIRED=0
843
+ SEED_HOME_BACKED_UP=0
844
+ SEED_BACKUP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/fm-home-seed.XXXXXX")
845
+ SEED_CREATED_PROJECTS_FILE="$SEED_BACKUP_DIR/created-projects"
846
+ : > "$SEED_CREATED_PROJECTS_FILE"
847
+ SEED_PARENT_REG_EXISTED=0
848
+ SEED_PARENT_BRIEF="$DATA/$id/brief.md"
849
+ SEED_PARENT_BRIEF_CREATED=0
850
+ SEED_PARENT_BRIEF_DIR_CREATED=0
851
+ SEED_SUB_REG_EXISTED=0
852
+ SEED_CHARTER_EXISTED=0
853
+ SEED_MARKER_EXISTED=0
854
+ if [ -f "$REG" ]; then
855
+ SEED_PARENT_REG_EXISTED=1
856
+ cp "$REG" "$SEED_BACKUP_DIR/parent-secondmates.md"
857
+ fi
858
+
859
+ if [ "$requested_home" = "-" ]; then
860
+ SEED_HOME_ACQUIRED=1
861
+ home=$(acquire_treehouse_home "$id")
862
+ SEED_HOME="$home"
863
+ home=$(verify_firstmate_home "$home")
864
+ else
865
+ requested_abs=$(abs_path_for_new "$requested_home")
866
+ refuse_active_home_path "$requested_abs" || return 1
867
+ validate_home_assignment "$id" "$requested_abs" || return 1
868
+ SEED_HOME="$requested_abs"
869
+ [ -e "$requested_abs" ] || SEED_HOME_CREATED=1
870
+ home=$(ensure_home "$id" "$requested_abs")
871
+ fi
872
+ SEED_HOME="$home"
873
+ validate_registry_home_text "$home" || return 1
874
+ validate_home_assignment "$id" "$home"
875
+ validate_operational_dirs "$home" || return 1
876
+ validate_seed_leaf_files "$home" || return 1
877
+ validate_existing_parent_binding "$home" || return 1
878
+ if [ "$no_projects" -eq 1 ]; then
879
+ refuse_populated_projectless_home "$home" || return 1
880
+ if [ -f "$SEED_PARENT_BRIEF" ]; then
881
+ refuse_projectful_projectless_charter "$id" "$SEED_PARENT_BRIEF" || return 1
882
+ fi
883
+ fi
884
+ mkdir -p "$DATA" "$home/data" "$home/state" "$home/config" "$home/projects"
885
+ if [ -f "$home/data/projects.md" ]; then
886
+ SEED_SUB_REG_EXISTED=1
887
+ cp "$home/data/projects.md" "$SEED_BACKUP_DIR/sub-projects.md"
888
+ fi
889
+ if [ -f "$home/data/charter.md" ]; then
890
+ SEED_CHARTER_EXISTED=1
891
+ cp "$home/data/charter.md" "$SEED_BACKUP_DIR/charter.md"
892
+ fi
893
+ if [ -f "$home/$SUB_HOME_MARKER" ]; then
894
+ SEED_MARKER_EXISTED=1
895
+ cp "$home/$SUB_HOME_MARKER" "$SEED_BACKUP_DIR/marker"
896
+ fi
897
+ if [ -f "$home/$SUB_HOME_PARENT_MARKER" ]; then
898
+ SEED_PARENT_MARKER_EXISTED=1
899
+ cp "$home/$SUB_HOME_PARENT_MARKER" "$SEED_BACKUP_DIR/parent-marker"
900
+ fi
901
+ SEED_HOME_BACKED_UP=1
902
+
903
+ if [ ! -f "$SEED_PARENT_BRIEF" ]; then
904
+ [ -n "${FM_SECONDMATE_CHARTER:-}" ] || {
905
+ echo "error: no filled secondmate charter brief at $SEED_PARENT_BRIEF; set FM_SECONDMATE_CHARTER or scaffold one and replace {TASK}" >&2
906
+ return 1
907
+ }
908
+ [ -d "$DATA/$id" ] || SEED_PARENT_BRIEF_DIR_CREATED=1
909
+ if [ "$no_projects" -eq 1 ]; then
910
+ "$FM_ROOT/bin/fm-brief.sh" "$id" --secondmate --no-projects
911
+ else
912
+ "$FM_ROOT/bin/fm-brief.sh" "$id" --secondmate "$@"
913
+ fi
914
+ SEED_PARENT_BRIEF_CREATED=1
915
+ fi
916
+ if grep -F '{TASK}' "$SEED_PARENT_BRIEF" >/dev/null 2>&1; then
917
+ echo "error: secondmate charter brief at $SEED_PARENT_BRIEF still contains {TASK}; fill it before seeding" >&2
918
+ return 1
919
+ fi
920
+ charter_summary=$(registry_summary_for_brief "$SEED_PARENT_BRIEF")
921
+ [ -n "$charter_summary" ] || {
922
+ echo "error: secondmate charter brief at $SEED_PARENT_BRIEF has an empty Charter section; fill it before seeding" >&2
923
+ return 1
924
+ }
925
+ charter_scope=$(registry_scope_for_brief "$SEED_PARENT_BRIEF")
926
+ [ -n "$charter_scope" ] || {
927
+ echo "error: secondmate charter brief at $SEED_PARENT_BRIEF has an empty Routing scope section; fill it before seeding" >&2
928
+ return 1
929
+ }
930
+
931
+ for project in "$@"; do
932
+ project_dst=$(validate_project_destination "$home" "$project") || return 1
933
+ [ -e "$project_dst" ] || printf '%s\n' "$project_dst" >> "$SEED_CREATED_PROJECTS_FILE"
934
+ clone_project "$project" "$home"
935
+ done
936
+ sync_project_registry "$home" "$@"
937
+ for project in "$@"; do
938
+ project_dst=$(validate_project_destination "$home" "$project") || return 1
939
+ if seed_project_was_created "$project_dst"; then
940
+ initialize_no_mistakes_project "$home" "$project" 1
941
+ else
942
+ initialize_no_mistakes_project "$home" "$project" 0
943
+ fi
944
+ done
945
+
946
+ cp "$SEED_PARENT_BRIEF" "$home/data/charter.md"
947
+
948
+ projects_csv=$(join_projects "$@")
949
+ # Durable record of this home's route to its parent, written once here next
950
+ # to the identity marker: the cleanup check in fm-teardown.sh reads it so a
951
+ # restart that drops the launch-time FM_PUBLIC_FOLLOWUP_PRIMARY_HOME prefix
952
+ # can still resolve the real parent instead of silently treating its relay
953
+ # as inactive.
954
+ {
955
+ printf 'schema=fm-secondmate-parent.v1\n'
956
+ printf 'route=local\n'
957
+ printf 'parent_home=%s\n' "$(resolved_path "$FM_HOME")"
958
+ } > "$home/$SUB_HOME_PARENT_MARKER.tmp.$$"
959
+ mv -f -- "$home/$SUB_HOME_PARENT_MARKER.tmp.$$" "$home/$SUB_HOME_PARENT_MARKER"
960
+ printf '%s\n' "$id" > "$home/$SUB_HOME_MARKER.tmp.$$"
961
+ mv -f -- "$home/$SUB_HOME_MARKER.tmp.$$" "$home/$SUB_HOME_MARKER"
962
+ write_registry "$id" "$home" "$projects_csv" "$SEED_PARENT_BRIEF"
963
+ validate_registry
964
+ SEED_COMMITTED=1
965
+ seed_registry_lock_release
966
+ trap - EXIT
967
+ rm -rf -- "$SEED_BACKUP_DIR"
968
+ printf 'home=%s\n' "$home"
969
+ }
970
+
971
+ case "${1:-}" in
972
+ validate)
973
+ [ $# -eq 1 ] || { usage; exit 1; }
974
+ validate_registry
975
+ ;;
976
+ -h|--help|'')
977
+ usage
978
+ exit 0
979
+ ;;
980
+ *)
981
+ [ $# -ge 3 ] || { usage; exit 1; }
982
+ seed_home "$@"
983
+ ;;
984
+ esac