@crouton-kit/crouter 0.3.27 → 0.3.29

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 (343) hide show
  1. package/dist/build-root.js +4 -2
  2. package/dist/builtin-memory/crouter-development/marketplaces.md +7 -6
  3. package/dist/builtin-memory/crouter-development/personas/base-prompt.md +1 -1
  4. package/dist/builtin-memory/crouter-development/personas/orchestrator-prompt.md +1 -1
  5. package/dist/builtin-memory/crouter-development/personas.md +1 -1
  6. package/dist/builtin-memory/crouter-development/plugins.md +20 -18
  7. package/dist/builtin-memory/design.md +1 -1
  8. package/dist/builtin-memory/development.md +1 -1
  9. package/dist/builtin-memory/internal/INDEX.md +1 -1
  10. package/dist/builtin-memory/internal/examples/INDEX.md +1 -1
  11. package/dist/builtin-memory/internal/examples/imessage-assistant.md +2 -2
  12. package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
  13. package/dist/builtin-memory/internal/storage-tiers.md +1 -1
  14. package/dist/builtin-memory/planning.md +1 -1
  15. package/dist/builtin-memory/spec.md +6 -4
  16. package/dist/builtin-personas/orchestration-kernel.md +4 -5
  17. package/dist/builtin-personas/runtime-base.md +8 -4
  18. package/dist/builtin-personas/spec/PERSONA.md +8 -4
  19. package/dist/builtin-personas/spec/orchestrator.md +5 -3
  20. package/dist/builtin-personas/spec/requirements/PERSONA.md +10 -0
  21. package/dist/builtin-views/canvas/core.mjs +586 -0
  22. package/dist/builtin-views/canvas/text.mjs +58 -0
  23. package/dist/builtin-views/canvas/tui.mjs +165 -0
  24. package/dist/builtin-views/canvas/web.jsx +120 -0
  25. package/dist/builtin-views/git-pr/core.mjs +673 -0
  26. package/dist/builtin-views/git-pr/text.mjs +84 -0
  27. package/dist/builtin-views/git-pr/tui.mjs +302 -0
  28. package/dist/builtin-views/git-pr/web.jsx +216 -0
  29. package/dist/builtin-views/inbox/_lib/render.mjs +1 -3
  30. package/dist/builtin-views/inbox/core.mjs +1273 -0
  31. package/dist/builtin-views/inbox/text.mjs +73 -0
  32. package/dist/builtin-views/inbox/tui.mjs +312 -0
  33. package/dist/builtin-views/inbox/web.jsx +188 -0
  34. package/dist/builtin-views/linkedin/core.mjs +906 -0
  35. package/dist/builtin-views/linkedin/text.mjs +69 -0
  36. package/dist/builtin-views/linkedin/tui.mjs +427 -0
  37. package/dist/builtin-views/linkedin/web.jsx +206 -0
  38. package/dist/builtin-views/workspace-sidebar/core.mjs +621 -0
  39. package/dist/builtin-views/workspace-sidebar/text.mjs +53 -0
  40. package/dist/builtin-views/workspace-sidebar/tui.mjs +142 -0
  41. package/dist/builtin-views/workspace-sidebar/web.jsx +109 -0
  42. package/dist/cli.js +3 -3
  43. package/dist/clients/attach/__tests__/action-parity.test.js +48 -0
  44. package/dist/clients/attach/__tests__/clipboard-image.test.js +76 -0
  45. package/dist/clients/attach/__tests__/editor-newline.test.js +57 -0
  46. package/dist/clients/attach/__tests__/git-info.test.js +31 -0
  47. package/dist/clients/attach/__tests__/onrequest-wired.test.js +20 -0
  48. package/dist/clients/attach/__tests__/reconnect-giveup.test.js +30 -0
  49. package/dist/clients/attach/__tests__/slash-quit-copy.test.js +42 -0
  50. package/dist/clients/attach/__tests__/titled-editor.test.d.ts +1 -0
  51. package/dist/clients/attach/__tests__/titled-editor.test.js +39 -0
  52. package/dist/clients/attach/attach-cmd.js +445 -41
  53. package/dist/clients/attach/auth-pickers.d.ts +9 -0
  54. package/dist/clients/attach/auth-pickers.js +194 -0
  55. package/dist/clients/attach/canvas-panels.d.ts +12 -0
  56. package/dist/clients/attach/canvas-panels.js +78 -0
  57. package/dist/clients/attach/chat-view.d.ts +27 -2
  58. package/dist/clients/attach/chat-view.js +98 -9
  59. package/dist/clients/attach/clipboard-image.d.ts +47 -8
  60. package/dist/clients/attach/clipboard-image.js +150 -26
  61. package/dist/clients/attach/clipboard-text.d.ts +3 -0
  62. package/dist/clients/attach/clipboard-text.js +39 -0
  63. package/dist/clients/attach/config-load.d.ts +54 -7
  64. package/dist/clients/attach/config-load.js +99 -3
  65. package/dist/clients/attach/context-message.d.ts +12 -0
  66. package/dist/clients/attach/context-message.js +72 -0
  67. package/dist/clients/attach/git-info.d.ts +20 -0
  68. package/dist/clients/attach/git-info.js +44 -0
  69. package/dist/clients/attach/graph-overlay.d.ts +43 -0
  70. package/dist/clients/attach/graph-overlay.js +306 -0
  71. package/dist/clients/attach/input-controller.d.ts +81 -13
  72. package/dist/clients/attach/input-controller.js +307 -67
  73. package/dist/clients/attach/pickers.d.ts +58 -0
  74. package/dist/clients/attach/pickers.js +171 -0
  75. package/dist/clients/attach/slash-commands.d.ts +44 -1
  76. package/dist/clients/attach/slash-commands.js +250 -27
  77. package/dist/clients/attach/titled-editor.d.ts +33 -0
  78. package/dist/clients/attach/titled-editor.js +84 -0
  79. package/dist/clients/attach/view-socket.d.ts +37 -2
  80. package/dist/clients/attach/view-socket.js +131 -7
  81. package/dist/clients/web/dev-server.d.ts +7 -0
  82. package/dist/clients/web/dev-server.js +59 -0
  83. package/dist/clients/web/events.d.ts +14 -0
  84. package/dist/clients/web/events.js +151 -0
  85. package/dist/clients/web/server.d.ts +18 -0
  86. package/dist/clients/web/server.js +450 -0
  87. package/dist/clients/web/web-cmd.d.ts +2 -0
  88. package/dist/clients/web/web-cmd.js +120 -0
  89. package/dist/commands/canvas.js +1 -2
  90. package/dist/commands/chord.js +1 -1
  91. package/dist/commands/dashboard.js +5 -1
  92. package/dist/commands/human/prompts.js +3 -3
  93. package/dist/commands/human/queue.d.ts +17 -0
  94. package/dist/commands/human/queue.js +111 -4
  95. package/dist/commands/memory/__tests__/lint-schema.test.js +27 -4
  96. package/dist/commands/memory/lint.d.ts +5 -4
  97. package/dist/commands/memory/lint.js +23 -7
  98. package/dist/commands/memory/read.js +2 -2
  99. package/dist/commands/memory/shared.d.ts +7 -1
  100. package/dist/commands/memory/shared.js +18 -3
  101. package/dist/commands/memory/write.js +20 -7
  102. package/dist/commands/memory.js +4 -4
  103. package/dist/commands/node.d.ts +1 -1
  104. package/dist/commands/node.js +64 -65
  105. package/dist/commands/pkg.js +1 -2
  106. package/dist/commands/revive.js +11 -3
  107. package/dist/commands/sys/feedback.d.ts +1 -0
  108. package/dist/commands/sys/feedback.js +163 -0
  109. package/dist/commands/sys/sync.d.ts +1 -0
  110. package/dist/commands/sys/sync.js +187 -0
  111. package/dist/commands/sys.js +4 -2
  112. package/dist/commands/view-cycle.js +2 -2
  113. package/dist/commands/view-list.js +8 -8
  114. package/dist/commands/view-new.js +21 -17
  115. package/dist/commands/view-pick.js +1 -1
  116. package/dist/commands/view-run.js +35 -14
  117. package/dist/commands/view.js +8 -6
  118. package/dist/commands/workspace.d.ts +2 -0
  119. package/dist/commands/workspace.js +161 -0
  120. package/dist/core/__tests__/broker-double-spawn.test.d.ts +1 -0
  121. package/dist/core/__tests__/broker-double-spawn.test.js +143 -0
  122. package/dist/core/__tests__/broker-fork-seam.test.d.ts +1 -0
  123. package/dist/core/__tests__/broker-fork-seam.test.js +102 -0
  124. package/dist/core/__tests__/broker-sdk-wiring.test.js +2 -0
  125. package/dist/core/__tests__/broker-snapshot-history.test.d.ts +1 -0
  126. package/dist/core/__tests__/broker-snapshot-history.test.js +105 -0
  127. package/dist/core/__tests__/child-death-wake.test.js +56 -111
  128. package/dist/core/__tests__/close.test.js +14 -20
  129. package/dist/core/__tests__/context-intro.test.js +19 -19
  130. package/dist/core/__tests__/daemon-boot.test.js +30 -23
  131. package/dist/core/__tests__/draw-style.test.js +1 -1
  132. package/dist/core/__tests__/error-stall-recycle.test.d.ts +1 -0
  133. package/dist/core/__tests__/error-stall-recycle.test.js +141 -0
  134. package/dist/core/__tests__/fixtures/fake-engine.d.ts +24 -1
  135. package/dist/core/__tests__/fixtures/fake-engine.js +32 -2
  136. package/dist/core/__tests__/fixtures/fake-pi-host.js +2 -2
  137. package/dist/core/__tests__/focuses.test.js +25 -13
  138. package/dist/core/__tests__/fork.test.js +22 -5
  139. package/dist/core/__tests__/full/broker-control-preempt.test.d.ts +1 -0
  140. package/dist/core/__tests__/full/broker-control-preempt.test.js +61 -0
  141. package/dist/core/__tests__/full/broker-model-changed-broadcast.test.d.ts +1 -0
  142. package/dist/core/__tests__/full/broker-model-changed-broadcast.test.js +57 -0
  143. package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.d.ts +1 -0
  144. package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.js +80 -0
  145. package/dist/core/__tests__/full/broker-pane-resolution.test.js +90 -0
  146. package/dist/core/__tests__/full/cascade-close.test.js +22 -8
  147. package/dist/core/__tests__/full/detach-focus.test.js +66 -169
  148. package/dist/core/__tests__/helpers/harness.d.ts +6 -9
  149. package/dist/core/__tests__/helpers/harness.js +19 -36
  150. package/dist/core/__tests__/human-node-not-supervised.test.d.ts +1 -0
  151. package/dist/core/__tests__/human-node-not-supervised.test.js +83 -0
  152. package/dist/core/__tests__/human-stranded-deliver.test.d.ts +1 -0
  153. package/dist/core/__tests__/human-stranded-deliver.test.js +108 -0
  154. package/dist/core/__tests__/lifecycle.test.js +1 -19
  155. package/dist/core/__tests__/live-mutation-verbs.test.js +5 -5
  156. package/dist/core/__tests__/memory-resolver.test.js +1 -1
  157. package/dist/core/__tests__/on-read-dedup-resume.test.d.ts +1 -0
  158. package/dist/core/__tests__/on-read-dedup-resume.test.js +81 -0
  159. package/dist/core/__tests__/refresh-stall-recycle.test.d.ts +1 -0
  160. package/dist/core/__tests__/refresh-stall-recycle.test.js +88 -0
  161. package/dist/core/__tests__/relaunch-root.test.d.ts +1 -0
  162. package/dist/core/__tests__/relaunch-root.test.js +114 -0
  163. package/dist/core/__tests__/reset.test.js +19 -79
  164. package/dist/core/__tests__/steer-note.test.js +9 -7
  165. package/dist/core/__tests__/tmux-surface.test.js +13 -7
  166. package/dist/core/bootstrap.d.ts +0 -3
  167. package/dist/core/bootstrap.js +1 -143
  168. package/dist/core/canvas/browse/__tests__/model.test.js +86 -1
  169. package/dist/core/canvas/browse/__tests__/render.test.js +2 -1
  170. package/dist/core/canvas/browse/app.js +131 -8
  171. package/dist/core/canvas/browse/model.d.ts +23 -5
  172. package/dist/core/canvas/browse/model.js +68 -13
  173. package/dist/core/canvas/browse/render.d.ts +7 -1
  174. package/dist/core/canvas/browse/render.js +178 -47
  175. package/dist/core/canvas/canvas.js +1 -1
  176. package/dist/core/canvas/focuses.d.ts +4 -4
  177. package/dist/core/canvas/focuses.js +7 -7
  178. package/dist/core/canvas/nav-model.d.ts +162 -0
  179. package/dist/core/canvas/nav-model.js +487 -0
  180. package/dist/core/canvas/paths.d.ts +7 -0
  181. package/dist/core/canvas/paths.js +9 -0
  182. package/dist/core/canvas/render.d.ts +68 -9
  183. package/dist/core/canvas/render.js +195 -61
  184. package/dist/core/canvas/types.d.ts +16 -23
  185. package/dist/core/config.js +1 -4
  186. package/dist/core/memory-resolver.js +43 -5
  187. package/dist/core/runtime/bearings.d.ts +1 -1
  188. package/dist/core/runtime/bearings.js +8 -8
  189. package/dist/core/runtime/branded-host.d.ts +16 -0
  190. package/dist/core/runtime/branded-host.js +127 -0
  191. package/dist/core/runtime/broker-protocol.d.ts +212 -6
  192. package/dist/core/runtime/broker-sdk.d.ts +0 -12
  193. package/dist/core/runtime/broker-sdk.js +77 -6
  194. package/dist/core/runtime/broker.d.ts +5 -1
  195. package/dist/core/runtime/broker.js +520 -59
  196. package/dist/core/runtime/close.d.ts +12 -2
  197. package/dist/core/runtime/close.js +37 -16
  198. package/dist/core/runtime/front-door.js +14 -7
  199. package/dist/core/runtime/host.d.ts +14 -34
  200. package/dist/core/runtime/host.js +14 -50
  201. package/dist/core/runtime/launch.d.ts +12 -9
  202. package/dist/core/runtime/launch.js +27 -15
  203. package/dist/core/runtime/lifecycle.d.ts +1 -1
  204. package/dist/core/runtime/lifecycle.js +15 -19
  205. package/dist/core/runtime/nodes.d.ts +0 -55
  206. package/dist/core/runtime/nodes.js +6 -74
  207. package/dist/core/runtime/placement.d.ts +91 -334
  208. package/dist/core/runtime/placement.js +262 -828
  209. package/dist/core/runtime/promote.d.ts +2 -0
  210. package/dist/core/runtime/promote.js +24 -6
  211. package/dist/core/runtime/recap.d.ts +8 -0
  212. package/dist/core/runtime/recap.js +107 -0
  213. package/dist/core/runtime/recycle.js +25 -61
  214. package/dist/core/runtime/reset.d.ts +43 -37
  215. package/dist/core/runtime/reset.js +131 -218
  216. package/dist/core/runtime/revive.d.ts +9 -29
  217. package/dist/core/runtime/revive.js +45 -135
  218. package/dist/core/runtime/spawn.d.ts +15 -11
  219. package/dist/core/runtime/spawn.js +168 -136
  220. package/dist/core/runtime/surface-bg.d.ts +11 -0
  221. package/dist/core/runtime/surface-bg.js +68 -0
  222. package/dist/core/runtime/tmux.d.ts +15 -43
  223. package/dist/core/runtime/tmux.js +38 -80
  224. package/dist/core/scope.d.ts +1 -2
  225. package/dist/core/scope.js +1 -5
  226. package/dist/core/skill-sync/__tests__/dry-run-wrote-count.test.d.ts +1 -0
  227. package/dist/core/skill-sync/__tests__/dry-run-wrote-count.test.js +57 -0
  228. package/dist/core/skill-sync/builtins.d.ts +42 -0
  229. package/dist/core/skill-sync/builtins.js +112 -0
  230. package/dist/core/skill-sync/claude-plugins.d.ts +23 -0
  231. package/dist/core/skill-sync/claude-plugins.js +71 -0
  232. package/dist/core/skill-sync/engine.d.ts +42 -0
  233. package/dist/core/skill-sync/engine.js +633 -0
  234. package/dist/core/skill-sync/export.d.ts +23 -0
  235. package/dist/core/skill-sync/export.js +86 -0
  236. package/dist/core/skill-sync/manifest.d.ts +64 -0
  237. package/dist/core/skill-sync/manifest.js +181 -0
  238. package/dist/core/skill-sync/profile.d.ts +76 -0
  239. package/dist/core/skill-sync/profile.js +173 -0
  240. package/dist/core/skill-sync/snapshot.d.ts +57 -0
  241. package/dist/core/skill-sync/snapshot.js +120 -0
  242. package/dist/core/spawn.d.ts +14 -0
  243. package/dist/core/spawn.js +29 -9
  244. package/dist/core/substrate/index.d.ts +2 -2
  245. package/dist/core/substrate/index.js +7 -7
  246. package/dist/core/substrate/injected-store.d.ts +10 -0
  247. package/dist/core/substrate/injected-store.js +55 -0
  248. package/dist/core/substrate/on-read.js +68 -6
  249. package/dist/core/substrate/render.d.ts +8 -11
  250. package/dist/core/substrate/render.js +29 -43
  251. package/dist/core/substrate/schema.d.ts +16 -11
  252. package/dist/core/substrate/schema.js +32 -31
  253. package/dist/core/tui/host.d.ts +12 -4
  254. package/dist/core/tui/host.js +280 -149
  255. package/dist/core/view/bridge.d.ts +10 -0
  256. package/dist/core/view/bridge.js +31 -0
  257. package/dist/core/view/chrome.d.ts +9 -0
  258. package/dist/core/view/chrome.js +22 -0
  259. package/dist/core/view/contract.d.ts +171 -0
  260. package/dist/core/view/contract.js +23 -0
  261. package/dist/core/view/loader.d.ts +31 -0
  262. package/dist/core/view/loader.js +188 -0
  263. package/dist/core/view/transport-local.d.ts +7 -0
  264. package/dist/core/view/transport-local.js +70 -0
  265. package/dist/core/view/transport.d.ts +4 -0
  266. package/dist/core/view/transport.js +15 -0
  267. package/dist/daemon/crtrd.d.ts +38 -27
  268. package/dist/daemon/crtrd.js +303 -376
  269. package/dist/daemon/manage.js +6 -1
  270. package/dist/index.js +1 -1
  271. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +28 -20
  272. package/dist/pi-extensions/canvas-context-intro.js +4 -4
  273. package/dist/pi-extensions/canvas-doc-substrate.js +29 -20
  274. package/dist/pi-extensions/canvas-nav.js +35 -385
  275. package/dist/pi-extensions/canvas-recap.d.ts +37 -0
  276. package/dist/pi-extensions/canvas-recap.js +236 -0
  277. package/dist/pi-extensions/canvas-resume.js +2 -1
  278. package/dist/pi-extensions/canvas-stophook.d.ts +15 -13
  279. package/dist/pi-extensions/canvas-stophook.js +119 -103
  280. package/dist/pi-extensions/canvas-view.js +2 -1
  281. package/dist/pi-extensions/widget-order-bus.d.ts +6 -0
  282. package/dist/pi-extensions/widget-order-bus.js +34 -0
  283. package/dist/prompts/view.d.ts +2 -2
  284. package/dist/prompts/view.js +145 -73
  285. package/dist/types.d.ts +1 -6
  286. package/dist/types.js +1 -3
  287. package/dist/web/ViewChrome.d.ts +7 -0
  288. package/dist/web/ViewChrome.js +28 -0
  289. package/dist/web/ViewPane.d.ts +39 -0
  290. package/dist/web/ViewPane.js +48 -0
  291. package/dist/web/index.d.ts +6 -0
  292. package/dist/web/index.js +16 -0
  293. package/dist/web/runtime.d.ts +39 -0
  294. package/dist/web/runtime.js +133 -0
  295. package/dist/web/states.d.ts +24 -0
  296. package/dist/web/states.js +24 -0
  297. package/dist/web/transport-http.d.ts +5 -0
  298. package/dist/web/transport-http.js +28 -0
  299. package/dist/web-client/assets/index-BUvQb4hR.css +2 -0
  300. package/dist/web-client/assets/index-ClLQXYAE.js +10 -0
  301. package/dist/web-client/index.html +13 -0
  302. package/package.json +20 -6
  303. package/dist/builtin-views/canvas/client.mjs +0 -303
  304. package/dist/builtin-views/canvas/view.mjs +0 -576
  305. package/dist/builtin-views/git-pr/client.mjs +0 -440
  306. package/dist/builtin-views/git-pr/view.mjs +0 -675
  307. package/dist/builtin-views/inbox/sources/gmail.mjs +0 -965
  308. package/dist/builtin-views/inbox/sources/linkedin.mjs +0 -427
  309. package/dist/builtin-views/inbox/view.mjs +0 -889
  310. package/dist/builtin-views/linkedin/client.mjs +0 -610
  311. package/dist/builtin-views/linkedin/view.mjs +0 -1171
  312. package/dist/commands/pkg/bridge.d.ts +0 -1
  313. package/dist/commands/pkg/bridge.js +0 -137
  314. package/dist/commands/skill/author.d.ts +0 -3
  315. package/dist/commands/skill/author.js +0 -140
  316. package/dist/commands/skill/shared.d.ts +0 -3
  317. package/dist/commands/skill/shared.js +0 -19
  318. package/dist/commands/skill.d.ts +0 -2
  319. package/dist/commands/skill.js +0 -21
  320. package/dist/commands/tmux-spread.d.ts +0 -2
  321. package/dist/commands/tmux-spread.js +0 -144
  322. package/dist/core/__tests__/full/daemon-liveness-pane.full.test.js +0 -292
  323. package/dist/core/__tests__/full/placement-focus.test.js +0 -309
  324. package/dist/core/__tests__/full/placement-reconcile.test.js +0 -212
  325. package/dist/core/__tests__/full/placement-revive.test.js +0 -238
  326. package/dist/core/__tests__/full/placement-teardown.test.js +0 -221
  327. package/dist/core/__tests__/home-session.test.js +0 -186
  328. package/dist/core/__tests__/relaunch.test.js +0 -335
  329. package/dist/core/bridge-map.d.ts +0 -19
  330. package/dist/core/bridge-map.js +0 -73
  331. package/dist/core/tui/contract.d.ts +0 -83
  332. package/dist/core/tui/contract.js +0 -8
  333. package/dist/core/tui/loader.d.ts +0 -16
  334. package/dist/core/tui/loader.js +0 -94
  335. package/dist/prompts/skill.d.ts +0 -2
  336. package/dist/prompts/skill.js +0 -650
  337. /package/dist/{core/__tests__/full/daemon-liveness-pane.full.test.d.ts → clients/attach/__tests__/action-parity.test.d.ts} +0 -0
  338. /package/dist/{core/__tests__/full/placement-focus.test.d.ts → clients/attach/__tests__/clipboard-image.test.d.ts} +0 -0
  339. /package/dist/{core/__tests__/full/placement-reconcile.test.d.ts → clients/attach/__tests__/editor-newline.test.d.ts} +0 -0
  340. /package/dist/{core/__tests__/full/placement-revive.test.d.ts → clients/attach/__tests__/git-info.test.d.ts} +0 -0
  341. /package/dist/{core/__tests__/full/placement-teardown.test.d.ts → clients/attach/__tests__/onrequest-wired.test.d.ts} +0 -0
  342. /package/dist/{core/__tests__/home-session.test.d.ts → clients/attach/__tests__/reconnect-giveup.test.d.ts} +0 -0
  343. /package/dist/{core/__tests__/relaunch.test.d.ts → clients/attach/__tests__/slash-quit-copy.test.d.ts} +0 -0
@@ -17,6 +17,7 @@ export interface PromoteResult {
17
17
  export declare function promote(nodeId: string, opts?: {
18
18
  kind?: string;
19
19
  resident?: boolean;
20
+ model?: string;
20
21
  }): PromoteResult;
21
22
  export interface YieldResult {
22
23
  meta: NodeMeta;
@@ -32,4 +33,5 @@ export interface YieldResult {
32
33
  * the daemon revives it fresh. */
33
34
  export declare function requestYield(nodeId: string, opts?: {
34
35
  kind?: string;
36
+ model?: string;
35
37
  }): YieldResult;
@@ -36,6 +36,9 @@ export function promote(nodeId, opts = {}) {
36
36
  throw new Error(`unknown node: ${nodeId}`);
37
37
  // The node may specialize as it promotes; default to its current kind.
38
38
  const targetKind = opts.kind ?? node.kind;
39
+ // ...and may raise/change its model tier; default to its current pin (so a
40
+ // promote with no --model preserves whatever it was running on).
41
+ const targetModel = opts.model ?? node.model_override ?? undefined;
39
42
  // Rewrite the launch spec to the target kind's orchestrator persona so the
40
43
  // *next* revive comes back orchestrating in that kind (polymorph stage 2).
41
44
  // nodeEnv reads meta.{kind,mode}, so CRTR_KIND/CRTR_MODE flip immediately for
@@ -46,9 +49,11 @@ export function promote(nodeId, opts = {}) {
46
49
  const { launch } = buildLaunchSpec(targetKind, 'orchestrator', {
47
50
  lifecycle: opts.resident === true ? 'resident' : node.lifecycle,
48
51
  hasManager: node.parent !== null,
49
- // Preserve a caller-pinned model tier across the polymorph (the persona
50
- // default is recomputed fresh for targetKind).
51
- model: node.model_override ?? undefined,
52
+ // A model tier chosen on this call (opts.model) overrides the persona
53
+ // default and is persisted below; absent one, the existing pin carries
54
+ // across the polymorph (the persona default is recomputed fresh for
55
+ // targetKind).
56
+ model: targetModel,
52
57
  });
53
58
  // Seed a barebones roadmap scaffold if absent so the file exists for a
54
59
  // refresh. Pre-fill its Goal from the node's goal doc when present (set at
@@ -67,6 +72,9 @@ export function promote(nodeId, opts = {}) {
67
72
  kind: targetKind,
68
73
  mode: 'orchestrator',
69
74
  launch,
75
+ // Persist a newly-chosen tier so it is durable across future revives; omit
76
+ // when unchanged so the existing pin (or persona default) stands.
77
+ ...(opts.model !== undefined ? { model_override: opts.model } : {}),
70
78
  ...(opts.resident === true ? { lifecycle: 'resident' } : {}),
71
79
  });
72
80
  return {
@@ -86,14 +94,24 @@ export function requestYield(nodeId, opts = {}) {
86
94
  const node = getNode(nodeId);
87
95
  if (node === null)
88
96
  throw new Error(`unknown node: ${nodeId}`);
97
+ // A yield may also RESHAPE the node as it refreshes — change kind and/or raise
98
+ // model tier. promote() is idempotent (on an already-orchestrator node it just
99
+ // rewrites the launch spec), so it doubles as the apply-path for that reshape.
100
+ const reshaping = opts.kind !== undefined || opts.model !== undefined;
101
+ const wasBase = node.mode !== 'orchestrator';
89
102
  let promoted = false;
90
- if (node.mode !== 'orchestrator') {
103
+ if (wasBase || reshaping) {
91
104
  // A yield needs a ROADMAP to refresh against — i.e. orchestrator mode, not
92
105
  // resident lifecycle. Ensure orchestrator (which seeds the roadmap + memory)
93
106
  // WITHOUT forcing resident: a terminal/orchestrator yields fine, since the
94
107
  // daemon's refresh-revive keys on intent='refresh', not lifecycle.
95
- promote(nodeId, opts.kind !== undefined ? { kind: opts.kind } : {});
96
- promoted = true;
108
+ promote(nodeId, {
109
+ ...(opts.kind !== undefined ? { kind: opts.kind } : {}),
110
+ ...(opts.model !== undefined ? { model: opts.model } : {}),
111
+ });
112
+ // "promoted" means a base node became an orchestrator — not a mere reshape
113
+ // of an already-orchestrator node.
114
+ promoted = wasBase;
97
115
  }
98
116
  // Mark the intent; the stophook enacts the shutdown, the daemon the revive.
99
117
  transition(nodeId, 'yield');
@@ -0,0 +1,8 @@
1
+ /** Ask pi headlessly for a three-fragment recap of `conversation`, async. Invokes
2
+ * `onRecap` with the parsed fragment lines on success, or never (silent) on any
3
+ * failure — non-zero exit, timeout, empty/garbled output. Owns the subprocess
4
+ * mechanics — crucially it hands pi an immediate stdin EOF: `pi -p` reads stdin,
5
+ * and execFile's default stdin is an OPEN pipe that never closes, so without
6
+ * this pi blocks waiting for EOF and the call exits non-zero (the same gotcha
7
+ * naming.ts documents). */
8
+ export declare function generateRecap(conversation: string, onRecap: (lines: string[]) => void): void;
@@ -0,0 +1,107 @@
1
+ // Inactivity recap — turn a dormant node's conversation into a three-fragment
2
+ // "where it left off" card (goal / doing-now / next) for the recap widget.
3
+ //
4
+ // One entry point: generateRecap — async (execFile, non-blocking), mirroring
5
+ // naming.ts's headless-`pi -p` pattern exactly. It runs Haiku over the literal
6
+ // back-and-forth (the caller concatenates user+assistant text) with a stripped-
7
+ // down pi invocation (no tools/session/context/extensions/skills), so it's fast
8
+ // and side-effect free and can never recurse into another spawn.
9
+ //
10
+ // Best-effort and silent on failure: a non-zero exit, timeout, empty or garbled
11
+ // output resolves to NO recap (the caller shows nothing). The recap is throwaway
12
+ // idle chrome — there is no local fallback, unlike naming, because a wrong or
13
+ // stale recap is worse than none.
14
+ //
15
+ // Plain TS-with-types — no imports from @earendil-works/* so it compiles inside
16
+ // crouter's own tsc build without a dep on the pi packages.
17
+ import { execFile } from 'node:child_process';
18
+ /** Wall-clock budget for the headless pi call before we give up (no recap). */
19
+ const RECAP_TIMEOUT_MS = 25_000;
20
+ /** Default recap model — Haiku. A recap is a one-shot summarization, so we pin
21
+ * the small/fast model rather than the node's heavyweight default. Override
22
+ * with CRTR_RECAP_MODEL (mirrors CRTR_NAME_MODEL). */
23
+ const DEFAULT_RECAP_MODEL = 'anthropic/claude-haiku-4-5';
24
+ const RECAP_SYSTEM_PROMPT = 'You write a terse "where we left off" recap of a coding-agent work session, ' +
25
+ 'read at a glance by someone returning to a paused conversation. You are given ' +
26
+ 'the literal back-and-forth between the user and the agent. Output EXACTLY three ' +
27
+ 'lines, nothing else — no labels, no numbering, no bullets, no punctuation at the ' +
28
+ 'end of a line, no prose:\n' +
29
+ ' Line 1: the GOAL — what this session is ultimately trying to achieve.\n' +
30
+ ' Line 2: DOING NOW — what was just happening / the active piece of work.\n' +
31
+ ' Line 3: NEXT — the immediate next step.\n' +
32
+ 'Each line is a short FRAGMENT, not a sentence (e.g. `wire up recap widget above editor`, ' +
33
+ 'not `We are wiring up the recap widget.`). Keep each under ~60 characters. ' +
34
+ 'If the session has barely started or you cannot tell, still give your best three ' +
35
+ 'fragments from whatever text exists. Output JUST the three lines.';
36
+ /** Put the conversation FIRST in a delimited block, then the instruction, so the
37
+ * model reads the content before being told what to do. */
38
+ function recapUserPrompt(conversation) {
39
+ return `<conversation>\n${conversation}\n</conversation>\n\nWrite the three-line recap of the session above (goal / doing-now / next). Output JUST the three lines.`;
40
+ }
41
+ /** The pi argv for a headless recap request. Stripped down (no tools, session,
42
+ * context files, extensions, skills, templates, themes) so it's fast and
43
+ * side-effect free. Pinned to Haiku with thinking off. Override the model with
44
+ * CRTR_RECAP_MODEL. */
45
+ function recapArgs(conversation) {
46
+ const override = process.env['CRTR_RECAP_MODEL'];
47
+ const model = override !== undefined && override.trim() !== '' ? override.trim() : DEFAULT_RECAP_MODEL;
48
+ const argv = [
49
+ '-p',
50
+ '--no-session',
51
+ '--no-context-files',
52
+ '--no-extensions',
53
+ '--no-skills',
54
+ '--no-prompt-templates',
55
+ '--no-themes',
56
+ '--no-tools',
57
+ '--mode', 'text',
58
+ '--thinking', 'off',
59
+ '--model', model,
60
+ '--system-prompt', RECAP_SYSTEM_PROMPT,
61
+ recapUserPrompt(conversation),
62
+ ];
63
+ return argv;
64
+ }
65
+ /** Parse the model's raw stdout into up to three short fragment lines. Strips any
66
+ * stray leading labels/bullets the model may have added despite instructions,
67
+ * drops empties, and hard-caps line length so a runaway line can't blow up the
68
+ * widget. Returns [] when nothing usable survives (→ no recap). */
69
+ function parseRecap(stdout) {
70
+ const LINE_CAP = 72;
71
+ const lines = stdout
72
+ .split('\n')
73
+ .map((l) => l.trim())
74
+ // Strip a leading `goal:` / `now:` / `next:` / `- ` / `1.` style prefix.
75
+ .map((l) => l.replace(/^(?:[-*•]\s*)?(?:\d+[.)]\s*)?(?:goal|now|doing(?:[\s-]now)?|next)\s*[:\-]\s*/i, '').trim())
76
+ .filter((l) => l !== '');
77
+ return lines.slice(0, 3).map((l) => (l.length > LINE_CAP ? l.slice(0, LINE_CAP) : l));
78
+ }
79
+ /** Ask pi headlessly for a three-fragment recap of `conversation`, async. Invokes
80
+ * `onRecap` with the parsed fragment lines on success, or never (silent) on any
81
+ * failure — non-zero exit, timeout, empty/garbled output. Owns the subprocess
82
+ * mechanics — crucially it hands pi an immediate stdin EOF: `pi -p` reads stdin,
83
+ * and execFile's default stdin is an OPEN pipe that never closes, so without
84
+ * this pi blocks waiting for EOF and the call exits non-zero (the same gotcha
85
+ * naming.ts documents). */
86
+ export function generateRecap(conversation, onRecap) {
87
+ const body = (conversation ?? '').trim();
88
+ if (body === '')
89
+ return;
90
+ try {
91
+ const child = execFile('pi', recapArgs(body), { encoding: 'utf8', timeout: RECAP_TIMEOUT_MS }, (err, stdout) => {
92
+ if (err || typeof stdout !== 'string')
93
+ return; // silent — no recap
94
+ const lines = parseRecap(stdout);
95
+ if (lines.length === 0)
96
+ return;
97
+ try {
98
+ onRecap(lines);
99
+ }
100
+ catch { /* best-effort */ }
101
+ });
102
+ child.stdin?.end(); // immediate EOF — see the doc above
103
+ }
104
+ catch {
105
+ // best-effort: no recap
106
+ }
107
+ }
@@ -5,8 +5,8 @@
5
5
  //
6
6
  // 1. Finalize — push the agent's last surfaced message as a `final` report so
7
7
  // every subscriber/manager waiting on it is unblocked, and mark it done.
8
- // 2. Close — kill the agent's pi (respawn-pane -k tears it down in place).
9
- // 3. Recycle — boot a fresh resident root in that same pane (a new `crtr`).
8
+ // 2. Close — tear the agent's broker engine down (the pane is only a viewer).
9
+ // 3. Recycle — boot a fresh resident broker root the pane re-attaches to.
10
10
  //
11
11
  // NOT to be confused with `node demote` (flip-to-terminal IN PLACE, which keeps
12
12
  // the agent focused and running): recycle ENDS this agent and boots a brand-new
@@ -17,14 +17,13 @@
17
17
  // message) — falling back to a short note when it never reported.
18
18
  import { readdirSync, readFileSync, statSync } from 'node:fs';
19
19
  import { join } from 'node:path';
20
- import { getNode, setPresence, updateNode, setFocusOccupant, fullName } from '../canvas/index.js';
20
+ import { getNode, setPresence, setFocusOccupant, fullName } from '../canvas/index.js';
21
21
  import { reportsDir } from '../canvas/paths.js';
22
22
  import { pushFinal } from '../feed/feed.js';
23
- import { spawnNode, nodeSession, rootOfSpine } from './nodes.js';
23
+ import { spawnNode, rootOfSpine } from './nodes.js';
24
24
  import { buildLaunchSpec, buildPiArgv } from './launch.js';
25
- import { FRONT_DOOR_ENV } from './front-door.js';
26
- import { focusOf, recycleFocusPane, piCommand, paneLocation, respawnPaneSync, setPaneOption, waitForBrokerViewSocket, viewerSplitEnv } from './placement.js';
27
- import { hostFor } from './host.js';
25
+ import { focusOf, respawnPaneSync, setPaneOption, waitForBrokerViewSocket, viewerSplitEnv } from './placement.js';
26
+ import { headlessBrokerHost } from './host.js';
28
27
  import { ensureDaemon } from '../../daemon/manage.js';
29
28
  /** The agent's most recent surfaced message: the newest reports/*.md body with
30
29
  * its YAML frontmatter stripped. Empty string when the node never reported. */
@@ -74,19 +73,15 @@ export async function recycleNode(nodeId, callerPane) {
74
73
  finalized = true;
75
74
  }
76
75
  catch { /* recycle the pane even if the report failed */ }
77
- // A broker node's pane is a VIEWER (`crtr attach`), not its engine: the engine
78
- // is the detached broker process, so respawn-pane -k below would only kill the
79
- // viewer, never the engine. Route teardown through the Host seam so the broker
80
- // PROCESS exits and releases the sole .jsonl writer (mirrors the T12
81
- // close.ts/reset.ts fix; review reuse MINOR-3). Status is already flipped done
82
- // by pushFinal above (crash-safe order: the daemon won't revive a done node).
83
- const isBroker = meta.host_kind === 'broker';
84
- if (isBroker) {
85
- try {
86
- hostFor(meta).teardown(nodeId);
87
- }
88
- catch { /* best-effort */ }
76
+ // The node's pane is a VIEWER (`crtr attach`), not its engine: the engine is
77
+ // the detached broker process, so respawn-pane -k below would only kill the
78
+ // viewer, never the engine. Tear the broker PROCESS down so it exits and
79
+ // releases the sole .jsonl writer. Status is already flipped done by pushFinal
80
+ // above (crash-safe order: the daemon won't revive a done node).
81
+ try {
82
+ headlessBrokerHost.teardown(nodeId);
89
83
  }
84
+ catch { /* best-effort */ }
90
85
  // Capture M's focus viewport (if any) BEFORE nulling — the fresh root inherits
91
86
  // it (the SAME focus row + pane). The demoted node no longer holds a pane: it is
92
87
  // being reclaimed.
@@ -95,17 +90,13 @@ export async function recycleNode(nodeId, callerPane) {
95
90
  setPresence(nodeId, { pane: null, window: null, tmux_session: null });
96
91
  }
97
92
  catch { /* best-effort */ }
98
- // 2 + 3. Recycle — boot a fresh resident root for the SAME pane, PRESERVING
99
- // the recycled node's host model: a tmux node recycles into a tmux root in the
100
- // pane; a broker node recycles into a fresh BROKER root the pane re-attaches to
101
- // (broker-is-the-host — the viewer pane stays a viewer, never becomes an engine
102
- // pane). Without preserving host_kind, recycling a broker node from its viewer
103
- // would silently respawn the viewer into a tmux pi root.
93
+ // 2 + 3. Recycle — boot a fresh resident BROKER root for the SAME pane: the
94
+ // viewer pane re-attaches to the fresh broker (broker-is-the-host the viewer
95
+ // pane stays a viewer, never becomes an engine pane).
104
96
  try {
105
97
  ensureDaemon();
106
98
  }
107
99
  catch { /* daemon is best-effort */ }
108
- const loc = paneLocation(pane);
109
100
  const { launch } = buildLaunchSpec('general', 'base', { lifecycle: 'resident', hasManager: false });
110
101
  const root = spawnNode({
111
102
  kind: 'general',
@@ -115,12 +106,7 @@ export async function recycleNode(nodeId, callerPane) {
115
106
  name: 'general',
116
107
  parent: null,
117
108
  launch,
118
- hostKind: isBroker ? 'broker' : 'tmux',
119
109
  });
120
- // REVIVE-HOME: a recycled root's durable revive target is the session
121
- // of the pane it was recycled into (the one place home_session is rewritten
122
- // after birth). Falls back to the backstage when the pane can't be located.
123
- updateNode(root.node_id, { home_session: loc?.session ?? nodeSession() });
124
110
  // Hand the viewport to the fresh root: reuse M's focus row over the SAME pane
125
111
  // (respawn-pane -k below keeps the %id), so the user keeps watching this slot.
126
112
  if (f !== null) {
@@ -131,33 +117,12 @@ export async function recycleNode(nodeId, callerPane) {
131
117
  }
132
118
  const fresh = getNode(root.node_id);
133
119
  const inv = buildPiArgv(fresh);
134
- // CRTR_ROOT_SESSION/CRTR_SUBTREE route the fresh root's children to the
135
- // backstage (both consumers below read this one authoritative env). FRONT_DOOR
136
- // is added per-consumer: the tmux command const adds it; the broker host sets
137
- // it itself, so the broker branch omits it.
138
- inv.env = { ...inv.env, CRTR_ROOT_SESSION: nodeSession(), CRTR_SUBTREE: rootOfSpine(root.node_id) };
139
- const ok = isBroker
140
- ? recycleBrokerViewer(fresh, pane, inv)
141
- : recycleTmuxRoot(root.node_id, pane, {
142
- command: piCommand(inv.argv),
143
- env: { ...inv.env, [FRONT_DOOR_ENV]: '1' },
144
- cwd: meta.cwd,
145
- name: fullName(fresh),
146
- });
120
+ // CRTR_SUBTREE groups the fresh root's subtree; FRONT_DOOR is set by the broker
121
+ // host itself, so it is not added here.
122
+ inv.env = { ...inv.env, CRTR_SUBTREE: rootOfSpine(root.node_id) };
123
+ const ok = recycleBrokerViewer(fresh, pane, inv);
147
124
  return { recycled: ok, finalized, newRoot: root.node_id, delivered };
148
125
  }
149
- /** Recycle a TMUX root into `pane`: respawn-pane -k boots the fresh pi engine in
150
- * place. Clears any stale `@crtr_node` viewer tag first — a prior `crtr attach`
151
- * in this pane may have left one (tmux pane options survive respawn-pane), and
152
- * since nodeInPane checks the tag BEFORE the window, a stale tag would shadow
153
- * the real window→node lookup for the fresh tmux engine now in the pane. */
154
- function recycleTmuxRoot(nodeId, pane, launch) {
155
- try {
156
- setPaneOption(pane, '@crtr_node', '');
157
- }
158
- catch { /* best-effort */ }
159
- return recycleFocusPane(nodeId, pane, { ...launch, resuming: false });
160
- }
161
126
  /** Recycle a BROKER root into `pane`: the fresh root is broker-hosted, so its
162
127
  * engine runs in a DETACHED broker, not the pane. Birth-launch that broker via
163
128
  * the Host seam (mirrors spawnChild's birth path — the host records its pid),
@@ -167,13 +132,12 @@ function recycleTmuxRoot(nodeId, pane, launch) {
167
132
  * pane was not respawned) when the broker never serves — the fresh root row
168
133
  * still exists, broker-hosted, for the daemon to revive. */
169
134
  function recycleBrokerViewer(fresh, pane, inv) {
170
- hostFor(fresh).launch(fresh.node_id, inv, { cwd: fresh.cwd, name: fullName(fresh), resuming: false });
135
+ headlessBrokerHost.launch(fresh.node_id, inv, { cwd: fresh.cwd, name: fullName(fresh), resuming: false });
171
136
  if (!waitForBrokerViewSocket(fresh.node_id))
172
137
  return false;
173
- // Clear the finalized node's stale `@crtr_node` tag before respawn (symmetry
174
- // with recycleTmuxRoot) so the tag never names a done node during the gap
175
- // before the new `crtr attach` re-tags on connect. Node ids are shell-safe
176
- // identifiers; no quoting needed.
138
+ // Clear the finalized node's stale `@crtr_node` tag before respawn so the tag
139
+ // never names a done node during the gap before the new `crtr attach` re-tags
140
+ // on connect. Node ids are shell-safe identifiers; no quoting needed.
177
141
  try {
178
142
  setPaneOption(pane, '@crtr_node', '');
179
143
  }
@@ -1,56 +1,62 @@
1
+ import { headlessBrokerHost } from './host.js';
2
+ import { respawnPaneSync } from './placement.js';
1
3
  /** Reap the descendant sub-DAG of `rootId`: mark each **canceled** (the user
2
4
  * moved on — a clean teardown, NOT a fault) + clear intent FIRST, then kill its
3
5
  * window (closes the daemon revive race). Edges are LEFT INTACT — descendants
4
6
  * keep parent=rootId. No wipe. Returns the reaped ids.
5
7
  *
6
8
  * Why `canceled` (A5, human-confirmed 2026-06-06): an externally-reaped node —
7
- * whether via `node close` OR a root reset/relaunch — did not finish its OWN
8
- * work, so it unifies on `canceled`; `done` is reserved for finalize. Why
9
- * marking is STILL explicit: a `closeWindow`/`respawn-pane -k` kill is abrupt
10
- * and fires NO clean `session_shutdown`, so the general quit→done rule does NOT
11
- * auto-resolve a force-killed descendant — we mark it `canceled` here via the
12
- * same `cancel` event the close cascade uses. Shared by relaunchRoot (option C)
13
- * and resetRoot's in-place fallback, so both leave their descendants `canceled`. */
9
+ * whether via `node close` OR a root reset — did not finish its OWN work, so it
10
+ * unifies on `canceled`; `done` is reserved for finalize. Why marking is STILL
11
+ * explicit: an abrupt broker teardown fires NO clean `session_shutdown`, so the
12
+ * general quit→done rule does NOT auto-resolve a force-killed descendant — we
13
+ * mark it `canceled` here via the same `cancel` event the close cascade uses. */
14
14
  export declare function reapDescendants(rootId: string): string[];
15
+ /** Injectable host/viewer seam, so the fast-tier test drives relaunchRoot's pure
16
+ * DB transitions without a real broker or tmux. Each field defaults to its
17
+ * production verb. */
18
+ export interface RelaunchDeps {
19
+ /** Boot the new node's detached broker engine. Default: headlessBrokerHost.launch. */
20
+ launchBroker?: typeof headlessBrokerHost.launch;
21
+ /** Wait for the new broker's view.sock to accept. Default: waitForBrokerViewSocket. */
22
+ waitForViewSocket?: (nodeId: string) => boolean;
23
+ /** Re-exec the viewer pane onto the new node. Default: respawnPaneSync. */
24
+ respawnViewer?: typeof respawnPaneSync;
25
+ /** Tear the old broker down. Default: headlessBrokerHost.teardown. */
26
+ teardownBroker?: typeof headlessBrokerHost.teardown;
27
+ }
28
+ export interface RelaunchRootResult {
29
+ /** The freshly-minted node now driving this pane. */
30
+ newNodeId: string;
31
+ }
32
+ /** Relaunch a ROOT on `/new`: park the old root `done` (kept as history) and
33
+ * mint a fresh node id + broker in the same pane/cwd, re-pointing the viewer at
34
+ * it. The new broker is booted FIRST and its pid confirmed BEFORE the old root
35
+ * is touched, so any pre-commit failure leaves the old root fully intact and
36
+ * live. Returns null when `oldId` is not a relaunchable root (unknown, a child,
37
+ * or already parked), or when the new broker failed to launch. */
38
+ export declare function relaunchRoot(oldId: string, deps?: RelaunchDeps): RelaunchRootResult | null;
15
39
  export interface ResetRootResult {
16
- /** Descendant node ids torn down (window killed + marked canceled). */
40
+ /** Descendant node ids torn down. Always empty a child `/new` reaps nothing. */
17
41
  reaped: string[];
18
- /** Direct subscriptions dropped off the root. */
42
+ /** Direct subscriptions dropped. Always empty — a child `/new` detaches nothing. */
19
43
  detached: string[];
20
- /** True when the node was a root and a full reset ran. */
44
+ /** Always false a child `/new` is not a graph reset (roots route to relaunchRoot). */
21
45
  reset: boolean;
22
46
  }
23
- /** Reset a root node to a pristine, empty graph (the legacy `/new` semantics
24
- * now used as the no-pane fallback and the non-root session-id refresh).
25
- *
26
- * For a non-root (spawned child), a `/new` is not a graph reset — we only
27
- * refresh its session id so a later `--session <id>` wakes the right conversation. */
47
+ /** Refresh a non-root child's pi session id on `/new`, so a later
48
+ * `--session <id>` wakes the right conversation. A `/new` on a child is NOT a
49
+ * graph reset — a root's `/new` is handled by relaunchRoot, never here; a root
50
+ * that reaches this is a no-op. */
28
51
  export declare function resetRoot(nodeId: string, newSessionId?: string, newSessionFile?: string | null): ResetRootResult;
29
- /** Injectable respawn seam tests pass a double since tmux isn't available. */
30
- export interface RelaunchDeps {
31
- relaunchRootInPane?: (nodeId: string, pane: string) => void;
32
- }
33
- export type HandleNewSessionPath = 'relaunch' | 'reset-root' | 'reset-child' | 'noop';
52
+ export type HandleNewSessionPath = 'reset-child' | 'noop';
34
53
  export interface HandleNewSessionResult {
35
54
  path: HandleNewSessionPath;
36
- newNodeId?: string;
37
55
  }
38
- /** The single entry the stophook calls on a detected `/new` (session id change).
39
- * Policy lives here so the stophook stays thin and this stays unit-testable:
40
- * - non-root child resetRoot(nodeId, newSessionId) (session-id refresh only)
41
- * - root + pane present → relaunchRoot(nodeId, pane) (option C)
42
- * - root + no pane (no tmux) → resetRoot(nodeId, newSessionId) (in-place fallback)
43
- * On a respawn-dispatch failure the live pi never died, so we degrade to the
44
- * legacy in-place reset. */
45
- export declare function handleNewSession(nodeId: string, newSessionId: string, pane: string | undefined, deps?: RelaunchDeps, newSessionFile?: string | null): HandleNewSessionResult;
46
- /** Park the old root + create+launch a fresh root in `pane` (option C). All DB
47
- * writes are synchronous and happen BEFORE the respawn (the respawn kills the
48
- * caller). Returns the new node id, or null on a defensive guard (not a root /
49
- * already parked). Throws only if the respawn dispatch fails — and self-rolls-
50
- * back its writes first so the caller can degrade to resetRoot. */
51
- export declare function relaunchRoot(oldId: string, pane: string, deps?: RelaunchDeps): {
52
- newNodeId: string;
53
- } | null;
56
+ /** The child-side `/new` entry the stophook calls (the root side goes to
57
+ * relaunchRoot directly). The broker already drove the engine-side new_session;
58
+ * this only refreshes the child's session id on the SAME node id. */
59
+ export declare function handleNewSession(nodeId: string, newSessionId: string, newSessionFile?: string | null): HandleNewSessionResult;
54
60
  /** Resolve a cleanly-exiting node to `done`. Returns true iff it transitioned.
55
61
  * Guard: only a real quit, and only a node still active|idle with no pending
56
62
  * intent — so it never clobbers a node already routed by agent_end to done