@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,827 @@
1
+ #!/usr/bin/env bash
2
+ # Behavior tests for fm-spawn.sh concrete dispatch profile flags.
3
+ #
4
+ # These tests drive fm-spawn through meta writing and launch construction with a
5
+ # fake tmux pane and a real isolated git worktree. The fake tmux captures the
6
+ # literal launch command sent with `tmux send-keys -l`, so assertions pin the
7
+ # command firstmate would run without starting any real harness.
8
+ set -u
9
+
10
+ # shellcheck source=tests/fixtures.sh
11
+ . "$(dirname "${BASH_SOURCE[0]}")/fixtures.sh"
12
+
13
+ SPAWN="$ROOT/bin/fm-spawn.sh"
14
+ TMP_ROOT=$(fm_test_tmproot fm-spawn-dispatch-profile)
15
+
16
+ make_spawn_pi_probe() {
17
+ local fakebin=$1 tool=$2
18
+ cat > "$fakebin/$tool" <<'SH'
19
+ #!/usr/bin/env bash
20
+ set -u
21
+ if [ "${1:-}" = --help ]; then
22
+ if [ "${FM_FAKE_PI_VERSION:-0.84.0}" = 0.82.0 ]; then
23
+ printf '%s\n' 'Pi 0.82.0' 'Options: --help'
24
+ else
25
+ printf '%s\n' "Pi ${FM_FAKE_PI_VERSION:-0.84.0}" 'Options: --help --tui-mode <mode>'
26
+ fi
27
+ fi
28
+ exit 0
29
+ SH
30
+ chmod +x "$fakebin/$tool"
31
+ }
32
+
33
+ make_spawn_fakebin() {
34
+ local dir=$1 fakebin
35
+ fakebin=$(fm_test_make_spawn_fakebin "$dir")
36
+ cat > "$fakebin/timeout" <<'SH'
37
+ #!/usr/bin/env bash
38
+ shift
39
+ exec "$@"
40
+ SH
41
+ cat > "$fakebin/cursor-agent" <<'SH'
42
+ #!/usr/bin/env bash
43
+ if [ "${1:-}" = --list-models ]; then
44
+ [ "${FM_FAKE_CURSOR_LIST_STATUS:-0}" -eq 0 ] || exit "${FM_FAKE_CURSOR_LIST_STATUS}"
45
+ printf '%b\n' "${FM_FAKE_CURSOR_MODELS:-Available models\ncursor-grok-4.5-high - Grok 4.5 High}"
46
+ fi
47
+ exit 0
48
+ SH
49
+ chmod +x "$fakebin/timeout" "$fakebin/cursor-agent"
50
+ make_spawn_pi_probe "$fakebin" pi
51
+ make_spawn_pi_probe "$fakebin" pi-signed
52
+ printf '%s\n' "$fakebin"
53
+ }
54
+
55
+ make_spawn_case() {
56
+ local name=$1 harness=$2 case_dir home proj wt fakebin launchlog id
57
+ shift 2
58
+ case_dir="$TMP_ROOT/$name"
59
+ home="$case_dir/home"
60
+ proj="$case_dir/project"
61
+ wt="$case_dir/wt"
62
+ launchlog="$case_dir/launch.log"
63
+ fakebin=$(make_spawn_fakebin "$case_dir/fake")
64
+ fm_test_spawn_home "$home" "$harness"
65
+ fm_git_worktree "$proj" "$wt" "wt-$name"
66
+ for id in "$@"; do
67
+ fm_test_spawn_brief "$home" "$id"
68
+ done
69
+ printf '%s\n' "$case_dir|$home|$proj|$wt|$fakebin|$launchlog"
70
+ }
71
+
72
+ enable_dispatch_profile() {
73
+ local home=$1
74
+ printf '%s\n' '{"rules":[{"when":"current events","use":{"harness":"grok","model":"grok-4","effort":"high"}}],"default":{"harness":"codex","model":"gpt-5","effort":"medium"}}' \
75
+ > "$home/config/crew-dispatch.json"
76
+ }
77
+
78
+ make_seeded_secondmate_home() {
79
+ local home=$1 id=$2
80
+ mkdir -p "$home/bin" "$home/data"
81
+ printf '# Firstmate\n' > "$home/AGENTS.md"
82
+ printf '%s\n' "$id" > "$home/.fm-secondmate-home"
83
+ printf 'charter for %s\n' "$id" > "$home/data/charter.md"
84
+ }
85
+
86
+ run_spawn() {
87
+ local home=$1 wt=$2 fakebin=$3 launchlog=$4
88
+ shift 4
89
+ : > "$launchlog"
90
+ # CLAUDE_CONFIG_DIR is forwarded onto claude launches by fm-spawn, so pin it
91
+ # explicitly (empty by default) instead of leaking the invoking shell's value,
92
+ # which would make launch assertions depend on the developer's environment.
93
+ # A test opts in to the set case via FM_TEST_CLAUDE_CONFIG_DIR.
94
+ CLAUDE_CONFIG_DIR="${FM_TEST_CLAUDE_CONFIG_DIR:-}" \
95
+ FM_FAKE_LAUNCH_LOG="$launchlog" FM_FAKE_PI_VERSION="${FM_TEST_PI_VERSION:-0.84.0}" \
96
+ FM_FAKE_CURSOR_MODELS="${FM_TEST_CURSOR_MODELS:-}" \
97
+ FM_FAKE_CURSOR_LIST_STATUS="${FM_TEST_CURSOR_LIST_STATUS:-0}" \
98
+ GROK_HOME="$home/grok-home" \
99
+ fm_test_run_spawn "$home" "$wt" "$fakebin" "$@"
100
+ }
101
+
102
+ # Ship spawns carry an explicit delivery contract (AGENTS.md section 7); these
103
+ # tests are about profile resolution, so they pass a fixed valid one.
104
+ run_ship_spawn() {
105
+ run_spawn "$@" --mode no-mistakes --yolo off
106
+ }
107
+
108
+ read_case_record() {
109
+ IFS='|' read -r CASE_DIR HOME_DIR PROJ_DIR WT_DIR FAKEBIN_DIR LAUNCH_LOG <<EOF
110
+ $1
111
+ EOF
112
+ }
113
+
114
+ assert_meta_profile() {
115
+ local meta=$1 harness=$2 model=$3 effort=$4
116
+ assert_grep "harness=$harness" "$meta" "meta missing harness=$harness"
117
+ assert_grep "model=$model" "$meta" "meta missing model=$model"
118
+ assert_grep "effort=$effort" "$meta" "meta missing effort=$effort"
119
+ }
120
+
121
+ test_no_profile_keeps_claude_profile_defaults() {
122
+ local rec id out status expected launch
123
+ id=profile-off-z1
124
+ rec=$(make_spawn_case profile-off claude "$id")
125
+ read_case_record "$rec"
126
+
127
+ out=$(run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$PROJ_DIR")
128
+ status=$?
129
+ expect_code 0 "$status" "claude spawn without profile flags should succeed"
130
+ assert_contains "$out" "spawned $id harness=claude" "spawn did not report claude"
131
+ assert_meta_profile "$HOME_DIR/state/$id.meta" claude default default
132
+
133
+ launch=$(cat "$LAUNCH_LOG")
134
+ expected="env -u CURSOR_AGENT -u CURSOR_INVOKED_AS CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION=false claude --dangerously-skip-permissions \"\$('${ROOT}/bin/fm-operational-input.sh' encode launch-brief < '$HOME_DIR/data/$id/brief.md')\""
135
+ [ "$launch" = "$expected" ] || fail "no-profile claude launch did not use the canonical launch kind"$'\n'"expected: $expected"$'\n'"actual: $launch"
136
+ pass "no --model/--effort records defaults and types the claude launch instructions"
137
+ }
138
+
139
+ test_non_cursor_launch_clears_inherited_cursor_markers() {
140
+ local rec id out status launch
141
+ id=profile-claude-cursor-markers-z1b
142
+ rec=$(make_spawn_case profile-claude-cursor-markers claude "$id")
143
+ read_case_record "$rec"
144
+
145
+ out=$(CURSOR_AGENT=1 CURSOR_INVOKED_AS=cursor-agent \
146
+ run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$PROJ_DIR")
147
+ status=$?
148
+ expect_code 0 "$status" "claude spawn under Cursor markers should succeed"
149
+ launch=$(cat "$LAUNCH_LOG")
150
+ assert_contains "$launch" "env -u CURSOR_AGENT -u CURSOR_INVOKED_AS" \
151
+ "non-cursor launch must clear both inherited Cursor identity markers"
152
+ pass "non-cursor launches clear inherited Cursor identity markers"
153
+ }
154
+
155
+ test_relative_home_overrides_launch_with_absolute_cross_process_paths() {
156
+ local rec id out status launch home_real
157
+ id=profile-relative-paths-z1b
158
+ rec=$(make_spawn_case profile-relative-paths pi "$id")
159
+ read_case_record "$rec"
160
+ home_real=$(cd "$HOME_DIR" && pwd -P)
161
+ mkdir -p "$CASE_DIR/cdpath/home/state" "$CASE_DIR/cdpath/home/data"
162
+ : > "$LAUNCH_LOG"
163
+
164
+ out=$(
165
+ cd "$CASE_DIR" || exit 1
166
+ CDPATH="$CASE_DIR/cdpath" FM_ROOT_OVERRIDE='' FM_HOME=home \
167
+ FM_STATE_OVERRIDE=home/state FM_DATA_OVERRIDE=home/data \
168
+ FM_PROJECTS_OVERRIDE=home/projects FM_CONFIG_OVERRIDE=home/config \
169
+ FM_SPAWN_NO_GUARD=1 FM_FAKE_PANE_PATH="$WT_DIR" TMUX="fake,1,0" \
170
+ CLAUDE_CONFIG_DIR='' FM_FAKE_LAUNCH_LOG="$LAUNCH_LOG" \
171
+ GROK_HOME=home/grok-home PATH="$FAKEBIN_DIR:$PATH" \
172
+ "$SPAWN" "$id" "$PROJ_DIR" --mode no-mistakes --yolo off 2>&1
173
+ )
174
+ status=$?
175
+ expect_code 0 "$status" "spawn with relative home overrides should succeed"
176
+ launch=$(cat "$LAUNCH_LOG")
177
+ assert_contains "$launch" "-e '$home_real/state/$id.pi-ext.ts'" \
178
+ "relative FM_STATE_OVERRIDE leaked into Pi's cross-process extension path"
179
+ assert_contains "$launch" "< '$home_real/data/$id/brief.md'" \
180
+ "relative FM_DATA_OVERRIDE leaked into the cross-process brief path"
181
+ pass "relative home overrides ignore CDPATH and become absolute before spawn launch construction"
182
+ }
183
+
184
+ test_home_defaults_preserve_absolute_or_resolve_relative_paths() {
185
+ local rec relative_id absolute_id out status launch home_real linked_home
186
+ relative_id=profile-relative-home-defaults-z1c
187
+ absolute_id=profile-absolute-home-defaults-z1d
188
+ rec=$(make_spawn_case profile-home-defaults pi "$relative_id" "$absolute_id")
189
+ read_case_record "$rec"
190
+ home_real=$(cd "$HOME_DIR" && pwd -P)
191
+
192
+ : > "$LAUNCH_LOG"
193
+ out=$(
194
+ cd "$CASE_DIR" || exit 1
195
+ FM_ROOT_OVERRIDE='' FM_HOME=home \
196
+ FM_STATE_OVERRIDE='' FM_DATA_OVERRIDE='' \
197
+ FM_PROJECTS_OVERRIDE=home/projects FM_CONFIG_OVERRIDE=home/config \
198
+ FM_SPAWN_NO_GUARD=1 FM_FAKE_PANE_PATH="$WT_DIR" TMUX="fake,1,0" \
199
+ CLAUDE_CONFIG_DIR='' FM_FAKE_LAUNCH_LOG="$LAUNCH_LOG" \
200
+ GROK_HOME=home/grok-home PATH="$FAKEBIN_DIR:$PATH" \
201
+ "$SPAWN" "$relative_id" "$PROJ_DIR" --mode no-mistakes --yolo off 2>&1
202
+ )
203
+ status=$?
204
+ expect_code 0 "$status" "spawn with relative FM_HOME defaults should succeed"
205
+ launch=$(cat "$LAUNCH_LOG")
206
+ assert_contains "$launch" "-e '$home_real/state/$relative_id.pi-ext.ts'" \
207
+ "relative FM_HOME leaked into Pi's default cross-process extension path"
208
+ assert_contains "$launch" "< '$home_real/data/$relative_id/brief.md'" \
209
+ "relative FM_HOME leaked into the default cross-process brief path"
210
+
211
+ linked_home="$CASE_DIR/home-link"
212
+ ln -s "$HOME_DIR" "$linked_home"
213
+ : > "$LAUNCH_LOG"
214
+ out=$(
215
+ FM_ROOT_OVERRIDE='' FM_HOME="$linked_home" \
216
+ FM_STATE_OVERRIDE='' FM_DATA_OVERRIDE='' \
217
+ FM_PROJECTS_OVERRIDE="$linked_home/projects" FM_CONFIG_OVERRIDE="$linked_home/config" \
218
+ FM_SPAWN_NO_GUARD=1 FM_FAKE_PANE_PATH="$WT_DIR" TMUX="fake,1,0" \
219
+ CLAUDE_CONFIG_DIR='' FM_FAKE_LAUNCH_LOG="$LAUNCH_LOG" \
220
+ GROK_HOME="$linked_home/grok-home" PATH="$FAKEBIN_DIR:$PATH" \
221
+ "$SPAWN" "$absolute_id" "$PROJ_DIR" --mode no-mistakes --yolo off 2>&1
222
+ )
223
+ status=$?
224
+ expect_code 0 "$status" "spawn with absolute symlink-spelled FM_HOME defaults should succeed"
225
+ launch=$(cat "$LAUNCH_LOG")
226
+ assert_contains "$launch" "-e '$linked_home/state/$absolute_id.pi-ext.ts'" \
227
+ "absolute FM_HOME spelling changed in Pi's default cross-process extension path"
228
+ assert_contains "$launch" "< '$linked_home/data/$absolute_id/brief.md'" \
229
+ "absolute FM_HOME spelling changed in the default cross-process brief path"
230
+ pass "FM_HOME defaults resolve relative paths and preserve absolute spellings"
231
+ }
232
+
233
+ test_absolute_override_spelling_is_preserved_in_launch_paths() {
234
+ local rec id out status launch linked_home
235
+ id=profile-absolute-paths-z1c
236
+ rec=$(make_spawn_case profile-absolute-paths pi "$id")
237
+ read_case_record "$rec"
238
+ linked_home="$CASE_DIR/home-link"
239
+ ln -s "$HOME_DIR" "$linked_home"
240
+ : > "$LAUNCH_LOG"
241
+
242
+ out=$(
243
+ FM_ROOT_OVERRIDE='' FM_HOME="$linked_home" \
244
+ FM_STATE_OVERRIDE="$linked_home/state" FM_DATA_OVERRIDE="$linked_home/data" \
245
+ FM_PROJECTS_OVERRIDE="$linked_home/projects" FM_CONFIG_OVERRIDE="$linked_home/config" \
246
+ FM_SPAWN_NO_GUARD=1 FM_FAKE_PANE_PATH="$WT_DIR" TMUX="fake,1,0" \
247
+ CLAUDE_CONFIG_DIR='' FM_FAKE_LAUNCH_LOG="$LAUNCH_LOG" \
248
+ GROK_HOME="$linked_home/grok-home" PATH="$FAKEBIN_DIR:$PATH" \
249
+ "$SPAWN" "$id" "$PROJ_DIR" --mode no-mistakes --yolo off 2>&1
250
+ )
251
+ status=$?
252
+ expect_code 0 "$status" "spawn with absolute symlink-spelled overrides should succeed"
253
+ launch=$(cat "$LAUNCH_LOG")
254
+ assert_contains "$launch" "-e '$linked_home/state/$id.pi-ext.ts'" \
255
+ "absolute FM_STATE_OVERRIDE spelling changed in Pi's cross-process extension path"
256
+ assert_contains "$launch" "< '$linked_home/data/$id/brief.md'" \
257
+ "absolute FM_DATA_OVERRIDE spelling changed in the cross-process brief path"
258
+ pass "absolute override spellings are preserved in spawn launch paths"
259
+ }
260
+
261
+ test_unresolvable_relative_overrides_fail_loudly() {
262
+ local rec id out status
263
+ id=profile-unresolvable-paths-z1d
264
+ rec=$(make_spawn_case profile-unresolvable-paths pi "$id")
265
+ read_case_record "$rec"
266
+
267
+ out=$(
268
+ cd "$CASE_DIR" || exit 1
269
+ FM_ROOT_OVERRIDE='' FM_HOME=missing-home \
270
+ FM_STATE_OVERRIDE='' FM_DATA_OVERRIDE='' \
271
+ "$SPAWN" "$id" "$PROJ_DIR" --mode no-mistakes --yolo off 2>&1
272
+ )
273
+ status=$?
274
+ expect_code 1 "$status" "spawn with an unresolvable relative home should fail"
275
+ assert_contains "$out" "FM_HOME directory cannot be resolved: missing-home" \
276
+ "spawn did not name the unresolvable FM_HOME"
277
+
278
+ out=$(
279
+ cd "$CASE_DIR" || exit 1
280
+ FM_ROOT_OVERRIDE='' FM_HOME=home \
281
+ FM_STATE_OVERRIDE=missing-state FM_DATA_OVERRIDE=home/data \
282
+ "$SPAWN" "$id" "$PROJ_DIR" --mode no-mistakes --yolo off 2>&1
283
+ )
284
+ status=$?
285
+ expect_code 1 "$status" "spawn with an unresolvable relative state override should fail"
286
+ assert_contains "$out" "FM_STATE_OVERRIDE directory cannot be resolved: missing-state" \
287
+ "spawn did not name the unresolvable FM_STATE_OVERRIDE"
288
+
289
+ out=$(
290
+ cd "$CASE_DIR" || exit 1
291
+ FM_ROOT_OVERRIDE='' FM_HOME=home \
292
+ FM_STATE_OVERRIDE=home/state FM_DATA_OVERRIDE=missing-data \
293
+ "$SPAWN" "$id" "$PROJ_DIR" --mode no-mistakes --yolo off 2>&1
294
+ )
295
+ status=$?
296
+ expect_code 1 "$status" "spawn with an unresolvable relative data override should fail"
297
+ assert_contains "$out" "FM_DATA_OVERRIDE directory cannot be resolved: missing-data" \
298
+ "spawn did not name the unresolvable FM_DATA_OVERRIDE"
299
+ pass "unresolvable relative spawn overrides fail with named diagnostics"
300
+ }
301
+
302
+ test_active_dispatch_profile_requires_explicit_harness_for_ship() {
303
+ local rec id out status
304
+ id=profile-required-ship-z11
305
+ rec=$(make_spawn_case profile-required-ship claude "$id")
306
+ read_case_record "$rec"
307
+ enable_dispatch_profile "$HOME_DIR"
308
+
309
+ out=$(run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$PROJ_DIR")
310
+ status=$?
311
+ expect_code 1 "$status" "ship spawn without explicit harness should fail when dispatch profiles are active"
312
+ assert_contains "$out" "config/crew-dispatch.json is active - pass an explicit harness resolved from the dispatch rules" \
313
+ "spawn did not explain the dispatch-profile backstop"
314
+ assert_absent "$HOME_DIR/state/$id.meta" "ship refusal should happen before meta is written"
315
+ pass "active crew-dispatch profile requires an explicit harness for ship spawns"
316
+ }
317
+
318
+ test_active_dispatch_profile_requires_explicit_harness_for_scout() {
319
+ local rec id out status
320
+ id=profile-required-scout-z12
321
+ rec=$(make_spawn_case profile-required-scout claude "$id")
322
+ read_case_record "$rec"
323
+ enable_dispatch_profile "$HOME_DIR"
324
+
325
+ out=$(run_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$PROJ_DIR" --scout)
326
+ status=$?
327
+ expect_code 1 "$status" "scout spawn without explicit harness should fail when dispatch profiles are active"
328
+ assert_contains "$out" "config/crew-dispatch.json is active - pass an explicit harness resolved from the dispatch rules" \
329
+ "scout refusal did not explain the dispatch-profile backstop"
330
+ assert_absent "$HOME_DIR/state/$id.meta" "scout refusal should happen before meta is written"
331
+ pass "active crew-dispatch profile requires an explicit harness for scout spawns"
332
+ }
333
+
334
+ test_active_dispatch_profile_allows_explicit_harness() {
335
+ local rec id out status launch
336
+ id=profile-explicit-z13
337
+ rec=$(make_spawn_case profile-explicit claude "$id")
338
+ read_case_record "$rec"
339
+ enable_dispatch_profile "$HOME_DIR"
340
+
341
+ out=$(run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" \
342
+ "$id" "$PROJ_DIR" --harness codex --model gpt-5 --effort high)
343
+ status=$?
344
+ expect_code 0 "$status" "explicit harness should satisfy active dispatch-profile requirement"
345
+ assert_contains "$out" "spawned $id harness=codex" "spawn did not report explicit codex harness"
346
+ assert_meta_profile "$HOME_DIR/state/$id.meta" codex gpt-5 high
347
+ launch=$(cat "$LAUNCH_LOG")
348
+ assert_contains "$launch" "codex --model 'gpt-5' -c 'model_reasoning_effort=\"high\"' --dangerously-bypass-approvals-and-sandbox" \
349
+ "explicit harness launch did not thread model and effort"
350
+ pass "active crew-dispatch profile allows an explicit resolved harness"
351
+ }
352
+
353
+ test_active_dispatch_profile_allows_positional_harness() {
354
+ local rec id out status
355
+ id=profile-positional-z14
356
+ rec=$(make_spawn_case profile-positional claude "$id")
357
+ read_case_record "$rec"
358
+ enable_dispatch_profile "$HOME_DIR"
359
+
360
+ out=$(run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" \
361
+ "$id" "$PROJ_DIR" codex --model gpt-5 --effort high)
362
+ status=$?
363
+ expect_code 0 "$status" "positional harness should satisfy active dispatch-profile requirement"
364
+ assert_contains "$out" "spawned $id harness=codex" "spawn did not report positional codex harness"
365
+ assert_meta_profile "$HOME_DIR/state/$id.meta" codex gpt-5 high
366
+ pass "active crew-dispatch profile allows the legacy positional harness form"
367
+ }
368
+
369
+ test_active_dispatch_profile_allows_raw_launch_command() {
370
+ local rec id out status launch
371
+ id=profile-raw-z15
372
+ rec=$(make_spawn_case profile-raw claude "$id")
373
+ read_case_record "$rec"
374
+ enable_dispatch_profile "$HOME_DIR"
375
+
376
+ out=$(run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" \
377
+ "$id" "$PROJ_DIR" "custom-agent --flag")
378
+ status=$?
379
+ expect_code 0 "$status" "raw launch command should satisfy active dispatch-profile requirement"
380
+ assert_contains "$out" "spawned $id harness=custom-agent" "spawn did not report raw command harness"
381
+ assert_meta_profile "$HOME_DIR/state/$id.meta" custom-agent default default
382
+ launch=$(cat "$LAUNCH_LOG")
383
+ [ "$launch" = "custom-agent --flag" ] || fail "raw launch command changed"$'\n'"actual: $launch"
384
+ pass "active crew-dispatch profile allows the raw launch-command escape hatch"
385
+ }
386
+
387
+ test_claude_threads_model_and_effort() {
388
+ local rec id out status launch
389
+ id=profile-claude-z2
390
+ rec=$(make_spawn_case profile-claude claude "$id")
391
+ read_case_record "$rec"
392
+
393
+ out=$(run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$PROJ_DIR" --model sonnet --effort high)
394
+ status=$?
395
+ expect_code 0 "$status" "claude spawn with profile flags should succeed"
396
+ assert_meta_profile "$HOME_DIR/state/$id.meta" claude sonnet high
397
+ launch=$(cat "$LAUNCH_LOG")
398
+ assert_contains "$launch" "claude --dangerously-skip-permissions --model 'sonnet' --effort 'high'" \
399
+ "claude launch did not thread model and effort flags"
400
+ assert_not_contains "$launch" "--tui-mode" "non-Pi launches must not receive Pi's TUI mode override"
401
+ pass "claude receives --model and --effort profile flags"
402
+ }
403
+
404
+ test_codex_threads_model_and_effort() {
405
+ local rec id out status launch
406
+ id=profile-codex-z3
407
+ rec=$(make_spawn_case profile-codex codex "$id")
408
+ read_case_record "$rec"
409
+
410
+ out=$(run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$PROJ_DIR" --model gpt-5 --effort high)
411
+ status=$?
412
+ expect_code 0 "$status" "codex spawn with profile flags should succeed"
413
+ assert_meta_profile "$HOME_DIR/state/$id.meta" codex gpt-5 high
414
+ launch=$(cat "$LAUNCH_LOG")
415
+ assert_contains "$launch" "codex --model 'gpt-5' -c 'model_reasoning_effort=\"high\"' --dangerously-bypass-approvals-and-sandbox" \
416
+ "codex launch did not thread model and reasoning effort config"
417
+ pass "codex receives --model and model_reasoning_effort profile flags"
418
+ }
419
+
420
+ test_codex_omits_invalid_max_effort() {
421
+ local rec id out status launch
422
+ id=profile-codex-max-z4
423
+ rec=$(make_spawn_case profile-codex-max codex "$id")
424
+ read_case_record "$rec"
425
+
426
+ out=$(run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$PROJ_DIR" --model gpt-5 --effort max)
427
+ status=$?
428
+ expect_code 0 "$status" "codex spawn with unsupported max effort should omit the effort flag"
429
+ assert_meta_profile "$HOME_DIR/state/$id.meta" codex gpt-5 max
430
+ launch=$(cat "$LAUNCH_LOG")
431
+ assert_contains "$launch" "codex --model 'gpt-5' --dangerously-bypass-approvals-and-sandbox" \
432
+ "codex launch did not preserve the model flag when max effort was omitted"
433
+ assert_not_contains "$launch" "model_reasoning_effort" "codex launch must omit unsupported max reasoning effort"
434
+ pass "codex omits unsupported max effort instead of passing a bad config value"
435
+ }
436
+
437
+ test_grok_threads_model_and_reasoning_effort() {
438
+ local rec id out status launch
439
+ id=profile-grok-z5
440
+ rec=$(make_spawn_case profile-grok grok "$id")
441
+ read_case_record "$rec"
442
+
443
+ out=$(run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$PROJ_DIR" --model grok-4 --effort high)
444
+ status=$?
445
+ expect_code 0 "$status" "grok spawn with profile flags should succeed"
446
+ assert_meta_profile "$HOME_DIR/state/$id.meta" grok grok-4 high
447
+ launch=$(cat "$LAUNCH_LOG")
448
+ assert_contains "$launch" "grok --always-approve --model 'grok-4' --reasoning-effort 'high'" \
449
+ "grok launch did not thread model and reasoning-effort flags"
450
+ assert_not_contains "$launch" "--effort" "grok launch must use --reasoning-effort, not --effort"
451
+ pass "grok receives --model and --reasoning-effort profile flags"
452
+ }
453
+
454
+ test_grok_omits_invalid_max_reasoning_effort() {
455
+ local rec id out status launch
456
+ id=profile-grok-max-z6
457
+ rec=$(make_spawn_case profile-grok-max grok "$id")
458
+ read_case_record "$rec"
459
+
460
+ out=$(run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$PROJ_DIR" --model grok-4 --effort max)
461
+ status=$?
462
+ expect_code 0 "$status" "grok spawn with unsupported max reasoning effort should omit the effort flag"
463
+ assert_meta_profile "$HOME_DIR/state/$id.meta" grok grok-4 max
464
+ launch=$(cat "$LAUNCH_LOG")
465
+ assert_contains "$launch" "grok --always-approve --model 'grok-4' \"\$('${ROOT}/bin/fm-operational-input.sh' encode launch-brief < " \
466
+ "grok launch did not preserve the model flag and typed brief when max effort was omitted"
467
+ assert_not_contains "$launch" "--reasoning-effort" "grok launch must omit unsupported max reasoning effort"
468
+ assert_not_contains "$launch" "--effort" "grok launch must not fall back to --effort for reasoning effort"
469
+ pass "grok omits unsupported max reasoning effort"
470
+ }
471
+
472
+ test_grok_omits_invalid_xhigh_reasoning_effort() {
473
+ local rec id out status launch
474
+ id=profile-grok-xhigh-z6b
475
+ rec=$(make_spawn_case profile-grok-xhigh grok "$id")
476
+ read_case_record "$rec"
477
+
478
+ # grok 0.2.99 rejects xhigh (accepted set is only low|medium|high).
479
+ out=$(run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$PROJ_DIR" --model grok-4 --effort xhigh)
480
+ status=$?
481
+ expect_code 0 "$status" "grok spawn with unsupported xhigh reasoning effort should omit the effort flag"
482
+ assert_meta_profile "$HOME_DIR/state/$id.meta" grok grok-4 xhigh
483
+ launch=$(cat "$LAUNCH_LOG")
484
+ assert_contains "$launch" "grok --always-approve --model 'grok-4' \"\$('${ROOT}/bin/fm-operational-input.sh' encode launch-brief < " \
485
+ "grok launch did not preserve the model flag and typed brief when xhigh effort was omitted"
486
+ assert_not_contains "$launch" "--reasoning-effort" "grok launch must omit unsupported xhigh reasoning effort"
487
+ assert_not_contains "$launch" "--effort" "grok launch must not fall back to --effort for reasoning effort"
488
+ pass "grok omits unsupported xhigh reasoning effort"
489
+ }
490
+
491
+ test_cursor_threads_model_workspace_and_omits_effort_axis() {
492
+ local rec id out status launch
493
+ id=profile-cursor-z6c
494
+ rec=$(make_spawn_case profile-cursor cursor "$id")
495
+ read_case_record "$rec"
496
+
497
+ out=$(run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$PROJ_DIR" \
498
+ --model cursor-grok-4.5-high --effort high)
499
+ status=$?
500
+ expect_code 0 "$status" "cursor spawn with a model-qualified reasoning class should succeed"
501
+ assert_meta_profile "$HOME_DIR/state/$id.meta" cursor cursor-grok-4.5-high high
502
+ launch=$(cat "$LAUNCH_LOG")
503
+ assert_contains "$launch" "--trust --yolo --model 'cursor-grok-4.5-high' --workspace '$WT_DIR'" \
504
+ "cursor launch did not carry trust, autonomy, model, and exact workspace flags"
505
+ # The executable is RESOLVED, never named: `cursor` is not the CLI, so a
506
+ # literal `cursor agent` command cannot run on a machine that has only the
507
+ # real installed names.
508
+ assert_not_contains "$launch" "cursor agent --trust" \
509
+ "cursor launch must resolve its executable, not invoke a literal 'cursor agent'"
510
+ assert_contains "$launch" "cursor-agent" "cursor launch did not resolve a cursor executable"
511
+ # -w/--worktree would allocate a SECOND worktree under ~/.cursor/worktrees and
512
+ # break the isolation contract the spawn assertion depends on.
513
+ assert_not_contains "$launch" " --worktree" "cursor launch must never allocate a second worktree"
514
+ assert_not_contains "$launch" " -w " "cursor launch must never allocate a second worktree"
515
+ # An inherited CLAUDECODE would otherwise outrank cursor's own marker.
516
+ assert_contains "$launch" "env -u CLAUDECODE" "cursor launch must clear foreign primary markers"
517
+ assert_contains "$launch" "encode launch-brief" "cursor launch did not deliver the brief positionally"
518
+ assert_not_contains "$launch" "--effort" "cursor launch must not invent a separate effort flag"
519
+ assert_not_contains "$launch" "--reasoning-effort" "cursor launch must not invent a separate reasoning-effort flag"
520
+ assert_grep 'harness=cursor' "$HOME_DIR/state/$id.meta" "cursor harness was not recorded in meta"
521
+ assert_grep 'model=cursor-grok-4.5-high' "$HOME_DIR/state/$id.meta" "cursor model was recorded as default"
522
+ pass "cursor receives its model-qualified reasoning class and exact task workspace"
523
+ }
524
+
525
+ test_cursor_refuses_model_absent_from_live_catalog() {
526
+ local rec id out status
527
+ id=profile-cursor-unsupported-z6d
528
+ rec=$(make_spawn_case profile-cursor-unsupported cursor "$id")
529
+ read_case_record "$rec"
530
+
531
+ out=$(run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$PROJ_DIR" \
532
+ --model cursor-grok-4.5)
533
+ status=$?
534
+ expect_code 1 "$status" "cursor spawn should refuse a model absent from a successful catalog"
535
+ assert_contains "$out" "Cursor model 'cursor-grok-4.5' is not available" \
536
+ "cursor model refusal did not identify the unavailable model"
537
+ assert_contains "$out" "--list-models" \
538
+ "cursor model refusal did not tell the caller how to find valid ids"
539
+ [ ! -s "$LAUNCH_LOG" ] || fail "cursor model refusal must happen before launch"
540
+ pass "cursor refuses model ids absent from its resolved binary's live catalog"
541
+ }
542
+
543
+ test_cursor_failed_catalog_probe_does_not_block_spawn() {
544
+ local rec id out status launch
545
+ id=profile-cursor-catalog-unreachable-z6e
546
+ rec=$(make_spawn_case profile-cursor-catalog-unreachable cursor "$id")
547
+ read_case_record "$rec"
548
+
549
+ FM_TEST_CURSOR_LIST_STATUS=124 \
550
+ out=$(run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$PROJ_DIR" \
551
+ --model cursor-catalog-unreachable)
552
+ status=$?
553
+ expect_code 0 "$status" "cursor spawn should fail open when the bounded catalog query fails"
554
+ launch=$(cat "$LAUNCH_LOG")
555
+ assert_contains "$launch" "--model 'cursor-catalog-unreachable'" \
556
+ "failed catalog lookup incorrectly removed the requested model"
557
+ assert_meta_profile "$HOME_DIR/state/$id.meta" cursor cursor-catalog-unreachable default
558
+ pass "cursor preserves the requested model when its live catalog is unreachable"
559
+ }
560
+
561
+ test_opencode_threads_model_and_ignores_effort_axis() {
562
+ local rec id out status launch
563
+ id=profile-opencode-z7
564
+ rec=$(make_spawn_case profile-opencode opencode "$id")
565
+ read_case_record "$rec"
566
+
567
+ out=$(run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$PROJ_DIR" --model anthropic/claude-sonnet-4-5 --effort high)
568
+ status=$?
569
+ expect_code 0 "$status" "opencode spawn with model and ignored effort should succeed"
570
+ assert_meta_profile "$HOME_DIR/state/$id.meta" opencode anthropic/claude-sonnet-4-5 high
571
+ launch=$(cat "$LAUNCH_LOG")
572
+ assert_contains "$launch" "opencode --model 'anthropic/claude-sonnet-4-5' --prompt" \
573
+ "opencode launch did not thread model"
574
+ assert_not_contains "$launch" "--effort" "opencode launch must not pass unsupported --effort"
575
+ assert_not_contains "$launch" "--variant" "opencode launch must not pass run-only --variant"
576
+ assert_not_contains "$launch" "--thinking" "opencode launch must not pass pi thinking flag"
577
+ pass "opencode receives --model and omits the unsupported effort axis"
578
+ }
579
+
580
+ test_pi_threads_model_and_max_effort() {
581
+ local rec id out status launch
582
+ id=profile-pi-z8
583
+ rec=$(make_spawn_case profile-pi pi "$id")
584
+ read_case_record "$rec"
585
+
586
+ out=$(run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$PROJ_DIR" \
587
+ --model openai-codex/gpt-5.6-sol --effort max)
588
+ status=$?
589
+ expect_code 0 "$status" "pi spawn with max effort should succeed"
590
+ assert_meta_profile "$HOME_DIR/state/$id.meta" pi openai-codex/gpt-5.6-sol max
591
+ launch=$(cat "$LAUNCH_LOG")
592
+ assert_contains "$launch" "FM_PI_HARNESS=pi '$FAKEBIN_DIR/pi' --tui-mode regular --model 'openai-codex/gpt-5.6-sol' --thinking 'max' -e" \
593
+ "pi launch did not force the regular TUI while threading the requested model and max thinking level"
594
+ assert_not_contains "$launch" "FM_FIRSTMATE_PI_LAUNCH_BRIEF=" \
595
+ "pi launch still exports the removed Calm input-reroute binding"
596
+ assert_contains "$launch" "fm-operational-input.sh' encode launch-brief" \
597
+ "pi launch lost the canonical typed launch-brief envelope"
598
+ pass "pi receives --model and --thinking max profile flags"
599
+ }
600
+
601
+ test_pi_signed_threads_shared_pi_profile_and_preserves_identity() {
602
+ local rec id out status launch
603
+ id=profile-pi-signed-z8b
604
+ rec=$(make_spawn_case profile-pi-signed pi-signed "$id")
605
+ read_case_record "$rec"
606
+
607
+ out=$(run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$PROJ_DIR" \
608
+ --model openai-codex/gpt-5.6-sol --effort max)
609
+ status=$?
610
+ expect_code 0 "$status" "pi-signed spawn with max effort should succeed"
611
+ assert_contains "$out" "spawned $id harness=pi-signed" "pi-signed spawn did not preserve its visible identity"
612
+ assert_meta_profile "$HOME_DIR/state/$id.meta" pi-signed openai-codex/gpt-5.6-sol max
613
+ launch=$(cat "$LAUNCH_LOG")
614
+ assert_contains "$launch" "FM_PI_HARNESS=pi-signed '$FAKEBIN_DIR/pi-signed' --tui-mode regular --model 'openai-codex/gpt-5.6-sol' --thinking 'max' -e" \
615
+ "pi-signed launch did not force the regular TUI with Pi's model, thinking, and extension semantics"
616
+ assert_contains "$launch" "fm-operational-input.sh' encode launch-brief" \
617
+ "pi-signed launch lost the canonical typed launch-brief envelope"
618
+ assert_present "$HOME_DIR/state/$id.pi-ext.ts" "pi-signed launch did not install Pi's turn-end extension"
619
+ assert_present "$HOME_DIR/state/$id.busy-gen" "pi-signed spawn did not arm the busy-state contract"
620
+ assert_contains "$(cat "$HOME_DIR/state/$id.busy-state")" "state=busy source=fm-spawn" \
621
+ "pi-signed spawn did not seed the busy-state record from the launch brief"
622
+ local ext gen
623
+ ext=$(cat "$HOME_DIR/state/$id.pi-ext.ts")
624
+ gen=$(cat "$HOME_DIR/state/$id.busy-gen")
625
+ assert_contains "$ext" 'pi.on("agent_start"' "pi extension lost the semantic agent_start busy edge"
626
+ assert_contains "$ext" 'pi.on("agent_settled"' "pi extension lost the semantic agent_settled idle edge"
627
+ assert_contains "$ext" 'ctx.isIdle()' "pi extension no longer confirms idle with ctx.isIdle()"
628
+ assert_contains "$ext" "\"--gen\", \"$gen\"" "pi extension does not carry the armed incarnation gen"
629
+ assert_contains "$ext" '"--source", "pi-ext"' "pi extension does not attribute its semantic source"
630
+ assert_contains "$ext" 'pi.on("turn_end"' "pi extension lost the turn-end notification touch"
631
+ pass "pi-signed shares Pi launch semantics while preserving its configured and recorded identity"
632
+ }
633
+
634
+ test_pi_tui_mode_probe_is_safe_for_old_and_new_pi() {
635
+ local harness version rec id out status launch
636
+ for harness in pi pi-signed; do
637
+ for version in 0.82.0 0.84.0; do
638
+ id="profile-${harness}-tui-${version//./}-z8d"
639
+ rec=$(make_spawn_case "profile-__MODELFLAG__-${harness}-tui-${version//./}" "$harness" "$id")
640
+ read_case_record "$rec"
641
+
642
+ out=$(FM_TEST_PI_VERSION="$version" \
643
+ run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" \
644
+ "$id" "$PROJ_DIR")
645
+ status=$?
646
+ expect_code 0 "$status" "$harness $version spawn should succeed"
647
+ launch=$(cat "$LAUNCH_LOG")
648
+ assert_contains "$launch" "'$FAKEBIN_DIR/$harness'" \
649
+ "$harness $version launch must use the executable selected for probing"
650
+ assert_not_contains "$launch" "FM_PI_HARNESS=$harness $harness" \
651
+ "$harness $version launch must not re-resolve a bare executable in the worker"
652
+ if [ "$version" = 0.82.0 ]; then
653
+ assert_not_contains "$launch" "--tui-mode" \
654
+ "$harness $version launch must omit unsupported --tui-mode"
655
+ else
656
+ assert_contains "$launch" "'$FAKEBIN_DIR/$harness' --tui-mode regular" \
657
+ "$harness $version launch must preserve the regular TUI"
658
+ fi
659
+ done
660
+ done
661
+ pass "Pi launch probing omits --tui-mode on older Pi and preserves it on supporting Pi"
662
+ }
663
+
664
+ test_pi_signed_missing_binary_refuses_before_endpoint_or_metadata() {
665
+ local rec id out status
666
+ id=profile-pi-signed-missing-z8c
667
+ rec=$(make_spawn_case profile-pi-signed-missing pi-signed "$id")
668
+ read_case_record "$rec"
669
+ rm -f "$FAKEBIN_DIR/pi-signed"
670
+ : > "$LAUNCH_LOG"
671
+
672
+ out=$(FM_ROOT_OVERRIDE='' FM_HOME="$HOME_DIR" \
673
+ FM_STATE_OVERRIDE="$HOME_DIR/state" FM_DATA_OVERRIDE="$HOME_DIR/data" \
674
+ FM_PROJECTS_OVERRIDE="$HOME_DIR/projects" FM_CONFIG_OVERRIDE="$HOME_DIR/config" \
675
+ FM_SPAWN_NO_GUARD=1 FM_FAKE_PANE_PATH="$WT_DIR" TMUX="fake,1,0" \
676
+ FM_FAKE_LAUNCH_LOG="$LAUNCH_LOG" PATH="$FAKEBIN_DIR:/usr/bin:/bin:/usr/sbin:/sbin" \
677
+ "$SPAWN" "$id" "$PROJ_DIR" --mode no-mistakes --yolo off 2>&1)
678
+ status=$?
679
+ expect_code 1 "$status" "a missing pi-signed executable should refuse the spawn"
680
+ assert_contains "$out" "pi-signed executable not found on PATH" \
681
+ "missing pi-signed refusal did not name the actionable requirement"
682
+ assert_absent "$HOME_DIR/state/$id.meta" "missing pi-signed refusal wrote task metadata"
683
+ [ ! -s "$LAUNCH_LOG" ] || fail "missing pi-signed refusal typed a launch command"
684
+ pass "pi-signed refuses safely and actionably when the selected executable is unavailable"
685
+ }
686
+
687
+ test_pi_signed_persistent_secondmate_uses_pi_extensions_and_identity() {
688
+ local rec id sm out status launch
689
+ id=profile-pi-signed-secondmate-z8d
690
+ rec=$(make_spawn_case profile-pi-signed-secondmate codex "$id")
691
+ read_case_record "$rec"
692
+ printf '%s\n' pi-signed > "$HOME_DIR/config/secondmate-harness"
693
+ sm="$CASE_DIR/secondmate-home"
694
+ make_seeded_secondmate_home "$sm" "$id"
695
+ sm=$(cd "$sm" && pwd -P)
696
+
697
+ out=$(run_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$sm" --secondmate)
698
+ status=$?
699
+ expect_code 0 "$status" "pi-signed persistent secondmate spawn should succeed"
700
+ assert_contains "$out" "spawned $id harness=pi-signed kind=secondmate" \
701
+ "pi-signed secondmate spawn did not preserve its runtime identity"
702
+ assert_meta_profile "$HOME_DIR/state/$id.meta" pi-signed default default
703
+ launch=$(cat "$LAUNCH_LOG")
704
+ assert_contains "$launch" "FM_PI_HARNESS=pi-signed '$FAKEBIN_DIR/pi-signed' --tui-mode regular -e '$sm/.pi/extensions/fm-primary-turnend-guard.ts' -e '$sm/.pi/extensions/fm-primary-pi-watch.ts'" \
705
+ "pi-signed secondmate did not force the regular TUI with Pi's primary extension launch shape"
706
+ pass "pi-signed is a distinct persistent secondmate runtime with shared Pi supervision semantics"
707
+ }
708
+
709
+ test_batch_forwards_shared_profile_flags() {
710
+ local rec id1 id2 out status
711
+ id1=profile-batch-a-z9
712
+ id2=profile-batch-b-z10
713
+ rec=$(make_spawn_case profile-batch claude "$id1" "$id2")
714
+ read_case_record "$rec"
715
+ enable_dispatch_profile "$HOME_DIR"
716
+
717
+ out=$(run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" \
718
+ "$id1=$PROJ_DIR" "$id2=$PROJ_DIR" --harness codex --model gpt-5 --effort high)
719
+ status=$?
720
+ expect_code 0 "$status" "batch spawn with shared profile flags should succeed"
721
+ assert_contains "$out" "spawned $id1 harness=codex" "first batch task did not use shared harness"
722
+ assert_contains "$out" "spawned $id2 harness=codex" "second batch task did not use shared harness"
723
+ assert_meta_profile "$HOME_DIR/state/$id1.meta" codex gpt-5 high
724
+ assert_meta_profile "$HOME_DIR/state/$id2.meta" codex gpt-5 high
725
+ pass "batch dispatch forwards shared --harness, --model, and --effort to every pair"
726
+ }
727
+
728
+ test_claude_forwards_firstmate_config_dir_when_set() {
729
+ local rec id out status launch
730
+ id=profile-claude-cfgdir-z17
731
+ rec=$(make_spawn_case profile-claude-cfgdir claude "$id")
732
+ read_case_record "$rec"
733
+
734
+ out=$(FM_TEST_CLAUDE_CONFIG_DIR="/opt/test/claude-work" \
735
+ run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$PROJ_DIR")
736
+ status=$?
737
+ expect_code 0 "$status" "claude spawn with CLAUDE_CONFIG_DIR set should succeed"
738
+ launch=$(cat "$LAUNCH_LOG")
739
+ assert_contains "$launch" "CLAUDE_CONFIG_DIR='/opt/test/claude-work' env -u CURSOR_AGENT -u CURSOR_INVOKED_AS CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION=false claude" \
740
+ "claude launch did not forward firstmate's CLAUDE_CONFIG_DIR to the crewmate pane"
741
+ pass "claude forwards firstmate's CLAUDE_CONFIG_DIR so the crewmate uses the same credential store"
742
+ }
743
+
744
+ test_claude_omits_config_dir_prefix_when_unset() {
745
+ local rec id out status launch
746
+ id=profile-claude-nocfgdir-z18
747
+ rec=$(make_spawn_case profile-claude-nocfgdir claude "$id")
748
+ read_case_record "$rec"
749
+
750
+ # run_spawn pins CLAUDE_CONFIG_DIR empty by default, exercising the single-store
751
+ # default path where fm-spawn adds no prefix.
752
+ out=$(run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$PROJ_DIR")
753
+ status=$?
754
+ expect_code 0 "$status" "claude spawn without CLAUDE_CONFIG_DIR should succeed"
755
+ launch=$(cat "$LAUNCH_LOG")
756
+ assert_not_contains "$launch" "CLAUDE_CONFIG_DIR=" \
757
+ "claude launch must not add a config-dir prefix when firstmate has no CLAUDE_CONFIG_DIR set"
758
+ pass "claude omits the config-dir prefix when firstmate runs with the single-store default"
759
+ }
760
+
761
+ test_non_claude_harness_ignores_config_dir() {
762
+ local rec id out status launch
763
+ id=profile-codex-nocfgdir-z19
764
+ rec=$(make_spawn_case profile-codex-nocfgdir codex "$id")
765
+ read_case_record "$rec"
766
+
767
+ out=$(FM_TEST_CLAUDE_CONFIG_DIR="/opt/test/claude-work" \
768
+ run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$PROJ_DIR")
769
+ status=$?
770
+ expect_code 0 "$status" "codex spawn with CLAUDE_CONFIG_DIR set should succeed"
771
+ launch=$(cat "$LAUNCH_LOG")
772
+ assert_not_contains "$launch" "CLAUDE_CONFIG_DIR=" \
773
+ "non-claude harness launch must not receive the claude-specific config-dir prefix"
774
+ pass "non-claude harnesses do not receive the claude CLAUDE_CONFIG_DIR prefix"
775
+ }
776
+
777
+ test_active_dispatch_profile_does_not_block_secondmate_launch() {
778
+ local rec id sm out status
779
+ id=profile-secondmate-z16
780
+ rec=$(make_spawn_case profile-secondmate codex "$id")
781
+ read_case_record "$rec"
782
+ enable_dispatch_profile "$HOME_DIR"
783
+ sm="$CASE_DIR/secondmate-home"
784
+ make_seeded_secondmate_home "$sm" "$id"
785
+
786
+ out=$(run_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$sm" --secondmate)
787
+ status=$?
788
+ expect_code 0 "$status" "secondmate spawn should be exempt from the dispatch-profile explicit harness requirement"
789
+ assert_contains "$out" "spawned $id harness=codex kind=secondmate" "secondmate launch did not use secondmate harness resolution"
790
+ assert_grep "kind=secondmate" "$HOME_DIR/state/$id.meta" "secondmate meta missing kind=secondmate"
791
+ assert_meta_profile "$HOME_DIR/state/$id.meta" codex default default
792
+ pass "active crew-dispatch profile does not block secondmate launches"
793
+ }
794
+
795
+ test_no_profile_keeps_claude_profile_defaults
796
+ test_non_cursor_launch_clears_inherited_cursor_markers
797
+ test_relative_home_overrides_launch_with_absolute_cross_process_paths
798
+ test_home_defaults_preserve_absolute_or_resolve_relative_paths
799
+ test_absolute_override_spelling_is_preserved_in_launch_paths
800
+ test_unresolvable_relative_overrides_fail_loudly
801
+ test_active_dispatch_profile_requires_explicit_harness_for_ship
802
+ test_active_dispatch_profile_requires_explicit_harness_for_scout
803
+ test_active_dispatch_profile_allows_explicit_harness
804
+ test_active_dispatch_profile_allows_positional_harness
805
+ test_active_dispatch_profile_allows_raw_launch_command
806
+ test_claude_threads_model_and_effort
807
+ test_codex_threads_model_and_effort
808
+ test_codex_omits_invalid_max_effort
809
+ test_grok_threads_model_and_reasoning_effort
810
+ test_grok_omits_invalid_max_reasoning_effort
811
+ test_grok_omits_invalid_xhigh_reasoning_effort
812
+ test_cursor_threads_model_workspace_and_omits_effort_axis
813
+ test_cursor_refuses_model_absent_from_live_catalog
814
+ test_cursor_failed_catalog_probe_does_not_block_spawn
815
+ test_opencode_threads_model_and_ignores_effort_axis
816
+ test_pi_threads_model_and_max_effort
817
+ test_pi_tui_mode_probe_is_safe_for_old_and_new_pi
818
+ test_pi_signed_threads_shared_pi_profile_and_preserves_identity
819
+ test_pi_signed_missing_binary_refuses_before_endpoint_or_metadata
820
+ test_pi_signed_persistent_secondmate_uses_pi_extensions_and_identity
821
+ test_batch_forwards_shared_profile_flags
822
+ test_claude_forwards_firstmate_config_dir_when_set
823
+ test_claude_omits_config_dir_prefix_when_unset
824
+ test_non_claude_harness_ignores_config_dir
825
+ test_active_dispatch_profile_does_not_block_secondmate_launch
826
+
827
+ echo "# all fm-spawn-dispatch-profile tests passed"