@crouton-kit/crouter 0.3.31 → 0.3.33

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 (443) hide show
  1. package/README.md +8 -0
  2. package/dist/build-root.js +1 -0
  3. package/dist/builtin-memory/crouter-development/marketplaces.md +2 -2
  4. package/dist/builtin-memory/crouter-development/personas/base-prompt.md +2 -2
  5. package/dist/builtin-memory/crouter-development/personas/orchestrator-prompt.md +5 -5
  6. package/dist/builtin-memory/crouter-development/personas.md +3 -4
  7. package/dist/builtin-memory/crouter-development/plugins.md +18 -18
  8. package/dist/builtin-memory/design.md +4 -1
  9. package/dist/builtin-memory/development.md +4 -1
  10. package/dist/builtin-memory/internal/INDEX.md +1 -1
  11. package/dist/builtin-memory/internal/nodes-and-canvas.md +6 -6
  12. package/dist/builtin-memory/internal/storage-tiers.md +5 -5
  13. package/dist/builtin-memory/planning.md +4 -1
  14. package/dist/builtin-memory/product.md +80 -0
  15. package/dist/builtin-memory/spec.md +4 -1
  16. package/dist/builtin-personas/advisor/PERSONA.md +10 -0
  17. package/dist/builtin-personas/design/PERSONA.md +2 -2
  18. package/dist/builtin-personas/design/orchestrator.md +3 -3
  19. package/dist/builtin-personas/developer/PERSONA.md +1 -1
  20. package/dist/builtin-personas/developer/orchestrator.md +2 -2
  21. package/dist/builtin-personas/explore/PERSONA.md +3 -3
  22. package/dist/builtin-personas/explore/orchestrator.md +4 -2
  23. package/dist/builtin-personas/general/PERSONA.md +1 -1
  24. package/dist/builtin-personas/general/orchestrator.md +1 -1
  25. package/dist/builtin-personas/orchestration-kernel.md +7 -14
  26. package/dist/builtin-personas/plan/PERSONA.md +1 -1
  27. package/dist/builtin-personas/plan/orchestrator.md +2 -2
  28. package/dist/builtin-personas/plan/reviewers/architecture-fit/PERSONA.md +1 -1
  29. package/dist/builtin-personas/plan/reviewers/code-smells/PERSONA.md +1 -1
  30. package/dist/builtin-personas/plan/reviewers/pattern-consistency/PERSONA.md +1 -1
  31. package/dist/builtin-personas/plan/reviewers/requirements-coverage/PERSONA.md +1 -1
  32. package/dist/builtin-personas/plan/reviewers/security/PERSONA.md +1 -1
  33. package/dist/builtin-personas/product/PERSONA.md +18 -0
  34. package/dist/builtin-personas/product/orchestrator.md +14 -0
  35. package/dist/builtin-personas/product/teardown/PERSONA.md +13 -0
  36. package/dist/builtin-personas/review/PERSONA.md +1 -1
  37. package/dist/builtin-personas/review/orchestrator.md +1 -1
  38. package/dist/builtin-personas/runtime-base.md +5 -0
  39. package/dist/builtin-personas/spec/PERSONA.md +1 -1
  40. package/dist/builtin-personas/spec/orchestrator.md +2 -2
  41. package/dist/builtin-personas/spec/requirements/PERSONA.md +1 -1
  42. package/dist/builtin-views/canvas/core.mjs +82 -1
  43. package/dist/builtin-views/canvas/tui.mjs +9 -5
  44. package/dist/builtin-views/canvas/web.jsx +3 -2
  45. package/dist/builtin-views/chat/core.mjs +725 -0
  46. package/dist/builtin-views/chat/text.mjs +101 -0
  47. package/dist/builtin-views/chat/tui.mjs +368 -0
  48. package/dist/builtin-views/chat/web.jsx +367 -0
  49. package/dist/builtin-views/prompt-review/core.mjs +863 -0
  50. package/dist/builtin-views/prompt-review/text.mjs +15 -0
  51. package/dist/builtin-views/prompt-review/tui.mjs +196 -0
  52. package/dist/builtin-views/prompt-review/web.jsx +484 -0
  53. package/dist/builtin-views/settings/core.mjs +397 -0
  54. package/dist/builtin-views/settings/text.mjs +40 -0
  55. package/dist/builtin-views/settings/tui.mjs +95 -0
  56. package/dist/builtin-views/settings/web.jsx +167 -0
  57. package/dist/cli.js +16 -3
  58. package/dist/clients/attach/__tests__/autocomplete-and-bash-mode.test.js +96 -0
  59. package/dist/clients/attach/__tests__/bash-bang-routing.test.js +58 -0
  60. package/dist/clients/attach/__tests__/bundle-pi-tui-dedup.test.d.ts +1 -0
  61. package/dist/clients/attach/__tests__/bundle-pi-tui-dedup.test.js +56 -0
  62. package/dist/clients/attach/__tests__/titled-editor.test.js +22 -1
  63. package/dist/clients/attach/attach-cmd.d.ts +18 -0
  64. package/dist/clients/attach/attach-cmd.js +1723 -795
  65. package/dist/clients/attach/canvas-panels.js +2 -2
  66. package/dist/clients/attach/chat-view.d.ts +10 -0
  67. package/dist/clients/attach/chat-view.js +23 -0
  68. package/dist/clients/attach/config-load.d.ts +8 -4
  69. package/dist/clients/attach/config-load.js +2 -0
  70. package/dist/clients/attach/extension-dialogs.d.ts +2 -3
  71. package/dist/clients/attach/extension-dialogs.js +7 -9
  72. package/dist/clients/attach/graph-overlay.js +3 -2
  73. package/dist/clients/attach/input-controller.d.ts +4 -3
  74. package/dist/clients/attach/input-controller.js +24 -3
  75. package/dist/clients/attach/slash-commands.d.ts +7 -7
  76. package/dist/clients/attach/slash-commands.js +38 -14
  77. package/dist/clients/attach/titled-editor.js +18 -14
  78. package/dist/clients/attach/view-socket.d.ts +2 -1
  79. package/dist/clients/attach/view-socket.js +27 -8
  80. package/dist/clients/web/__tests__/source-cache.test.d.ts +1 -0
  81. package/dist/clients/web/__tests__/source-cache.test.js +32 -0
  82. package/dist/clients/web/dev-server.js +1 -0
  83. package/dist/clients/web/events.js +9 -11
  84. package/dist/clients/web/server.d.ts +4 -3
  85. package/dist/clients/web/server.js +138 -31
  86. package/dist/clients/web/source-cache.d.ts +10 -0
  87. package/dist/clients/web/source-cache.js +57 -0
  88. package/dist/clients/web/web-cmd.js +28 -9
  89. package/dist/commands/__tests__/human.test.js +30 -28
  90. package/dist/commands/canvas-history/search.js +1 -1
  91. package/dist/commands/canvas-history.js +5 -8
  92. package/dist/commands/canvas-issue.d.ts +2 -0
  93. package/dist/commands/canvas-issue.js +148 -0
  94. package/dist/commands/canvas-prune.js +19 -0
  95. package/dist/commands/canvas-rebuild-index.d.ts +2 -0
  96. package/dist/commands/canvas-rebuild-index.js +57 -0
  97. package/dist/commands/canvas-snapshot.d.ts +2 -0
  98. package/dist/commands/canvas-snapshot.js +48 -0
  99. package/dist/commands/canvas-tmux-spread.d.ts +2 -0
  100. package/dist/commands/canvas-tmux-spread.js +188 -0
  101. package/dist/commands/canvas.d.ts +1 -0
  102. package/dist/commands/canvas.js +16 -1
  103. package/dist/commands/chord.js +143 -48
  104. package/dist/commands/daemon.js +3 -3
  105. package/dist/commands/human/prompts.d.ts +0 -1
  106. package/dist/commands/human/prompts.js +39 -54
  107. package/dist/commands/human/queue.d.ts +12 -1
  108. package/dist/commands/human/queue.js +468 -73
  109. package/dist/commands/human/shared.d.ts +3 -4
  110. package/dist/commands/human/shared.js +3 -3
  111. package/dist/commands/human.js +11 -10
  112. package/dist/commands/memory/find.js +3 -2
  113. package/dist/commands/memory/list.js +4 -3
  114. package/dist/commands/memory/read.js +3 -3
  115. package/dist/commands/memory/shared.d.ts +1 -4
  116. package/dist/commands/memory/shared.js +6 -9
  117. package/dist/commands/memory/write.js +3 -3
  118. package/dist/commands/memory.js +4 -7
  119. package/dist/commands/node-context.d.ts +2 -0
  120. package/dist/commands/node-context.js +172 -0
  121. package/dist/commands/node-snapshot.d.ts +2 -0
  122. package/dist/commands/node-snapshot.js +123 -0
  123. package/dist/commands/node.js +228 -52
  124. package/dist/commands/pkg/plugin-inspect.js +6 -6
  125. package/dist/commands/pkg/plugin-manage.js +1 -1
  126. package/dist/commands/pkg/plugin.js +2 -2
  127. package/dist/commands/pkg.js +2 -2
  128. package/dist/commands/push.d.ts +2 -0
  129. package/dist/commands/push.js +79 -11
  130. package/dist/commands/revive.js +74 -1
  131. package/dist/commands/search/answer.d.ts +1 -0
  132. package/dist/commands/search/answer.js +50 -0
  133. package/dist/commands/search/contents.d.ts +1 -0
  134. package/dist/commands/search/contents.js +96 -0
  135. package/dist/commands/search/exa.d.ts +53 -0
  136. package/dist/commands/search/exa.js +155 -0
  137. package/dist/commands/search/puremd.d.ts +11 -0
  138. package/dist/commands/search/puremd.js +53 -0
  139. package/dist/commands/search/web.d.ts +1 -0
  140. package/dist/commands/search/web.js +65 -0
  141. package/dist/commands/search.d.ts +2 -0
  142. package/dist/commands/search.js +24 -0
  143. package/dist/commands/sys/__tests__/sync-import.test.d.ts +1 -0
  144. package/dist/commands/sys/__tests__/sync-import.test.js +72 -0
  145. package/dist/commands/sys/config.js +59 -10
  146. package/dist/commands/sys/doctor.js +56 -4
  147. package/dist/commands/sys/prompt-review.d.ts +1 -0
  148. package/dist/commands/sys/prompt-review.js +178 -0
  149. package/dist/commands/sys/promptstudio.d.ts +2 -0
  150. package/dist/commands/sys/promptstudio.js +65 -0
  151. package/dist/commands/sys/settings.d.ts +2 -0
  152. package/dist/commands/sys/settings.js +16 -0
  153. package/dist/commands/sys/sync.js +311 -159
  154. package/dist/commands/sys/sysprompt.d.ts +1 -0
  155. package/dist/commands/sys/sysprompt.js +86 -0
  156. package/dist/commands/sys.js +9 -5
  157. package/dist/commands/view-new.js +2 -2
  158. package/dist/core/__tests__/artifact-paths.test.d.ts +1 -0
  159. package/dist/core/__tests__/artifact-paths.test.js +44 -0
  160. package/dist/core/__tests__/broker-preflight.test.d.ts +1 -0
  161. package/dist/core/__tests__/broker-preflight.test.js +85 -0
  162. package/dist/core/__tests__/broker-sdk-wiring.test.js +15 -0
  163. package/dist/core/__tests__/canvas.test.js +37 -1
  164. package/dist/core/__tests__/chat-view-reconnect.test.d.ts +1 -0
  165. package/dist/core/__tests__/chat-view-reconnect.test.js +70 -0
  166. package/dist/core/__tests__/child-death-wake.test.js +11 -2
  167. package/dist/core/__tests__/close.test.js +39 -1
  168. package/dist/core/__tests__/connection-reconnect-resume.test.d.ts +1 -0
  169. package/dist/core/__tests__/connection-reconnect-resume.test.js +37 -0
  170. package/dist/core/__tests__/context-intro.test.js +48 -14
  171. package/dist/core/__tests__/daemon-boot.test.js +182 -9
  172. package/dist/core/__tests__/editor-label.test.d.ts +1 -0
  173. package/dist/core/__tests__/editor-label.test.js +26 -0
  174. package/dist/core/__tests__/fault-marker.test.d.ts +1 -0
  175. package/dist/core/__tests__/fault-marker.test.js +112 -0
  176. package/dist/core/__tests__/fault-retry-rewind.test.d.ts +1 -0
  177. package/dist/core/__tests__/fault-retry-rewind.test.js +123 -0
  178. package/dist/core/__tests__/fixtures/fake-engine.d.ts +30 -4
  179. package/dist/core/__tests__/fixtures/fake-engine.js +156 -17
  180. package/dist/core/__tests__/fixtures/fake-pi-host.js +10 -1
  181. package/dist/core/__tests__/full/human-new-window-regression.test.js +1 -1
  182. package/dist/core/__tests__/helpers/harness.d.ts +1 -1
  183. package/dist/core/__tests__/helpers/harness.js +9 -3
  184. package/dist/core/__tests__/human-stranded-deliver.test.js +38 -1
  185. package/dist/core/__tests__/human-surface-target.test.js +1 -1
  186. package/dist/core/__tests__/kickoff.test.js +18 -19
  187. package/dist/core/__tests__/memory-resolver.test.js +12 -1
  188. package/dist/core/__tests__/migration.test.js +49 -14
  189. package/dist/core/__tests__/model-ladders.test.d.ts +1 -0
  190. package/dist/core/__tests__/model-ladders.test.js +160 -0
  191. package/dist/core/__tests__/node-env.test.d.ts +1 -0
  192. package/dist/core/__tests__/node-env.test.js +26 -0
  193. package/dist/core/__tests__/push-final-guard.test.js +7 -1
  194. package/dist/core/__tests__/relaunch-root.test.js +9 -9
  195. package/dist/core/__tests__/revive.test.js +36 -6
  196. package/dist/core/__tests__/spawn-root.test.js +24 -1
  197. package/dist/core/__tests__/stop-guard.test.js +10 -0
  198. package/dist/core/__tests__/stranded-relaunch.test.d.ts +1 -0
  199. package/dist/core/__tests__/stranded-relaunch.test.js +72 -0
  200. package/dist/core/__tests__/tmux-surface.test.js +5 -1
  201. package/dist/core/__tests__/unknown-path.test.js +19 -19
  202. package/dist/core/__tests__/yield-ensures-daemon.test.d.ts +1 -0
  203. package/dist/core/__tests__/yield-ensures-daemon.test.js +54 -0
  204. package/dist/core/artifact.d.ts +2 -33
  205. package/dist/core/artifact.js +27 -87
  206. package/dist/core/bootstrap.js +2 -0
  207. package/dist/core/canvas/browse/__tests__/model.test.js +35 -1
  208. package/dist/core/canvas/browse/app.js +87 -17
  209. package/dist/core/canvas/browse/model.d.ts +10 -1
  210. package/dist/core/canvas/browse/model.js +37 -1
  211. package/dist/core/canvas/browse/render.js +35 -33
  212. package/dist/core/canvas/canvas.d.ts +7 -0
  213. package/dist/core/canvas/canvas.js +54 -5
  214. package/dist/core/canvas/db.js +35 -8
  215. package/dist/core/canvas/labels.d.ts +6 -8
  216. package/dist/core/canvas/labels.js +8 -11
  217. package/dist/core/canvas/nav-model.d.ts +5 -4
  218. package/dist/core/canvas/nav-model.js +31 -17
  219. package/dist/core/canvas/paths.d.ts +18 -1
  220. package/dist/core/canvas/paths.js +37 -2
  221. package/dist/core/canvas/render.d.ts +25 -0
  222. package/dist/core/canvas/render.js +96 -13
  223. package/dist/core/canvas/status-glyph.d.ts +35 -0
  224. package/dist/core/canvas/status-glyph.js +104 -0
  225. package/dist/core/canvas/types.d.ts +2 -2
  226. package/dist/core/config.js +114 -16
  227. package/dist/core/fault-classifier.d.ts +41 -0
  228. package/dist/core/fault-classifier.js +110 -0
  229. package/dist/core/feed/__tests__/empty-node-guard.test.d.ts +1 -0
  230. package/dist/core/feed/__tests__/empty-node-guard.test.js +45 -0
  231. package/dist/core/feed/feed.js +8 -0
  232. package/dist/core/feed/inbox.d.ts +15 -0
  233. package/dist/core/feed/inbox.js +40 -14
  234. package/dist/core/frontmatter.d.ts +1 -11
  235. package/dist/core/frontmatter.js +1 -55
  236. package/dist/core/hearth/config.d.ts +2 -0
  237. package/dist/core/hearth/config.js +75 -0
  238. package/dist/core/hearth/guest-env.d.ts +2 -0
  239. package/dist/core/hearth/guest-env.js +11 -0
  240. package/dist/core/hearth/index.d.ts +5 -0
  241. package/dist/core/hearth/index.js +5 -0
  242. package/dist/core/hearth/provider.d.ts +21 -0
  243. package/dist/core/hearth/provider.js +10 -0
  244. package/dist/core/hearth/providers/blaxel-bootstrap.d.ts +10 -0
  245. package/dist/core/hearth/providers/blaxel-bootstrap.js +39 -0
  246. package/dist/core/hearth/providers/blaxel-home.d.ts +11 -0
  247. package/dist/core/hearth/providers/blaxel-home.js +126 -0
  248. package/dist/core/hearth/providers/blaxel.d.ts +26 -0
  249. package/dist/core/hearth/providers/blaxel.js +208 -0
  250. package/dist/core/hearth/providers/types.d.ts +72 -0
  251. package/dist/core/hearth/providers/types.js +1 -0
  252. package/dist/core/hearth/registry.d.ts +15 -0
  253. package/dist/core/hearth/registry.js +179 -0
  254. package/dist/core/hearth/types.d.ts +121 -0
  255. package/dist/core/hearth/types.js +1 -0
  256. package/dist/core/host-exports/__tests__/export-prunes-boot-skill.test.d.ts +1 -0
  257. package/dist/core/host-exports/__tests__/export-prunes-boot-skill.test.js +79 -0
  258. package/dist/core/{skill-sync → host-exports}/builtins.d.ts +21 -13
  259. package/dist/core/host-exports/builtins.js +68 -0
  260. package/dist/core/{skill-sync → host-exports}/export.d.ts +9 -6
  261. package/dist/core/{skill-sync → host-exports}/export.js +37 -14
  262. package/dist/core/io.js +1 -1
  263. package/dist/core/log.d.ts +9 -0
  264. package/dist/core/log.js +113 -0
  265. package/dist/core/memory-resolver.d.ts +8 -8
  266. package/dist/core/memory-resolver.js +15 -28
  267. package/dist/core/personas/index.d.ts +4 -4
  268. package/dist/core/personas/index.js +2 -2
  269. package/dist/core/personas/loader.d.ts +51 -0
  270. package/dist/core/personas/loader.js +54 -50
  271. package/dist/core/personas/resolve.d.ts +43 -27
  272. package/dist/core/personas/resolve.js +336 -94
  273. package/dist/core/runtime/auth-reload.d.ts +7 -0
  274. package/dist/core/runtime/auth-reload.js +69 -0
  275. package/dist/core/runtime/bearings.d.ts +35 -15
  276. package/dist/core/runtime/bearings.js +305 -44
  277. package/dist/core/runtime/branded-host.d.ts +4 -2
  278. package/dist/core/runtime/branded-host.js +66 -4
  279. package/dist/core/runtime/broker-protocol.d.ts +38 -3
  280. package/dist/core/runtime/broker.js +343 -18
  281. package/dist/core/runtime/close.js +37 -29
  282. package/dist/core/runtime/connectivity.d.ts +12 -0
  283. package/dist/core/runtime/connectivity.js +73 -0
  284. package/dist/core/runtime/fault-recovery-nudge.d.ts +2 -0
  285. package/dist/core/runtime/fault-recovery-nudge.js +2 -0
  286. package/dist/core/runtime/fault-recovery.d.ts +23 -0
  287. package/dist/core/runtime/fault-recovery.js +74 -0
  288. package/dist/core/runtime/fault.d.ts +25 -0
  289. package/dist/core/runtime/fault.js +176 -0
  290. package/dist/core/runtime/front-door.d.ts +1 -1
  291. package/dist/core/runtime/front-door.js +2 -2
  292. package/dist/core/runtime/host.d.ts +10 -0
  293. package/dist/core/runtime/host.js +71 -9
  294. package/dist/core/runtime/kickoff.js +31 -45
  295. package/dist/core/runtime/launch.d.ts +32 -18
  296. package/dist/core/runtime/launch.js +148 -43
  297. package/dist/core/runtime/model-swap.d.ts +18 -0
  298. package/dist/core/runtime/model-swap.js +95 -0
  299. package/dist/core/runtime/naming.d.ts +7 -0
  300. package/dist/core/runtime/naming.js +61 -9
  301. package/dist/core/runtime/nodes.js +6 -1
  302. package/dist/core/runtime/persona.js +16 -17
  303. package/dist/core/runtime/placement.d.ts +36 -31
  304. package/dist/core/runtime/placement.js +149 -64
  305. package/dist/core/runtime/promote.d.ts +2 -0
  306. package/dist/core/runtime/promote.js +23 -3
  307. package/dist/core/runtime/recycle.js +6 -4
  308. package/dist/core/runtime/reset.d.ts +5 -2
  309. package/dist/core/runtime/reset.js +2 -2
  310. package/dist/core/runtime/revive.d.ts +4 -0
  311. package/dist/core/runtime/revive.js +27 -9
  312. package/dist/core/runtime/roadmap.d.ts +1 -1
  313. package/dist/core/runtime/roadmap.js +1 -1
  314. package/dist/core/runtime/spawn.d.ts +2 -2
  315. package/dist/core/runtime/spawn.js +30 -6
  316. package/dist/core/runtime/stop-guard.js +6 -1
  317. package/dist/core/runtime/tmux-chrome.d.ts +1 -1
  318. package/dist/core/runtime/tmux-chrome.js +1 -1
  319. package/dist/core/runtime/tmux.d.ts +29 -6
  320. package/dist/core/runtime/tmux.js +134 -80
  321. package/dist/core/runtime/view-socket-client.d.ts +46 -0
  322. package/dist/core/runtime/view-socket-client.js +203 -0
  323. package/dist/core/substrate/index.d.ts +1 -1
  324. package/dist/core/substrate/index.js +1 -1
  325. package/dist/core/substrate/on-read.js +16 -4
  326. package/dist/core/substrate/render.d.ts +10 -13
  327. package/dist/core/substrate/render.js +56 -51
  328. package/dist/core/tui/host.js +83 -18
  329. package/dist/core/view/__tests__/transport-cache.test.d.ts +1 -0
  330. package/dist/core/view/__tests__/transport-cache.test.js +62 -0
  331. package/dist/core/view/contract.d.ts +20 -0
  332. package/dist/core/view/stream-local.d.ts +3 -0
  333. package/dist/core/view/stream-local.js +184 -0
  334. package/dist/core/view/transport-cache.d.ts +8 -0
  335. package/dist/core/view/transport-cache.js +38 -0
  336. package/dist/core/view/transport-local.js +4 -0
  337. package/dist/core/view/transport.d.ts +7 -1
  338. package/dist/daemon/crtrd.d.ts +3 -19
  339. package/dist/daemon/crtrd.js +139 -178
  340. package/dist/daemon/manage.d.ts +18 -1
  341. package/dist/daemon/manage.js +54 -9
  342. package/dist/hearth/wake-proxy/__tests__/anthropic-oauth.test.d.ts +1 -0
  343. package/dist/hearth/wake-proxy/__tests__/anthropic-oauth.test.js +289 -0
  344. package/dist/hearth/wake-proxy/__tests__/config-timeout.test.d.ts +1 -0
  345. package/dist/hearth/wake-proxy/__tests__/config-timeout.test.js +34 -0
  346. package/dist/hearth/wake-proxy/__tests__/guest-source.test.d.ts +1 -0
  347. package/dist/hearth/wake-proxy/__tests__/guest-source.test.js +203 -0
  348. package/dist/hearth/wake-proxy/__tests__/hardening.test.d.ts +1 -0
  349. package/dist/hearth/wake-proxy/__tests__/hardening.test.js +59 -0
  350. package/dist/hearth/wake-proxy/__tests__/hearth-status-route.test.d.ts +1 -0
  351. package/dist/hearth/wake-proxy/__tests__/hearth-status-route.test.js +372 -0
  352. package/dist/hearth/wake-proxy/__tests__/http-running-route-fast-path.test.d.ts +1 -0
  353. package/dist/hearth/wake-proxy/__tests__/http-running-route-fast-path.test.js +258 -0
  354. package/dist/hearth/wake-proxy/__tests__/model-auth-routes.test.d.ts +1 -0
  355. package/dist/hearth/wake-proxy/__tests__/model-auth-routes.test.js +437 -0
  356. package/dist/hearth/wake-proxy/__tests__/source-bridge-gate.test.d.ts +1 -0
  357. package/dist/hearth/wake-proxy/__tests__/source-bridge-gate.test.js +455 -0
  358. package/dist/hearth/wake-proxy/__tests__/static-asset-allowlist.test.d.ts +1 -0
  359. package/dist/hearth/wake-proxy/__tests__/static-asset-allowlist.test.js +15 -0
  360. package/dist/hearth/wake-proxy/__tests__/warm-path-concurrency.test.d.ts +1 -0
  361. package/dist/hearth/wake-proxy/__tests__/warm-path-concurrency.test.js +141 -0
  362. package/dist/hearth/wake-proxy/__tests__/ws-teardown-accounting.test.d.ts +1 -0
  363. package/dist/hearth/wake-proxy/__tests__/ws-teardown-accounting.test.js +143 -0
  364. package/dist/hearth/wake-proxy/anthropic-oauth.d.ts +58 -0
  365. package/dist/hearth/wake-proxy/anthropic-oauth.js +189 -0
  366. package/dist/hearth/wake-proxy/auth.d.ts +22 -0
  367. package/dist/hearth/wake-proxy/auth.js +128 -0
  368. package/dist/hearth/wake-proxy/config.d.ts +2 -0
  369. package/dist/hearth/wake-proxy/config.js +151 -0
  370. package/dist/hearth/wake-proxy/guest-source.d.ts +14 -0
  371. package/dist/hearth/wake-proxy/guest-source.js +130 -0
  372. package/dist/hearth/wake-proxy/hearth-status.d.ts +44 -0
  373. package/dist/hearth/wake-proxy/hearth-status.js +267 -0
  374. package/dist/hearth/wake-proxy/home.d.ts +67 -0
  375. package/dist/hearth/wake-proxy/home.js +297 -0
  376. package/dist/hearth/wake-proxy/main.d.ts +1 -0
  377. package/dist/hearth/wake-proxy/main.js +134 -0
  378. package/dist/hearth/wake-proxy/model-auth.d.ts +13 -0
  379. package/dist/hearth/wake-proxy/model-auth.js +345 -0
  380. package/dist/hearth/wake-proxy/proxy.d.ts +35 -0
  381. package/dist/hearth/wake-proxy/proxy.js +716 -0
  382. package/dist/hearth/wake-proxy/public-source-gate.d.ts +9 -0
  383. package/dist/hearth/wake-proxy/public-source-gate.js +409 -0
  384. package/dist/hearth/wake-proxy/redact.d.ts +1 -0
  385. package/dist/hearth/wake-proxy/redact.js +17 -0
  386. package/dist/hearth/wake-proxy/server.d.ts +11 -0
  387. package/dist/hearth/wake-proxy/server.js +142 -0
  388. package/dist/hearth/wake-proxy/state.d.ts +18 -0
  389. package/dist/hearth/wake-proxy/state.js +342 -0
  390. package/dist/hearth/wake-proxy/types.d.ts +76 -0
  391. package/dist/hearth/wake-proxy/types.js +1 -0
  392. package/dist/index.js +3 -2
  393. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +6 -5
  394. package/dist/pi-extensions/canvas-context-intro.js +7 -7
  395. package/dist/pi-extensions/canvas-doc-substrate.js +19 -22
  396. package/dist/pi-extensions/canvas-nav.js +15 -8
  397. package/dist/pi-extensions/canvas-stophook.d.ts +1 -1
  398. package/dist/pi-extensions/canvas-stophook.js +78 -11
  399. package/dist/types.d.ts +39 -20
  400. package/dist/types.js +38 -13
  401. package/dist/web/runtime.js +141 -42
  402. package/dist/web/transport-http.js +7 -5
  403. package/dist/web/transport-stream.d.ts +3 -0
  404. package/dist/web/transport-stream.js +204 -0
  405. package/dist/web-client/assets/fragment-mono-latin-400-normal-BYwT3kSJ.woff +0 -0
  406. package/dist/web-client/assets/fragment-mono-latin-400-normal-yxdJ5AmL.woff2 +0 -0
  407. package/dist/web-client/assets/fragment-mono-latin-ext-400-normal-BbKYyvR9.woff2 +0 -0
  408. package/dist/web-client/assets/fragment-mono-latin-ext-400-normal-CT4YFKeK.woff +0 -0
  409. package/dist/web-client/assets/fraunces-latin-ext-wght-normal-Ca2vKHc0.woff2 +0 -0
  410. package/dist/web-client/assets/fraunces-latin-wght-normal-ukD16Tqj.woff2 +0 -0
  411. package/dist/web-client/assets/fraunces-vietnamese-wght-normal-CnvboYUG.woff2 +0 -0
  412. package/dist/web-client/assets/index-BZUxTkv5.css +2 -0
  413. package/dist/web-client/assets/index-D36PNBj4.js +80 -0
  414. package/dist/web-client/assets/instrument-sans-latin-ext-wght-normal-B5bTHO_g.woff2 +0 -0
  415. package/dist/web-client/assets/instrument-sans-latin-wght-normal-BbzFLZTg.woff2 +0 -0
  416. package/dist/web-client/assets/martian-mono-cyrillic-wght-normal-B84CD5C_.woff2 +0 -0
  417. package/dist/web-client/assets/martian-mono-latin-ext-wght-normal-DlL6xMw5.woff2 +0 -0
  418. package/dist/web-client/assets/martian-mono-latin-wght-normal-5W32yIyr.woff2 +0 -0
  419. package/dist/web-client/index.html +3 -2
  420. package/package.json +32 -10
  421. package/dist/core/__tests__/error-stall-recycle.test.js +0 -141
  422. package/dist/core/skill-sync/__tests__/dry-run-wrote-count.test.js +0 -57
  423. package/dist/core/skill-sync/builtins.js +0 -112
  424. package/dist/core/skill-sync/claude-plugins.d.ts +0 -23
  425. package/dist/core/skill-sync/claude-plugins.js +0 -71
  426. package/dist/core/skill-sync/engine.d.ts +0 -42
  427. package/dist/core/skill-sync/engine.js +0 -633
  428. package/dist/core/skill-sync/manifest.d.ts +0 -64
  429. package/dist/core/skill-sync/manifest.js +0 -181
  430. package/dist/core/skill-sync/profile.d.ts +0 -76
  431. package/dist/core/skill-sync/profile.js +0 -173
  432. package/dist/core/skill-sync/snapshot.d.ts +0 -57
  433. package/dist/core/skill-sync/snapshot.js +0 -120
  434. package/dist/pi-extensions/canvas-commands.d.ts +0 -37
  435. package/dist/pi-extensions/canvas-commands.js +0 -113
  436. package/dist/pi-extensions/canvas-resume.d.ts +0 -21
  437. package/dist/pi-extensions/canvas-resume.js +0 -83
  438. package/dist/pi-extensions/canvas-view.d.ts +0 -21
  439. package/dist/pi-extensions/canvas-view.js +0 -76
  440. package/dist/web-client/assets/index-BUvQb4hR.css +0 -2
  441. package/dist/web-client/assets/index-ClLQXYAE.js +0 -10
  442. /package/dist/{core/__tests__/error-stall-recycle.test.d.ts → clients/attach/__tests__/autocomplete-and-bash-mode.test.d.ts} +0 -0
  443. /package/dist/{core/skill-sync/__tests__/dry-run-wrote-count.test.d.ts → clients/attach/__tests__/bash-bang-routing.test.d.ts} +0 -0
@@ -1,6 +1,6 @@
1
1
  // Promotion — the worker→orchestrator polymorph (mode→orchestrator).
2
2
  //
3
- // Two stages (the pi-mode-switch pattern):
3
+ // Two stages:
4
4
  // 1. Promotion → mode flips to orchestrator (mid-turn). This call flips the
5
5
  // node's mode and (optionally) its KIND, REWRITES its launch spec to that
6
6
  // kind's orchestrator persona (so the next revive comes back as that
@@ -20,6 +20,7 @@
20
20
  // never the mere act of spawning a child.
21
21
  import { getNode, updateNode } from '../canvas/index.js';
22
22
  import { transition } from './lifecycle.js';
23
+ import { ensureDaemon } from '../../daemon/manage.js';
23
24
  import { buildLaunchSpec } from './launch.js';
24
25
  import { hasRoadmap, seedRoadmap, roadmapPath } from './roadmap.js';
25
26
  import { readGoal, goalPath } from './kickoff.js';
@@ -58,7 +59,7 @@ export function promote(nodeId, opts = {}) {
58
59
  // Seed a barebones roadmap scaffold if absent so the file exists for a
59
60
  // refresh. Pre-fill its Goal from the node's goal doc when present (set at
60
61
  // spawn, or captured from the first user message); the node fleshes out the
61
- // body next, guided by the kind skill dumped below.
62
+ // body next, guided by the kind's roadmap memory doc dumped below.
62
63
  let roadmapWritten = false;
63
64
  if (!hasRoadmap(nodeId)) {
64
65
  const goal = readGoal(nodeId);
@@ -68,10 +69,17 @@ export function promote(nodeId, opts = {}) {
68
69
  // Flip mode→orchestrator + kind + launch spec. Lifecycle is independent:
69
70
  // only set resident when the caller asked for it (the common self-promotion
70
71
  // stays terminal/orchestrator — it still reports up + reaps).
72
+ // If the handle is still the spawn-time kind default (name === old kind),
73
+ // carry it to the new kind so the "name === kind ⇒ default, drop it" invariant
74
+ // in fullName() holds across a kind change. Otherwise a node spawned `general`
75
+ // (name="general") that reshapes to `plan` would surface a stale "general"
76
+ // handle in front of its real description.
77
+ const carriesDefaultHandle = node.name === node.kind && targetKind !== node.kind;
71
78
  const meta = updateNode(nodeId, {
72
79
  kind: targetKind,
73
80
  mode: 'orchestrator',
74
81
  launch,
82
+ ...(carriesDefaultHandle ? { name: targetKind } : {}),
75
83
  // Persist a newly-chosen tier so it is durable across future revives; omit
76
84
  // when unchanged so the existing pin (or persona default) stands.
77
85
  ...(opts.model !== undefined ? { model_override: opts.model } : {}),
@@ -90,7 +98,8 @@ export function promote(nodeId, opts = {}) {
90
98
  * so it comes back as an orchestrator, optionally specializing its kind. Sets
91
99
  * intent='refresh'; the stophook shuts the process down on the next stop and
92
100
  * the daemon revives it fresh. */
93
- export function requestYield(nodeId, opts = {}) {
101
+ export function requestYield(nodeId, opts = {}, deps = {}) {
102
+ const ensure = deps.ensure ?? ensureDaemon;
94
103
  const node = getNode(nodeId);
95
104
  if (node === null)
96
105
  throw new Error(`unknown node: ${nodeId}`);
@@ -113,6 +122,17 @@ export function requestYield(nodeId, opts = {}) {
113
122
  // of an already-orchestrator node.
114
123
  promoted = wasBase;
115
124
  }
125
+ // The refresh-revive is the DAEMON's job: the stophook shuts this broker down
126
+ // on its next stop, and crtrd then sees the dead pid + intent='refresh' and
127
+ // relaunches it fresh. That handoff is silent if the daemon isn't running — the
128
+ // broker exits and nothing ever revives it (the viewer redials its view.sock
129
+ // for ~30s and reports "broker gone"). So ensure the supervisor is alive HERE,
130
+ // before we arm the yield — the same best-effort ensure spawn/recycle do, on
131
+ // the one other path that hands a node off to the daemon. Runs in the fresh
132
+ // `crtr node yield` subprocess, so it always uses current dist (never a stale
133
+ // in-process hook). Injectable for the regression test that locks in this
134
+ // ensure (default = ensureDaemon).
135
+ ensure();
116
136
  // Mark the intent; the stophook enacts the shutdown, the daemon the revive.
117
137
  transition(nodeId, 'yield');
118
138
  const meta = getNode(nodeId);
@@ -120,7 +120,7 @@ export async function recycleNode(nodeId, callerPane) {
120
120
  // CRTR_SUBTREE groups the fresh root's subtree; FRONT_DOOR is set by the broker
121
121
  // host itself, so it is not added here.
122
122
  inv.env = { ...inv.env, CRTR_SUBTREE: rootOfSpine(root.node_id) };
123
- const ok = recycleBrokerViewer(fresh, pane, inv);
123
+ const ok = await recycleBrokerViewer(fresh, pane, inv);
124
124
  return { recycled: ok, finalized, newRoot: root.node_id, delivered };
125
125
  }
126
126
  /** Recycle a BROKER root into `pane`: the fresh root is broker-hosted, so its
@@ -131,9 +131,11 @@ export async function recycleNode(nodeId, callerPane) {
131
131
  * `@crtr_node`); it never hosts the engine. Returns false (recycle reports the
132
132
  * pane was not respawned) when the broker never serves — the fresh root row
133
133
  * still exists, broker-hosted, for the daemon to revive. */
134
- function recycleBrokerViewer(fresh, pane, inv) {
135
- headlessBrokerHost.launch(fresh.node_id, inv, { cwd: fresh.cwd, name: fullName(fresh), resuming: false });
136
- if (!waitForBrokerViewSocket(fresh.node_id))
134
+ async function recycleBrokerViewer(fresh, pane, inv) {
135
+ const placed = headlessBrokerHost.launch(fresh.node_id, inv, { cwd: fresh.cwd, name: fullName(fresh), resuming: false });
136
+ if (placed.pid === null)
137
+ return false;
138
+ if (!(await waitForBrokerViewSocket(fresh.node_id, placed.exited)))
137
139
  return false;
138
140
  // Clear the finalized node's stale `@crtr_node` tag before respawn so the tag
139
141
  // never names a done node during the gap before the new `crtr attach` re-tags
@@ -19,7 +19,10 @@ export interface RelaunchDeps {
19
19
  /** Boot the new node's detached broker engine. Default: headlessBrokerHost.launch. */
20
20
  launchBroker?: typeof headlessBrokerHost.launch;
21
21
  /** Wait for the new broker's view.sock to accept. Default: waitForBrokerViewSocket. */
22
- waitForViewSocket?: (nodeId: string) => boolean;
22
+ waitForViewSocket?: (nodeId: string, exited?: Promise<{
23
+ code: number | null;
24
+ signal: NodeJS.Signals | null;
25
+ }>) => boolean | Promise<boolean>;
23
26
  /** Re-exec the viewer pane onto the new node. Default: respawnPaneSync. */
24
27
  respawnViewer?: typeof respawnPaneSync;
25
28
  /** Tear the old broker down. Default: headlessBrokerHost.teardown. */
@@ -35,7 +38,7 @@ export interface RelaunchRootResult {
35
38
  * is touched, so any pre-commit failure leaves the old root fully intact and
36
39
  * live. Returns null when `oldId` is not a relaunchable root (unknown, a child,
37
40
  * or already parked), or when the new broker failed to launch. */
38
- export declare function relaunchRoot(oldId: string, deps?: RelaunchDeps): RelaunchRootResult | null;
41
+ export declare function relaunchRoot(oldId: string, deps?: RelaunchDeps): Promise<RelaunchRootResult | null>;
39
42
  export interface ResetRootResult {
40
43
  /** Descendant node ids torn down. Always empty — a child `/new` reaps nothing. */
41
44
  reaped: string[];
@@ -68,7 +68,7 @@ export function reapDescendants(rootId) {
68
68
  * is touched, so any pre-commit failure leaves the old root fully intact and
69
69
  * live. Returns null when `oldId` is not a relaunchable root (unknown, a child,
70
70
  * or already parked), or when the new broker failed to launch. */
71
- export function relaunchRoot(oldId, deps = {}) {
71
+ export async function relaunchRoot(oldId, deps = {}) {
72
72
  const launchBroker = deps.launchBroker ?? headlessBrokerHost.launch;
73
73
  const waitForViewSocket = deps.waitForViewSocket ?? waitForBrokerViewSocket;
74
74
  const respawnViewer = deps.respawnViewer ?? respawnPaneSync;
@@ -115,7 +115,7 @@ export function relaunchRoot(oldId, deps = {}) {
115
115
  transition(newMeta.node_id, 'crash');
116
116
  return null;
117
117
  }
118
- waitForViewSocket(newMeta.node_id); // best-effort; attach auto-redials on miss
118
+ await waitForViewSocket(newMeta.node_id, placed.exited); // best-effort; attach auto-redials on miss
119
119
  // --- COMMIT: park + reap the old root, re-point the viewer, kill the old
120
120
  // broker. Past this point the new node is the live root. ---
121
121
  reapDescendants(oldId); // old workers → canceled + torn down
@@ -1,5 +1,6 @@
1
1
  import { type NodeMeta } from '../canvas/index.js';
2
2
  import type { WakeOrigin } from './bearings.js';
3
+ import { headlessBrokerHost } from './host.js';
3
4
  /** Pick the `--session` source for a revive. resume=true prefers the absolute
4
5
  * session-file path (immune to cwd; pi opens it directly) and keeps the bare
5
6
  * session id as the fallback for older nodes booted before pi_session_file was
@@ -19,6 +20,9 @@ export interface ReviveResult {
19
20
  session: string | null;
20
21
  /** True when pi was instructed to resume its saved conversation (`--session <id>`). */
21
22
  resumed: boolean;
23
+ /** Launch handle for the detached broker, so callers can fail fast on its real
24
+ * exit before the socket appears. */
25
+ launch?: ReturnType<typeof headlessBrokerHost.launch>;
22
26
  }
23
27
  /** Relaunch `nodeId`'s broker engine from its persisted recipe and update canvas
24
28
  * meta. Opens no viewer (engine-only).
@@ -21,6 +21,7 @@ import { buildPiArgv } from './launch.js';
21
21
  import { buildReviveKickoff, drainBearings } from './kickoff.js';
22
22
  import { headlessBrokerHost } from './host.js';
23
23
  import { isPidAlive } from '../canvas/pid.js';
24
+ import { clearFault } from './fault.js';
24
25
  import { clearInjectedDocs } from '../substrate/injected-store.js';
25
26
  // ---------------------------------------------------------------------------
26
27
  // resumeArgs — which session source a revive resumes from
@@ -72,9 +73,9 @@ export function reviveNode(nodeId, opts) {
72
73
  resumed: false,
73
74
  };
74
75
  }
75
- // Every (re)launch is a new cycle — bump the counter so the editor label's
76
- // trailing N advances. Mutate the in-memory meta too so buildPiArgv below
77
- // builds the label with the incremented count.
76
+ // Every (re)launch is a new cycle — bump the counter so CRTR_CYCLES and the
77
+ // footer stay in sync. Mutate the in-memory meta too so buildPiArgv below
78
+ // launches with the incremented count.
78
79
  meta.cycles = (meta.cycles ?? 0) + 1;
79
80
  updateNode(nodeId, { cycles: meta.cycles });
80
81
  // Decide whether to wake the saved pi conversation or start fresh. Prefer the
@@ -106,19 +107,36 @@ export function reviveNode(nodeId, opts) {
106
107
  // opens NO viewer — engine-only; existing viewers reconnect, and a viewer-less
107
108
  // node is brought on screen by the next `focus`.
108
109
  transition(nodeId, 'revive');
110
+ // Clear any active fault the instant this node is (re)launched — don't wait
111
+ // for the fresh agent_start. A revive (auto or on-demand) is the recovery
112
+ // this marker advertised.
113
+ clearFault(nodeId);
109
114
  // Cancel-on-wake (design §6.4, AC-E1): every revive-for-any-reason (an inbox
110
115
  // event, a different wake, a manual focus) drops this node's pending deadline,
111
116
  // so the deadline always belongs to the dormancy being left. Writes only the
112
117
  // wakeups table, after the atomic transition above.
113
118
  cancelDeadlinesFor(nodeId);
114
- headlessBrokerHost.launch(nodeId, inv, {
115
- cwd: meta.cwd,
116
- name: fullName(meta),
117
- resuming,
118
- });
119
+ let launched;
120
+ try {
121
+ launched = headlessBrokerHost.launch(nodeId, inv, {
122
+ cwd: meta.cwd,
123
+ name: fullName(meta),
124
+ resuming,
125
+ });
126
+ }
127
+ catch (error) {
128
+ try {
129
+ transition(nodeId, 'crash');
130
+ }
131
+ catch {
132
+ /* best-effort cleanup */
133
+ }
134
+ clearPid(nodeId);
135
+ throw new Error(`[broker] refusing to revive ${nodeId}: ${error.message}`);
136
+ }
119
137
  // Clear the stale pid so the daemon won't re-fire on it during the new
120
138
  // broker's boot. The fresh broker re-records its pid during extension bind; if
121
139
  // it never boots, the daemon's boot-grace + surfaceBootFailure own that case.
122
140
  clearPid(nodeId);
123
- return { window: null, session: meta.tmux_session ?? null, resumed: resuming };
141
+ return { window: null, session: meta.tmux_session ?? null, resumed: resuming, launch: launched };
124
142
  }
@@ -4,7 +4,7 @@ export declare function readRoadmap(nodeId: string): string | null;
4
4
  /** Seed a fresh, EXTREMELY BAREBONES roadmap scaffold — just the section
5
5
  * skeleton with one-line prompts. Promotion lays this down so the file exists
6
6
  * for a refresh; the owner fleshes it out as its next act (guided by its
7
- * kind's roadmap skill). `goal`/`exitCriteria` pre-fill those sections when
7
+ * roadmap memory doc). `goal`/`exitCriteria` pre-fill those sections when
8
8
  * known (e.g. from the node's goal doc). Idempotent only if you intend it —
9
9
  * call sites guard on hasRoadmap to avoid clobbering an evolved map. */
10
10
  export declare function seedRoadmap(nodeId: string, opts?: {
@@ -23,7 +23,7 @@ export function readRoadmap(nodeId) {
23
23
  /** Seed a fresh, EXTREMELY BAREBONES roadmap scaffold — just the section
24
24
  * skeleton with one-line prompts. Promotion lays this down so the file exists
25
25
  * for a refresh; the owner fleshes it out as its next act (guided by its
26
- * kind's roadmap skill). `goal`/`exitCriteria` pre-fill those sections when
26
+ * roadmap memory doc). `goal`/`exitCriteria` pre-fill those sections when
27
27
  * known (e.g. from the node's goal doc). Idempotent only if you intend it —
28
28
  * call sites guard on hasRoadmap to avoid clobbering an evolved map. */
29
29
  export function seedRoadmap(nodeId, opts = {}) {
@@ -11,7 +11,7 @@ export interface BootRootOpts {
11
11
  * inline so THIS terminal becomes the broker's controller-viewer. Does not
12
12
  * return — it process.exit()s when the inline attach exits (detach leaves the
13
13
  * resident broker running, to be reconnected later). */
14
- export declare function bootRoot(opts: BootRootOpts): NodeMeta;
14
+ export declare function bootRoot(opts: BootRootOpts): Promise<NodeMeta>;
15
15
  export interface SpawnChildOpts {
16
16
  kind: string;
17
17
  mode?: Mode;
@@ -70,4 +70,4 @@ export declare function resolveSpawner(parent: string | undefined, ctxNodeId: st
70
70
  * With `root`: an independent resident root — parent=null, NO subscription back
71
71
  * to the spawner (it carries spawned_by=spawner for provenance only), brought
72
72
  * forefront so a human can pick up the conversation directly. */
73
- export declare function spawnChild(opts: SpawnChildOpts): SpawnChildResult;
73
+ export declare function spawnChild(opts: SpawnChildOpts): Promise<SpawnChildResult>;
@@ -24,11 +24,29 @@ import { registerViewerFocus, openViewerWindow, waitForBrokerViewSocket, viewerS
24
24
  import { transition } from './lifecycle.js';
25
25
  import { headlessBrokerHost } from './host.js';
26
26
  import { ensureDaemon } from '../../daemon/manage.js';
27
+ // ---------------------------------------------------------------------------
28
+ // Shared broker-launch wrapper — catch launch/preflight failures at the call
29
+ // site, mark the node crashed, then rethrow a clear error.
30
+ // ---------------------------------------------------------------------------
31
+ function launchBrokerOrCrash(nodeId, inv, opts) {
32
+ try {
33
+ return headlessBrokerHost.launch(nodeId, inv, opts);
34
+ }
35
+ catch (error) {
36
+ try {
37
+ transition(nodeId, 'crash');
38
+ }
39
+ catch {
40
+ /* best-effort cleanup */
41
+ }
42
+ throw new Error(`[broker] refusing to launch ${nodeId}: ${error.message}`);
43
+ }
44
+ }
27
45
  /** Create the front-door root: launch its broker engine, then exec `crtr attach`
28
46
  * inline so THIS terminal becomes the broker's controller-viewer. Does not
29
47
  * return — it process.exit()s when the inline attach exits (detach leaves the
30
48
  * resident broker running, to be reconnected later). */
31
- export function bootRoot(opts) {
49
+ export async function bootRoot(opts) {
32
50
  // crtr is tmux-only: the front door execs `crtr attach` inline in THIS pane to
33
51
  // become the root's controller-viewer, so there must be a tmux pane to anchor
34
52
  // on. Outside tmux there is no viewer surface — throw with a friendly message
@@ -98,7 +116,7 @@ export function bootRoot(opts) {
98
116
  // broker and the viewer reconnects), and THIS terminal execs `crtr attach`
99
117
  // inline to become its controller-viewer. The host sets CRTR_FRONT_DOOR.
100
118
  inv.env = { ...inv.env, CRTR_SUBTREE: rootOfSpine(meta.node_id) };
101
- const placed = headlessBrokerHost.launch(meta.node_id, inv, {
119
+ const placed = launchBrokerOrCrash(meta.node_id, inv, {
102
120
  cwd: opts.cwd,
103
121
  name: fullName(meta),
104
122
  resuming: false,
@@ -112,7 +130,13 @@ export function bootRoot(opts) {
112
130
  // The terminal has nothing to attach to until view.sock accepts. The root is
113
131
  // useless without its engine, so a socket timeout IS fatal here (unlike a
114
132
  // background child's optional viewer, which is skipped on timeout).
115
- if (!waitForBrokerViewSocket(meta.node_id)) {
133
+ if (!(await waitForBrokerViewSocket(meta.node_id, placed.exited))) {
134
+ try {
135
+ transition(meta.node_id, 'crash');
136
+ }
137
+ catch {
138
+ /* best-effort cleanup */
139
+ }
116
140
  throw new Error(`the front-door root broker ${meta.node_id} never bound its view socket — cannot attach.`);
117
141
  }
118
142
  const attachEnv = { ...process.env, ...viewerSplitEnv() };
@@ -210,7 +234,7 @@ export function resolveSpawner(parent, ctxNodeId, root) {
210
234
  * With `root`: an independent resident root — parent=null, NO subscription back
211
235
  * to the spawner (it carries spawned_by=spawner for provenance only), brought
212
236
  * forefront so a human can pick up the conversation directly. */
213
- export function spawnChild(opts) {
237
+ export async function spawnChild(opts) {
214
238
  try {
215
239
  ensureDaemon();
216
240
  }
@@ -292,7 +316,7 @@ export function spawnChild(opts) {
292
316
  // gets NO viewer — spawning it returns once the engine is launched and a human
293
317
  // opens a viewer on demand via `crtr node focus` / `crtr attach`. A --root gets
294
318
  // one foreground viewer below.
295
- const placed = headlessBrokerHost.launch(meta.node_id, inv, {
319
+ const placed = launchBrokerOrCrash(meta.node_id, inv, {
296
320
  cwd: meta.cwd,
297
321
  name: fullName(meta),
298
322
  resuming: false,
@@ -313,7 +337,7 @@ export function spawnChild(opts) {
313
337
  // returns null) or the socket never binds — `focus` opens a viewer later.
314
338
  let window = null;
315
339
  let session = null;
316
- if (root && here !== null && waitForBrokerViewSocket(meta.node_id)) {
340
+ if (root && here !== null && await waitForBrokerViewSocket(meta.node_id, placed.exited)) {
317
341
  const viewer = openViewerWindow(meta.node_id, here.session, { name: fullName(meta), cwd: opts.cwd });
318
342
  if (viewer !== null && viewer.pane !== null && viewer.pane !== '') {
319
343
  session = here.session;
@@ -26,12 +26,17 @@ export function evaluateStop(nodeId, signals) {
26
26
  return { action: 'allow', reason: 'finished' };
27
27
  if (signals.askedHuman)
28
28
  return { action: 'allow', reason: 'escalated' };
29
+ // Already-terminal stored state wins before any stall logic: a node that is
30
+ // done/dead/canceled is not waiting to be re-prompted.
31
+ const node = getNode(nodeId);
32
+ if (node !== null && (node.status === 'done' || node.status === 'dead' || node.status === 'canceled')) {
33
+ return { action: 'allow', reason: 'finished' };
34
+ }
29
35
  // A RESIDENT node is interactable / human-driven and is never forced to submit
30
36
  // a final: stopping to go dormant is always legitimate (the inbox or the human
31
37
  // wakes it). Keyed on lifecycle, not parent — whether it has a parent doesn't
32
38
  // matter, only whether it's resident. Roots are resident by birth default, so
33
39
  // this still covers "don't nag the human's root" while generalizing it.
34
- const node = getNode(nodeId);
35
40
  if (node !== null && node.lifecycle === 'resident') {
36
41
  return { action: 'allow', reason: 'dormant' };
37
42
  }
@@ -1 +1 @@
1
- export { installMenuBinding, installNavBindings, installViewNavBindings, sendKeysEnter } from './tmux.js';
1
+ export { installMenuBinding, installNavBindings, installViewNavBindings, sendKeysEnter, displayMessage, paneCurrentPath } from './tmux.js';
@@ -1,4 +1,4 @@
1
1
  // tmux-chrome.ts — chrome seam (§2.1): stateless keybind/input verbs.
2
2
  // The ONLY non-placement module allowed to import the tmux driver, per the
3
3
  // §5.1 lint. Re-exports the menu/nav/send-keys verbs callers (spawn, chord) need.
4
- export { installMenuBinding, installNavBindings, installViewNavBindings, sendKeysEnter } from './tmux.js';
4
+ export { installMenuBinding, installNavBindings, installViewNavBindings, sendKeysEnter, displayMessage, paneCurrentPath } from './tmux.js';
@@ -72,6 +72,18 @@ export declare function closeWindow(window: string): boolean;
72
72
  * root relaunch to re-title the viewer window when its pane is re-pointed at
73
73
  * the freshly-minted node. Best-effort; false if tmux fails. */
74
74
  export declare function renameWindow(window: string, name: string): boolean;
75
+ /** Break a single PANE out into a BRAND-NEW window of its own (`tmux break-pane
76
+ * -d`). `-d` keeps the new window in the background (does not switch the client
77
+ * to it); `-s <pane>` names the source pane — the §2.2 HARD DRIVER INVARIANT, so
78
+ * the break never falls back to tmux's global current pane. The pane keeps its
79
+ * durable `%id` across the move (only its window changes), so callers can keep
80
+ * using the same pane handle. Returns the new `{window, pane}` location, or null
81
+ * if tmux fails. Used by `canvas tmux-spread` to lift the caller's viewer into a
82
+ * fresh window before tiling sibling viewers beside it. */
83
+ export declare function breakPane(pane: string): {
84
+ window: string;
85
+ pane: string;
86
+ } | null;
75
87
  /** Close a single PANE. Its window closes automatically once this was the last
76
88
  * pane, but sibling panes survive — so co-located nodes (several agents sharing
77
89
  * one window via swap-pane focus) are torn down one at a time instead of all
@@ -122,6 +134,11 @@ export declare function listLivePanes(): Set<string> | null;
122
134
  * '#{pane_current_path}'`). Used to preserve a view monitor's cwd across a
123
135
  * view-cycle respawn so project-scoped views still resolve. Null if tmux fails. */
124
136
  export declare function paneCurrentPath(pane: string): string | null;
137
+ /** Flash a transient status-line toast on the client showing `pane` (or the
138
+ * current client when `pane` is omitted). `ms` sets the display duration. Used
139
+ * by `crtr canvas issue new` to confirm a capture from inside its popup.
140
+ * Best-effort; never throws. */
141
+ export declare function displayMessage(message: string, pane?: string, ms?: number): boolean;
125
142
  /** Set a PANE-scoped tmux option (`tmux set-option -p -t <pane> <name> <value>`).
126
143
  * Used to tag a pane with the view id it currently hosts (`@crtr_view`) so the
127
144
  * view-nav cycle can read it back and switch to the next/prev view in place.
@@ -169,6 +186,17 @@ export declare function windowAlive(session: string | null | undefined, window:
169
186
  /** Activate a window within its session (same-session navigation). Equivalent
170
187
  * to `tmux select-window -t <session>:<window>`. Best-effort; never throws. */
171
188
  export declare function selectWindow(session: string, window: string): boolean;
189
+ /** Apply a named tmux layout to a window (`tmux select-layout -t <window>
190
+ * <layout>`). `canvas tmux-spread` calls it with `tiled` to evenly grid every
191
+ * viewer pane in the spread window (and between splits, to redistribute space so
192
+ * the next split has room). Best-effort; false if tmux fails. */
193
+ export declare function selectLayout(window: string, layout: string): boolean;
194
+ /** Make a pane the ACTIVE pane in its window (`tmux select-pane -t <pane>`). A
195
+ * `split-window -d` keeps the CALLER active, so a freshly-opened viewer pane is
196
+ * not focused until this runs — `focus` calls it so picking a node (e.g. from the
197
+ * alt+g graph) lands the keyboard on the new viewer. Best-effort; false if tmux
198
+ * fails. */
199
+ export declare function selectPane(pane: string): boolean;
172
200
  /** Switch the tmux client to a different session (cross-session focus). Runs
173
201
  * `tmux switch-client -t <session>`. Best-effort; never throws. The caller is
174
202
  * responsible for following up with selectWindow to land on the right window. */
@@ -177,12 +205,7 @@ export declare function switchClient(session: string): boolean;
177
205
  * (`tmux send-keys -t <pane> '<text>' Enter`). Requires the pane's editor be
178
206
  * empty, same limitation as the menu's `/promote` item. Best-effort. */
179
207
  export declare function sendKeysEnter(pane: string, text: string): boolean;
180
- /** Bind Alt+C to the crouter action menu. Best-effort; false if tmux fails.
181
- * The built-in items (promote/resume/demote/detach/close) are static; the canvas-nav
182
- * chords (default g→graph, m→manager + any custom prefixBind) are appended
183
- * from `canvasNav.prefixBinds`, each routed through `crtr canvas chord` (or, for
184
- * the `__graph__` sentinel, a `send-keys '/graph'`) so the menu stays static
185
- * while behaviour is config-driven. */
208
+ /** Bind Alt+C to the crouter action menu. Best-effort; false if tmux fails. */
186
209
  export declare function installMenuBinding(): boolean;
187
210
  /** Bind Alt+] (forward) and Alt+[ (back) to the DFS canvas walk. Best-effort;
188
211
  * false if either bind fails. NOTE: Alt+[ is only delivered cleanly when the