@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,932 @@
1
+ #!/usr/bin/env bash
2
+ # Behavior tests for the muse (Muse Code) crewmate adapter: harness detection,
3
+ # spawn launch shape and credential preflight, the secondmate refusal, the
4
+ # session-log busy source, and teardown cleanup of the busy binding.
5
+ #
6
+ # The session-log fixtures below reproduce muse 0.1.0-R708.1's real record
7
+ # shapes, including the nested "record":{"kind":"terminal"} cleanup payload that
8
+ # is NOT a run terminal. That decoy is the whole reason the fold matches an
9
+ # anchored structural prefix instead of searching for "kind":"terminal", so a
10
+ # fixture without it would let a naive implementation pass.
11
+ set -u
12
+
13
+ # shellcheck source=tests/lib.sh
14
+ . "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
15
+
16
+ # bin/fm-harness.sh checks verified ENV markers before ancestry. Muse is
17
+ # markerless, so an inherited Cursor/Claude/Pi/Grok marker would outrank the
18
+ # versioned muse-bin ancestor these detection cases launch. Drop the ambient
19
+ # markers so the asserted verdict does not depend on which harness launched
20
+ # the suite.
21
+ unset CLAUDECODE PI_CODING_AGENT FM_PI_HARNESS GROK_AGENT CURSOR_AGENT CURSOR_INVOKED_AS
22
+
23
+ SPAWN="$ROOT/bin/fm-spawn.sh"
24
+ TEARDOWN="$ROOT/bin/fm-teardown.sh"
25
+ HARNESS="$ROOT/bin/fm-harness.sh"
26
+ TMP_ROOT=$(fm_test_tmproot fm-muse-harness)
27
+
28
+ # --- session-log fixtures ---------------------------------------------------
29
+
30
+ # muse_log_metadata <workspace-root>: the first record of every session log,
31
+ # which is what binds a log to a task worktree.
32
+ muse_log_metadata() {
33
+ printf '{"schema_version":1,"id":"d77de583","stream":{"kind":"session","id":"52f21aea"},"sequence":1,"record_type":"event","durability":"durable","payload_type":"runtime.session.metadata","payload":{"kind":"metadata","record":{"workspace_root":"%s","provider_id":"meta","build":{"sha":"427a430436","semver":"0.1.0"}}}}\n' "$1"
34
+ }
35
+
36
+ muse_log_run_started() { # <run-id>
37
+ printf '{"schema_version":1,"payload_type":"runtime.session","payload":{"kind":"run","run_id":"%s","event":{"kind":"started","prompt":"launch brief"}}}\n' "$1"
38
+ }
39
+
40
+ muse_log_run_terminal() { # <run-id> <completed|cancelled>
41
+ printf '{"schema_version":1,"payload_type":"runtime.session","payload":{"kind":"run","run_id":"%s","event":{"kind":"terminal","terminal":"%s","reason":null,"turn_duration_ms":8152}}}\n' "$1" "$2"
42
+ }
43
+
44
+ # The decoy: a cleanup-effect payload whose NESTED record is "terminal". It is
45
+ # not a run lifecycle terminal and must not settle an open run.
46
+ muse_log_cleanup_terminal_decoy() { # <run-id>
47
+ printf '{"schema_version":1,"payload_type":"runtime.session","payload":{"kind":"reminder_cleanup_effect","run_id":"%s","record":{"kind":"terminal","cleanup_effect_id":1,"outcome":{"kind":"applied"}}}}\n' "$1"
48
+ }
49
+
50
+ muse_log_noise() { # <run-id>
51
+ printf '{"schema_version":1,"payload_type":"runtime.session","payload":{"kind":"run","run_id":"%s","event":{"kind":"context_block_diagnostic","block_id":"rules_file","message":"mentions kind terminal and kind started in prose"}}}\n' "$1"
52
+ }
53
+
54
+ # write_session_log <sessions-root> <yyyy> <mm> <dd> <uuid> <workspace-root>
55
+ # Body records are read from stdin. Writes the log at muse's real depth
56
+ # (<root>/YYYY/MM/DD/<uuid>/session.jsonl) and echoes the path.
57
+ write_session_log() {
58
+ local root=$1 y=$2 m=$3 d=$4 uuid=$5 ws=$6 dir path
59
+ dir="$root/$y/$m/$d/$uuid"
60
+ mkdir -p "$dir"
61
+ path="$dir/session.jsonl"
62
+ muse_log_metadata "$ws" > "$path"
63
+ cat >> "$path"
64
+ printf '%s\n' "$path"
65
+ }
66
+
67
+ # --- spawn scaffolding ------------------------------------------------------
68
+
69
+ make_spawn_fakebin() {
70
+ local dir=$1 fakebin
71
+ fakebin=$(fm_fakebin "$dir")
72
+ cat > "$fakebin/tmux" <<'SH'
73
+ #!/usr/bin/env bash
74
+ set -u
75
+ case "$*" in
76
+ *"#{pane_current_path}"*) printf '%s\n' "${FM_FAKE_PANE_PATH:-}"; exit 0 ;;
77
+ esac
78
+ case "${1:-}" in
79
+ show-environment)
80
+ [ "${FM_FAKE_WORKER_META_KEY:-}" = present ] || exit 1
81
+ printf 'META_API_KEY=worker-key\n'
82
+ exit 0
83
+ ;;
84
+ display-message) printf 'firstmate\n'; exit 0 ;;
85
+ list-windows) exit 0 ;;
86
+ has-session|new-session|new-window|kill-window) exit 0 ;;
87
+ send-keys)
88
+ prev=
89
+ for arg in "$@"; do
90
+ if [ "$prev" = -l ]; then
91
+ printf '%s\n' "$arg" >> "$FM_FAKE_LAUNCH_LOG"
92
+ if [ "${FM_FAKE_EXECUTE_MUSE_LAUNCH:-}" = 1 ]; then
93
+ case "$arg" in
94
+ *"$FM_FAKE_MUSE_EXECUTABLE"*) (cd "$FM_FAKE_PANE_PATH" && bash -c "$arg") ;;
95
+ esac
96
+ fi
97
+ break
98
+ fi
99
+ prev=$arg
100
+ done
101
+ exit 0
102
+ ;;
103
+ esac
104
+ exit 0
105
+ SH
106
+ chmod +x "$fakebin/tmux"
107
+ cp "$(command -v bash)" "$fakebin/muse-bin-test-version"
108
+ cat > "$fakebin/muse" <<'SH'
109
+ #!/usr/bin/env bash
110
+ set -u
111
+ [ -n "${FM_FAKE_HARNESS_RESULT:-}" ] || exit 0
112
+ exec "$FM_FAKE_MUSE_VERSIONED" -c 'result=$($FM_FAKE_HARNESS_PROBE); printf "%s" "$result" > "$FM_FAKE_HARNESS_RESULT"'
113
+ SH
114
+ chmod +x "$fakebin/muse"
115
+ fm_fake_exit0 "$fakebin" treehouse gh-axi gh
116
+ printf '%s\n' "$fakebin"
117
+ }
118
+
119
+ make_spawn_case() {
120
+ local name=$1 case_dir home proj wt fakebin id
121
+ case_dir="$TMP_ROOT/$name"
122
+ home="$case_dir/home"
123
+ proj="$case_dir/project"
124
+ wt="$case_dir/wt"
125
+ fakebin=$(make_spawn_fakebin "$case_dir/fake")
126
+ id="muse-$name-x1"
127
+ mkdir -p "$home/data/$id" "$home/projects" "$home/state" "$home/config" \
128
+ "$home/xdgconfig" "$home/xdgdata"
129
+ printf 'brief\n' > "$home/data/$id/brief.md"
130
+ fm_git_worktree "$proj" "$wt" "fm/$id"
131
+ touch "$home/state/.last-watcher-beat"
132
+ printf '%s\n' "$case_dir|$home|$proj|$wt|$fakebin|$id"
133
+ }
134
+
135
+ run_muse_spawn() { # <home> <proj> <wt> <fakebin> <id> [extra args...]
136
+ local home=$1 proj=$2 wt=$3 fakebin=$4 id=$5
137
+ shift 5
138
+ FM_ROOT_OVERRIDE='' FM_HOME="$home" \
139
+ FM_STATE_OVERRIDE="$home/state" FM_DATA_OVERRIDE="$home/data" \
140
+ FM_PROJECTS_OVERRIDE="$home/projects" FM_CONFIG_OVERRIDE="$home/config" \
141
+ FM_SPAWN_NO_GUARD=1 FM_FAKE_PANE_PATH="$wt" TMUX="fake,1,0" \
142
+ FM_FAKE_LAUNCH_LOG="$home/launch.log" \
143
+ FM_FAKE_MUSE_EXECUTABLE="$fakebin/muse" \
144
+ FM_FAKE_MUSE_VERSIONED="$fakebin/muse-bin-test-version" \
145
+ FM_FAKE_HARNESS_PROBE="$HARNESS" \
146
+ FM_FAKE_EXECUTE_MUSE_LAUNCH="${FM_FAKE_EXECUTE_MUSE_LAUNCH:-}" \
147
+ FM_FAKE_HARNESS_RESULT="${FM_FAKE_HARNESS_RESULT:-}" \
148
+ FM_FAKE_WORKER_META_KEY="${FM_TEST_MUSE_WORKER_KEY-present}" \
149
+ META_API_KEY="${FM_TEST_MUSE_KEY-test-key}" \
150
+ XDG_CONFIG_HOME="${FM_TEST_MUSE_CONFIG_HOME-$home/xdgconfig}" \
151
+ XDG_DATA_HOME="${FM_TEST_MUSE_DATA_HOME-$home/xdgdata}" \
152
+ PATH="$fakebin:$PATH" \
153
+ "$SPAWN" "$id" "$proj" muse "$@" 2>&1
154
+ }
155
+
156
+ # --- detection --------------------------------------------------------------
157
+
158
+ # The installed muse launcher execs a VERSION-SUFFIXED binary
159
+ # (~/.local/bin/muse-bin-<version>), so the name in the process tree changes on
160
+ # every auto-update. Detection must follow a real running process rather than a
161
+ # string, so each case launches an actual renamed executable and asks
162
+ # fm-harness.sh from a child of it.
163
+ #
164
+ # The foreign env markers, including Cursor's, are cleared because muse is
165
+ # markerless and the marker layer deliberately outranks ancestry: with one
166
+ # retained, these cases would assert the marker's verdict instead of the
167
+ # ancestry match they exist to pin.
168
+ # The command substitution around the probe is load-bearing: a bare `-c <cmd>`
169
+ # lets the shell exec the probe in place, which REPLACES the muse-bin-* process
170
+ # name the walk is supposed to find. Real muse keeps its TUI process alive and
171
+ # runs tools as children, so forcing a fork is what reproduces that shape.
172
+ test_detects_versioned_process_ancestor() {
173
+ local dir bin out
174
+ dir="$TMP_ROOT/detect"
175
+ mkdir -p "$dir"
176
+ for bin in muse-bin-0.1.0-R708.1 muse-bin-9.9.9-RZZZ.9 muse; do
177
+ cp "$(command -v bash)" "$dir/$bin"
178
+ out=$(env -u CLAUDECODE -u PI_CODING_AGENT -u FM_PI_HARNESS -u GROK_AGENT \
179
+ -u CURSOR_AGENT -u CURSOR_INVOKED_AS \
180
+ "$dir/$bin" -c "r=\$(\"$HARNESS\"); printf '%s' \"\$r\"")
181
+ [ "$out" = muse ] || fail "fm-harness.sh under process '$bin' reported '$out', expected muse"
182
+ done
183
+ pass "muse is detected through any versioned muse-bin ancestor"
184
+ }
185
+
186
+ # The match must be anchored: an unrelated command whose name merely CONTAINS
187
+ # muse is a different program and must not be claimed by this adapter.
188
+ test_detection_is_anchored() {
189
+ local dir bin out
190
+ dir="$TMP_ROOT/detect-neg"
191
+ mkdir -p "$dir"
192
+ for bin in musescore amuse notmuse-bin muse-binary muse-bind; do
193
+ cp "$(command -v bash)" "$dir/$bin"
194
+ out=$(env -u CLAUDECODE -u PI_CODING_AGENT -u FM_PI_HARNESS -u GROK_AGENT \
195
+ -u CURSOR_AGENT -u CURSOR_INVOKED_AS \
196
+ "$dir/$bin" -c "r=\$(\"$HARNESS\"); printf '%s' \"\$r\"")
197
+ [ "$out" != muse ] || fail "fm-harness.sh misdetected unrelated process '$bin' as muse"
198
+ done
199
+ pass "muse detection does not claim unrelated muse-containing commands"
200
+ }
201
+
202
+ test_spawn_clears_inherited_foreign_harness_markers() {
203
+ local rec case_dir home proj wt fakebin id result out status
204
+ rec=$(make_spawn_case inherited-markers)
205
+ IFS='|' read -r case_dir home proj wt fakebin id <<EOF
206
+ $rec
207
+ EOF
208
+ result="$case_dir/harness-result"
209
+ out=$(CLAUDECODE=1 PI_CODING_AGENT=true GROK_AGENT=1 FM_PI_HARNESS=pi-signed \
210
+ CURSOR_AGENT=1 CURSOR_INVOKED_AS=cursor-agent \
211
+ FM_FAKE_EXECUTE_MUSE_LAUNCH=1 FM_FAKE_HARNESS_RESULT="$result" \
212
+ run_muse_spawn "$home" "$proj" "$wt" "$fakebin" "$id" --mode no-mistakes --yolo off)
213
+ status=$?
214
+ expect_code 0 "$status" "muse spawn from a marked backend should succeed: $out"
215
+ [ -f "$result" ] || fail "the generated muse launch never executed its harness probe"
216
+ [ "$(cat "$result")" = muse ] \
217
+ || fail "muse worker inherited a foreign harness identity: $(cat "$result")"
218
+ pass "muse launch clears foreign harness markers before ancestry detection"
219
+ }
220
+
221
+ # --- spawn ------------------------------------------------------------------
222
+
223
+ test_spawn_launch_shape() {
224
+ local rec case_dir home proj wt fakebin id out status launch
225
+ rec=$(make_spawn_case launch)
226
+ IFS='|' read -r case_dir home proj wt fakebin id <<EOF
227
+ $rec
228
+ EOF
229
+ out=$(run_muse_spawn "$home" "$proj" "$wt" "$fakebin" "$id" --mode no-mistakes --yolo off)
230
+ status=$?
231
+ expect_code 0 "$status" "muse spawn should succeed"
232
+ assert_contains "$out" "spawned $id harness=muse" "muse spawn did not report success"
233
+
234
+ launch=$(cat "$home/launch.log")
235
+ # --yolo is what makes a crewmate pane viable at all: without it muse holds
236
+ # every tool call for approval and sandboxes the network to proxy-only.
237
+ assert_contains "$launch" ' --yolo ' "muse launch omitted --yolo"
238
+ # The privacy control. Its absence would ship the operator's foreign personal
239
+ # rules to Meta-hosted inference on every crewmate turn.
240
+ assert_contains "$launch" 'MUSE_EXPERIMENTAL_FOREIGN_PERSONAL_CONTEXT_KILL=on' \
241
+ "muse launch omitted the foreign-personal-context kill"
242
+ # exec-only flag: the interactive TUI exits with "unexpected argument" on it.
243
+ assert_not_contains "$launch" '--no-foreign-personal-context' \
244
+ "muse launch passed the exec-only foreign-context flag to the TUI"
245
+ # The captain accepted muse's self-update risk, so firstmate must not pin it.
246
+ assert_not_contains "$launch" 'MUSE_NO_AUTO_UPDATE' \
247
+ "muse launch pinned auto-update, which the captain declined"
248
+ assert_contains "$launch" "XDG_CONFIG_HOME='$home/xdgconfig'" \
249
+ "muse launch did not forward its non-secret config root"
250
+ assert_contains "$launch" "XDG_DATA_HOME='$home/xdgdata'" \
251
+ "muse launch did not forward its non-secret data root"
252
+ assert_not_contains "$launch" 'META_API_KEY' "muse launch exposed META_API_KEY in worker argv"
253
+ assert_not_contains "$launch" 'test-key' "muse launch exposed the credential value in worker argv"
254
+ assert_contains "$launch" 'encode launch-brief' "muse launch did not deliver the brief positionally"
255
+ assert_grep 'harness=muse' "$home/state/$id.meta" "muse harness was not recorded in meta"
256
+ pass "muse spawn launches with autonomy, privacy control, and a positional brief"
257
+ }
258
+
259
+ test_spawn_maps_effort_and_model() {
260
+ local rec case_dir home proj wt fakebin id launch
261
+ local -a cases=(
262
+ "low|--reasoning-effort 'low'"
263
+ "medium|--reasoning-effort 'medium'"
264
+ "high|--reasoning-effort 'high'"
265
+ "xhigh|--reasoning-effort 'xhigh'"
266
+ "max|--reasoning-effort 'ultra'"
267
+ )
268
+ local entry effort expect
269
+ for entry in "${cases[@]}"; do
270
+ effort=${entry%%|*}
271
+ expect=${entry#*|}
272
+ rec=$(make_spawn_case "effort-$effort")
273
+ IFS='|' read -r case_dir home proj wt fakebin id <<EOF
274
+ $rec
275
+ EOF
276
+ run_muse_spawn "$home" "$proj" "$wt" "$fakebin" "$id" \
277
+ --mode no-mistakes --yolo off --model muse-spark-1.2 --effort "$effort" >/dev/null \
278
+ || fail "muse spawn with effort $effort failed"
279
+ launch=$(cat "$home/launch.log")
280
+ assert_contains "$launch" "$expect" "muse effort $effort did not map to '$expect'"
281
+ assert_contains "$launch" "--model 'muse-spark-1.2'" "muse spawn dropped the model axis"
282
+ done
283
+ # ultra is muse's max-class level and must be reachable ONLY through an
284
+ # explicit max, never as the fallback when no effort was chosen.
285
+ rec=$(make_spawn_case effort-default)
286
+ IFS='|' read -r case_dir home proj wt fakebin id <<EOF
287
+ $rec
288
+ EOF
289
+ run_muse_spawn "$home" "$proj" "$wt" "$fakebin" "$id" --mode no-mistakes --yolo off >/dev/null \
290
+ || fail "muse spawn without an effort axis failed"
291
+ launch=$(cat "$home/launch.log")
292
+ assert_not_contains "$launch" '--reasoning-effort' "muse spawn invented an effort when none was chosen"
293
+ pass "muse maps the shared effort vocabulary and reaches ultra only via explicit max"
294
+ }
295
+
296
+ # An unauthenticated muse pane does not exit: it sits on an OAuth device-code
297
+ # prompt forever, which supervision would read as a wedged worker rather than a
298
+ # missing credential. The spawn must refuse before an endpoint exists.
299
+ test_spawn_refuses_without_credential() {
300
+ local rec case_dir home proj wt fakebin id out status
301
+ rec=$(make_spawn_case no-cred)
302
+ IFS='|' read -r case_dir home proj wt fakebin id <<EOF
303
+ $rec
304
+ EOF
305
+ mkdir -p "$home/xdgconfig/muse"
306
+ out=$(FM_TEST_MUSE_KEY='' FM_TEST_MUSE_WORKER_KEY='' run_muse_spawn "$home" "$proj" "$wt" "$fakebin" "$id" \
307
+ --mode no-mistakes --yolo off)
308
+ status=$?
309
+ [ "$status" -ne 0 ] || fail "muse spawn succeeded with no credential available"
310
+ assert_contains "$out" "no worker-reachable credential" "muse spawn did not name the missing credential"
311
+ assert_absent "$home/state/$id.meta" "refused muse spawn still published task metadata"
312
+ pass "muse spawn refuses when no credential can reach the provider"
313
+ }
314
+
315
+ test_spawn_refuses_caller_only_environment_credential() {
316
+ local rec case_dir home proj wt fakebin id out status
317
+ rec=$(make_spawn_case caller-only-cred)
318
+ IFS='|' read -r case_dir home proj wt fakebin id <<EOF
319
+ $rec
320
+ EOF
321
+ out=$(FM_TEST_MUSE_KEY='caller-only-secret' FM_TEST_MUSE_WORKER_KEY='' \
322
+ run_muse_spawn "$home" "$proj" "$wt" "$fakebin" "$id" --mode no-mistakes --yolo off)
323
+ status=$?
324
+ [ "$status" -ne 0 ] || fail "muse spawn accepted a caller-only META_API_KEY"
325
+ assert_contains "$out" "set for fm-spawn but cannot be proven present" \
326
+ "muse spawn did not explain that the caller credential cannot reach the worker"
327
+ assert_contains "$out" "$home/xdgconfig/muse/auth.json" \
328
+ "muse spawn did not name the supported stored credential path"
329
+ assert_absent "$home/launch.log" "caller-only credential refusal created an endpoint"
330
+ pass "muse spawn refuses a META_API_KEY that cannot reach the worker"
331
+ }
332
+
333
+ test_spawn_accepts_stored_credential() {
334
+ local rec case_dir home proj wt fakebin id status
335
+ rec=$(make_spawn_case stored-cred)
336
+ IFS='|' read -r case_dir home proj wt fakebin id <<EOF
337
+ $rec
338
+ EOF
339
+ mkdir -p "$home/xdgconfig/muse"
340
+ printf '{"schema_version":1}\n' > "$home/xdgconfig/muse/auth.json"
341
+ FM_TEST_MUSE_KEY='' FM_TEST_MUSE_WORKER_KEY='' \
342
+ run_muse_spawn "$home" "$proj" "$wt" "$fakebin" "$id" \
343
+ --mode no-mistakes --yolo off >/dev/null
344
+ status=$?
345
+ expect_code 0 "$status" "muse spawn should accept a stored credential"
346
+ pass "muse spawn accepts a stored credential without META_API_KEY"
347
+ }
348
+
349
+ test_spawn_resolves_relative_xdg_roots() {
350
+ local rec case_dir home proj wt fakebin id caller resolved_caller launch binding out status
351
+ rec=$(make_spawn_case relative-xdg)
352
+ IFS='|' read -r case_dir home proj wt fakebin id <<EOF
353
+ $rec
354
+ EOF
355
+ caller="$case_dir/caller"
356
+ mkdir -p "$caller/cfg/muse" "$caller/data"
357
+ resolved_caller=$(cd "$caller" && pwd -P)
358
+ printf '{"schema_version":1}\n' > "$caller/cfg/muse/auth.json"
359
+ out=$(cd "$caller" && FM_TEST_MUSE_KEY='' FM_TEST_MUSE_WORKER_KEY='' \
360
+ FM_TEST_MUSE_CONFIG_HOME=cfg FM_TEST_MUSE_DATA_HOME=data \
361
+ run_muse_spawn "$home" "$proj" "$wt" "$fakebin" "$id" --mode no-mistakes --yolo off)
362
+ status=$?
363
+ expect_code 0 "$status" "muse spawn with relative XDG roots should succeed: $out"
364
+ launch=$(cat "$home/launch.log")
365
+ assert_contains "$launch" "XDG_CONFIG_HOME='$resolved_caller/cfg'" \
366
+ "muse launch did not forward the resolved config root"
367
+ assert_contains "$launch" "XDG_DATA_HOME='$resolved_caller/data'" \
368
+ "muse launch did not forward the resolved data root"
369
+ binding="$home/state/$id.muse-session"
370
+ assert_grep "sessions_root=$resolved_caller/data/muse/sessions" "$binding" \
371
+ "muse busy binding did not use the worker's resolved data root"
372
+ pass "muse resolves relative XDG roots before preflight and launch"
373
+ }
374
+
375
+ # muse has no primary supervision protocol, and its Claude-compatible hook
376
+ # dialect rejects the model-reawakening handlers a firstmate primary needs, so a
377
+ # secondmate on muse could never arm a supervision cycle.
378
+ test_spawn_refuses_secondmate() {
379
+ local case_dir home fakebin id out status
380
+ case_dir="$TMP_ROOT/secondmate"
381
+ home="$case_dir/home"
382
+ fakebin=$(make_spawn_fakebin "$case_dir/fake")
383
+ id="muse-secondmate-x1"
384
+ mkdir -p "$home/data/$id" "$home/projects" "$home/state" "$home/config" "$case_dir/muse"
385
+ printf 'charter\n' > "$home/data/$id/brief.md"
386
+ out=$(cd "$case_dir" && FM_ROOT_OVERRIDE='' FM_HOME="$home" \
387
+ FM_STATE_OVERRIDE="$home/state" FM_DATA_OVERRIDE="$home/data" \
388
+ FM_PROJECTS_OVERRIDE="$home/projects" FM_CONFIG_OVERRIDE="$home/config" \
389
+ FM_SPAWN_NO_GUARD=1 TMUX="fake,1,0" META_API_KEY=test-key \
390
+ PATH="$fakebin:$PATH" \
391
+ "$SPAWN" "$id" muse --secondmate 2>&1)
392
+ status=$?
393
+ [ "$status" -ne 0 ] || fail "muse was accepted as a secondmate harness"
394
+ assert_contains "$out" "crewmate/scout adapter only" "muse secondmate refusal did not explain the boundary"
395
+ pass "muse is refused as a secondmate harness"
396
+ }
397
+
398
+ test_spawn_writes_busy_binding_and_teardown_removes_it() {
399
+ local rec case_dir home proj wt fakebin id binding prior
400
+ rec=$(make_spawn_case binding)
401
+ IFS='|' read -r case_dir home proj wt fakebin id <<EOF
402
+ $rec
403
+ EOF
404
+ prior=$(write_session_log "$case_dir/xdgdata/muse/sessions" 2026 08 05 prior "$wt" </dev/null)
405
+ prior=$(printf '%s\n' "$prior" | sed 's://*:/:g')
406
+ FM_TEST_MUSE_DATA_HOME="$case_dir/xdgdata" \
407
+ run_muse_spawn "$home" "$proj" "$wt" "$fakebin" "$id" --mode no-mistakes --yolo off >/dev/null \
408
+ || fail "muse spawn failed"
409
+
410
+ binding="$home/state/$id.muse-session"
411
+ assert_present "$binding" "muse spawn did not write the session binding"
412
+ assert_grep "sessions_root=$case_dir/xdgdata/muse/sessions" "$binding" \
413
+ "muse binding did not record the resolved sessions root"
414
+ assert_grep "workspace_root=$wt" "$binding" "muse binding did not record the task worktree"
415
+ assert_grep "prior_log=$prior" "$binding" \
416
+ "muse binding did not exclude the pre-existing session: $(tr '\n' ';' < "$binding")"
417
+ # No busy record is armed for muse: the source is pull-only with no writer, so
418
+ # a seeded busy record could never be settled.
419
+ assert_absent "$home/state/$id.busy-gen" "muse spawn armed a busy record it can never clear"
420
+ printf 'binding_id=retired\nsession_log=%s\n' "$prior" > "$home/state/$id.muse-session-current"
421
+
422
+ FM_ROOT_OVERRIDE="$ROOT" FM_HOME="$home" FM_STATE_OVERRIDE="$home/state" \
423
+ PATH="$fakebin:$PATH" "$TEARDOWN" "$id" --force >/dev/null 2>&1 \
424
+ || fail "muse teardown failed"
425
+ assert_absent "$binding" "muse session binding survived teardown"
426
+ assert_absent "$home/state/$id.muse-session-current" "muse session cache survived teardown"
427
+ pass "muse spawn writes a session binding that teardown removes"
428
+ }
429
+
430
+ # --- interrupt --------------------------------------------------------------
431
+
432
+ # muse RESTORES the interrupted prompt into the composer after Escape, as real
433
+ # bright text. Left there, the next steer types onto the end of it and submits
434
+ # both as one garbled message, so the interrupt is not complete until the
435
+ # composer is cleared.
436
+ make_send_case() { # <name> <harness>
437
+ local name=$1 harness=$2 case_dir home fakebin id
438
+ case_dir="$TMP_ROOT/send-$name"
439
+ home="$case_dir/home"
440
+ fakebin=$(fm_fakebin "$case_dir/fake")
441
+ id="send-$name"
442
+ mkdir -p "$home/state"
443
+ cat > "$fakebin/tmux" <<'SH'
444
+ #!/usr/bin/env bash
445
+ set -u
446
+ case "${1:-}" in
447
+ display-message) printf 'fakepane\n'; exit 0 ;;
448
+ has-session) exit 0 ;;
449
+ list-panes|list-windows) printf 'fm-send:0\n'; exit 0 ;;
450
+ send-keys)
451
+ shift
452
+ printf '%s\n' "$*" >> "$FM_FAKE_KEY_LOG"
453
+ [ "${FM_FAKE_KEY_FAIL:-}" = "$*" ] && exit 1
454
+ exit 0
455
+ ;;
456
+ esac
457
+ exit 0
458
+ SH
459
+ chmod +x "$fakebin/tmux"
460
+ fm_write_meta "$home/state/$id.meta" \
461
+ "window=fm-send:0" "endpoint_task_id=$id" "worktree=$case_dir" \
462
+ "project=$case_dir" "harness=$harness" "kind=ship" "mode=no-mistakes" "yolo=off"
463
+ printf '%s\n' "$case_dir|$home|$fakebin|$id"
464
+ }
465
+
466
+ run_send_key() { # <home> <fakebin> <id> <key> <keylog>
467
+ FM_ROOT_OVERRIDE="$ROOT" FM_HOME="$1" FM_STATE_OVERRIDE="$1/state" \
468
+ FM_FAKE_KEY_LOG="$5" PATH="$2:$PATH" \
469
+ "$ROOT/bin/fm-send.sh" "$3" --key "$4" 2>&1
470
+ }
471
+
472
+ test_muse_escape_aliases_clear_the_composer() {
473
+ local entry name key rec case_dir home fakebin id keylog out status
474
+ for entry in exact:Escape lower:escape short:Esc short-lower:esc; do
475
+ name=${entry%%:*}
476
+ key=${entry#*:}
477
+ rec=$(make_send_case "muse-$name" muse)
478
+ IFS='|' read -r case_dir home fakebin id <<EOF
479
+ $rec
480
+ EOF
481
+ keylog="$case_dir/keys.log"
482
+ : > "$keylog"
483
+ out=$(run_send_key "$home" "$fakebin" "$id" "$key" "$keylog")
484
+ status=$?
485
+ expect_code 0 "$status" "muse $key send should succeed: $out"
486
+ assert_grep "$key" "$keylog" "$key never reached the muse pane"
487
+ assert_grep 'C-u' "$keylog" "muse $key did not clear the restored composer"
488
+ [ "$(grep -c . "$keylog")" -ge 2 ] || fail "expected both the interrupt and the clear for $key"
489
+ head -1 "$keylog" | grep -q "$key" || fail "the clear was sent before the $key interrupt"
490
+ done
491
+ pass "every accepted muse Escape alias clears the restored composer"
492
+ }
493
+
494
+ test_non_muse_escape_does_not_clear() {
495
+ local rec case_dir home fakebin id keylog
496
+ rec=$(make_send_case codex codex)
497
+ IFS='|' read -r case_dir home fakebin id <<EOF
498
+ $rec
499
+ EOF
500
+ keylog="$case_dir/keys.log"
501
+ : > "$keylog"
502
+ run_send_key "$home" "$fakebin" "$id" Escape "$keylog" >/dev/null
503
+ assert_grep 'Escape' "$keylog" "Escape never reached the codex pane"
504
+ assert_no_grep 'C-u' "$keylog" "a non-muse interrupt sent a composer clear it does not need"
505
+ pass "the composer clear is scoped to muse and does not touch other adapters"
506
+ }
507
+
508
+ # A silent clear failure would leave the restored prompt in place and corrupt
509
+ # the next steer, so the failure has to be loud.
510
+ test_failed_clear_is_reported() {
511
+ local rec case_dir home fakebin id keylog out status
512
+ rec=$(make_send_case clearfail muse)
513
+ IFS='|' read -r case_dir home fakebin id <<EOF
514
+ $rec
515
+ EOF
516
+ keylog="$case_dir/keys.log"
517
+ : > "$keylog"
518
+ out=$(FM_FAKE_KEY_FAIL='-t fm-send:0 C-u' run_send_key "$home" "$fakebin" "$id" Escape "$keylog")
519
+ status=$?
520
+ [ "$status" -ne 0 ] || fail "a failed muse composer clear was reported as success"
521
+ assert_contains "$out" "could not be cleared" "the failed clear did not explain the pane state"
522
+ pass "a failed muse composer clear fails loudly instead of leaving stale input"
523
+ }
524
+
525
+ # --- busy source ------------------------------------------------------------
526
+
527
+ classify_muse() { # <state-dir> <id>
528
+ (
529
+ # shellcheck source=bin/fm-busy-lib.sh
530
+ . "$ROOT/bin/fm-busy-lib.sh"
531
+ fm_busy_classify tmux fake:0 muse "$2" "$1"
532
+ )
533
+ }
534
+
535
+ run_state() { # <log>
536
+ (
537
+ # shellcheck source=bin/fm-busy-lib.sh
538
+ . "$ROOT/bin/fm-busy-lib.sh"
539
+ fm_busy_muse_run_state "$1"
540
+ )
541
+ }
542
+
543
+ test_run_fold_tracks_open_and_settled_turns() {
544
+ local dir log out
545
+ dir="$TMP_ROOT/fold"
546
+ mkdir -p "$dir"
547
+
548
+ log=$(write_session_log "$dir/open" 2026 08 05 aaaa "$dir/ws" <<EOF
549
+ $(muse_log_run_started run-1)
550
+ $(muse_log_noise run-1)
551
+ EOF
552
+ )
553
+ out=$(run_state "$log")
554
+ [ "$out" = busy ] || fail "an open run folded to '$out', expected busy"
555
+
556
+ log=$(write_session_log "$dir/settled" 2026 08 05 bbbb "$dir/ws" <<EOF
557
+ $(muse_log_run_started run-1)
558
+ $(muse_log_run_terminal run-1 completed)
559
+ EOF
560
+ )
561
+ out=$(run_state "$log")
562
+ [ "$out" = settled ] || fail "a completed run folded to '$out', expected settled"
563
+
564
+ # An Escape interrupt closes its run with terminal=cancelled, so unlike a
565
+ # Stop-hook adapter this source covers the interrupt path itself.
566
+ log=$(write_session_log "$dir/cancelled" 2026 08 05 cccc "$dir/ws" <<EOF
567
+ $(muse_log_run_started run-1)
568
+ $(muse_log_run_terminal run-1 cancelled)
569
+ EOF
570
+ )
571
+ out=$(run_state "$log")
572
+ [ "$out" = settled ] || fail "an interrupted run folded to '$out', expected settled"
573
+
574
+ # A second turn reopens the fold after the first settled.
575
+ log=$(write_session_log "$dir/second" 2026 08 05 dddd "$dir/ws" <<EOF
576
+ $(muse_log_run_started run-1)
577
+ $(muse_log_run_terminal run-1 completed)
578
+ $(muse_log_run_started run-2)
579
+ EOF
580
+ )
581
+ out=$(run_state "$log")
582
+ [ "$out" = busy ] || fail "a reopened second turn folded to '$out', expected busy"
583
+
584
+ # A log with no run lifecycle at all (an unauthenticated pane stuck on the
585
+ # sign-in prompt produces exactly this) is not a settled turn.
586
+ log=$(write_session_log "$dir/none" 2026 08 05 eeee "$dir/ws" </dev/null)
587
+ out=$(run_state "$log")
588
+ [ "$out" = none ] || fail "a run-free log folded to '$out', expected none"
589
+ pass "the run fold tracks open, settled, interrupted, reopened, and run-free logs"
590
+ }
591
+
592
+ test_nested_terminal_record_does_not_settle_a_run() {
593
+ local dir log out
594
+ dir="$TMP_ROOT/decoy"
595
+ mkdir -p "$dir"
596
+ log=$(write_session_log "$dir/root" 2026 08 05 ffff "$dir/ws" <<EOF
597
+ $(muse_log_run_started run-1)
598
+ $(muse_log_cleanup_terminal_decoy run-1)
599
+ $(muse_log_noise run-1)
600
+ EOF
601
+ )
602
+ out=$(run_state "$log")
603
+ [ "$out" = busy ] \
604
+ || fail "a nested cleanup 'terminal' record settled an open run (folded '$out', expected busy)"
605
+ pass "a nested terminal record never settles an in-flight run"
606
+ }
607
+
608
+ test_binding_selects_the_matching_main_log() {
609
+ local dir state id verdict root
610
+ dir="$TMP_ROOT/bind"
611
+ state="$dir/state"
612
+ root="$dir/sessions"
613
+ id=bindtask
614
+ mkdir -p "$state"
615
+
616
+ # Another task's log lives in the same root and must never be folded here.
617
+ write_session_log "$root" 2026 08 05 other "$dir/other-ws" >/dev/null <<EOF
618
+ $(muse_log_run_started other-run)
619
+ EOF
620
+
621
+ write_session_log "$root" 2026 08 05 mine "$dir/my-ws" >/dev/null <<EOF
622
+ $(muse_log_run_started my-run)
623
+ $(muse_log_run_terminal my-run completed)
624
+ EOF
625
+
626
+ printf 'sessions_root=%s\nworkspace_root=%s\n' "$root" "$dir/my-ws" > "$state/$id.muse-session"
627
+ verdict=$(classify_muse "$state" "$id")
628
+ # This task's own log is settled; the OTHER task's open run must not leak in
629
+ # as busy. With the idle half verified, this task's settled log reads idle.
630
+ [ "$verdict" = "idle muse-session-log" ] \
631
+ || fail "binding leaked another workspace's run state: got '$verdict'"
632
+
633
+ printf 'sessions_root=%s\nworkspace_root=%s\n' "$root" "$dir/other-ws" > "$state/$id.muse-session"
634
+ verdict=$(classify_muse "$state" "$id")
635
+ [ "$verdict" = "busy muse-session-log" ] \
636
+ || fail "binding did not fold the workspace it was pointed at: got '$verdict'"
637
+ pass "the session binding folds only the log matching this task's worktree"
638
+ }
639
+
640
+ test_workspace_binding_treats_glob_characters_literally() {
641
+ local dir state id root verdict
642
+ dir="$TMP_ROOT/workspace-literal"
643
+ state="$dir/state"
644
+ root="$dir/sessions"
645
+ id=literal-task
646
+ mkdir -p "$state"
647
+
648
+ write_session_log "$root" 2026 08 05 own "$dir/ws[1]" >/dev/null <<EOF
649
+ $(muse_log_run_started own-run)
650
+ $(muse_log_run_terminal own-run completed)
651
+ EOF
652
+ write_session_log "$root" 2026 08 05 decoy "$dir/ws1" >/dev/null <<EOF
653
+ $(muse_log_run_started decoy-run)
654
+ EOF
655
+
656
+ printf 'sessions_root=%s\nworkspace_root=%s\n' \
657
+ "$root" "$dir/ws[1]" > "$state/$id.muse-session"
658
+ verdict=$(classify_muse "$state" "$id")
659
+ [ "$verdict" = "idle muse-session-log" ] \
660
+ || fail "a bracketed workspace imported another session's busy state: got '$verdict'"
661
+ pass "workspace bindings compare decoded paths literally"
662
+ }
663
+
664
+ test_binding_excludes_preexisting_log_when_mtimes_tie() {
665
+ local dir state id root old current verdict
666
+ dir="$TMP_ROOT/mtime-tie"
667
+ state="$dir/state"
668
+ root="$dir/sessions"
669
+ id=tietask
670
+ mkdir -p "$state"
671
+
672
+ old=$(write_session_log "$root" 2026 08 05 aaaa-old "$dir/ws" <<EOF
673
+ $(muse_log_run_started old-run)
674
+ $(muse_log_run_terminal old-run completed)
675
+ EOF
676
+ )
677
+ current=$(write_session_log "$root" 2026 08 05 zzzz-current "$dir/ws" <<EOF
678
+ $(muse_log_run_started current-run)
679
+ EOF
680
+ )
681
+ old=$(printf '%s\n' "$old" | sed 's://*:/:g')
682
+ current=$(printf '%s\n' "$current" | sed 's://*:/:g')
683
+ touch -t 202608050101.01 "$old" "$current"
684
+ { [ ! "$old" -nt "$current" ] && [ ! "$current" -nt "$old" ]; } \
685
+ || fail "the session-selection regression does not reproduce equal mtimes"
686
+
687
+ printf 'sessions_root=%s\nworkspace_root=%s\nprior_log=%s\n' \
688
+ "$root" "$dir/ws" "$old" > "$state/$id.muse-session"
689
+ verdict=$(classify_muse "$state" "$id")
690
+ [ "$verdict" = "busy muse-session-log" ] \
691
+ || fail "the current open session lost an mtime tie to the prior settled session: got '$verdict'"
692
+ pass "spawn-time exclusions select the current session across equal mtimes"
693
+ }
694
+
695
+ test_session_log_cache_reuses_and_refreshes_binding() {
696
+ local dir state id root old fresh verdict fakebin
697
+ dir="$TMP_ROOT/cache"
698
+ state="$dir/state"
699
+ root="$dir/sessions"
700
+ id=cachetask
701
+ mkdir -p "$state"
702
+
703
+ old=$(write_session_log "$root" 2026 08 05 old "$dir/ws" <<EOF
704
+ $(muse_log_run_started old-run)
705
+ EOF
706
+ )
707
+ old=$(printf '%s\n' "$old" | sed 's://*:/:g')
708
+ printf 'sessions_root=%s\nworkspace_root=%s\nbinding_id=incarnation-one\n' \
709
+ "$root" "$dir/ws" > "$state/$id.muse-session"
710
+ verdict=$(classify_muse "$state" "$id")
711
+ [ "$verdict" = "busy muse-session-log" ] \
712
+ || fail "the initial session did not resolve before caching: got '$verdict'"
713
+
714
+ fakebin=$(fm_fakebin "$dir/fake")
715
+ cat > "$fakebin/node" <<'SH'
716
+ #!/usr/bin/env bash
717
+ exit 97
718
+ SH
719
+ chmod +x "$fakebin/node"
720
+ verdict=$(PATH="$fakebin:$PATH" classify_muse "$state" "$id")
721
+ [ "$verdict" = "busy muse-session-log" ] \
722
+ || fail "a cached session triggered another tree resolution: got '$verdict'"
723
+
724
+ muse_log_run_terminal old-run completed >> "$old"
725
+ fresh=$(write_session_log "$root" 2026 08 05 fresh "$dir/ws" <<EOF
726
+ $(muse_log_run_started fresh-run)
727
+ EOF
728
+ )
729
+ printf 'sessions_root=%s\nworkspace_root=%s\nbinding_id=incarnation-two\nprior_log=%s\n' \
730
+ "$root" "$dir/ws" "$old" > "$state/$id.muse-session"
731
+ verdict=$(classify_muse "$state" "$id")
732
+ [ "$verdict" = "busy muse-session-log" ] \
733
+ || fail "a fresh session did not supersede the prior cached session: got '$verdict'"
734
+
735
+ rm -f "$fresh"
736
+ verdict=$(classify_muse "$state" "$id")
737
+ [ "$verdict" = "unknown muse-session-log" ] \
738
+ || fail "a missing cached session produced '$verdict' instead of unknown"
739
+
740
+ write_session_log "$root" 2026 08 05 ambiguous-a "$dir/ws" >/dev/null <<EOF
741
+ $(muse_log_run_started ambiguous-a)
742
+ EOF
743
+ write_session_log "$root" 2026 08 05 ambiguous-b "$dir/ws" >/dev/null <<EOF
744
+ $(muse_log_run_started ambiguous-b)
745
+ EOF
746
+ verdict=$(classify_muse "$state" "$id")
747
+ [ "$verdict" = "unknown muse-session-log" ] \
748
+ || fail "ambiguous replacement sessions produced '$verdict' instead of unknown"
749
+ pass "the Muse session cache avoids rescans and refreshes safely across incarnations"
750
+ }
751
+
752
+ test_cached_session_revalidates_after_namespace_change() {
753
+ local dir state id root second_log verdict today year month day
754
+ dir="$TMP_ROOT/cache-ambiguity"
755
+ state="$dir/state"
756
+ root="$dir/sessions"
757
+ id=cacheambiguity
758
+ mkdir -p "$state"
759
+ today=$(date '+%Y/%m/%d')
760
+ year=${today%%/*}
761
+ today=${today#*/}
762
+ month=${today%%/*}
763
+ day=${today#*/}
764
+
765
+ write_session_log "$root" "$year" "$month" "$day" first "$dir/ws" >/dev/null <<EOF
766
+ $(muse_log_run_started first-run)
767
+ EOF
768
+ printf 'sessions_root=%s\nworkspace_root=%s\nbinding_id=cache-ambiguity\n' \
769
+ "$root" "$dir/ws" > "$state/$id.muse-session"
770
+ verdict=$(classify_muse "$state" "$id")
771
+ [ "$verdict" = "busy muse-session-log" ] \
772
+ || fail "the first session did not resolve before the ambiguity check: got '$verdict'"
773
+
774
+ second_log="$root/$year/$month/$day/second/session.jsonl"
775
+ mkdir -p "${second_log%/*}"
776
+ : > "$second_log"
777
+ verdict=$(classify_muse "$state" "$id")
778
+ [ "$verdict" = "busy muse-session-log" ] \
779
+ || fail "an uninitialized second session changed the resolved verdict to '$verdict'"
780
+
781
+ write_session_log "$root" "$year" "$month" "$day" second "$dir/ws" >/dev/null <<EOF
782
+ $(muse_log_run_started second-run)
783
+ EOF
784
+ verdict=$(classify_muse "$state" "$id")
785
+ [ "$verdict" = "unknown muse-session-log" ] \
786
+ || fail "a second concurrent main session left the cached verdict at '$verdict'"
787
+ pass "a changed Muse namespace revalidates cached session uniqueness"
788
+ }
789
+
790
+ # muse's own native sub-agents write independent run lifecycles one directory
791
+ # deeper, under subagent/<child-session-id>/. Folding a child's log would report
792
+ # the parent busy long after the parent's turn ended.
793
+ test_subagent_logs_are_excluded() {
794
+ local dir state id root verdict child
795
+ dir="$TMP_ROOT/subagent"
796
+ state="$dir/state"
797
+ root="$dir/sessions"
798
+ id=subtask
799
+ mkdir -p "$state"
800
+
801
+ write_session_log "$root" 2026 08 05 parent "$dir/ws" >/dev/null <<EOF
802
+ $(muse_log_run_started parent-run)
803
+ $(muse_log_run_terminal parent-run completed)
804
+ EOF
805
+
806
+ child="$root/2026/08/05/parent/subagent/child-session"
807
+ mkdir -p "$child"
808
+ {
809
+ muse_log_metadata "$dir/ws"
810
+ muse_log_run_started child-run
811
+ } > "$child/session.jsonl"
812
+ # Make the child log strictly newer, so a depth-blind resolver that also
813
+ # ranks by mtime would pick it.
814
+ touch "$child/session.jsonl"
815
+
816
+ # Prove the child fixture really is an open run, so the exclusion below is
817
+ # doing work rather than passing on an inert file.
818
+ [ "$(run_state "$child/session.jsonl")" = busy ] \
819
+ || fail "the sub-agent fixture is not an open run, so the exclusion case would be vacuous"
820
+
821
+ printf 'sessions_root=%s\nworkspace_root=%s\nbinding_id=subagent-incarnation\n' \
822
+ "$root" "$dir/ws" > "$state/$id.muse-session"
823
+ verdict=$(classify_muse "$state" "$id")
824
+ [ "$verdict" != "busy muse-session-log" ] \
825
+ || fail "a sub-agent's open run was folded as the parent task's busy state"
826
+ # And prove the parent log was genuinely resolved, so the non-busy verdict is
827
+ # the exclusion working rather than the binding silently failing.
828
+ [ "$(run_state "$root/2026/08/05/parent/session.jsonl")" = settled ] \
829
+ || fail "the parent fixture did not fold as settled"
830
+ printf 'binding_id=subagent-incarnation\nsession_log=%s\n' \
831
+ "$child/session.jsonl" > "$state/$id.muse-session-current"
832
+ verdict=$(classify_muse "$state" "$id")
833
+ [ "$verdict" != "busy muse-session-log" ] \
834
+ || fail "a cached sub-agent log was folded as the parent task's busy state"
835
+ pass "sub-agent session logs are excluded from the parent's busy fold"
836
+ }
837
+
838
+ # Every path with no positive proof of an in-flight turn must be unknown, never
839
+ # idle: unknown is not promoted to either boolean pole, while a wrong idle would
840
+ # report a working crewmate as finished.
841
+ test_missing_and_unreadable_bindings_are_unknown_never_idle() {
842
+ local dir state id verdict root
843
+ dir="$TMP_ROOT/unknowns"
844
+ state="$dir/state"
845
+ root="$dir/sessions"
846
+ id=unk
847
+ mkdir -p "$state"
848
+
849
+ verdict=$(classify_muse "$state" "$id")
850
+ [ "$verdict" = "unknown muse-session-log" ] || fail "absent binding classified '$verdict'"
851
+
852
+ printf 'sessions_root=%s\nworkspace_root=%s\n' "$root/missing" "$dir/ws" > "$state/$id.muse-session"
853
+ verdict=$(classify_muse "$state" "$id")
854
+ [ "$verdict" = "unknown muse-session-log" ] || fail "missing sessions root classified '$verdict'"
855
+
856
+ write_session_log "$root" 2026 08 05 nomatch "$dir/somewhere-else" >/dev/null <<EOF
857
+ $(muse_log_run_started r1)
858
+ EOF
859
+ printf 'sessions_root=%s\nworkspace_root=%s\n' "$root" "$dir/ws" > "$state/$id.muse-session"
860
+ verdict=$(classify_muse "$state" "$id")
861
+ [ "$verdict" = "unknown muse-session-log" ] || fail "unmatched workspace classified '$verdict'"
862
+
863
+ printf 'garbage\n' > "$state/$id.muse-session"
864
+ verdict=$(classify_muse "$state" "$id")
865
+ [ "$verdict" = "unknown muse-session-log" ] || fail "malformed binding classified '$verdict'"
866
+ pass "every unproven muse binding classifies unknown rather than idle"
867
+ }
868
+
869
+ # The credentialed multi-step smoke proved one real turn stays inside one run
870
+ # pair, so a settled log is a finished turn and reads idle with no opt-in. Both
871
+ # terminal shapes settle: a completed turn and an interrupted one.
872
+ test_settled_log_reads_idle() {
873
+ local dir state id root verdict terminal
874
+ dir="$TMP_ROOT/idle"
875
+ state="$dir/state"
876
+ root="$dir/sessions"
877
+ mkdir -p "$state"
878
+
879
+ for terminal in completed cancelled; do
880
+ id="idle-$terminal"
881
+ write_session_log "$root" 2026 08 05 "settled-$terminal" "$dir/ws-$terminal" >/dev/null <<EOF
882
+ $(muse_log_run_started r1)
883
+ $(muse_log_run_terminal r1 "$terminal")
884
+ EOF
885
+ printf 'sessions_root=%s\nworkspace_root=%s\n' \
886
+ "$root" "$dir/ws-$terminal" > "$state/$id.muse-session"
887
+
888
+ verdict=$(classify_muse "$state" "$id")
889
+ [ "$verdict" = "idle muse-session-log" ] \
890
+ || fail "a log settled by a '$terminal' terminal classified '$verdict'"
891
+ done
892
+ pass "a settled session log reads idle for both completed and interrupted turns"
893
+ }
894
+
895
+ # muse records nothing, so it must trust no record source. A trusted source with
896
+ # no writer would seed a busy record that nothing could ever settle.
897
+ test_muse_trusts_no_record_sources() {
898
+ local out
899
+ out=$(
900
+ # shellcheck source=bin/fm-busy-lib.sh
901
+ . "$ROOT/bin/fm-busy-lib.sh"
902
+ fm_busy_sources_for_harness muse
903
+ )
904
+ [ -z "$out" ] || fail "muse trusts record sources it has no writer for: '$out'"
905
+ pass "muse trusts no busy record source"
906
+ }
907
+
908
+ test_detects_versioned_process_ancestor
909
+ test_detection_is_anchored
910
+ test_spawn_clears_inherited_foreign_harness_markers
911
+ test_spawn_launch_shape
912
+ test_spawn_maps_effort_and_model
913
+ test_spawn_refuses_without_credential
914
+ test_spawn_refuses_caller_only_environment_credential
915
+ test_spawn_accepts_stored_credential
916
+ test_spawn_resolves_relative_xdg_roots
917
+ test_spawn_refuses_secondmate
918
+ test_spawn_writes_busy_binding_and_teardown_removes_it
919
+ test_muse_escape_aliases_clear_the_composer
920
+ test_non_muse_escape_does_not_clear
921
+ test_failed_clear_is_reported
922
+ test_run_fold_tracks_open_and_settled_turns
923
+ test_nested_terminal_record_does_not_settle_a_run
924
+ test_binding_selects_the_matching_main_log
925
+ test_workspace_binding_treats_glob_characters_literally
926
+ test_binding_excludes_preexisting_log_when_mtimes_tie
927
+ test_session_log_cache_reuses_and_refreshes_binding
928
+ test_cached_session_revalidates_after_namespace_change
929
+ test_subagent_logs_are_excluded
930
+ test_missing_and_unreadable_bindings_are_unknown_never_idle
931
+ test_settled_log_reads_idle
932
+ test_muse_trusts_no_record_sources