@zerwiz/ymir 0.1.4 → 0.1.7

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 (865) 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/README.md +74 -0
  27. package/.agents/backend/backends/cmux.sh +649 -0
  28. package/.agents/backend/backends/herdr-eventwait.py +157 -0
  29. package/.agents/backend/backends/herdr-workspace-move.py +114 -0
  30. package/.agents/backend/backends/herdr.sh +3386 -0
  31. package/.agents/backend/backends/orca.sh +290 -0
  32. package/.agents/backend/backends/tmux.sh +357 -0
  33. package/.agents/backend/backends/zellij.sh +700 -0
  34. package/.agents/backend/fm-afk-launch.sh +654 -0
  35. package/.agents/backend/fm-afk-return.sh +241 -0
  36. package/.agents/backend/fm-afk-start.sh +172 -0
  37. package/.agents/backend/fm-arm-command-policy.mjs +960 -0
  38. package/.agents/backend/fm-arm-pretool-check.sh +200 -0
  39. package/.agents/backend/fm-backend-hometag-lib.sh +52 -0
  40. package/.agents/backend/fm-backend.sh +981 -0
  41. package/.agents/backend/fm-backlog-handoff.sh +909 -0
  42. package/.agents/backend/fm-backlog-receive.sh +187 -0
  43. package/.agents/backend/fm-backlog-transition-lib.sh +779 -0
  44. package/.agents/backend/fm-bearings-board.sh +204 -0
  45. package/.agents/backend/fm-bearings-snapshot.sh +546 -0
  46. package/.agents/backend/fm-bootstrap.sh +1568 -0
  47. package/.agents/backend/fm-branch-outcome.sh +203 -0
  48. package/.agents/backend/fm-branch-prompt.sh +101 -0
  49. package/.agents/backend/fm-brief.sh +452 -0
  50. package/.agents/backend/fm-busy-event.sh +234 -0
  51. package/.agents/backend/fm-busy-lib.sh +986 -0
  52. package/.agents/backend/fm-captain-hold.sh +1001 -0
  53. package/.agents/backend/fm-cd-command-policy.mjs +153 -0
  54. package/.agents/backend/fm-cd-pretool-check.sh +190 -0
  55. package/.agents/backend/fm-check-lib.sh +74 -0
  56. package/.agents/backend/fm-check-register.sh +42 -0
  57. package/.agents/backend/fm-check-unregister.sh +52 -0
  58. package/.agents/backend/fm-classify-lib.sh +1770 -0
  59. package/.agents/backend/fm-claude-stop-autoarm.sh +334 -0
  60. package/.agents/backend/fm-composer-lib.sh +1416 -0
  61. package/.agents/backend/fm-config-inherit-lib.sh +1202 -0
  62. package/.agents/backend/fm-config-push.sh +254 -0
  63. package/.agents/backend/fm-control-lib.sh +251 -0
  64. package/.agents/backend/fm-control.sh +878 -0
  65. package/.agents/backend/fm-crew-state.sh +625 -0
  66. package/.agents/backend/fm-cursor-lib.sh +243 -0
  67. package/.agents/backend/fm-decision-hold.sh +232 -0
  68. package/.agents/backend/fm-doc-audience-check.sh +269 -0
  69. package/.agents/backend/fm-dod-lib.sh +67 -0
  70. package/.agents/backend/fm-ensure-agents-md.sh +253 -0
  71. package/.agents/backend/fm-extension-launch-barrier.mjs +129 -0
  72. package/.agents/backend/fm-extension.mjs +2577 -0
  73. package/.agents/backend/fm-extension.sh +16 -0
  74. package/.agents/backend/fm-ff-lib.sh +420 -0
  75. package/.agents/backend/fm-fleet-snapshot.sh +1463 -0
  76. package/.agents/backend/fm-fleet-sync.sh +458 -0
  77. package/.agents/backend/fm-fleet-view.sh +96 -0
  78. package/.agents/backend/fm-gate-refuse-lib.sh +102 -0
  79. package/.agents/backend/fm-guard.sh +242 -0
  80. package/.agents/backend/fm-harness.sh +195 -0
  81. package/.agents/backend/fm-herdr-ci-cleanup.sh +115 -0
  82. package/.agents/backend/fm-herdr-lab.sh +346 -0
  83. package/.agents/backend/fm-herdr-session-cleanup.sh +337 -0
  84. package/.agents/backend/fm-home-seed.sh +984 -0
  85. package/.agents/backend/fm-home-summary-refresh.sh +255 -0
  86. package/.agents/backend/fm-hook-host-lib.sh +36 -0
  87. package/.agents/backend/fm-inactive-reconcile.sh +531 -0
  88. package/.agents/backend/fm-inbox.sh +399 -0
  89. package/.agents/backend/fm-install-actionlint.sh +84 -0
  90. package/.agents/backend/fm-install-herdr.sh +96 -0
  91. package/.agents/backend/fm-install-shellcheck.sh +84 -0
  92. package/.agents/backend/fm-install-treehouse.sh +95 -0
  93. package/.agents/backend/fm-kimi-turnend-hook.sh +276 -0
  94. package/.agents/backend/fm-lease-lib.sh +218 -0
  95. package/.agents/backend/fm-lease.sh +189 -0
  96. package/.agents/backend/fm-line-cap-lib.sh +51 -0
  97. package/.agents/backend/fm-lint-workflows.sh +137 -0
  98. package/.agents/backend/fm-lint.sh +591 -0
  99. package/.agents/backend/fm-lock-lib.sh +104 -0
  100. package/.agents/backend/fm-lock.sh +107 -0
  101. package/.agents/backend/fm-marker-lib.sh +12 -0
  102. package/.agents/backend/fm-merge-local.sh +74 -0
  103. package/.agents/backend/fm-merge-outcome-lib.sh +138 -0
  104. package/.agents/backend/fm-nm-run-lib.sh +124 -0
  105. package/.agents/backend/fm-on.sh +125 -0
  106. package/.agents/backend/fm-operational-input.sh +253 -0
  107. package/.agents/backend/fm-peek.sh +46 -0
  108. package/.agents/backend/fm-pending-reply-lib.sh +1409 -0
  109. package/.agents/backend/fm-pr-check.sh +135 -0
  110. package/.agents/backend/fm-pr-lib.sh +1016 -0
  111. package/.agents/backend/fm-pr-merge.sh +707 -0
  112. package/.agents/backend/fm-pr-poll.sh +110 -0
  113. package/.agents/backend/fm-primary-scope-lib.sh +33 -0
  114. package/.agents/backend/fm-procevent-extension-capture.pl +259 -0
  115. package/.agents/backend/fm-procevent-lavish.sh +628 -0
  116. package/.agents/backend/fm-procevent-lib.sh +892 -0
  117. package/.agents/backend/fm-procevent-quota.sh +290 -0
  118. package/.agents/backend/fm-procevent-remote-reply.sh +577 -0
  119. package/.agents/backend/fm-procevent-when.sh +504 -0
  120. package/.agents/backend/fm-procevent.sh +1466 -0
  121. package/.agents/backend/fm-project-mode.sh +92 -0
  122. package/.agents/backend/fm-project-origin-lib.sh +180 -0
  123. package/.agents/backend/fm-promote.sh +282 -0
  124. package/.agents/backend/fm-public-followup-emit.sh +260 -0
  125. package/.agents/backend/fm-public-followup-lib.sh +398 -0
  126. package/.agents/backend/fm-public-followup.sh +1330 -0
  127. package/.agents/backend/fm-push-transition-lib.sh +168 -0
  128. package/.agents/backend/fm-quota-axi-lib.sh +93 -0
  129. package/.agents/backend/fm-quota-choose.sh +384 -0
  130. package/.agents/backend/fm-remote-delta-read.sh +189 -0
  131. package/.agents/backend/fm-remote-doctor.sh +800 -0
  132. package/.agents/backend/fm-remote-entrypoint.sh +193 -0
  133. package/.agents/backend/fm-remote-file.sh +234 -0
  134. package/.agents/backend/fm-remote-home-provision.sh +259 -0
  135. package/.agents/backend/fm-remote-home-seed.sh +259 -0
  136. package/.agents/backend/fm-remote-inherit-push.sh +90 -0
  137. package/.agents/backend/fm-remote-inherit.sh +179 -0
  138. package/.agents/backend/fm-remote-job-lib.sh +1241 -0
  139. package/.agents/backend/fm-remote-job-reap-orphans.sh +137 -0
  140. package/.agents/backend/fm-remote-job-worker.sh +1124 -0
  141. package/.agents/backend/fm-remote-readiness-lib.sh +44 -0
  142. package/.agents/backend/fm-remote-secondmate-control.sh +340 -0
  143. package/.agents/backend/fm-review-diff.sh +158 -0
  144. package/.agents/backend/fm-secondmate-charter-lib.sh +44 -0
  145. package/.agents/backend/fm-secondmate-nudge-lib.sh +68 -0
  146. package/.agents/backend/fm-secondmate-parent-lib.sh +70 -0
  147. package/.agents/backend/fm-secondmate-reconcile.sh +371 -0
  148. package/.agents/backend/fm-secondmate-registry-lib.sh +311 -0
  149. package/.agents/backend/fm-secondmate-report.sh +88 -0
  150. package/.agents/backend/fm-send.sh +1059 -0
  151. package/.agents/backend/fm-session-lock-lib.sh +176 -0
  152. package/.agents/backend/fm-session-start.sh +970 -0
  153. package/.agents/backend/fm-sessionstart-cursor.sh +40 -0
  154. package/.agents/backend/fm-sessionstart-nudge.sh +45 -0
  155. package/.agents/backend/fm-sessionstart-run.sh +145 -0
  156. package/.agents/backend/fm-spawn.sh +3153 -0
  157. package/.agents/backend/fm-startup-memory-budget-lib.sh +224 -0
  158. package/.agents/backend/fm-startup-memory-budget.sh +94 -0
  159. package/.agents/backend/fm-startup-network.sh +642 -0
  160. package/.agents/backend/fm-stow-cascade.sh +251 -0
  161. package/.agents/backend/fm-subagent-pretool-check.sh +207 -0
  162. package/.agents/backend/fm-supervise-daemon.sh +1732 -0
  163. package/.agents/backend/fm-supervision-instructions.sh +215 -0
  164. package/.agents/backend/fm-supervision-lib.sh +90 -0
  165. package/.agents/backend/fm-supervisor-target-lib.sh +78 -0
  166. package/.agents/backend/fm-tangle-lib.sh +53 -0
  167. package/.agents/backend/fm-task-inbox-lib.sh +402 -0
  168. package/.agents/backend/fm-tasks-axi-lib.sh +123 -0
  169. package/.agents/backend/fm-teardown.sh +2922 -0
  170. package/.agents/backend/fm-test-isolation-proof.sh +588 -0
  171. package/.agents/backend/fm-test-run.sh +2191 -0
  172. package/.agents/backend/fm-timeout-lib.sh +141 -0
  173. package/.agents/backend/fm-timing-lib.sh +179 -0
  174. package/.agents/backend/fm-tmux-lib.sh +291 -0
  175. package/.agents/backend/fm-tool-update-check.sh +898 -0
  176. package/.agents/backend/fm-trace-context-lib.sh +227 -0
  177. package/.agents/backend/fm-transition-lib.sh +103 -0
  178. package/.agents/backend/fm-turnend-guard-cursor.sh +391 -0
  179. package/.agents/backend/fm-turnend-guard-grok.sh +90 -0
  180. package/.agents/backend/fm-turnend-guard.sh +432 -0
  181. package/.agents/backend/fm-update.sh +110 -0
  182. package/.agents/backend/fm-vendor-auth-probe.sh +190 -0
  183. package/.agents/backend/fm-voice-client.py +1373 -0
  184. package/.agents/backend/fm-voice-relay.py +1256 -0
  185. package/.agents/backend/fm-wake-drain.sh +592 -0
  186. package/.agents/backend/fm-wake-grant.sh +127 -0
  187. package/.agents/backend/fm-wake-lib.sh +1849 -0
  188. package/.agents/backend/fm-watch-arm.sh +602 -0
  189. package/.agents/backend/fm-watch-checkpoint.sh +109 -0
  190. package/.agents/backend/fm-watch.sh +1962 -0
  191. package/.agents/backend/fm-x-dismiss.sh +116 -0
  192. package/.agents/backend/fm-x-followup.sh +286 -0
  193. package/.agents/backend/fm-x-lib.sh +1000 -0
  194. package/.agents/backend/fm-x-link.sh +234 -0
  195. package/.agents/backend/fm-x-poll.sh +185 -0
  196. package/.agents/backend/fm-x-reply.sh +385 -0
  197. package/.agents/backend/fm_voice_frame.py +166 -0
  198. package/.agents/backend/fm_voice_records.py +574 -0
  199. package/.agents/backend/model-bridge.py +360 -0
  200. package/.agents/backend/opencode-go-bridge.py +30 -0
  201. package/.agents/bus/README.md +12 -0
  202. package/.agents/bus/messages.json +1 -0
  203. package/.agents/config/agents.machine.example.yaml +16 -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 +11 -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/filebrowser/.filebrowser.json +6 -0
  211. package/.agents/filebrowser/README.md +11 -0
  212. package/.agents/gateway/README.md +12 -0
  213. package/.agents/github/README.md +15 -0
  214. package/.agents/github/webhooks/.gitkeep +0 -0
  215. package/.agents/github/workflows/.gitkeep +0 -0
  216. package/.agents/harness/opencode/plugins/lib/rodd-operational-input.js +37 -0
  217. package/.agents/harness/opencode/plugins/package.json +4 -0
  218. package/.agents/harness/opencode/plugins/saga-sessionstart.js +77 -0
  219. package/.agents/harness/opencode/plugins/syn-cd-check.js +61 -0
  220. package/.agents/harness/opencode/plugins/syn-pretool-check.js +68 -0
  221. package/.agents/harness/opencode/plugins/syn-turnend-guard.js +105 -0
  222. package/.agents/harness/opencode/plugins/syn-watch-arm.js +521 -0
  223. package/.agents/memory/README.md +46 -0
  224. package/.agents/memory/runes_audit.md +5 -0
  225. package/.agents/migrations/0001-hodd-layout.sh +38 -0
  226. package/.agents/migrations/0002-a2a-mcp.sh +27 -0
  227. package/.agents/migrations/0003-private-data-separation.sh +121 -0
  228. package/.agents/migrations/0004-hoard-and-realms.sh +104 -0
  229. package/.agents/migrations/0005-roots-out-of-tree.sh +158 -0
  230. package/.agents/sandbox/Dockerfile.utgard +19 -0
  231. package/.agents/sandbox/README.md +14 -0
  232. package/.agents/sandbox/utgard.config.json +14 -0
  233. package/.agents/skills/README.md +59 -0
  234. package/.agents/skills/bragi-marketing/README.md +3 -0
  235. package/.agents/skills/bragi-marketing/SKILL.md +82 -0
  236. package/.agents/skills/eindri-homes/README.md +3 -0
  237. package/.agents/skills/eindri-homes/SKILL.md +291 -0
  238. package/.agents/skills/eindri-homes/assets/control-plane.md +122 -0
  239. package/.agents/skills/eindri-homes/assets/dispatch.md +80 -0
  240. package/.agents/skills/frigg-consent/README.md +3 -0
  241. package/.agents/skills/frigg-consent/SKILL.md +56 -0
  242. package/.agents/skills/galdr-ymirsystem/README.md +3 -0
  243. package/.agents/skills/galdr-ymirsystem/SKILL.md +159 -0
  244. package/.agents/skills/galdr-ymirsystem/assets/README.md +74 -0
  245. package/.agents/skills/galdr-ymirsystem/assets/brokk-distro-runtime.md +390 -0
  246. package/.agents/skills/galdr-ymirsystem/assets/build-method.md +113 -0
  247. package/.agents/skills/galdr-ymirsystem/assets/build-tool-categories.md +178 -0
  248. package/.agents/skills/galdr-ymirsystem/assets/eindri-orchestration.md +518 -0
  249. package/.agents/skills/galdr-ymirsystem/assets/eindri-profiles.md +136 -0
  250. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/README.md +736 -0
  251. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/claude-code.md +197 -0
  252. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/codex.md +191 -0
  253. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/cursor.md +193 -0
  254. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/opencode.md +262 -0
  255. package/.agents/skills/galdr-ymirsystem/assets/harness-integration/pi.md +295 -0
  256. package/.agents/skills/galdr-ymirsystem/assets/hlidskjalf-ui.md +539 -0
  257. package/.agents/skills/galdr-ymirsystem/assets/installation.md +763 -0
  258. package/.agents/skills/galdr-ymirsystem/assets/local-models/HOST-DATA.example.md +72 -0
  259. package/.agents/skills/galdr-ymirsystem/assets/local-models.md +274 -0
  260. package/.agents/skills/galdr-ymirsystem/assets/memory-well.md +163 -0
  261. package/.agents/skills/galdr-ymirsystem/assets/nornir-jobs.md +415 -0
  262. package/.agents/skills/galdr-ymirsystem/assets/norse-naming.md +325 -0
  263. package/.agents/skills/galdr-ymirsystem/assets/odrerir-hall.md +133 -0
  264. package/.agents/skills/galdr-ymirsystem/assets/pi-boot/einherjar-spawn.schema.json +81 -0
  265. package/.agents/skills/galdr-ymirsystem/assets/pi-boot/herdr-profile.toml +75 -0
  266. package/.agents/skills/galdr-ymirsystem/assets/pi-boot/pi-profile.yml +101 -0
  267. package/.agents/skills/galdr-ymirsystem/assets/pi-boot/supervision-tree.yml +163 -0
  268. package/.agents/skills/galdr-ymirsystem/assets/pi-boot-guide.md +58 -0
  269. package/.agents/skills/galdr-ymirsystem/assets/porting-upstream-to-norse.md +301 -0
  270. package/.agents/skills/galdr-ymirsystem/assets/principles.md +385 -0
  271. package/.agents/skills/galdr-ymirsystem/assets/reference-adoption.md +99 -0
  272. package/.agents/skills/galdr-ymirsystem/assets/registry.md +379 -0
  273. package/.agents/skills/galdr-ymirsystem/assets/runtime-compliance.md +463 -0
  274. package/.agents/skills/galdr-ymirsystem/assets/runtime-components.md +553 -0
  275. package/.agents/skills/galdr-ymirsystem/assets/smidja.md +180 -0
  276. package/.agents/skills/galdr-ymirsystem/schemas/toon-schemas.md +190 -0
  277. package/.agents/skills/galdr-ymirsystem/scripts/README.md +45 -0
  278. package/.agents/skills/galdr-ymirsystem/scripts/bench-one.sh +248 -0
  279. package/.agents/skills/galdr-ymirsystem/scripts/compliance-check.sh +503 -0
  280. package/.agents/skills/galdr-ymirsystem/scripts/gpu-sample.sh +43 -0
  281. package/.agents/skills/galdr-ymirsystem/scripts/stop-all.sh +34 -0
  282. package/.agents/skills/galdr-ymirsystem/scripts/toon-check.py +188 -0
  283. package/.agents/skills/gjallarhorn-relay/README.md +3 -0
  284. package/.agents/skills/gjallarhorn-relay/SKILL.md +283 -0
  285. package/.agents/skills/groa-update/SKILL.md +90 -0
  286. package/.agents/skills/hamr-adapters/README.md +3 -0
  287. package/.agents/skills/hamr-adapters/SKILL.md +123 -0
  288. package/.agents/skills/hamr-adapters/references/common/control-and-recovery.md +37 -0
  289. package/.agents/skills/hamr-adapters/references/common/dispatch.md +32 -0
  290. package/.agents/skills/hamr-adapters/references/common/model-and-effort.md +42 -0
  291. package/.agents/skills/hamr-adapters/references/common/primary-hooks.md +40 -0
  292. package/.agents/skills/hamr-adapters/references/harness/claude.md +55 -0
  293. package/.agents/skills/hamr-adapters/references/harness/codex.md +43 -0
  294. package/.agents/skills/hamr-adapters/references/harness/cursor.md +75 -0
  295. package/.agents/skills/hamr-adapters/references/harness/grok.md +69 -0
  296. package/.agents/skills/hamr-adapters/references/harness/kimi.md +51 -0
  297. package/.agents/skills/hamr-adapters/references/harness/muse.md +70 -0
  298. package/.agents/skills/hamr-adapters/references/harness/opencode.md +42 -0
  299. package/.agents/skills/hamr-adapters/references/harness/pi.md +56 -0
  300. package/.agents/skills/herdr-panes/README.md +3 -0
  301. package/.agents/skills/herdr-panes/SKILL.md +92 -0
  302. package/.agents/skills/herdr-panes/assets/herdr-backend.md +346 -0
  303. package/.agents/skills/herdr-panes/assets/tmux-backend.md +115 -0
  304. package/.agents/skills/hnoss-design/DESIGN.md +19 -0
  305. package/.agents/skills/hnoss-design/README.md +3 -0
  306. package/.agents/skills/hnoss-design/SKILL.md +83 -0
  307. package/.agents/skills/hvild-afk/README.md +3 -0
  308. package/.agents/skills/hvild-afk/SKILL.md +241 -0
  309. package/.agents/skills/jord-projects/README.md +3 -0
  310. package/.agents/skills/jord-projects/SKILL.md +92 -0
  311. package/.agents/skills/lifecycle/SKILL.md +56 -0
  312. package/.agents/skills/lifecycle/smoke_test.sh +57 -0
  313. package/.agents/skills/lifecycle/start.sh +21 -0
  314. package/.agents/skills/lifecycle/status.sh +35 -0
  315. package/.agents/skills/lifecycle/stop.sh +16 -0
  316. package/.agents/skills/muninn-stow/README.md +3 -0
  317. package/.agents/skills/muninn-stow/SKILL.md +309 -0
  318. package/.agents/skills/no-mistakes/SKILL.md +379 -0
  319. package/.agents/skills/nornir-schedule/README.md +3 -0
  320. package/.agents/skills/nornir-schedule/SKILL.md +25 -0
  321. package/.agents/skills/nornir-schedule/assets/events.md +137 -0
  322. package/.agents/skills/nornir-schedule/assets/quota.md +131 -0
  323. package/.agents/skills/nsr-compliance/README.md +3 -0
  324. package/.agents/skills/nsr-compliance/SKILL.md +29 -0
  325. package/.agents/skills/nsr-compliance/assets/nsr/README.md +40 -0
  326. package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/README.md +15 -0
  327. package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/git-workflow.md +18 -0
  328. package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/security.md +22 -0
  329. package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/tech-stack.md +8 -0
  330. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/SKILL.md +71 -0
  331. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/config/core_four.yaml +16 -0
  332. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/check_danger.sh +102 -0
  333. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/check_wiring.sh +69 -0
  334. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/validate_code.sh +29 -0
  335. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/verify_docs.py +66 -0
  336. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/generate.sh +109 -0
  337. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/envelopes/result_envelope.json +14 -0
  338. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/envelopes/task_envelope.json +20 -0
  339. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/runner.py +303 -0
  340. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/telemetry/logger.py +112 -0
  341. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/README.md +18 -0
  342. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/config/README.md +10 -0
  343. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/README.md +12 -0
  344. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_env.sh +23 -0
  345. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_paths.sh +20 -0
  346. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_platform.sh +23 -0
  347. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/harness/README.md +11 -0
  348. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/harness/envelopes/README.md +10 -0
  349. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/installer/README.md +10 -0
  350. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/installer/install.sh +125 -0
  351. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/telemetry/README.md +11 -0
  352. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/README.md +20 -0
  353. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/features/README.md +36 -0
  354. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/features/SKILL-template.md +14 -0
  355. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/README.md +25 -0
  356. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/SKILL.md +13 -0
  357. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/create_branch.sh +6 -0
  358. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/safe_commit.sh +9 -0
  359. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/sync_upstream.sh +6 -0
  360. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/README.md +27 -0
  361. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/SKILL.md +15 -0
  362. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/smoke_test.sh +12 -0
  363. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/start.sh +19 -0
  364. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/status.sh +12 -0
  365. package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/stop.sh +15 -0
  366. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/README.md +18 -0
  367. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/config/README.md +10 -0
  368. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/config/core_four.yaml +13 -0
  369. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/README.md +12 -0
  370. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_danger.sh +102 -0
  371. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_env.sh +23 -0
  372. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_paths.sh +20 -0
  373. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_platform.sh +23 -0
  374. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_wiring.sh +69 -0
  375. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/README.md +11 -0
  376. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/README.md +10 -0
  377. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/result_envelope.json +14 -0
  378. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/task_envelope.json +20 -0
  379. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/runner.py +303 -0
  380. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/installer/README.md +10 -0
  381. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/installer/install.sh +125 -0
  382. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/telemetry/README.md +11 -0
  383. package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/telemetry/logger.py +112 -0
  384. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/README.md +14 -0
  385. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/api.md +17 -0
  386. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/compliance-wiring.md +155 -0
  387. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/frontend.md +15 -0
  388. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/README.md +11 -0
  389. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/README.md +23 -0
  390. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/clients/README.md +16 -0
  391. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/clients/template-README.md +11 -0
  392. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/deploy.sh +49 -0
  393. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/README.md +12 -0
  394. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/development.env.example +17 -0
  395. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/production.env.example +17 -0
  396. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/staging.env.example +17 -0
  397. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/tenants/README.md +11 -0
  398. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/tenants/template.env.example +8 -0
  399. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/README.md +26 -0
  400. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/agent.md +7 -0
  401. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/developers/dev-1.md +20 -0
  402. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/linux.md +9 -0
  403. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/macos.md +10 -0
  404. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/shared.md +19 -0
  405. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/windows.md +14 -0
  406. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/README.md +25 -0
  407. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/_template.md +41 -0
  408. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/hosting-1.md +41 -0
  409. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/README.md +21 -0
  410. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/README.md +15 -0
  411. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/deployment.md +19 -0
  412. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/disaster-recovery.md +15 -0
  413. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/ops-tasks.md +14 -0
  414. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/features/README.md +16 -0
  415. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/project-skills.md +146 -0
  416. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/research/README.md +11 -0
  417. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/research/software-compliance-research.md +269 -0
  418. package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/working-with-agents.md +260 -0
  419. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/AGENTS.md +38 -0
  420. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/ARCHITECTURE.md +36 -0
  421. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/BEST_PRACTICES.md +27 -0
  422. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/CI_CD.md +23 -0
  423. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/FEATURES.md +15 -0
  424. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/README.md +22 -0
  425. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/RULES.md +37 -0
  426. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/STRUCTURE.md +45 -0
  427. package/.agents/skills/nsr-compliance/assets/nsr/assets/root/TECH_STACK.md +28 -0
  428. package/.agents/skills/nsr-compliance/assets/nsr/scaffold-spec.md +63 -0
  429. package/.agents/skills/nsr-compliance/assets/nsr/scripts/scaffold.sh +103 -0
  430. package/.agents/skills/nsr-compliance/assets/nsr/scripts/validate.sh +52 -0
  431. package/.agents/skills/nsr-compliance/assets/nsrcompliance/SKILL.md +71 -0
  432. package/.agents/skills/nsr-compliance/assets/nsrcompliance/config/core_four.yaml +16 -0
  433. package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/check_danger.sh +102 -0
  434. package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/check_wiring.sh +69 -0
  435. package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/validate_code.sh +29 -0
  436. package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/verify_docs.py +66 -0
  437. package/.agents/skills/nsr-compliance/assets/nsrcompliance/generate.sh +109 -0
  438. package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/envelopes/result_envelope.json +14 -0
  439. package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/envelopes/task_envelope.json +20 -0
  440. package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/runner.py +303 -0
  441. package/.agents/skills/nsr-compliance/assets/nsrcompliance/telemetry/logger.py +112 -0
  442. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/README.md +18 -0
  443. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/config/README.md +10 -0
  444. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/README.md +12 -0
  445. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_env.sh +23 -0
  446. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_paths.sh +20 -0
  447. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_platform.sh +23 -0
  448. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/harness/README.md +11 -0
  449. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/harness/envelopes/README.md +10 -0
  450. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/installer/README.md +10 -0
  451. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/installer/install.sh +125 -0
  452. package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/telemetry/README.md +11 -0
  453. package/.agents/skills/pr-ops/README.md +3 -0
  454. package/.agents/skills/pr-ops/SKILL.md +109 -0
  455. package/.agents/skills/ratatoskr-a2a/README.md +3 -0
  456. package/.agents/skills/ratatoskr-a2a/SKILL.md +148 -0
  457. package/.agents/skills/rules-check-drift/SKILL.md +81 -0
  458. package/.agents/skills/saga-bearings/README.md +3 -0
  459. package/.agents/skills/saga-bearings/SKILL.md +26 -0
  460. package/.agents/skills/saga-bearings/assets/bearings.md +161 -0
  461. package/.agents/skills/saga-bearings/assets/board-template.html +731 -0
  462. package/.agents/skills/saga-bearings/assets/recap.md +56 -0
  463. package/.agents/skills/syn-recovery/README.md +3 -0
  464. package/.agents/skills/syn-recovery/SKILL.md +54 -0
  465. package/.agents/skills/tyr-check/README.md +3 -0
  466. package/.agents/skills/tyr-check/SKILL.md +218 -0
  467. package/.agents/skills/urdh-hold/README.md +3 -0
  468. package/.agents/skills/urdh-hold/SKILL.md +25 -0
  469. package/.agents/skills/urdh-hold/assets/decisions.md +15 -0
  470. package/.agents/skills/urdh-hold/assets/hold.md +54 -0
  471. package/.agents/skills/vor-diagnostics/README.md +3 -0
  472. package/.agents/skills/vor-diagnostics/SKILL.md +68 -0
  473. package/.agents/skills/ymir-host/README.md +3 -0
  474. package/.agents/skills/ymir-host/SKILL.md +35 -0
  475. package/.agents/skills/ymir-host/assets/desktop.md +36 -0
  476. package/.agents/skills/ymir-host/assets/install.md +69 -0
  477. package/.agents/skills/ymir-host/assets/omarchy.md +297 -0
  478. package/.agents/skills/ymir-host/assets/runbooks.md +15 -0
  479. package/.agents/skills/ymir-host/assets/thjazi.md +220 -0
  480. package/.agents/skills/ymir-host/assets/update.md +64 -0
  481. package/.agents/tests/assets/board-render-harness.mjs +117 -0
  482. package/.agents/tests/cmux-test-safety.sh +51 -0
  483. package/.agents/tests/fixtures.sh +291 -0
  484. package/.agents/tests/fm-afk-inject-e2e.test.sh +428 -0
  485. package/.agents/tests/fm-afk-inject-herdr-e2e.test.sh +536 -0
  486. package/.agents/tests/fm-afk-launch.test.sh +961 -0
  487. package/.agents/tests/fm-afk-pi-herdr-return-e2e.test.sh +297 -0
  488. package/.agents/tests/fm-afk-return.test.sh +283 -0
  489. package/.agents/tests/fm-arm-pretool-check.test.sh +482 -0
  490. package/.agents/tests/fm-ask-user-authority.test.sh +42 -0
  491. package/.agents/tests/fm-backend-autodetect-smoke.test.sh +176 -0
  492. package/.agents/tests/fm-backend-cmux-smoke.test.sh +188 -0
  493. package/.agents/tests/fm-backend-cmux.test.sh +1166 -0
  494. package/.agents/tests/fm-backend-herdr-eventwait-smoke.test.sh +136 -0
  495. package/.agents/tests/fm-backend-herdr-eventwait.test.py +106 -0
  496. package/.agents/tests/fm-backend-herdr-focus-flash-e2e.test.sh +409 -0
  497. package/.agents/tests/fm-backend-herdr-launcher-workspace-e2e.test.sh +437 -0
  498. package/.agents/tests/fm-backend-herdr-presentation-e2e.test.sh +1424 -0
  499. package/.agents/tests/fm-backend-herdr-prune-safety-e2e.test.sh +180 -0
  500. package/.agents/tests/fm-backend-herdr-respawn-idem-e2e.test.sh +182 -0
  501. package/.agents/tests/fm-backend-herdr-smoke.test.sh +355 -0
  502. package/.agents/tests/fm-backend-herdr-workspace-per-home-e2e.test.sh +251 -0
  503. package/.agents/tests/fm-backend-herdr.test.sh +4606 -0
  504. package/.agents/tests/fm-backend-orca.test.sh +1357 -0
  505. package/.agents/tests/fm-backend-tmux-smoke.test.sh +173 -0
  506. package/.agents/tests/fm-backend-zellij-smoke.test.sh +205 -0
  507. package/.agents/tests/fm-backend-zellij.test.sh +1360 -0
  508. package/.agents/tests/fm-backend.test.sh +1142 -0
  509. package/.agents/tests/fm-backlog-atomicity.test.sh +2302 -0
  510. package/.agents/tests/fm-backlog-handoff.test.sh +1360 -0
  511. package/.agents/tests/fm-bearings-board-render.test.sh +135 -0
  512. package/.agents/tests/fm-bearings-board.test.sh +414 -0
  513. package/.agents/tests/fm-bearings-snapshot.test.sh +1990 -0
  514. package/.agents/tests/fm-bootstrap-network-parallel.test.sh +316 -0
  515. package/.agents/tests/fm-bootstrap.test.sh +1178 -0
  516. package/.agents/tests/fm-branch-supervision.test.sh +552 -0
  517. package/.agents/tests/fm-brief.test.sh +785 -0
  518. package/.agents/tests/fm-busy-adapter-wiring.test.sh +324 -0
  519. package/.agents/tests/fm-busy-state.test.sh +465 -0
  520. package/.agents/tests/fm-calm-pi-extension.test.sh +3979 -0
  521. package/.agents/tests/fm-captain-hold-lifecycle.test.sh +1187 -0
  522. package/.agents/tests/fm-cd-pretool-check.test.sh +400 -0
  523. package/.agents/tests/fm-check-unregister.test.sh +198 -0
  524. package/.agents/tests/fm-classify-corr-token.test.sh +543 -0
  525. package/.agents/tests/fm-classify-decision-key.test.sh +340 -0
  526. package/.agents/tests/fm-claude-stop-autoarm-live-e2e.test.sh +164 -0
  527. package/.agents/tests/fm-claude-stop-autoarm.test.sh +1190 -0
  528. package/.agents/tests/fm-cmux-claude-composer-live-e2e.test.sh +110 -0
  529. package/.agents/tests/fm-codex-continuity-live-e2e.test.sh +55 -0
  530. package/.agents/tests/fm-composer-ghost.test.sh +716 -0
  531. package/.agents/tests/fm-composer-lib.test.sh +666 -0
  532. package/.agents/tests/fm-composer-matrix-live-e2e.test.sh +220 -0
  533. package/.agents/tests/fm-control-herdr-smoke.test.sh +149 -0
  534. package/.agents/tests/fm-control-relaunch.test.sh +1530 -0
  535. package/.agents/tests/fm-control.test.sh +910 -0
  536. package/.agents/tests/fm-crew-state.test.sh +1610 -0
  537. package/.agents/tests/fm-cursor-harness.test.sh +404 -0
  538. package/.agents/tests/fm-cursor-primary-live-e2e.test.sh +217 -0
  539. package/.agents/tests/fm-cursor-primary.test.sh +708 -0
  540. package/.agents/tests/fm-daemon.test.sh +2740 -0
  541. package/.agents/tests/fm-documentation-audiences.test.sh +141 -0
  542. package/.agents/tests/fm-ensure-agents-md.test.sh +371 -0
  543. package/.agents/tests/fm-extension-binding.test.sh +2187 -0
  544. package/.agents/tests/fm-fleet-snapshot-view.test.sh +816 -0
  545. package/.agents/tests/fm-fleet-sync.test.sh +721 -0
  546. package/.agents/tests/fm-gate-refuse.test.sh +356 -0
  547. package/.agents/tests/fm-gitignore-config.test.sh +89 -0
  548. package/.agents/tests/fm-gotmp.test.sh +230 -0
  549. package/.agents/tests/fm-grok-continuity-live-e2e.test.sh +112 -0
  550. package/.agents/tests/fm-grok-harness.test.sh +117 -0
  551. package/.agents/tests/fm-grok-stop-live-e2e.test.sh +219 -0
  552. package/.agents/tests/fm-guard-stale-banner.test.sh +709 -0
  553. package/.agents/tests/fm-harness-adapter-instructions-live-e2e.test.sh +134 -0
  554. package/.agents/tests/fm-harness-adapter-references.test.sh +30 -0
  555. package/.agents/tests/fm-harness-liveness-drift-live-e2e.test.sh +151 -0
  556. package/.agents/tests/fm-herdr-lab.test.sh +243 -0
  557. package/.agents/tests/fm-herdr-session-cleanup-e2e.test.sh +146 -0
  558. package/.agents/tests/fm-herdr-session-cleanup.test.sh +329 -0
  559. package/.agents/tests/fm-herdr-submit-confirm-live-e2e.test.sh +125 -0
  560. package/.agents/tests/fm-herdr-version-floor-live-e2e.test.sh +144 -0
  561. package/.agents/tests/fm-home-summary-refresh.test.sh +971 -0
  562. package/.agents/tests/fm-inactive-reconcile.test.sh +485 -0
  563. package/.agents/tests/fm-kimi-harness.test.sh +687 -0
  564. package/.agents/tests/fm-lint-workflows.test.sh +532 -0
  565. package/.agents/tests/fm-lint.test.sh +1023 -0
  566. package/.agents/tests/fm-muse-harness.test.sh +932 -0
  567. package/.agents/tests/fm-muse-signals-live-e2e.test.sh +205 -0
  568. package/.agents/tests/fm-no-mistakes-required.test.sh +72 -0
  569. package/.agents/tests/fm-on.test.sh +507 -0
  570. package/.agents/tests/fm-opencode-primary-live-e2e.test.sh +357 -0
  571. package/.agents/tests/fm-operational-input.test.sh +160 -0
  572. package/.agents/tests/fm-peek-remote.test.sh +110 -0
  573. package/.agents/tests/fm-pending-reply.test.sh +1288 -0
  574. package/.agents/tests/fm-pi-branch-extension.test.sh +3182 -0
  575. package/.agents/tests/fm-pi-branch-live-e2e.test.sh +527 -0
  576. package/.agents/tests/fm-pi-primary-live-e2e.test.sh +345 -0
  577. package/.agents/tests/fm-pi-primary-types.test.sh +68 -0
  578. package/.agents/tests/fm-pi-watch-extension.test.sh +2843 -0
  579. package/.agents/tests/fm-pr-check-security.test.sh +2140 -0
  580. package/.agents/tests/fm-pr-merge.test.sh +2135 -0
  581. package/.agents/tests/fm-procevent-quota.test.sh +225 -0
  582. package/.agents/tests/fm-procevent-when.test.sh +406 -0
  583. package/.agents/tests/fm-procevent.test.sh +1745 -0
  584. package/.agents/tests/fm-project-origin.test.sh +110 -0
  585. package/.agents/tests/fm-public-followup.test.sh +2272 -0
  586. package/.agents/tests/fm-quota-array-dispatch-live-e2e.test.sh +526 -0
  587. package/.agents/tests/fm-quota-choose.test.sh +626 -0
  588. package/.agents/tests/fm-remote-backlog-handoff.test.sh +453 -0
  589. package/.agents/tests/fm-remote-doctor.test.sh +625 -0
  590. package/.agents/tests/fm-remote-entrypoint.test.sh +59 -0
  591. package/.agents/tests/fm-remote-job-orphan-reap.test.sh +205 -0
  592. package/.agents/tests/fm-remote-job.test.sh +768 -0
  593. package/.agents/tests/fm-remote-reply.test.sh +520 -0
  594. package/.agents/tests/fm-remote-secondmate-lifecycle-e2e.test.sh +1256 -0
  595. package/.agents/tests/fm-remote-secondmate-parent-binding.test.sh +326 -0
  596. package/.agents/tests/fm-remote-secondmate-trace-context.test.sh +310 -0
  597. package/.agents/tests/fm-remote-transport-lanes.test.sh +431 -0
  598. package/.agents/tests/fm-review-diff.test.sh +176 -0
  599. package/.agents/tests/fm-secondmate-harness.test.sh +2600 -0
  600. package/.agents/tests/fm-secondmate-lifecycle-e2e.test.sh +259 -0
  601. package/.agents/tests/fm-secondmate-liveness.test.sh +559 -0
  602. package/.agents/tests/fm-secondmate-reconcile.test.sh +732 -0
  603. package/.agents/tests/fm-secondmate-safety.test.sh +2972 -0
  604. package/.agents/tests/fm-secondmate-sync.test.sh +913 -0
  605. package/.agents/tests/fm-send-inbox-doorbell-live-e2e.test.sh +206 -0
  606. package/.agents/tests/fm-send-inbox.test.sh +352 -0
  607. package/.agents/tests/fm-send-popup-settle.test.sh +167 -0
  608. package/.agents/tests/fm-send-remote-delivery.test.sh +796 -0
  609. package/.agents/tests/fm-send-resolve-key.test.sh +551 -0
  610. package/.agents/tests/fm-send-secondmate-marker-herdr-e2e.test.sh +187 -0
  611. package/.agents/tests/fm-send-secondmate-marker.test.sh +278 -0
  612. package/.agents/tests/fm-send-settle.test.sh +147 -0
  613. package/.agents/tests/fm-send-strict.test.sh +241 -0
  614. package/.agents/tests/fm-session-lock-ancestry.test.sh +365 -0
  615. package/.agents/tests/fm-session-start.test.sh +2515 -0
  616. package/.agents/tests/fm-sessionstart-hook-live-e2e.test.sh +631 -0
  617. package/.agents/tests/fm-sessionstart-instruction-refresh-live-e2e.test.sh +230 -0
  618. package/.agents/tests/fm-sessionstart-nudge.test.sh +1039 -0
  619. package/.agents/tests/fm-shared-captain-inheritance.test.sh +404 -0
  620. package/.agents/tests/fm-spawn-batch.test.sh +148 -0
  621. package/.agents/tests/fm-spawn-dispatch-profile.test.sh +827 -0
  622. package/.agents/tests/fm-spawn-pool-base-freshen.test.sh +440 -0
  623. package/.agents/tests/fm-spawn-worktree-settle.test.sh +147 -0
  624. package/.agents/tests/fm-startup-memory-budget.test.sh +333 -0
  625. package/.agents/tests/fm-startup-network.test.sh +712 -0
  626. package/.agents/tests/fm-stow-cascade.test.sh +370 -0
  627. package/.agents/tests/fm-subagent-pretool-check.test.sh +291 -0
  628. package/.agents/tests/fm-supervision-events.test.sh +156 -0
  629. package/.agents/tests/fm-supervision-instructions.test.sh +189 -0
  630. package/.agents/tests/fm-tangle-guard.test.sh +277 -0
  631. package/.agents/tests/fm-task-delivery.test.sh +420 -0
  632. package/.agents/tests/fm-task-inbox.test.sh +513 -0
  633. package/.agents/tests/fm-teardown-endpoint-safety.test.sh +374 -0
  634. package/.agents/tests/fm-teardown.test.sh +2665 -0
  635. package/.agents/tests/fm-test-fixture-cleanup.test.sh +172 -0
  636. package/.agents/tests/fm-test-fixtures.test.sh +132 -0
  637. package/.agents/tests/fm-test-isolation-proof.test.sh +278 -0
  638. package/.agents/tests/fm-test-run.test.sh +1196 -0
  639. package/.agents/tests/fm-tmux-agent-liveness.test.sh +354 -0
  640. package/.agents/tests/fm-tmux-submit-busy.test.sh +340 -0
  641. package/.agents/tests/fm-tool-update-check.test.sh +1044 -0
  642. package/.agents/tests/fm-trace-context-lib.test.sh +253 -0
  643. package/.agents/tests/fm-trace-context-spawn.test.sh +581 -0
  644. package/.agents/tests/fm-transition-lib.test.sh +54 -0
  645. package/.agents/tests/fm-turnend-guard.test.sh +1822 -0
  646. package/.agents/tests/fm-update.test.sh +304 -0
  647. package/.agents/tests/fm-vendor-auth-probe.test.sh +395 -0
  648. package/.agents/tests/fm-voice-relay.test.sh +4741 -0
  649. package/.agents/tests/fm-wake-daemon-lifecycle-e2e.test.sh +171 -0
  650. package/.agents/tests/fm-wake-drain-open-decisions-cursor.test.sh +356 -0
  651. package/.agents/tests/fm-wake-drain-open-decisions.test.sh +226 -0
  652. package/.agents/tests/fm-wake-drain-unread-status.test.sh +379 -0
  653. package/.agents/tests/fm-wake-queue.test.sh +1224 -0
  654. package/.agents/tests/fm-watch-arm.test.sh +821 -0
  655. package/.agents/tests/fm-watch-checkpoint.test.sh +87 -0
  656. package/.agents/tests/fm-watch-recovery-loop.test.sh +223 -0
  657. package/.agents/tests/fm-watch-triage.test.sh +3889 -0
  658. package/.agents/tests/fm-watcher-lock.test.sh +1133 -0
  659. package/.agents/tests/fm-x-mode.test.sh +3042 -0
  660. package/.agents/tests/gleipnir-guard-pretool-check.test.sh +51 -0
  661. package/.agents/tests/gleipnir-machine-lock.test.sh +130 -0
  662. package/.agents/tests/herdr-test-safety.sh +42 -0
  663. package/.agents/tests/lib.sh +315 -0
  664. package/.agents/tests/remote-herdr-fixture.sh +125 -0
  665. package/.agents/tests/secondmate-helpers.sh +193 -0
  666. package/.agents/tests/smoke.test.sh +93 -0
  667. package/.agents/tests/wake-helpers.sh +338 -0
  668. package/.agents/tests/zellij-test-safety.sh +60 -0
  669. package/.agents/tools/README.md +10 -0
  670. package/.agents/tools/bin/tasks-cli +267 -0
  671. package/.agents/tools/tasks-cli.ts +216 -0
  672. package/AGENTS.md +498 -0
  673. package/CHANGELOG.md +1913 -0
  674. package/LICENSE +1 -1
  675. package/NOTICE +63 -0
  676. package/README.md +114 -60
  677. package/RULES/01-domains.md +51 -0
  678. package/RULES/02-agents.md +78 -0
  679. package/RULES/03-houses.md +61 -0
  680. package/RULES/04-hoard.md +97 -0
  681. package/RULES/05-platforms.md +67 -0
  682. package/RULES/06-append-only.md +108 -0
  683. package/RULES/07-config.md +101 -0
  684. package/RULES/08-delivery-gate.md +75 -0
  685. package/RULES/09-electron.md +58 -0
  686. package/RULES/README.md +22 -0
  687. package/bin/README.md +107 -0
  688. package/bin/a2a-mcp.sh +133 -0
  689. package/bin/a2a-serve.py +103 -0
  690. package/bin/a2a-serve.sh +8 -0
  691. package/bin/a2a-talk.sh +50 -0
  692. package/bin/a2abridge-ensure.sh +108 -0
  693. package/bin/agent-run.sh +43 -0
  694. package/bin/agents-config.sh +256 -0
  695. package/bin/apodex-smoke-test.sh +105 -0
  696. package/bin/bifrost-bridge.sh +131 -0
  697. package/bin/bifrost-ingress.sh +77 -0
  698. package/bin/bootstrap-macos.sh +112 -0
  699. package/bin/bootstrap-windows.ps1 +112 -0
  700. package/bin/branch-guard.sh +64 -0
  701. package/bin/brokk +73 -0
  702. package/bin/brokk-classify-lib.sh +1770 -0
  703. package/bin/brokk-lease-lib.sh +222 -0
  704. package/bin/brokk-lease.sh +193 -0
  705. package/bin/brokk-lint.sh +65 -0
  706. package/bin/brokk-send.sh +51 -0
  707. package/bin/brokk-update.sh +9 -0
  708. package/bin/brokk-wake-grant.sh +127 -0
  709. package/bin/brokk-wake-lib.sh +1849 -0
  710. package/bin/changelog-assemble.sh +154 -0
  711. package/bin/changelog-guard.sh +197 -0
  712. package/bin/crash-sense.sh +173 -0
  713. package/bin/design-check.sh +80 -0
  714. package/bin/design-icon.sh +153 -0
  715. package/bin/desktop-place.sh +224 -0
  716. package/bin/docs-guard.sh +39 -0
  717. package/bin/editor-place.sh +225 -0
  718. package/bin/eindri-acclaim.sh +47 -0
  719. package/bin/eindri-control.sh +28 -0
  720. package/bin/eindri-role.sh +83 -0
  721. package/bin/eindri-seat.sh +83 -0
  722. package/bin/eindri-seen.sh +54 -0
  723. package/bin/eindri-send.sh +15 -0
  724. package/bin/eindri-start.sh +98 -0
  725. package/bin/eindri-watch.sh +57 -0
  726. package/bin/einherjar-spawn.sh +576 -0
  727. package/bin/eir-doctor.sh +158 -0
  728. package/bin/erindi-brief.sh +271 -0
  729. package/bin/feature-inventory.sh +73 -0
  730. package/bin/fleet-apply.sh +81 -0
  731. package/bin/github-deploy.sh +94 -0
  732. package/bin/gjallarhorn-expose.sh +136 -0
  733. package/bin/gjallarhorn-notify.sh +71 -0
  734. package/bin/gjallarhorn-purge.sh +67 -0
  735. package/bin/gjallarhorn-tunnel.sh +85 -0
  736. package/bin/gleipnir-lock-lib.sh +284 -0
  737. package/bin/groa-update.sh +130 -0
  738. package/bin/hall-snapshot.sh +111 -0
  739. package/bin/hamr-harness.sh +246 -0
  740. package/bin/heimdall-ssh-keys.sh +374 -0
  741. package/bin/herdr-agents.py +44 -0
  742. package/bin/herdr-ensure.sh +104 -0
  743. package/bin/herdr-run.sh +452 -0
  744. package/bin/hermes-ensure.sh +88 -0
  745. package/bin/hlidskjalf-agents.sh +172 -0
  746. package/bin/hlidskjalf-usage.sh +196 -0
  747. package/bin/hoard-guard.sh +135 -0
  748. package/bin/hoard-lib.sh +105 -0
  749. package/bin/hodd.sh +102 -0
  750. package/bin/host-sense.sh +199 -0
  751. package/bin/huginn-research-worker.sh +121 -0
  752. package/bin/local-model-lock.sh +70 -0
  753. package/bin/mimir-bridge.py +259 -0
  754. package/bin/mimir-bridge.sh +100 -0
  755. package/bin/mimir-ingest.sh +131 -0
  756. package/bin/mimir-reflect.sh +27 -0
  757. package/bin/mimir.sh +113 -0
  758. package/bin/mjollnir-webhook.sh +72 -0
  759. package/bin/mjollnir.sh +104 -0
  760. package/bin/model-hardware.sh +96 -0
  761. package/bin/model-resolve.sh +160 -0
  762. package/bin/models-detect.sh +178 -0
  763. package/bin/nornir-cron-start.sh +162 -0
  764. package/bin/nornir-job-daily-briefing.sh +191 -0
  765. package/bin/nornir-job-git-sync.sh +152 -0
  766. package/bin/nornir-job-hall-snapshot.sh +28 -0
  767. package/bin/nornir-job-memory-housekeeping.sh +114 -0
  768. package/bin/nornir-job-nsr-compliance.sh +54 -0
  769. package/bin/nornir-job-observer.sh +166 -0
  770. package/bin/nornir-job-skillopt-sleep.sh +76 -0
  771. package/bin/npm-publish.sh +136 -0
  772. package/bin/omarchy-hook-install.sh +60 -0
  773. package/bin/omarchy-install.sh +161 -0
  774. package/bin/omarchy-plugins.sh +187 -0
  775. package/bin/omarchy-sense.sh +162 -0
  776. package/bin/perm-guard.sh +30 -0
  777. package/bin/pi-agent.sh +68 -0
  778. package/bin/pi-ensure.sh +77 -0
  779. package/bin/pi-local.sh +37 -0
  780. package/bin/pi-model-agnostic.sh +71 -0
  781. package/bin/pi-seat.sh +63 -0
  782. package/bin/prereq-ensure.sh +166 -0
  783. package/bin/private-guard.sh +58 -0
  784. package/bin/project-git.sh +69 -0
  785. package/bin/public-guard.sh +71 -0
  786. package/bin/ratatoskr.sh +49 -0
  787. package/bin/realm-lib.sh +32 -0
  788. package/bin/repo-scrub.sh +62 -0
  789. package/bin/rodd-operational-input.sh +250 -0
  790. package/bin/runes-append.sh +198 -0
  791. package/bin/saga-session-start.sh +172 -0
  792. package/bin/saga-sessionstart-run.sh +79 -0
  793. package/bin/saga-wake-drain.sh +41 -0
  794. package/bin/secret-guard.sh +63 -0
  795. package/bin/sessrumnir-ensure.sh +100 -0
  796. package/bin/sessrumnir-sync.sh +237 -0
  797. package/bin/sessrumnir.sh +104 -0
  798. package/bin/skillopt-setup.sh +76 -0
  799. package/bin/skuld-branch-outcome.sh +203 -0
  800. package/bin/skuld-branch-prompt.sh +101 -0
  801. package/bin/smidja-bootstrap.sh +94 -0
  802. package/bin/smidja-observe.sh +86 -0
  803. package/bin/syn-arm-pretool-check.sh +57 -0
  804. package/bin/syn-asset-pretool-check.sh +89 -0
  805. package/bin/syn-cd-pretool-check.sh +28 -0
  806. package/bin/syn-guard-pretool-check.sh +83 -0
  807. package/bin/syn-spawn-pretool-check.sh +58 -0
  808. package/bin/syn-turnend-guard.sh +36 -0
  809. package/bin/syn-watch-arm.sh +99 -0
  810. package/bin/tailscale-sync.sh +203 -0
  811. package/bin/telegram-bot.sh +82 -0
  812. package/bin/toolchain.sh +74 -0
  813. package/bin/ui-truth-check.sh +75 -0
  814. package/bin/utgard.sh +111 -0
  815. package/bin/valhalla.sh +115 -0
  816. package/bin/valknut-load.sh +298 -0
  817. package/bin/vor-crew-state.sh +124 -0
  818. package/bin/wedge-notify.sh +60 -0
  819. package/bin/workspace-provision.sh +80 -0
  820. package/bin/workspace-rag.sh +163 -0
  821. package/bin/wyrd-db.sh +47 -0
  822. package/bin/yggdrasil.sh +152 -0
  823. package/bin/ymir-edit.sh +145 -0
  824. package/bin/ymir-install.sh +806 -0
  825. package/bin/ymir-invite.sh +93 -0
  826. package/bin/ymir-isolation.sh +88 -0
  827. package/bin/ymir-migrate.sh +61 -0
  828. package/bin/ymir-plan.sh +356 -0
  829. package/bin/ymir-platform.sh +348 -0
  830. package/bin/ymir-say.sh +110 -0
  831. package/bin/ymir-setup-auth.sh +119 -0
  832. package/bin/ymir-validate.sh +193 -0
  833. package/bin/ymir.js +74 -16
  834. package/docs/Architecture.md +339 -0
  835. package/docs/design.md +351 -0
  836. package/docs/installations/README.md +63 -0
  837. package/docs/installations/ymir-home.md +93 -0
  838. package/docs/integration.md +105 -0
  839. package/docs/lore.md +1060 -0
  840. package/docs/research/agent-harnesses.md +290 -0
  841. package/docs/runbooks/README.md +19 -0
  842. package/docs/runbooks/a2a.md +91 -0
  843. package/docs/runbooks/agent-permissions.md +99 -0
  844. package/docs/runbooks/agents.md +57 -0
  845. package/docs/runbooks/models.md +69 -0
  846. package/docs/runbooks/realm-onboarding.md +60 -0
  847. package/docs/runbooks/secrets-and-hoard.md +60 -0
  848. package/docs/runbooks/updates-and-migrations.md +110 -0
  849. package/docs/runbooks/worktrees-isolation.md +72 -0
  850. package/docs/session-start.md +105 -0
  851. package/docs/skillopt-integration.md +321 -0
  852. package/docs/sync-system.md +66 -0
  853. package/docs/workspaces.md +104 -0
  854. package/docs/ymir-rut.md +260 -0
  855. package/package.json +54 -14
  856. package/packaging/build.sh +74 -0
  857. package/packaging/macos/Ymir Installer.command +43 -0
  858. package/packaging/windows/ymir-setup.nsi +74 -0
  859. package/scripts/README.md +22 -0
  860. package/scripts/electron.sh +269 -0
  861. package/scripts/lower.sh +34 -0
  862. package/scripts/raise.sh +42 -0
  863. package/scripts/start.sh +217 -0
  864. package/scripts/stop.sh +113 -0
  865. package/install.sh +0 -35
@@ -0,0 +1,507 @@
1
+ #!/usr/bin/env bash
2
+ # Behavior tests for the generic SSH transport and fixed remote entrypoint.
3
+ set -u
4
+
5
+ # shellcheck source=tests/lib.sh
6
+ . "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
7
+
8
+ ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
9
+ TMP_ROOT=$(fm_test_tmproot fm-on)
10
+ # The helper is called in command substitution, so recreate the registered path
11
+ # and physicalize macOS's /var -> /private/var alias before transport validation.
12
+ mkdir -p "$TMP_ROOT"
13
+ TMP_ROOT=$(cd "$TMP_ROOT" && pwd -P)
14
+ trap 'if [ -f "$TMP_ROOT/remote-jobs/worker.pid" ]; then kill "$(cat "$TMP_ROOT/remote-jobs/worker.pid")" 2>/dev/null || true; fi; rm -rf -- "$TMP_ROOT"' EXIT
15
+ LOCAL_HOME="$TMP_ROOT/local-home"
16
+ REMOTE_ROOT="$TMP_ROOT/remote-root"
17
+ REMOTE_HOME="$TMP_ROOT/remote-home"
18
+ TOOL_PROBE_LOG="$TMP_ROOT/tool-probe.log"
19
+ FAKEBIN=$(fm_fakebin "$TMP_ROOT/fakebin")
20
+ SSH_LOG="$TMP_ROOT/ssh.log"
21
+ SSH_COUNT="$TMP_ROOT/ssh.count"
22
+ mkdir -p "$LOCAL_HOME/data" "$REMOTE_ROOT/bin" "$REMOTE_HOME"
23
+ printf 'fixture\n' > "$REMOTE_ROOT/AGENTS.md"
24
+ cp "$ROOT/bin/fm-remote-entrypoint.sh" "$ROOT/bin/fm-remote-job-lib.sh" \
25
+ "$ROOT/bin/fm-remote-job-worker.sh" "$REMOTE_ROOT/bin/"
26
+
27
+ cat > "$REMOTE_ROOT/bin/fm-probe-one.sh" <<'SH'
28
+ #!/usr/bin/env bash
29
+ set -u
30
+ out=$1
31
+ rc=$2
32
+ shift 2
33
+ printf '%s\0' "$@" > "$out"
34
+ printf 'stdout: %s args\n' "$#"
35
+ printf 'stderr: separate\n' >&2
36
+ while IFS= read -r line || [ -n "$line" ]; do printf 'stdin: %s\n' "$line"; done
37
+ exit "$rc"
38
+ SH
39
+ cat > "$REMOTE_ROOT/bin/fm-probe-two.sh" <<'SH'
40
+ #!/usr/bin/env bash
41
+ printf 'home=%s\nroot=%s\nworker=%s\n' "$FM_HOME" "$FM_ROOT_OVERRIDE" "${FM_REMOTE_JOB_ACTIVE:-}"
42
+ if [ -n "${TOP_SECRET:-}" ]; then printf 'secret=leaked\n'; else printf 'secret=absent\n'; fi
43
+ SH
44
+ cat > "$REMOTE_ROOT/bin/fm-probe-path.sh" <<'SH'
45
+ #!/usr/bin/env bash
46
+ printf '%s\n' "$PATH"
47
+ SH
48
+ cat > "$REMOTE_ROOT/bin/tasks-axi" <<SH
49
+ #!/usr/bin/env bash
50
+ printf '%s\n' "\${FM_REMOTE_JOB_ACTIVE:-absent}" >> "$TOOL_PROBE_LOG"
51
+ case "\${1:-}:\${2:-}" in
52
+ --version:*) printf '0.2.4\n' ;;
53
+ update:--help) printf '%s\n' --archive-body ;;
54
+ mv:--help) printf '%s\n' 'usage: tasks-axi mv <id> [<id>...]' ;;
55
+ esac
56
+ SH
57
+ cp "$ROOT/bin/fm-remote-doctor.sh" "$ROOT/bin/fm-tasks-axi-lib.sh" \
58
+ "$ROOT/bin/fm-backend.sh" "$REMOTE_ROOT/bin/"
59
+ mkdir -p "$REMOTE_ROOT/bin/backends"
60
+ cp "$ROOT/bin/backends/herdr.sh" "$REMOTE_ROOT/bin/backends/herdr.sh"
61
+ cat > "$REMOTE_ROOT/bin/fm-mutate.sh" <<'SH'
62
+ #!/usr/bin/env bash
63
+ printf 'mutation\n' >> "$1"
64
+ SH
65
+ chmod +x "$REMOTE_ROOT/bin"/*.sh
66
+ chmod +x "$REMOTE_ROOT/bin/tasks-axi"
67
+ git -C "$REMOTE_ROOT" init -q -b main
68
+ git -C "$REMOTE_ROOT" config user.email test@example.com
69
+ git -C "$REMOTE_ROOT" config user.name Test
70
+ git -C "$REMOTE_ROOT" add AGENTS.md bin
71
+ git -C "$REMOTE_ROOT" commit -qm 'tracked remote fixture'
72
+
73
+ cat > "$FAKEBIN/fake-ssh" <<'SH'
74
+ #!/usr/bin/env bash
75
+ count=$(cat "$FM_FAKE_SSH_COUNT" 2>/dev/null || echo 0)
76
+ printf '%s\n' "$((count + 1))" > "$FM_FAKE_SSH_COUNT"
77
+ printf '%s\n' "$*" >> "$FM_FAKE_SSH_LOG"
78
+ while [ "$#" -gt 0 ]; do
79
+ case "$1" in
80
+ -o) shift 2 ;;
81
+ --) shift; break ;;
82
+ *) exit 90 ;;
83
+ esac
84
+ done
85
+ host=$1
86
+ entry=$2
87
+ shift 2
88
+ [ "$host" = remote-mac ] || exit 91
89
+ [ "$entry" = fm-remote-entrypoint.sh ] || exit 92
90
+ case "${FM_FAKE_SSH_MODE:-normal}" in
91
+ unreachable) exit 255 ;;
92
+ ambiguous)
93
+ "$FM_FAKE_REMOTE_ENTRYPOINT" "$@"
94
+ exit 255
95
+ ;;
96
+ *) exec "$FM_FAKE_REMOTE_ENTRYPOINT" "$@" ;;
97
+ esac
98
+ SH
99
+ chmod +x "$FAKEBIN/fake-ssh"
100
+
101
+ write_registry() {
102
+ cat > "$LOCAL_HOME/data/secondmates.md" <<EOF
103
+ - ios - iOS delivery (host: remote-mac; root: $REMOTE_ROOT; home: $REMOTE_HOME; scope: iOS work; projects: alpha; added 2026-08-02)
104
+ EOF
105
+ }
106
+ write_registry
107
+
108
+ fm_on() {
109
+ FM_HOME="$LOCAL_HOME" \
110
+ FM_ROOT_OVERRIDE="$REMOTE_ROOT" \
111
+ FM_SSH_BIN="$FAKEBIN/fake-ssh" \
112
+ FM_FAKE_SSH_COUNT="$SSH_COUNT" \
113
+ FM_FAKE_SSH_LOG="$SSH_LOG" \
114
+ FM_FAKE_REMOTE_ENTRYPOINT="$REMOTE_ROOT/bin/fm-remote-entrypoint.sh" \
115
+ FM_REMOTE_JOB_PLATFORM_OVERRIDE=Linux \
116
+ FM_REMOTE_JOB_STATE_ROOT="$TMP_ROOT/remote-jobs" \
117
+ "$ROOT/bin/fm-on.sh" "$@"
118
+ }
119
+
120
+ # The pre-feature user path had no executable transport at all. The regression
121
+ # exercises the adopted public surface end to end through a deterministic SSH
122
+ # process boundary rather than checking script source. A payload caller passes
123
+ # --stdin explicitly; without it the remote command's stdin is /dev/null.
124
+ ARGV_ACTUAL="$REMOTE_HOME/argv.bin"
125
+ ARGV_EXPECTED="$TMP_ROOT/argv-expected.bin"
126
+ # shellcheck disable=SC2016 # Literal shell-looking argv is the injection probe.
127
+ printf '%s\0' 'plain' 'two words' '$(touch /tmp/fm-on-injected)' '' $'line one\nline two' > "$ARGV_EXPECTED"
128
+ printf 'payload one\npayload two\n' > "$TMP_ROOT/stdin"
129
+ set +e
130
+ # shellcheck disable=SC2016 # Literal shell-looking argv is the injection probe.
131
+ fm_on --stdin ios fm-probe-one.sh "$ARGV_ACTUAL" 23 \
132
+ 'plain' 'two words' '$(touch /tmp/fm-on-injected)' '' $'line one\nline two' \
133
+ < "$TMP_ROOT/stdin" > "$TMP_ROOT/stdout" 2> "$TMP_ROOT/stderr"
134
+ rc=$?
135
+ set -e
136
+ [ "$rc" -eq 23 ] || fail "remote exit status was not preserved (got $rc)"
137
+ cmp -s "$ARGV_EXPECTED" "$ARGV_ACTUAL" || fail "remote argv boundaries were not preserved byte-for-byte"
138
+ assert_grep 'stdout: 5 args' "$TMP_ROOT/stdout" "remote stdout was not preserved"
139
+ assert_grep 'stdin: payload one' "$TMP_ROOT/stdout" "remote stdin was not preserved"
140
+ assert_grep 'stdin: payload two' "$TMP_ROOT/stdout" "remote stdin lost its second line"
141
+ assert_grep 'stderr: separate' "$TMP_ROOT/stderr" "remote stderr was not preserved separately"
142
+ assert_absent /tmp/fm-on-injected "shell-looking argv was interpreted"
143
+ pass "fm-on --stdin preserves argv, stdin, stdout, stderr, and exit status without shell interpretation"
144
+
145
+ # Without --stdin the remote command must see EOF even when the caller's own
146
+ # stdin holds bytes: staging captures stdin to EOF, so an open caller stream
147
+ # must never reach it by default.
148
+ set +e
149
+ fm_on ios fm-probe-one.sh "$REMOTE_HOME/argv-default.bin" 0 'default-closed' \
150
+ < "$TMP_ROOT/stdin" > "$TMP_ROOT/stdout-default" 2> "$TMP_ROOT/stderr-default"
151
+ rc=$?
152
+ set -e
153
+ [ "$rc" -eq 0 ] || fail "the default-closed invocation did not preserve exit status (got $rc)"
154
+ if grep -q 'stdin:' "$TMP_ROOT/stdout-default"; then
155
+ fail "caller stdin crossed the transport without --stdin: $(cat "$TMP_ROOT/stdout-default")"
156
+ fi
157
+ pass "fm-on defaults the remote command's stdin to /dev/null"
158
+
159
+ # A vanished remote peer must become a bounded ssh failure instead of an
160
+ # indefinite hang on a half-open TCP connection, so the existing no-result ->
161
+ # reconcile re-arm recovery can self-heal without manual intervention. Assert
162
+ # this on the real ssh argv the FM_SSH_BIN process seam captured, never on
163
+ # fm-on.sh source text.
164
+ LAST_SSH_ARGV=$(tail -n 1 "$SSH_LOG")
165
+ DEFAULT_INTERVAL=$(printf '%s\n' "$LAST_SSH_ARGV" | grep -oE 'ServerAliveInterval=[0-9]+' | cut -d= -f2)
166
+ DEFAULT_COUNT=$(printf '%s\n' "$LAST_SSH_ARGV" | grep -oE 'ServerAliveCountMax=[0-9]+' | cut -d= -f2)
167
+ [ -n "$DEFAULT_INTERVAL" ] || fail "the ssh transport did not arm ServerAliveInterval dead-peer detection"
168
+ [ -n "$DEFAULT_COUNT" ] || fail "the ssh transport did not arm ServerAliveCountMax dead-peer detection"
169
+ [ "$DEFAULT_INTERVAL" -gt 0 ] || fail "ServerAliveInterval was not a positive interval (got $DEFAULT_INTERVAL)"
170
+ [ "$DEFAULT_COUNT" -gt 0 ] || fail "ServerAliveCountMax was not a positive count (got $DEFAULT_COUNT)"
171
+ DEFAULT_WINDOW=$((DEFAULT_INTERVAL * DEFAULT_COUNT))
172
+ [ "$DEFAULT_WINDOW" -le 120 ] \
173
+ || fail "the default dead-peer detection window is not bounded to a sane ceiling (got ${DEFAULT_WINDOW}s = ${DEFAULT_INTERVAL}s x $DEFAULT_COUNT)"
174
+ pass "fm-on arms a bounded SSH dead-peer detection window by default (${DEFAULT_INTERVAL}s x $DEFAULT_COUNT = ${DEFAULT_WINDOW}s)"
175
+
176
+ : > "$SSH_LOG"
177
+ FM_SSH_ALIVE_INTERVAL=7 FM_SSH_ALIVE_COUNT_MAX=2 fm_on ios fm-probe-two.sh >/dev/null
178
+ OVERRIDE_ARGV=$(tail -n 1 "$SSH_LOG")
179
+ assert_contains "$OVERRIDE_ARGV" 'ServerAliveInterval=7' "FM_SSH_ALIVE_INTERVAL override was not honored on the ssh transport"
180
+ assert_contains "$OVERRIDE_ARGV" 'ServerAliveCountMax=2' "FM_SSH_ALIVE_COUNT_MAX override was not honored on the ssh transport"
181
+ pass "fm-on's dead-peer detection window is env-overridable"
182
+
183
+ SSH_CALLS_BEFORE_INVALID=$(cat "$SSH_COUNT")
184
+ set +e
185
+ INVALID_INTERVAL_OUT=$(FM_SSH_ALIVE_INTERVAL=0 fm_on ios fm-probe-two.sh 2>&1)
186
+ INVALID_INTERVAL_RC=$?
187
+ INVALID_COUNT_OUT=$(FM_SSH_ALIVE_COUNT_MAX=not-a-number fm_on ios fm-probe-two.sh 2>&1)
188
+ INVALID_COUNT_RC=$?
189
+ set -e
190
+ [ "$INVALID_INTERVAL_RC" -eq 1 ] || fail "a zero FM_SSH_ALIVE_INTERVAL was accepted (got exit $INVALID_INTERVAL_RC)"
191
+ [ "$INVALID_COUNT_RC" -eq 1 ] || fail "a non-integer FM_SSH_ALIVE_COUNT_MAX was accepted (got exit $INVALID_COUNT_RC)"
192
+ assert_contains "$INVALID_INTERVAL_OUT" 'FM_SSH_ALIVE_INTERVAL must be a positive integer' "invalid interval did not explain its constraint"
193
+ assert_contains "$INVALID_COUNT_OUT" 'FM_SSH_ALIVE_COUNT_MAX must be a positive integer' "invalid count did not explain its constraint"
194
+ [ "$(cat "$SSH_COUNT")" -eq "$SSH_CALLS_BEFORE_INVALID" ] || fail "invalid keepalive configuration launched ssh"
195
+ pass "fm-on rejects invalid dead-peer settings before launching ssh"
196
+
197
+ out=$(TOP_SECRET='must-not-cross' fm_on remote-mac fm-probe-two.sh)
198
+ assert_contains "$out" "home=$REMOTE_HOME" "remote FM_HOME was not explicit"
199
+ assert_contains "$out" "root=$REMOTE_ROOT" "remote root was not explicit"
200
+ assert_contains "$out" 'secret=absent' "the primary ambient environment crossed the transport"
201
+ assert_contains "$out" 'worker=1' "the fixed entrypoint executed outside the remote job worker"
202
+ pass "the fixed entrypoint runs every command in the worker's explicit environment"
203
+
204
+ # The child PATH is the entrypoint's own composition, so it is asserted on the
205
+ # PATH a real child receives rather than on the script that builds it. The
206
+ # expectation is rebuilt here from the documented contract - fixed head, the
207
+ # package-manager directories that exist on this host, fixed tail - so a host
208
+ # with nix, homebrew, or neither exercises both the include and omit directions.
209
+ ACCOUNT_HOME=$(unset HOME; CDPATH='' cd ~ && pwd -P)
210
+ ACCOUNT_USER=$(id -un)
211
+ MANAGER_DIRS=(
212
+ "$ACCOUNT_HOME/.asdf/shims"
213
+ "$ACCOUNT_HOME"/.asdf/installs/*/*/bin
214
+ "$ACCOUNT_HOME/.local/share/mise/shims"
215
+ "$ACCOUNT_HOME/.mise/shims"
216
+ "$ACCOUNT_HOME"/.local/share/mise/installs/*/*/bin
217
+ "$ACCOUNT_HOME"/.mise/installs/*/*/bin
218
+ )
219
+ OPTIONAL_DIRS=(
220
+ "$ACCOUNT_HOME/.nix-profile/bin"
221
+ "/etc/profiles/per-user/$ACCOUNT_USER/bin"
222
+ /run/current-system/sw/bin
223
+ /opt/homebrew/bin
224
+ /usr/local/bin
225
+ )
226
+ EXPECTED_PATH=
227
+ expect_dir() {
228
+ case ":$EXPECTED_PATH:" in *":$1:"*) return 0 ;; esac
229
+ EXPECTED_PATH="${EXPECTED_PATH:+$EXPECTED_PATH:}$1"
230
+ }
231
+ path_has() { case ":$1:" in *":$2:"*) return 0 ;; esac; return 1; }
232
+ CHILD_PATH=$(fm_on ios fm-probe-path.sh)
233
+ NVM_CHILD_DIRS=()
234
+ while IFS= read -r candidate; do
235
+ [ -z "$candidate" ] || NVM_CHILD_DIRS+=("$candidate")
236
+ done < <(printf '%s\n' "$CHILD_PATH" | tr ':' '\n' | sed -n "\|^$ACCOUNT_HOME/.nvm/versions/node/[^/]*/bin$|p")
237
+ [ "${#NVM_CHILD_DIRS[@]}" -le 1 ] || fail "the child PATH selected more than one nvm version"
238
+ expect_dir "$REMOTE_ROOT/bin"
239
+ if [ -d "$ACCOUNT_HOME/.local/bin" ] && [ ! -L "$ACCOUNT_HOME/.local/bin" ]; then
240
+ expect_dir "$ACCOUNT_HOME/.local/bin"
241
+ fi
242
+ for candidate in "${NVM_CHILD_DIRS[@]}"; do expect_dir "$candidate"; done
243
+ for candidate in "${MANAGER_DIRS[@]}"; do
244
+ [ -d "$candidate" ] && [ ! -L "$candidate" ] && expect_dir "$candidate"
245
+ done
246
+ for candidate in "${OPTIONAL_DIRS[@]}"; do
247
+ [ -d "$candidate" ] && [ ! -L "$candidate" ] && expect_dir "$candidate"
248
+ done
249
+ for fixed in /usr/bin /bin /usr/sbin /sbin; do expect_dir "$fixed"; done
250
+
251
+ [ "$CHILD_PATH" = "$EXPECTED_PATH" ] \
252
+ || fail "composed child PATH did not match the portable contract"$'\n'"expected: $EXPECTED_PATH"$'\n'"actual: $CHILD_PATH"
253
+ [ "${CHILD_PATH%%:*}" = "$REMOTE_ROOT/bin" ] || fail "the remote code root's bin was not first on the child PATH"
254
+ if [ -d "$ACCOUNT_HOME/.local/bin" ] && [ ! -L "$ACCOUNT_HOME/.local/bin" ]; then
255
+ [ "$(printf '%s' "$CHILD_PATH" | cut -d: -f2)" = "$ACCOUNT_HOME/.local/bin" ] \
256
+ || fail "the account's discovered ~/.local/bin was not second on the child PATH"
257
+ else
258
+ path_has "$CHILD_PATH" "$ACCOUNT_HOME/.local/bin" \
259
+ && fail "the account's absent or symlinked ~/.local/bin was added to the child PATH"
260
+ fi
261
+ case "$CHILD_PATH" in *:/usr/bin:/bin:/usr/sbin:/sbin) ;; *) fail "the child PATH did not end with the portable system tail" ;; esac
262
+ DUPES=$(printf '%s\n' "$CHILD_PATH" | tr ':' '\n' | sort | uniq -d)
263
+ [ -z "$DUPES" ] || fail "the child PATH repeated entries: $DUPES"
264
+ PRESENT_CHECKED=0
265
+ ABSENT_CHECKED=0
266
+ for candidate in "${MANAGER_DIRS[@]}" "${OPTIONAL_DIRS[@]}"; do
267
+ if [ -d "$candidate" ] && [ ! -L "$candidate" ]; then
268
+ path_has "$CHILD_PATH" "$candidate" || fail "an existing discovered PATH directory was dropped: $candidate"
269
+ PRESENT_CHECKED=$((PRESENT_CHECKED + 1))
270
+ else
271
+ path_has "$CHILD_PATH" "$candidate" && fail "an absent or symlinked PATH directory was added: $candidate"
272
+ ABSENT_CHECKED=$((ABSENT_CHECKED + 1))
273
+ fi
274
+ done
275
+ pass "the entrypoint composes a deduplicated discovered child PATH (kept $PRESENT_CHECKED existing, omitted $ABSENT_CHECKED absent)"
276
+
277
+ WORKER_PID=$(cat "$TMP_ROOT/remote-jobs/worker.pid")
278
+ kill -TERM "$WORKER_PID"
279
+ for _ in $(seq 1 100); do
280
+ [ ! -f "$TMP_ROOT/remote-jobs/worker.pid" ] && break
281
+ sleep 0.05
282
+ done
283
+ assert_absent "$TMP_ROOT/remote-jobs/worker.pid" "the worker did not stop for the doctor bootstrap fixture"
284
+ set +e
285
+ out=$(fm_on ios fm-remote-doctor.sh 2>&1)
286
+ set -e
287
+ assert_contains "$out" 'check remote-job-worker=fixable:' "read-only doctor did not report the stopped worker"
288
+ assert_absent "$TMP_ROOT/remote-jobs/worker.pid" "read-only doctor repaired the stopped worker"
289
+ pass "read-only doctor inspects worker gaps over plain SSH without repair"
290
+
291
+ # The doctor's readiness verdict depends on the host it runs on, which is this
292
+ # developer's or runner's real account here, so this transport test asserts only
293
+ # what the transport itself owns: the PATH the entrypoint handed the child.
294
+ # tests/fm-remote-doctor.test.sh owns the verdict against controlled fixtures.
295
+ set +e
296
+ out=$(fm_on ios fm-remote-doctor.sh 2>/dev/null)
297
+ set -e
298
+ assert_contains "$out" "path=$EXPECTED_PATH" "the remote doctor did not report the entrypoint child PATH"
299
+ assert_contains "$out" 'entrypoint=yes' "the remote doctor did not detect its entrypoint launch"
300
+ assert_contains "$out" 'required git=' "the remote doctor did not report the required tool"
301
+ pass "the remote doctor reports the same PATH the entrypoint hands its children"
302
+
303
+ fm_on ios fm-probe-two.sh >/dev/null
304
+ : > "$TOOL_PROBE_LOG"
305
+ set +e
306
+ out=$(fm_on ios fm-remote-doctor.sh 2>&1)
307
+ set -e
308
+ assert_contains "$out" 'check remote-job-probe=ok: the remote job worker completed the required-tool probe' \
309
+ "the doctor did not use a completed worker probe for tool readiness"
310
+ assert_grep '1' "$TOOL_PROBE_LOG" "the required-tool probe did not execute inside the worker"
311
+ assert_not_contains "$(cat "$TOOL_PROBE_LOG")" absent "the bootstrap process probed required tools locally"
312
+ pass "the remote doctor derives tool readiness from the installed worker"
313
+
314
+ DOCTOR_BIN="$TMP_ROOT/doctor-bin"
315
+ DOCTOR_HOME="$TMP_ROOT/doctor-home"
316
+ mkdir -p "$DOCTOR_BIN" "$DOCTOR_HOME"
317
+ ln -sf "$(command -v bash)" "$DOCTOR_BIN/bash"
318
+ # Report a non-darwin host so this file keeps testing tool resolution alone and
319
+ # never reads or writes the real account's launch agents.
320
+ cat > "$DOCTOR_BIN/uname" <<'SH'
321
+ #!/usr/bin/env bash
322
+ [ "${1:-}" = -s ] && { printf 'Linux\n'; exit 0; }
323
+ printf 'Linux\n'
324
+ SH
325
+ chmod +x "$DOCTOR_BIN/uname"
326
+ set +e
327
+ out=$(HOME="$DOCTOR_HOME" PATH="$DOCTOR_BIN:/usr/bin:/bin:/usr/sbin:/sbin" "$ROOT/bin/fm-remote-doctor.sh" 2>&1)
328
+ rc=$?
329
+ set -e
330
+ [ "$rc" -ne 0 ] || fail "the remote doctor passed with a missing required tool"
331
+ assert_contains "$out" 'required herdr=MISSING' "the remote doctor did not mark a missing required tool"
332
+ assert_contains "$out" 'required tasks-axi=MISSING' "the remote doctor did not mark every missing required tool"
333
+ assert_contains "$out" 'required tools do not resolve on the remote runtime PATH: herdr tasks-axi treehouse harness' "the remote doctor did not name the missing tools"
334
+ assert_contains "$out" '.local/bin' "the remote doctor did not offer the wrapper escape hatch"
335
+ ln -sf "$(command -v git)" "$DOCTOR_BIN/git"
336
+ # The direct doctor fixture needs the complete required tool set. These stubs
337
+ # exercise resolution only; the dedicated doctor suite owns worker and Herdr
338
+ # lifecycle behavior against controlled launchctl fixtures.
339
+ printf '#!/usr/bin/env bash\nexit 0\n' > "$DOCTOR_BIN/jq"
340
+ printf '#!/usr/bin/env bash\nprintf "{\\\"server\\\":{\\\"running\\\":false}}\\n"\n' > "$DOCTOR_BIN/herdr"
341
+ cat > "$DOCTOR_BIN/tasks-axi" <<'SH'
342
+ #!/usr/bin/env bash
343
+ case "${1:-}:${2:-}" in
344
+ --version:*) printf '0.2.4\n' ;;
345
+ update:--help) printf '%s\n' --archive-body ;;
346
+ mv:--help) printf '%s\n' 'usage: tasks-axi mv <id> [<id>...]' ;;
347
+ esac
348
+ SH
349
+ printf '#!/usr/bin/env bash\nexit 0\n' > "$DOCTOR_BIN/treehouse"
350
+ printf '#!/usr/bin/env bash\nexit 0\n' > "$DOCTOR_BIN/claude"
351
+ chmod +x "$DOCTOR_BIN/jq" "$DOCTOR_BIN/herdr" "$DOCTOR_BIN/tasks-axi" "$DOCTOR_BIN/treehouse" "$DOCTOR_BIN/claude"
352
+ set +e
353
+ out=$(HOME="$DOCTOR_HOME" PATH="$DOCTOR_BIN:/usr/bin:/bin:/usr/sbin:/sbin" "$ROOT/bin/fm-remote-doctor.sh" 2>&1)
354
+ rc=$?
355
+ set -e
356
+ assert_contains "$out" "required git=$DOCTOR_BIN/git" "the remote doctor did not report where the required tool resolved"
357
+ doctor_tmux=$(PATH="$DOCTOR_BIN:/usr/bin:/bin:/usr/sbin:/sbin" command -v tmux 2>/dev/null || true)
358
+ if [ -n "$doctor_tmux" ]; then
359
+ assert_contains "$out" "optional tmux=$doctor_tmux" "the remote doctor did not report the resolved optional tool"
360
+ else
361
+ assert_contains "$out" 'optional tmux=absent' "the remote doctor did not report an absent optional tool"
362
+ fi
363
+ assert_contains "$out" "required herdr=$DOCTOR_BIN/herdr" "the remote doctor did not require herdr"
364
+ assert_contains "$out" "required tasks-axi=$DOCTOR_BIN/tasks-axi" "the remote doctor did not require compatible tasks-axi"
365
+ assert_contains "$out" "required treehouse=$DOCTOR_BIN/treehouse" "the remote doctor did not require treehouse"
366
+ assert_contains "$out" "required harness=claude:$DOCTOR_BIN/claude" "the remote doctor did not require a verified harness"
367
+ assert_not_contains "$out" 'required tools do not resolve' "a resolved required tool was still reported missing"
368
+ pass "the remote doctor reports its required runtime tool set and optional tools"
369
+
370
+ out=$(fm_on ios fm-probe-two.sh)
371
+ assert_contains "$out" "home=$REMOTE_HOME" "first dynamic command stopped resolving"
372
+ ARGV_TWO="$REMOTE_HOME/argv-two.bin"
373
+ printf 'second command\0' > "$TMP_ROOT/argv-two-expected.bin"
374
+ fm_on ios fm-probe-one.sh "$ARGV_TWO" 0 'second command' >/dev/null 2>/dev/null
375
+ cmp -s "$TMP_ROOT/argv-two-expected.bin" "$ARGV_TWO" || fail "second dynamic command did not execute"
376
+ pass "multiple fm-*.sh executables work without a command table"
377
+
378
+ for bad in '../fm-probe-one.sh' 'fm-probe-one.sh/extra' 'sh' 'fm-../../bin/sh'; do
379
+ if fm_on ios "$bad" >/dev/null 2>&1; then
380
+ fail "unsafe command name was accepted: $bad"
381
+ fi
382
+ done
383
+ ln -s fm-probe-one.sh "$REMOTE_ROOT/bin/fm-symlink.sh"
384
+ if fm_on ios fm-symlink.sh >/dev/null 2>&1; then
385
+ fail "a symlinked command was accepted"
386
+ fi
387
+ cat > "$REMOTE_ROOT/bin/fm-untracked.sh" <<'SH'
388
+ #!/usr/bin/env bash
389
+ printf 'untracked command ran\n'
390
+ SH
391
+ chmod +x "$REMOTE_ROOT/bin/fm-untracked.sh"
392
+ GIT_SHADOW_LOG="$TMP_ROOT/git-shadow.log"
393
+ cat > "$REMOTE_ROOT/bin/git" <<'SH'
394
+ #!/usr/bin/env bash
395
+ printf 'consulted\n' >> "$FM_GIT_SHADOW_LOG"
396
+ exit 0
397
+ SH
398
+ chmod +x "$REMOTE_ROOT/bin/git"
399
+ FM_GIT_SHADOW_LOG="$GIT_SHADOW_LOG" "$REMOTE_ROOT/bin/git" -C "$REMOTE_ROOT" ls-files --error-unmatch bin/fm-untracked.sh \
400
+ || fail "the checkout-local git shim did not demonstrate that it would authorize the untracked command"
401
+ untracked_root_b64=$(printf '%s' "$REMOTE_ROOT" | base64 | tr -d '\n')
402
+ untracked_home_b64=$(printf '%s' "$REMOTE_HOME" | base64 | tr -d '\n')
403
+ untracked_argv_b64=$(printf '%s\0' fm-untracked.sh | base64 | tr -d '\n')
404
+ set +e
405
+ out=$(FM_GIT_SHADOW_LOG="$GIT_SHADOW_LOG" FM_REMOTE_JOB_PLATFORM_OVERRIDE=Linux \
406
+ FM_REMOTE_JOB_STATE_ROOT="$TMP_ROOT/remote-jobs" "$REMOTE_ROOT/bin/fm-remote-entrypoint.sh" \
407
+ 1 "$untracked_root_b64" "$untracked_home_b64" "$untracked_argv_b64" 2>&1)
408
+ rc=$?
409
+ set -e
410
+ if [ "$rc" -eq 0 ]; then
411
+ fail "an untracked fm-*.sh executable was accepted"
412
+ fi
413
+ assert_contains "$out" 'command is not tracked by the configured remote root' "the untracked command did not fail at tracked-command authorization"
414
+ [ "$(wc -l < "$GIT_SHADOW_LOG" | tr -d ' ')" -eq 1 ] \
415
+ || fail "the tracked-command authorization consulted checkout-local git"
416
+ pass "tracked-command authorization excludes checkout-local git"
417
+
418
+ set +e
419
+ out=$(
420
+ # shellcheck disable=SC2329 # Exported for indirect use by fm_on.
421
+ command() {
422
+ if [ "${1:-}" = -v ] && [ "${2:-}" = git ]; then return 1; fi
423
+ builtin command "$@"
424
+ }
425
+ export -f command
426
+ fm_on ios fm-remote-doctor.sh 2>&1
427
+ )
428
+ set -e
429
+ assert_contains "$out" 'mode=check' "the trusted doctor could not bootstrap while git was unavailable"
430
+ printf '\n' >> "$REMOTE_ROOT/bin/fm-remote-doctor.sh"
431
+ set +e
432
+ out=$(
433
+ # shellcheck disable=SC2329 # Exported for indirect use by fm_on.
434
+ command() {
435
+ if [ "${1:-}" = -v ] && [ "${2:-}" = git ]; then return 1; fi
436
+ builtin command "$@"
437
+ }
438
+ export -f command
439
+ fm_on ios fm-remote-doctor.sh 2>&1
440
+ )
441
+ rc=$?
442
+ set -e
443
+ [ "$rc" -ne 0 ] || fail "an altered doctor bootstrapped without tracked-command validation"
444
+ assert_contains "$out" 'doctor does not match the trusted bootstrap identity' \
445
+ "an altered doctor did not fail closed when git was unavailable"
446
+ cp "$ROOT/bin/fm-remote-doctor.sh" "$REMOTE_ROOT/bin/fm-remote-doctor.sh"
447
+ chmod +x "$REMOTE_ROOT/bin/fm-remote-doctor.sh"
448
+ pass "doctor bootstrap remains authenticated when git is unavailable"
449
+
450
+ if FM_HOME="$LOCAL_HOME" FM_ROOT_OVERRIDE="$REMOTE_ROOT" FM_SSH_BIN="$FAKEBIN/fake-ssh" \
451
+ "$ROOT/bin/fm-on.sh" '-oProxyCommand=bad' fm-probe-two.sh >/dev/null 2>&1; then
452
+ fail "an option-shaped SSH route was accepted"
453
+ fi
454
+ ssh_before_bad_path=$(cat "$SSH_COUNT")
455
+ cat > "$LOCAL_HOME/data/secondmates.md" <<EOF
456
+ - ios - iOS delivery (host: remote-mac; root: $REMOTE_ROOT/../remote-root; home: $REMOTE_HOME; scope: iOS work; projects: alpha; added 2026-08-02)
457
+ EOF
458
+ if fm_on ios fm-probe-two.sh >/dev/null 2>&1; then
459
+ fail "a configured remote root with traversal was accepted"
460
+ fi
461
+ [ "$(cat "$SSH_COUNT")" -eq "$ssh_before_bad_path" ] || fail "unsafe configured paths reached SSH"
462
+ write_registry
463
+ pass "transport rejects shell escape, traversal, symlink, and option-injection surfaces"
464
+
465
+ root_b64=$(printf '%s' "$REMOTE_ROOT" | base64 | tr -d '\n')
466
+ home_b64=$(printf '%s' "$REMOTE_HOME" | base64 | tr -d '\n')
467
+ argv_b64=$(printf '%s\0' fm-probe-two.sh | base64 | tr -d '\n')
468
+ if "$REMOTE_ROOT/bin/fm-remote-entrypoint.sh" 2 "$root_b64" "$home_b64" "$argv_b64" >/dev/null 2>&1; then
469
+ fail "an incompatible transport protocol was accepted"
470
+ fi
471
+ traversal_root_b64=$(printf '%s' "$REMOTE_ROOT/../remote-root" | base64 | tr -d '\n')
472
+ if "$REMOTE_ROOT/bin/fm-remote-entrypoint.sh" 1 "$traversal_root_b64" "$home_b64" "$argv_b64" >/dev/null 2>&1; then
473
+ fail "the fixed entrypoint accepted traversal in the configured root"
474
+ fi
475
+ pass "the fixed entrypoint refuses incompatible protocols and unsafe roots"
476
+
477
+ cat >> "$LOCAL_HOME/data/secondmates.md" <<EOF
478
+ - build - build delivery (host: remote-mac; root: $REMOTE_ROOT; home: $TMP_ROOT/other-remote-home; scope: build work; projects: beta; added 2026-08-02)
479
+ EOF
480
+ if fm_on remote-mac fm-probe-two.sh >/dev/null 2>&1; then
481
+ fail "an ambiguous SSH alias was accepted"
482
+ fi
483
+ out=$(fm_on ios fm-probe-two.sh)
484
+ assert_contains "$out" "home=$REMOTE_HOME" "secondmate-id routing broke after alias ambiguity"
485
+ write_registry
486
+ pass "ambiguous aliases refuse while exact secondmate ids remain routable"
487
+
488
+ : > "$SSH_COUNT"
489
+ set +e
490
+ FM_FAKE_SSH_MODE=unreachable fm_on ios fm-mutate.sh "$REMOTE_HOME/mutations" >/dev/null 2>&1
491
+ rc=$?
492
+ set -e
493
+ [ "$rc" -eq 255 ] || fail "unreachable transport did not preserve ssh status 255 (got $rc)"
494
+ [ "$(cat "$SSH_COUNT")" -eq 1 ] || fail "unreachable transport was retried"
495
+ assert_absent "$REMOTE_HOME/mutations" "unreachable transport ran the mutation"
496
+
497
+ : > "$SSH_COUNT"
498
+ set +e
499
+ FM_FAKE_SSH_MODE=ambiguous fm_on ios fm-mutate.sh "$REMOTE_HOME/mutations" >/dev/null 2>&1
500
+ rc=$?
501
+ set -e
502
+ [ "$rc" -eq 255 ] || fail "ambiguous completion did not surface status 255 (got $rc)"
503
+ [ "$(cat "$SSH_COUNT")" -eq 1 ] || fail "ambiguous completion was retried"
504
+ [ "$(grep -c mutation "$REMOTE_HOME/mutations")" -eq 1 ] || fail "ambiguous mutation did not execute exactly once"
505
+ pass "unreachable and ambiguous transport failures are surfaced without retry"
506
+
507
+ echo "ALL TESTS PASSED"