@north-light/crouter 0.3.173 → 0.3.175

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 (674) hide show
  1. package/bin/runtime-selector.mjs +8 -1
  2. package/dist/api/__tests__/{client.test.js → serial/client.test.js} +2 -135
  3. package/dist/api/client.d.ts +12 -21
  4. package/dist/api/client.js +22 -31
  5. package/dist/api/dto/broker-ops.d.ts +158 -0
  6. package/dist/api/dto/broker-ops.js +6 -0
  7. package/dist/api/dto/crons.d.ts +6 -0
  8. package/dist/api/dto/human.d.ts +7 -1
  9. package/dist/api/dto/inbox.d.ts +1 -71
  10. package/dist/api/dto/inbox.js +1 -9
  11. package/dist/api/dto/nodes.d.ts +6 -7
  12. package/dist/api/dto/reviews.d.ts +1 -11
  13. package/dist/api/routes.d.ts +7 -4
  14. package/dist/api/routes.js +8 -5
  15. package/dist/build-root.js +3 -3
  16. package/dist/builtin-memory/04-base-worker.md +1 -4
  17. package/dist/builtin-memory/05-kinds/advisor/00-base.md +1 -5
  18. package/dist/builtin-memory/05-kinds/advisor/01-orchestrator.md +2 -7
  19. package/dist/builtin-memory/05-kinds/design/00-base.md +1 -6
  20. package/dist/builtin-memory/05-kinds/developer/00-base.md +1 -6
  21. package/dist/builtin-memory/05-kinds/explore/00-base.md +1 -4
  22. package/dist/builtin-memory/05-kinds/explore/01-orchestrator.md +1 -2
  23. package/dist/builtin-memory/05-kinds/general/00-base.md +1 -3
  24. package/dist/builtin-memory/05-kinds/plan/00-base.md +1 -6
  25. package/dist/builtin-memory/05-kinds/plan/reviewers/00-base.md +1 -2
  26. package/dist/builtin-memory/05-kinds/plan/reviewers/architecture-fit.md +1 -3
  27. package/dist/builtin-memory/05-kinds/plan/reviewers/code-smells.md +1 -3
  28. package/dist/builtin-memory/05-kinds/plan/reviewers/pattern-consistency.md +1 -3
  29. package/dist/builtin-memory/05-kinds/plan/reviewers/requirements-coverage.md +1 -3
  30. package/dist/builtin-memory/05-kinds/plan/reviewers/security.md +1 -4
  31. package/dist/builtin-memory/05-kinds/review/companion/00-base.md +2 -3
  32. package/dist/builtin-memory/05-kinds/spec/00-base.md +1 -2
  33. package/dist/builtin-memory/advisor/council.md +1 -6
  34. package/dist/builtin-memory/design.md +2 -7
  35. package/dist/builtin-memory/development.md +9 -14
  36. package/dist/builtin-memory/internal/marketplaces.md +2 -6
  37. package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
  38. package/dist/builtin-memory/internal/plugins.md +2 -8
  39. package/dist/builtin-memory/internal/storage-tiers.md +1 -2
  40. package/dist/builtin-memory/testing.md +41 -0
  41. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/{provider-rotation.test.ts → serial/provider-rotation.test.ts} +27 -179
  42. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/claude-plugin-commands.ts +5 -15
  43. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/frontmatter-rules/index.ts +1 -28
  44. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +43 -88
  45. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +7 -1
  46. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +9 -1
  47. package/dist/cli.js +2 -2
  48. package/dist/clients/attach/__tests__/attach-remote-readonly.test.js +37 -131
  49. package/dist/clients/attach/__tests__/chat-view-snapshot-ordering.test.js +71 -152
  50. package/dist/clients/attach/__tests__/context-message.test.js +16 -174
  51. package/dist/clients/attach/__tests__/crtr-output.test.js +36 -2069
  52. package/dist/clients/attach/__tests__/diagram.test.js +2 -2
  53. package/dist/clients/attach/__tests__/edit-diff.test.js +0 -4
  54. package/dist/clients/attach/__tests__/file-review-focus.test.js +2 -1
  55. package/dist/clients/attach/__tests__/group-activity.test.js +40 -229
  56. package/dist/clients/attach/__tests__/oauth-dialog-lifecycle.test.js +26 -76
  57. package/dist/clients/attach/__tests__/prompt-preview.test.js +4 -70
  58. package/dist/clients/attach/__tests__/ref-autocomplete.test.js +11 -125
  59. package/dist/clients/attach/__tests__/titled-editor-preview.test.js +14 -205
  60. package/dist/clients/attach/command.d.ts +2 -1
  61. package/dist/clients/attach/command.js +81 -76
  62. package/dist/clients/attach/input/capabilities.d.ts +27 -0
  63. package/dist/clients/attach/input/capabilities.js +96 -0
  64. package/dist/clients/attach/input/controller.d.ts +20 -182
  65. package/dist/clients/attach/input/controller.js +128 -537
  66. package/dist/clients/attach/input/overlay-owner.d.ts +41 -0
  67. package/dist/clients/attach/input/overlay-owner.js +199 -0
  68. package/dist/clients/attach/overlays/file-review.d.ts +0 -4
  69. package/dist/clients/attach/overlays/file-review.js +13 -5
  70. package/dist/clients/attach/overlays/graph.js +2 -10
  71. package/dist/clients/attach/render/chat-view.d.ts +4 -3
  72. package/dist/clients/attach/render/chat-view.js +39 -33
  73. package/dist/clients/attach/render/group-activity.d.ts +1 -0
  74. package/dist/clients/attach/render/group-activity.js +20 -13
  75. package/dist/clients/attach/render/group-recap.js +12 -3
  76. package/dist/clients/attach/session/connection.js +9 -15
  77. package/dist/clients/attach/session/editor-inventory.d.ts +6 -5
  78. package/dist/clients/attach/session/editor-inventory.js +7 -8
  79. package/dist/clients/attach/session/file-links.d.ts +13 -0
  80. package/dist/clients/attach/session/file-links.js +107 -0
  81. package/dist/clients/attach/session/frame.d.ts +3 -0
  82. package/dist/clients/attach/session/frame.js +10 -1
  83. package/dist/clients/attach/session/frames.js +2 -3
  84. package/dist/clients/attach/session/input-wiring.d.ts +4 -1
  85. package/dist/clients/attach/session/input-wiring.js +15 -14
  86. package/dist/clients/attach/session/mouse.d.ts +6 -1
  87. package/dist/clients/attach/session/mouse.js +8 -5
  88. package/dist/clients/attach/session/profile-files.js +18 -12
  89. package/dist/clients/attach/session/reconnect.js +1 -1
  90. package/dist/clients/attach/session/state-sync.js +1 -2
  91. package/dist/clients/attach/session/surface-host.d.ts +3 -2
  92. package/dist/clients/attach/session/surface-host.js +4 -4
  93. package/dist/clients/attach/slash/dispatch.d.ts +8 -31
  94. package/dist/clients/attach/slash/dispatch.js +34 -81
  95. package/dist/clients/attach/viewer.js +820 -860
  96. package/dist/clients/conversation/projection.d.ts +79 -0
  97. package/dist/clients/conversation/projection.js +341 -0
  98. package/dist/clients/inbox/__tests__/serial/inbox-controller.test.js +159 -0
  99. package/dist/clients/inbox/__tests__/serial/mount-panel.test.js +151 -0
  100. package/dist/clients/inbox/controller.d.ts +0 -4
  101. package/dist/clients/inbox/controller.js +0 -2
  102. package/dist/clients/inbox/review/__tests__/review-core.test.js +4 -293
  103. package/dist/clients/inbox/review/__tests__/teardown-notice.test.js +100 -0
  104. package/dist/clients/inbox/review/comments-client.d.ts +3 -2
  105. package/dist/clients/inbox/review/comments-client.js +12 -12
  106. package/dist/clients/inbox/review/companion-pane.d.ts +30 -0
  107. package/dist/clients/inbox/review/companion-pane.js +86 -0
  108. package/dist/clients/inbox/review/document-surface.d.ts +182 -0
  109. package/dist/clients/inbox/review/{document-region.js → document-surface.js} +252 -48
  110. package/dist/clients/inbox/review/frame.js +5 -4
  111. package/dist/clients/inbox/review/launch.d.ts +8 -8
  112. package/dist/clients/inbox/review/launch.js +52 -92
  113. package/dist/clients/inbox/review/nvim.d.ts +2 -0
  114. package/dist/clients/inbox/review/nvim.js +14 -12
  115. package/dist/clients/inbox/review/review-client.d.ts +12 -8
  116. package/dist/clients/inbox/review/review-client.js +46 -35
  117. package/dist/clients/inbox/review-adapter.d.ts +3 -10
  118. package/dist/clients/inbox/review-adapter.js +27 -19
  119. package/dist/clients/inbox/surface.d.ts +0 -4
  120. package/dist/clients/inbox/surface.js +0 -2
  121. package/dist/clients/surfaces/host.d.ts +11 -3
  122. package/dist/commands/__tests__/api-client-cold-start-diagnostic.test.js +7 -34
  123. package/dist/commands/__tests__/human.test.js +11 -322
  124. package/dist/commands/api-client.d.ts +5 -5
  125. package/dist/commands/api-client.js +6 -85
  126. package/dist/commands/canvas-browse.js +3 -29
  127. package/dist/commands/canvas-config.js +1 -1
  128. package/dist/commands/canvas-use.js +3 -3
  129. package/dist/commands/canvas.js +1 -1
  130. package/dist/commands/cron.js +5 -1
  131. package/dist/commands/human/queue.d.ts +0 -4
  132. package/dist/commands/human/queue.js +7 -40
  133. package/dist/commands/memory/list.d.ts +14 -0
  134. package/dist/commands/memory/list.js +35 -31
  135. package/dist/commands/memory/read.d.ts +7 -0
  136. package/dist/commands/memory/read.js +14 -8
  137. package/dist/commands/memory/write.js +13 -12
  138. package/dist/commands/node/bash.d.ts +1 -0
  139. package/dist/commands/node/bash.js +198 -0
  140. package/dist/commands/node/create.d.ts +23 -0
  141. package/dist/commands/node/create.js +207 -0
  142. package/dist/commands/node/inspect.d.ts +2 -0
  143. package/dist/commands/node/inspect.js +302 -0
  144. package/dist/commands/node/lifecycle.d.ts +4 -0
  145. package/dist/commands/node/lifecycle.js +415 -0
  146. package/dist/commands/node/message.d.ts +1 -0
  147. package/dist/commands/node/message.js +164 -0
  148. package/dist/commands/node/pyramid.d.ts +2 -0
  149. package/dist/commands/node/pyramid.js +79 -0
  150. package/dist/commands/node/subscription.d.ts +1 -0
  151. package/dist/commands/node/subscription.js +82 -0
  152. package/dist/commands/node/wait.d.ts +1 -0
  153. package/dist/commands/node/wait.js +159 -0
  154. package/dist/commands/node-lifecycle-revive.js +10 -57
  155. package/dist/commands/node.d.ts +0 -42
  156. package/dist/commands/node.js +11 -2065
  157. package/dist/commands/search.js +1 -1
  158. package/dist/commands/surface/node/cycle.d.ts +1 -0
  159. package/dist/commands/surface/node/cycle.js +83 -0
  160. package/dist/commands/surface/node/focus.d.ts +1 -0
  161. package/dist/commands/surface/node/focus.js +67 -0
  162. package/dist/commands/surface/node/id.d.ts +1 -0
  163. package/dist/commands/surface/node/id.js +38 -0
  164. package/dist/commands/surface/node/pin.d.ts +1 -0
  165. package/dist/commands/surface/node/pin.js +42 -0
  166. package/dist/commands/surface/node/placement.d.ts +46 -0
  167. package/dist/commands/surface/node/placement.js +124 -0
  168. package/dist/commands/surface-node.js +4 -1
  169. package/dist/commands/surface-reload.js +1 -2
  170. package/dist/commands/surface-tmux-spread.js +1 -1
  171. package/dist/commands/surface.js +5 -20
  172. package/dist/commands/sys/__tests__/setup-core.test.js +18 -271
  173. package/dist/commands/sys/config.js +6 -6
  174. package/dist/commands/sys/logs.js +1 -1
  175. package/dist/commands/sys/panels/broker-limits-panel.d.ts +17 -0
  176. package/dist/commands/sys/panels/broker-limits-panel.js +104 -0
  177. package/dist/commands/sys/panels/dependencies-panel.d.ts +14 -0
  178. package/dist/commands/sys/panels/dependencies-panel.js +80 -0
  179. package/dist/commands/sys/panels/keybindings-panel.d.ts +56 -0
  180. package/dist/commands/sys/panels/keybindings-panel.js +703 -0
  181. package/dist/commands/sys/panels/keys-panel.d.ts +16 -0
  182. package/dist/commands/sys/panels/keys-panel.js +60 -0
  183. package/dist/commands/sys/panels/models-panel.d.ts +77 -0
  184. package/dist/commands/sys/panels/models-panel.js +647 -0
  185. package/dist/commands/sys/panels/panel.d.ts +45 -0
  186. package/dist/commands/sys/panels/panel.js +137 -0
  187. package/dist/commands/sys/panels/plugins-panel.d.ts +16 -0
  188. package/dist/commands/sys/panels/plugins-panel.js +80 -0
  189. package/dist/commands/sys/panels/prefs-panel.d.ts +21 -0
  190. package/dist/commands/sys/panels/prefs-panel.js +85 -0
  191. package/dist/commands/sys/panels/provider-panel.d.ts +62 -0
  192. package/dist/commands/sys/panels/provider-panel.js +538 -0
  193. package/dist/commands/sys/settings-shell.d.ts +55 -0
  194. package/dist/commands/sys/settings-shell.js +400 -0
  195. package/dist/commands/sys/settings.d.ts +2 -0
  196. package/dist/commands/sys/settings.js +31 -0
  197. package/dist/commands/sys/setup-core.d.ts +3 -33
  198. package/dist/commands/sys/setup-core.js +27 -78
  199. package/dist/commands/sys/setup-settings-runner.d.ts +24 -0
  200. package/dist/commands/sys/setup-settings-runner.js +63 -0
  201. package/dist/commands/sys/setup-wizard.d.ts +26 -125
  202. package/dist/commands/sys/setup-wizard.js +209 -2473
  203. package/dist/commands/sys/setup.js +5 -7
  204. package/dist/commands/sys.js +3 -2
  205. package/dist/core/__tests__/broker-extension-canvas-db-boundary.test.js +50 -0
  206. package/dist/core/__tests__/broker-launch-candidates.test.js +20 -9
  207. package/dist/core/__tests__/broker-preflight.test.js +1 -1
  208. package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +108 -27
  209. package/dist/core/__tests__/canvas-inbox-watcher.test.js +14 -0
  210. package/dist/core/__tests__/canvas.test.js +2 -36
  211. package/dist/core/__tests__/close.test.js +14 -3
  212. package/dist/core/__tests__/context-intro.test.js +32 -143
  213. package/dist/core/__tests__/cron-broker-capacity.test.js +22 -3
  214. package/dist/core/__tests__/daemon-boot.test.js +2 -20
  215. package/dist/core/__tests__/daemon-wedge.test.js +1 -1
  216. package/dist/core/__tests__/dead-node-policy-table.test.js +1 -18
  217. package/dist/core/__tests__/fixtures/fake-engine.d.ts +1 -1
  218. package/dist/core/__tests__/fixtures/fake-engine.js +2 -2
  219. package/dist/core/__tests__/fixtures/fake-pi-host.js +2 -2
  220. package/dist/core/__tests__/focuses.test.js +4 -98
  221. package/dist/core/__tests__/helpers/broker-clients.d.ts +0 -3
  222. package/dist/core/__tests__/helpers/broker-clients.js +0 -14
  223. package/dist/core/__tests__/helpers/harness.d.ts +0 -8
  224. package/dist/core/__tests__/helpers/harness.js +7 -87
  225. package/dist/core/__tests__/helpers/viewer-panes.js +1 -1
  226. package/dist/core/__tests__/inline-memory-refs.test.js +5 -134
  227. package/dist/core/__tests__/kickoff.test.js +1 -1
  228. package/dist/core/__tests__/memory-resolver-precedence.test.js +29 -1
  229. package/dist/core/__tests__/migration.test.js +35 -48
  230. package/dist/core/__tests__/on-read-dedup-resume.test.js +22 -12
  231. package/dist/core/__tests__/passive-subscription.test.js +26 -49
  232. package/dist/core/__tests__/preview-registry-sync.test.js +1 -2
  233. package/dist/core/__tests__/prune.test.js +94 -1
  234. package/dist/core/__tests__/review-model-floor.test.js +0 -32
  235. package/dist/core/__tests__/seam/broker-attach-multiclient.test.js +255 -0
  236. package/dist/core/__tests__/{full → seam}/broker-attach-stream.test.js +39 -7
  237. package/dist/core/__tests__/{full → seam}/broker-crash-teardown.test.js +30 -29
  238. package/dist/core/__tests__/{full → seam}/broker-pane-resolution.test.js +54 -5
  239. package/dist/core/__tests__/{full → seam}/broker-provider-retry.test.js +134 -82
  240. package/dist/core/__tests__/{full → seam}/broker-whip-interrupt.test.js +15 -4
  241. package/dist/core/__tests__/{full/idle-release-settlement.test.js → seam/dormancy-release.test.js} +69 -17
  242. package/dist/core/__tests__/{full/yield-message-transaction.test.js → seam/yield-refresh-transaction.test.js} +31 -9
  243. package/dist/core/__tests__/secrets.test.js +1 -7
  244. package/dist/core/__tests__/{broker-fork-seam.test.js → serial/broker-fork-seam.test.js} +58 -7
  245. package/dist/core/__tests__/{broker-sdk-wiring.test.js → serial/broker-sdk-wiring.test.js} +18 -162
  246. package/dist/core/__tests__/{broker-snapshot-history.test.js → serial/broker-snapshot-history.test.js} +9 -9
  247. package/dist/core/__tests__/{command-plugins.test.js → serial/command-plugins.test.js} +105 -15
  248. package/dist/core/__tests__/{deferred-no-wake.test.js → serial/deferred-no-wake.test.js} +23 -20
  249. package/dist/core/__tests__/{flagship-lifecycle.test.js → serial/flagship-lifecycle.test.js} +7 -7
  250. package/dist/core/__tests__/{host-teardown-process-group.test.js → serial/host-teardown-process-group.test.js} +6 -6
  251. package/dist/core/__tests__/{human-deliver-e2e.test.js → serial/human-deliver-e2e.test.js} +12 -12
  252. package/dist/core/__tests__/{live-mutation.test.js → serial/live-mutation.test.js} +5 -5
  253. package/dist/core/__tests__/{refresh-stall-recycle.test.js → serial/refresh-stall-recycle.test.js} +5 -14
  254. package/dist/core/__tests__/{revive.test.js → serial/revive.test.js} +15 -100
  255. package/dist/core/__tests__/{spawn-root.test.js → serial/spawn-root.test.js} +32 -15
  256. package/dist/core/__tests__/serial/subscription-delivery.test.js +126 -0
  257. package/dist/core/__tests__/serial/tmux-surface.test.js +256 -0
  258. package/dist/core/__tests__/{worktree.test.js → serial/worktree.test.js} +15 -15
  259. package/dist/core/__tests__/session-model.test.js +0 -18
  260. package/dist/core/__tests__/spawn-worktree-id-conflict.test.js +9 -0
  261. package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +50 -0
  262. package/dist/core/broker-client/__tests__/transport-relay.test.js +15 -16
  263. package/dist/core/broker-client/__tests__/transport-socket.test.js +28 -0
  264. package/dist/core/broker-client/client.d.ts +2 -2
  265. package/dist/core/broker-client/client.js +4 -7
  266. package/dist/core/broker-client/transport-relay.d.ts +13 -19
  267. package/dist/core/broker-client/transport-relay.js +19 -34
  268. package/dist/core/broker-client/transport-socket.d.ts +2 -2
  269. package/dist/core/broker-client/transport-socket.js +9 -2
  270. package/dist/core/broker-client/transport.d.ts +7 -3
  271. package/dist/core/broker-client/transport.js +4 -4
  272. package/dist/core/canvas/__tests__/attention.test.js +1 -18
  273. package/dist/core/canvas/__tests__/remote-canvas-source.test.js +7 -64
  274. package/dist/core/canvas/__tests__/remote-transport.test.js +2 -3
  275. package/dist/core/canvas/__tests__/render-remote.test.js +7 -52
  276. package/dist/core/canvas/browse/app.d.ts +2 -17
  277. package/dist/core/canvas/browse/app.js +16 -88
  278. package/dist/core/canvas/browse/model.d.ts +0 -4
  279. package/dist/core/canvas/browse/model.js +1 -12
  280. package/dist/core/canvas/browse/render.js +6 -3
  281. package/dist/core/canvas/crons.d.ts +8 -5
  282. package/dist/core/canvas/crons.js +7 -6
  283. package/dist/core/canvas/extensions.d.ts +7 -3
  284. package/dist/core/canvas/extensions.js +16 -4
  285. package/dist/core/canvas/nav-model.d.ts +0 -4
  286. package/dist/core/canvas/nav-model.js +2 -14
  287. package/dist/core/canvas/node-order.d.ts +3 -0
  288. package/dist/core/canvas/node-order.js +12 -0
  289. package/dist/core/canvas/remote-canvas-source.d.ts +3 -6
  290. package/dist/core/canvas/remote-canvas-source.js +8 -15
  291. package/dist/core/command.js +11 -4
  292. package/dist/core/config.js +3 -1
  293. package/dist/core/events/envelope.js +1 -1
  294. package/dist/core/events/read.js +7 -21
  295. package/dist/core/events/source.d.ts +0 -2
  296. package/dist/core/events/source.js +0 -16
  297. package/dist/core/events/types.d.ts +1 -1
  298. package/dist/core/fault-classifier.d.ts +1 -1
  299. package/dist/core/feed/passive.d.ts +0 -11
  300. package/dist/core/feed/passive.js +1 -62
  301. package/dist/core/human/__tests__/{inbox-core.test.js → serial/inbox-core.test.js} +6 -6
  302. package/dist/core/keybindings/__tests__/resolve.test.js +1 -96
  303. package/dist/core/keybindings/background-bash.js +3 -4
  304. package/dist/core/keybindings/catalog.js +1 -1
  305. package/dist/core/memory/inline-ref-grammar.js +3 -3
  306. package/dist/core/memory-resolver.d.ts +11 -25
  307. package/dist/core/memory-resolver.js +51 -33
  308. package/dist/core/model-routes.d.ts +15 -0
  309. package/dist/core/model-routes.js +12 -0
  310. package/dist/core/pool-credential-store.js +1 -1
  311. package/dist/core/preview-registry.js +8 -9
  312. package/dist/core/profiles/__tests__/root-profile.test.js +4 -14
  313. package/dist/core/review/realize.d.ts +0 -13
  314. package/dist/core/review/realize.js +0 -40
  315. package/dist/core/review/types.d.ts +1 -1
  316. package/dist/core/runtime/__tests__/engine-route.test.js +2 -2
  317. package/dist/core/runtime/bearings.js +1 -11
  318. package/dist/core/runtime/broker/client-registry.d.ts +33 -0
  319. package/dist/core/runtime/broker/client-registry.js +164 -0
  320. package/dist/core/runtime/broker/daemon-ops.d.ts +19 -0
  321. package/dist/core/runtime/broker/daemon-ops.js +49 -0
  322. package/dist/core/runtime/broker/event-projection.d.ts +42 -0
  323. package/dist/core/runtime/broker/event-projection.js +178 -0
  324. package/dist/core/runtime/broker/fault-retry.d.ts +39 -0
  325. package/dist/core/runtime/broker/fault-retry.js +277 -0
  326. package/dist/core/runtime/broker/frame-dispatch.d.ts +238 -0
  327. package/dist/core/runtime/broker/frame-dispatch.js +1537 -0
  328. package/dist/core/runtime/broker/inbox.d.ts +22 -0
  329. package/dist/core/runtime/broker/inbox.js +167 -0
  330. package/dist/core/runtime/broker/passive.d.ts +16 -0
  331. package/dist/core/runtime/broker/passive.js +44 -0
  332. package/dist/core/runtime/broker/read-ops.d.ts +23 -0
  333. package/dist/core/runtime/broker/read-ops.js +150 -0
  334. package/dist/core/runtime/broker/rebind.d.ts +74 -0
  335. package/dist/core/runtime/broker/rebind.js +211 -0
  336. package/dist/core/runtime/broker/tool-groups.d.ts +39 -0
  337. package/dist/core/runtime/broker/tool-groups.js +244 -0
  338. package/dist/core/runtime/broker-extension-render.d.ts +11 -0
  339. package/dist/core/runtime/broker-extension-render.js +181 -0
  340. package/dist/core/runtime/broker-persona-guidance.d.ts +13 -0
  341. package/dist/core/runtime/broker-persona-guidance.js +58 -0
  342. package/dist/core/runtime/broker-protocol.d.ts +1 -1
  343. package/dist/core/runtime/broker-protocol.js +1 -1
  344. package/dist/core/runtime/broker.d.ts +5 -196
  345. package/dist/core/runtime/broker.js +276 -3059
  346. package/dist/core/runtime/canvas-extensions.js +11 -2
  347. package/dist/core/runtime/fault.js +1 -1
  348. package/dist/core/runtime/model-selection.d.ts +9 -0
  349. package/dist/core/runtime/model-selection.js +12 -0
  350. package/dist/core/runtime/model-swap.d.ts +3 -3
  351. package/dist/core/runtime/model-swap.js +33 -25
  352. package/dist/core/runtime/placement-tmux.d.ts +3 -14
  353. package/dist/core/runtime/placement-tmux.js +11 -80
  354. package/dist/core/runtime/placement.d.ts +4 -2
  355. package/dist/core/runtime/placement.js +7 -12
  356. package/dist/core/runtime/promote.d.ts +14 -1
  357. package/dist/core/runtime/promote.js +1 -1
  358. package/dist/core/runtime/reset.d.ts +1 -1
  359. package/dist/core/runtime/roadmap.js +1 -1
  360. package/dist/core/runtime/spawn.d.ts +8 -0
  361. package/dist/core/runtime/spawn.js +36 -6
  362. package/dist/core/runtime/stop-guard.d.ts +4 -3
  363. package/dist/core/runtime/stop-guard.js +36 -18
  364. package/dist/core/runtime/stop-signals.d.ts +4 -1
  365. package/dist/core/runtime/stream-watchdog.js +4 -5
  366. package/dist/core/runtime/structured-output.d.ts +15 -2
  367. package/dist/core/runtime/structured-output.js +35 -12
  368. package/dist/core/runtime/tmux-bindings.d.ts +25 -0
  369. package/dist/core/runtime/tmux-bindings.js +682 -0
  370. package/dist/core/runtime/tmux-chrome.d.ts +2 -1
  371. package/dist/core/runtime/tmux-chrome.js +3 -2
  372. package/dist/core/runtime/{tmux.d.ts → tmux-driver.d.ts} +18 -26
  373. package/dist/core/runtime/tmux-driver.js +598 -0
  374. package/dist/core/runtime/view-socket.d.ts +14 -0
  375. package/dist/core/runtime/view-socket.js +83 -0
  376. package/dist/core/session-model/session-state.d.ts +1 -2
  377. package/dist/core/session-model/session-state.js +5 -8
  378. package/dist/core/spawn.d.ts +1 -1
  379. package/dist/core/spawn.js +2 -2
  380. package/dist/core/substrate/gate.d.ts +1 -1
  381. package/dist/core/substrate/on-read-pure.d.ts +7 -0
  382. package/dist/core/substrate/on-read-pure.js +272 -0
  383. package/dist/core/termrender/termrender.js +32 -2
  384. package/dist/core/user-settings.d.ts +23 -1
  385. package/dist/core/user-settings.js +18 -1
  386. package/dist/daemon/api/__tests__/node-model-validation.test.js +134 -0
  387. package/dist/daemon/api/__tests__/review-terminal-conflict.test.js +98 -0
  388. package/dist/daemon/api/__tests__/{full → seam}/api-server.test.js +6 -48
  389. package/dist/daemon/api/__tests__/{full → seam}/b10-attach-modelauth.test.js +17 -44
  390. package/dist/daemon/api/__tests__/{full/push-parity.test.js → seam/leaf-api-parity.test.js} +61 -42
  391. package/dist/daemon/api/bridge.js +40 -81
  392. package/dist/daemon/api/handlers/broker-ops.d.ts +2 -0
  393. package/dist/daemon/api/handlers/broker-ops.js +383 -0
  394. package/dist/daemon/api/handlers/crons.js +9 -4
  395. package/dist/daemon/api/handlers/files.js +6 -7
  396. package/dist/daemon/api/handlers/inbox.js +2 -340
  397. package/dist/daemon/api/handlers/nodes.d.ts +10 -1
  398. package/dist/daemon/api/handlers/nodes.js +74 -39
  399. package/dist/daemon/api/handlers/review-comments.js +5 -1
  400. package/dist/daemon/api/handlers/reviews.js +0 -19
  401. package/dist/daemon/api/map.js +25 -4
  402. package/dist/daemon/api/router.js +2 -3
  403. package/dist/daemon/api/server.js +5 -7
  404. package/dist/daemon/cron-run.d.ts +4 -0
  405. package/dist/daemon/cron-run.js +30 -13
  406. package/dist/daemon/crtrd.d.ts +3 -58
  407. package/dist/daemon/crtrd.js +28 -1244
  408. package/dist/daemon/manage.js +0 -1
  409. package/dist/daemon/reconcilers/broker-supervision.d.ts +50 -0
  410. package/dist/daemon/reconcilers/broker-supervision.js +549 -0
  411. package/dist/daemon/reconcilers/cron-lane.d.ts +10 -0
  412. package/dist/daemon/reconcilers/cron-lane.js +32 -0
  413. package/dist/daemon/reconcilers/dormant-inbox.d.ts +18 -0
  414. package/dist/daemon/reconcilers/dormant-inbox.js +143 -0
  415. package/dist/daemon/reconcilers/storage-maintenance.d.ts +22 -0
  416. package/dist/daemon/reconcilers/storage-maintenance.js +213 -0
  417. package/dist/daemon/review/finish.js +2 -5
  418. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +34 -53
  419. package/dist/pi-extensions/__tests__/canvas-recap.test.js +16 -113
  420. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +72 -99
  421. package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.js +29 -12
  422. package/dist/pi-extensions/broker-local.d.ts +20 -0
  423. package/dist/pi-extensions/broker-local.js +89 -0
  424. package/dist/pi-extensions/canvas-context-intro.d.ts +3 -3
  425. package/dist/pi-extensions/canvas-context-intro.js +22 -11
  426. package/dist/pi-extensions/canvas-doc-substrate.js +17 -34
  427. package/dist/pi-extensions/canvas-goal-capture.js +7 -12
  428. package/dist/pi-extensions/canvas-inbox-watcher.js +124 -139
  429. package/dist/pi-extensions/canvas-passive-context.d.ts +3 -3
  430. package/dist/pi-extensions/canvas-passive-context.js +22 -18
  431. package/dist/pi-extensions/canvas-recap.d.ts +2 -2
  432. package/dist/pi-extensions/canvas-recap.js +48 -21
  433. package/dist/pi-extensions/canvas-review-boundary.js +10 -4
  434. package/dist/pi-extensions/canvas-stophook.d.ts +0 -5
  435. package/dist/pi-extensions/canvas-stophook.js +149 -431
  436. package/dist/pi-extensions/canvas-structured-output.js +52 -30
  437. package/dist/pi-extensions/envelope-merge.d.ts +13 -0
  438. package/dist/pi-extensions/envelope-merge.js +29 -0
  439. package/dist/shared/working-activity.d.ts +3 -2
  440. package/dist/shared/working-activity.js +3 -2
  441. package/dist/types.d.ts +6 -5
  442. package/dist/types.js +2 -2
  443. package/docs/compat/hearth-crtr-v1.md +4 -12
  444. package/docs/compat/hearth-crtr-v2.md +3 -11
  445. package/docs/compat/hearth-crtr-v3.md +4 -12
  446. package/docs/compat/hearth-crtr-v4.md +3 -11
  447. package/docs/compat/hearth-crtr-v5.md +3 -11
  448. package/docs/public-api.md +3 -7
  449. package/package.json +7 -49
  450. package/runtime.lock.json +2766 -14533
  451. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/claude-plugin-commands.test.ts +0 -49
  452. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/memory-slash-commands.test.ts +0 -194
  453. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/statusline.test.ts +0 -68
  454. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/frontmatter-rules/test.ts +0 -119
  455. package/dist/clients/attach/__tests__/attach-chrome-remote.test.js +0 -439
  456. package/dist/clients/attach/__tests__/attach-keybindings.test.js +0 -170
  457. package/dist/clients/attach/__tests__/crtr-output-coverage.test.js +0 -57
  458. package/dist/clients/attach/__tests__/editor-frame-title.test.js +0 -19
  459. package/dist/clients/attach/__tests__/input-controller-extension-command.test.js +0 -32
  460. package/dist/clients/attach/__tests__/markdown-headings.test.js +0 -35
  461. package/dist/clients/attach/__tests__/session-identity-refresh.test.js +0 -32
  462. package/dist/clients/conversation/conversation.d.ts +0 -65
  463. package/dist/clients/conversation/conversation.js +0 -318
  464. package/dist/clients/conversation/frames.d.ts +0 -30
  465. package/dist/clients/conversation/frames.js +0 -52
  466. package/dist/clients/conversation/region.d.ts +0 -51
  467. package/dist/clients/conversation/region.js +0 -265
  468. package/dist/clients/inbox/__tests__/inbox-controller.test.js +0 -247
  469. package/dist/clients/inbox/__tests__/mount-panel.test.js +0 -776
  470. package/dist/clients/inbox/review/__tests__/remap.test.js +0 -196
  471. package/dist/clients/inbox/review/columns.d.ts +0 -22
  472. package/dist/clients/inbox/review/columns.js +0 -40
  473. package/dist/clients/inbox/review/composition.d.ts +0 -60
  474. package/dist/clients/inbox/review/composition.js +0 -278
  475. package/dist/clients/inbox/review/document-region.d.ts +0 -120
  476. package/dist/clients/surfaces/region.d.ts +0 -16
  477. package/dist/clients/web/__tests__/push-engine.test.js +0 -158
  478. package/dist/clients/web/__tests__/push-registry.test.d.ts +0 -1
  479. package/dist/clients/web/__tests__/push-registry.test.js +0 -177
  480. package/dist/clients/web/dev-server.d.ts +0 -7
  481. package/dist/clients/web/dev-server.js +0 -46
  482. package/dist/clients/web/events.d.ts +0 -19
  483. package/dist/clients/web/events.js +0 -163
  484. package/dist/clients/web/push-engine.d.ts +0 -44
  485. package/dist/clients/web/push-engine.js +0 -125
  486. package/dist/clients/web/push-registry.d.ts +0 -85
  487. package/dist/clients/web/push-registry.js +0 -373
  488. package/dist/clients/web/server.d.ts +0 -19
  489. package/dist/clients/web/server.js +0 -661
  490. package/dist/clients/web/web-client/shared/protocol.d.ts +0 -214
  491. package/dist/clients/web/web-client/shared/protocol.js +0 -8
  492. package/dist/clients/web/web-cmd.d.ts +0 -2
  493. package/dist/clients/web/web-cmd.js +0 -141
  494. package/dist/commands/__tests__/api-canvas-source.test.d.ts +0 -1
  495. package/dist/commands/__tests__/api-canvas-source.test.js +0 -37
  496. package/dist/commands/__tests__/canvas-config.test.d.ts +0 -1
  497. package/dist/commands/__tests__/canvas-config.test.js +0 -107
  498. package/dist/commands/__tests__/node-no-kickoff-flag.test.d.ts +0 -1
  499. package/dist/commands/__tests__/node-no-kickoff-flag.test.js +0 -73
  500. package/dist/commands/__tests__/node-worktree-flag.test.d.ts +0 -1
  501. package/dist/commands/__tests__/node-worktree-flag.test.js +0 -49
  502. package/dist/commands/__tests__/search-contents.test.d.ts +0 -1
  503. package/dist/commands/__tests__/search-contents.test.js +0 -52
  504. package/dist/commands/memory/__tests__/lint.test.d.ts +0 -1
  505. package/dist/commands/memory/__tests__/lint.test.js +0 -15
  506. package/dist/commands/sys/__tests__/config-broker-thresholds.test.d.ts +0 -1
  507. package/dist/commands/sys/__tests__/config-broker-thresholds.test.js +0 -95
  508. package/dist/commands/sys/__tests__/config-keybindings.test.d.ts +0 -1
  509. package/dist/commands/sys/__tests__/config-keybindings.test.js +0 -55
  510. package/dist/commands/sys/__tests__/helpers/setup-runtime.d.ts +0 -5
  511. package/dist/commands/sys/__tests__/helpers/setup-runtime.js +0 -19
  512. package/dist/commands/sys/__tests__/setup-front-door.test.d.ts +0 -1
  513. package/dist/commands/sys/__tests__/setup-front-door.test.js +0 -102
  514. package/dist/commands/sys/__tests__/setup-models.test.d.ts +0 -1
  515. package/dist/commands/sys/__tests__/setup-models.test.js +0 -205
  516. package/dist/commands/sys/__tests__/setup-providers-viewport.test.d.ts +0 -1
  517. package/dist/commands/sys/__tests__/setup-providers-viewport.test.js +0 -155
  518. package/dist/commands/sys/__tests__/sync-deps.test.d.ts +0 -1
  519. package/dist/commands/sys/__tests__/sync-deps.test.js +0 -179
  520. package/dist/commands/sys/__tests__/sync-import.test.d.ts +0 -1
  521. package/dist/commands/sys/__tests__/sync-import.test.js +0 -315
  522. package/dist/core/__tests__/base-worker-prompt.test.d.ts +0 -1
  523. package/dist/core/__tests__/base-worker-prompt.test.js +0 -57
  524. package/dist/core/__tests__/command-plugins-surfaces.test.d.ts +0 -1
  525. package/dist/core/__tests__/command-plugins-surfaces.test.js +0 -359
  526. package/dist/core/__tests__/connection-reconnect-resume.test.d.ts +0 -1
  527. package/dist/core/__tests__/connection-reconnect-resume.test.js +0 -36
  528. package/dist/core/__tests__/finalization-migration.test.d.ts +0 -1
  529. package/dist/core/__tests__/finalization-migration.test.js +0 -38
  530. package/dist/core/__tests__/fixtures/extra-extension.d.ts +0 -1
  531. package/dist/core/__tests__/fixtures/extra-extension.js +0 -3
  532. package/dist/core/__tests__/fixtures/spawn-proof-target.test.d.ts +0 -1
  533. package/dist/core/__tests__/fixtures/spawn-proof-target.test.js +0 -15
  534. package/dist/core/__tests__/fork.test.d.ts +0 -1
  535. package/dist/core/__tests__/fork.test.js +0 -108
  536. package/dist/core/__tests__/full/broker-attach-limits.test.d.ts +0 -1
  537. package/dist/core/__tests__/full/broker-attach-limits.test.js +0 -147
  538. package/dist/core/__tests__/full/broker-deliver-ack.test.d.ts +0 -1
  539. package/dist/core/__tests__/full/broker-deliver-ack.test.js +0 -73
  540. package/dist/core/__tests__/full/broker-dialogs.test.d.ts +0 -1
  541. package/dist/core/__tests__/full/broker-dialogs.test.js +0 -180
  542. package/dist/core/__tests__/full/broker-display-snapshot.test.d.ts +0 -1
  543. package/dist/core/__tests__/full/broker-display-snapshot.test.js +0 -75
  544. package/dist/core/__tests__/full/broker-dormant-wake.test.d.ts +0 -1
  545. package/dist/core/__tests__/full/broker-dormant-wake.test.js +0 -130
  546. package/dist/core/__tests__/full/broker-model-changed-broadcast.test.d.ts +0 -1
  547. package/dist/core/__tests__/full/broker-model-changed-broadcast.test.js +0 -57
  548. package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.d.ts +0 -1
  549. package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.js +0 -80
  550. package/dist/core/__tests__/full/cascade-close.test.d.ts +0 -1
  551. package/dist/core/__tests__/full/cascade-close.test.js +0 -240
  552. package/dist/core/__tests__/full/detach-focus.test.d.ts +0 -1
  553. package/dist/core/__tests__/full/detach-focus.test.js +0 -126
  554. package/dist/core/__tests__/full/idle-release-settlement.test.d.ts +0 -1
  555. package/dist/core/__tests__/full/issue-146-yield-spawn-focus.test.d.ts +0 -1
  556. package/dist/core/__tests__/full/issue-146-yield-spawn-focus.test.js +0 -107
  557. package/dist/core/__tests__/full/park-clock-release.test.d.ts +0 -1
  558. package/dist/core/__tests__/full/park-clock-release.test.js +0 -56
  559. package/dist/core/__tests__/full/yield-message-transaction.test.d.ts +0 -1
  560. package/dist/core/__tests__/memory-index-render.test.d.ts +0 -1
  561. package/dist/core/__tests__/memory-index-render.test.js +0 -60
  562. package/dist/core/__tests__/model-routes.test.d.ts +0 -1
  563. package/dist/core/__tests__/model-routes.test.js +0 -41
  564. package/dist/core/__tests__/on-read-identity.test.d.ts +0 -1
  565. package/dist/core/__tests__/on-read-identity.test.js +0 -61
  566. package/dist/core/__tests__/phase4-review-migration.test.d.ts +0 -1
  567. package/dist/core/__tests__/phase4-review-migration.test.js +0 -100
  568. package/dist/core/__tests__/prune-to-limit.test.d.ts +0 -1
  569. package/dist/core/__tests__/prune-to-limit.test.js +0 -126
  570. package/dist/core/__tests__/reset.test.d.ts +0 -1
  571. package/dist/core/__tests__/reset.test.js +0 -69
  572. package/dist/core/__tests__/spawn-no-kickoff.test.d.ts +0 -1
  573. package/dist/core/__tests__/spawn-no-kickoff.test.js +0 -115
  574. package/dist/core/__tests__/steer-note.test.d.ts +0 -1
  575. package/dist/core/__tests__/steer-note.test.js +0 -41
  576. package/dist/core/__tests__/subcommand-tier.test.d.ts +0 -1
  577. package/dist/core/__tests__/subcommand-tier.test.js +0 -99
  578. package/dist/core/__tests__/subscription-delivery.test.js +0 -211
  579. package/dist/core/__tests__/test-runner-cheap-sharding.test.d.ts +0 -1
  580. package/dist/core/__tests__/test-runner-cheap-sharding.test.js +0 -97
  581. package/dist/core/__tests__/tmux-surface.test.js +0 -484
  582. package/dist/core/__tests__/wake-bearings.test.d.ts +0 -1
  583. package/dist/core/__tests__/wake-bearings.test.js +0 -102
  584. package/dist/core/canvas/__tests__/remote-event-stream.test.d.ts +0 -1
  585. package/dist/core/canvas/__tests__/remote-event-stream.test.js +0 -146
  586. package/dist/core/canvas/__tests__/source-resolve.test.d.ts +0 -1
  587. package/dist/core/canvas/__tests__/source-resolve.test.js +0 -77
  588. package/dist/core/canvas/browse/__tests__/model.test.d.ts +0 -1
  589. package/dist/core/canvas/browse/__tests__/model.test.js +0 -290
  590. package/dist/core/canvas/browse/__tests__/rebuild-coalescer.test.d.ts +0 -1
  591. package/dist/core/canvas/browse/__tests__/rebuild-coalescer.test.js +0 -134
  592. package/dist/core/canvas/browse/__tests__/render.test.d.ts +0 -1
  593. package/dist/core/canvas/browse/__tests__/render.test.js +0 -111
  594. package/dist/core/canvas/browse/rebuild-coalescer.d.ts +0 -7
  595. package/dist/core/canvas/browse/rebuild-coalescer.js +0 -61
  596. package/dist/core/canvas/remote-event-stream.d.ts +0 -24
  597. package/dist/core/canvas/remote-event-stream.js +0 -94
  598. package/dist/core/feed/__tests__/coalesce-human.test.d.ts +0 -1
  599. package/dist/core/feed/__tests__/coalesce-human.test.js +0 -36
  600. package/dist/core/feed/__tests__/empty-node-guard.test.d.ts +0 -1
  601. package/dist/core/feed/__tests__/empty-node-guard.test.js +0 -45
  602. package/dist/core/host-exports/__tests__/export-prunes-boot-skill.test.d.ts +0 -1
  603. package/dist/core/host-exports/__tests__/export-prunes-boot-skill.test.js +0 -84
  604. package/dist/core/human/__tests__/visible-paths.test.d.ts +0 -1
  605. package/dist/core/human/__tests__/visible-paths.test.js +0 -28
  606. package/dist/core/keybindings/__tests__/inbox-affordance.test.d.ts +0 -1
  607. package/dist/core/keybindings/__tests__/inbox-affordance.test.js +0 -38
  608. package/dist/core/review/__tests__/project.test.d.ts +0 -1
  609. package/dist/core/review/__tests__/project.test.js +0 -71
  610. package/dist/core/runtime/__tests__/command-expansion.test.d.ts +0 -1
  611. package/dist/core/runtime/__tests__/command-expansion.test.js +0 -25
  612. package/dist/core/runtime/__tests__/session-visibility.test.d.ts +0 -1
  613. package/dist/core/runtime/__tests__/session-visibility.test.js +0 -119
  614. package/dist/core/runtime/__tests__/spawn-at-given-id.test.d.ts +0 -1
  615. package/dist/core/runtime/__tests__/spawn-at-given-id.test.js +0 -34
  616. package/dist/core/runtime/tmux.js +0 -1314
  617. package/dist/daemon/api/__tests__/full/push-parity.test.d.ts +0 -1
  618. package/dist/daemon/api/__tests__/full/worktree-parity.test.d.ts +0 -1
  619. package/dist/daemon/api/__tests__/full/worktree-parity.test.js +0 -160
  620. package/dist/daemon/api/__tests__/inbox.test.d.ts +0 -1
  621. package/dist/daemon/api/__tests__/inbox.test.js +0 -489
  622. package/dist/web-client/apple-touch-icon.png +0 -0
  623. package/dist/web-client/assets/fragment-mono-latin-400-normal-BYwT3kSJ.woff +0 -0
  624. package/dist/web-client/assets/fragment-mono-latin-400-normal-yxdJ5AmL.woff2 +0 -0
  625. package/dist/web-client/assets/fragment-mono-latin-ext-400-normal-BbKYyvR9.woff2 +0 -0
  626. package/dist/web-client/assets/fragment-mono-latin-ext-400-normal-CT4YFKeK.woff +0 -0
  627. package/dist/web-client/assets/index-CCPaLeW7.css +0 -2
  628. package/dist/web-client/assets/index-kyOWsnZK.js +0 -86
  629. package/dist/web-client/assets/martian-mono-cyrillic-wght-normal-B84CD5C_.woff2 +0 -0
  630. package/dist/web-client/assets/martian-mono-latin-ext-wght-normal-DlL6xMw5.woff2 +0 -0
  631. package/dist/web-client/assets/martian-mono-latin-wght-normal-5W32yIyr.woff2 +0 -0
  632. package/dist/web-client/assets/workbox-window.prod.es5-Bd17z0YL.js +0 -2
  633. package/dist/web-client/icon-192.png +0 -0
  634. package/dist/web-client/icon-512.png +0 -0
  635. package/dist/web-client/icon-maskable-512.png +0 -0
  636. package/dist/web-client/index.html +0 -17
  637. package/dist/web-client/manifest.webmanifest +0 -1
  638. package/dist/web-client/sw.js +0 -1
  639. /package/dist/api/__tests__/{client.test.d.ts → serial/client.test.d.ts} +0 -0
  640. /package/dist/clients/inbox/__tests__/{inbox-controller.test.d.ts → serial/inbox-controller.test.d.ts} +0 -0
  641. /package/dist/clients/inbox/__tests__/{mount-panel.test.d.ts → serial/mount-panel.test.d.ts} +0 -0
  642. /package/dist/clients/{attach/__tests__/attach-chrome-remote.test.d.ts → inbox/review/__tests__/teardown-notice.test.d.ts} +0 -0
  643. /package/dist/{clients/attach/__tests__/attach-keybindings.test.d.ts → core/__tests__/broker-extension-canvas-db-boundary.test.d.ts} +0 -0
  644. /package/dist/{clients/attach/__tests__/crtr-output-coverage.test.d.ts → core/__tests__/seam/broker-attach-multiclient.test.d.ts} +0 -0
  645. /package/dist/core/__tests__/{full → seam}/broker-attach-stream.test.d.ts +0 -0
  646. /package/dist/core/__tests__/{full → seam}/broker-crash-teardown.test.d.ts +0 -0
  647. /package/dist/core/__tests__/{full → seam}/broker-pane-resolution.test.d.ts +0 -0
  648. /package/dist/core/__tests__/{full → seam}/broker-provider-retry.test.d.ts +0 -0
  649. /package/dist/core/__tests__/{full → seam}/broker-whip-interrupt.test.d.ts +0 -0
  650. /package/dist/{clients/attach/__tests__/editor-frame-title.test.d.ts → core/__tests__/seam/dormancy-release.test.d.ts} +0 -0
  651. /package/dist/{clients/attach/__tests__/input-controller-extension-command.test.d.ts → core/__tests__/seam/yield-refresh-transaction.test.d.ts} +0 -0
  652. /package/dist/core/__tests__/{broker-fork-seam.test.d.ts → serial/broker-fork-seam.test.d.ts} +0 -0
  653. /package/dist/core/__tests__/{broker-sdk-wiring.test.d.ts → serial/broker-sdk-wiring.test.d.ts} +0 -0
  654. /package/dist/core/__tests__/{broker-snapshot-history.test.d.ts → serial/broker-snapshot-history.test.d.ts} +0 -0
  655. /package/dist/core/__tests__/{command-plugins.test.d.ts → serial/command-plugins.test.d.ts} +0 -0
  656. /package/dist/core/__tests__/{deferred-no-wake.test.d.ts → serial/deferred-no-wake.test.d.ts} +0 -0
  657. /package/dist/core/__tests__/{flagship-lifecycle.test.d.ts → serial/flagship-lifecycle.test.d.ts} +0 -0
  658. /package/dist/core/__tests__/{host-teardown-process-group.test.d.ts → serial/host-teardown-process-group.test.d.ts} +0 -0
  659. /package/dist/core/__tests__/{human-deliver-e2e.test.d.ts → serial/human-deliver-e2e.test.d.ts} +0 -0
  660. /package/dist/core/__tests__/{live-mutation.test.d.ts → serial/live-mutation.test.d.ts} +0 -0
  661. /package/dist/core/__tests__/{refresh-stall-recycle.test.d.ts → serial/refresh-stall-recycle.test.d.ts} +0 -0
  662. /package/dist/core/__tests__/{revive.test.d.ts → serial/revive.test.d.ts} +0 -0
  663. /package/dist/core/__tests__/{spawn-root.test.d.ts → serial/spawn-root.test.d.ts} +0 -0
  664. /package/dist/core/__tests__/{subscription-delivery.test.d.ts → serial/subscription-delivery.test.d.ts} +0 -0
  665. /package/dist/core/__tests__/{tmux-surface.test.d.ts → serial/tmux-surface.test.d.ts} +0 -0
  666. /package/dist/core/__tests__/{worktree.test.d.ts → serial/worktree.test.d.ts} +0 -0
  667. /package/dist/{clients/attach/__tests__/markdown-headings.test.d.ts → core/__tests__/watchdog-abort-arms-retry.test.d.ts} +0 -0
  668. /package/dist/{clients/attach/__tests__/session-identity-refresh.test.d.ts → core/broker-client/__tests__/transport-socket.test.d.ts} +0 -0
  669. /package/dist/core/human/__tests__/{inbox-core.test.d.ts → serial/inbox-core.test.d.ts} +0 -0
  670. /package/dist/{clients/inbox/review/__tests__/remap.test.d.ts → daemon/api/__tests__/node-model-validation.test.d.ts} +0 -0
  671. /package/dist/{clients/surfaces/region.js → daemon/api/__tests__/review-terminal-conflict.test.d.ts} +0 -0
  672. /package/dist/daemon/api/__tests__/{full → seam}/api-server.test.d.ts +0 -0
  673. /package/dist/daemon/api/__tests__/{full → seam}/b10-attach-modelauth.test.d.ts +0 -0
  674. /package/dist/{clients/web/__tests__/push-engine.test.d.ts → daemon/api/__tests__/seam/leaf-api-parity.test.d.ts} +0 -0
@@ -12,50 +12,26 @@
12
12
  // turn_end — accumulate token usage and flush telemetry.json under the node's
13
13
  // job/ dir so the dashboard shows live counts.
14
14
  //
15
- // agent_end — stage the completed attempt for Pi's settlement boundary.
15
+ // agent_end — stage the latest Pi attempt for Pi's settlement boundary.
16
16
  //
17
- // agent_settled — decide what happens after recovery and queued continuations:
18
- // (a) stopReason is 'aborted' or 'error' → stay alive for re-steering; return.
19
- // (b) node.status is already 'done' (agent called `crtr push --final` this
20
- // turn, which sets status synchronously) → shut down; work is complete.
21
- // (c) Natural stop ('stop' | 'length') — run the stop-guard (the node is
22
- // NEVER auto-pushed; it reports only via its own explicit `crtr push`):
23
- // • 'reprompt' → pi.sendUserMessage so the node finishes or escalates.
24
- // • 'allow' (awaiting) → stay dormant when focused; otherwise release
25
- // and shut down. A subscribed node, controller, or
26
- // background bash job delivers the inbox wake.
27
- // • 'allow' (attended root) → stay alive, dormant; the human wakes it.
17
+ // agent_settled — report Pi-only stop facts to crtrd, then enact its one
18
+ // returned directive: follow-up reprompt, stay dormant, or
19
+ // shut down. crtrd owns every stop-policy and canvas effect.
28
20
  //
29
21
  // Plain TS-with-types — no imports from @earendil-works/* so this compiles inside
30
22
  // crouter's own tsc build without a dep on the pi packages.
31
23
  import { writeFileSync, mkdirSync, existsSync, readFileSync } from 'node:fs';
32
24
  import { join } from 'node:path';
33
- import { getNode, jobDir, updateNode, recordPid, setPresence } from '../core/canvas/index.js';
34
- import { transition } from '../core/runtime/lifecycle.js';
35
- import { markBusy, clearBusy, touchBusy, isBusy } from '../core/runtime/busy.js';
36
- import { clearFault, readFault } from '../core/runtime/fault.js';
37
- import { nextFaultRetry } from '../core/runtime/fault-recovery.js';
38
- import { evaluateStop } from '../core/runtime/stop-guard.js';
39
- import { personaDrift, commitPersonaAck } from '../core/runtime/persona.js';
40
- import { clearYieldMessage } from '../core/runtime/kickoff.js';
41
- import { handleNewSession, markCleanExitDone } from '../core/runtime/reset.js';
25
+ import { contextDir, jobDir } from '../core/canvas/paths.js';
26
+ import { markBusy, clearBusy, touchBusy } from '../core/runtime/busy.js';
27
+ import { clearFault } from '../core/runtime/fault.js';
28
+ import { personaDriftFromBrokerState } from '../core/runtime/broker-persona-guidance.js';
42
29
  import { clearStopSignals, consumeStopSignals } from '../core/runtime/stop-signals.js';
43
- import { cliClient } from '../commands/api-client.js';
44
- import { focusOf, tearDownNode } from '../core/runtime/placement.js';
45
- import { readCursor, readInboxSince } from '../core/feed/inbox.js';
30
+ import { bindBrokerSession, brokerExtensionState, commitBrokerPersonaAck, relaunchBrokerRoot, settleBroker } from '../core/runtime/broker/daemon-ops.js';
31
+ import { emitEvent } from '../core/events/emit.js';
32
+ import { activeBackgroundBashJobs } from '../core/bash-jobs.js';
46
33
  import { CONTEXT_NUDGE_CUSTOM_TYPE, formatContextNudge, formatPersonaTransition } from '../shared/generated-context.js';
47
34
  import { isReviewBoundary } from '../core/runtime/session-visibility.js';
48
- /** Universal upper bound for an unfocused broker parked without runnable work. */
49
- export const UNATTENDED_PARK_MS = (() => {
50
- const testOverride = process.env['CRTR_TEST_UNATTENDED_PARK_MS'];
51
- if (testOverride === undefined)
52
- return 15 * 60_000;
53
- const parsed = Number(testOverride);
54
- return Number.isFinite(parsed) && parsed > 0 ? parsed : 15 * 60_000;
55
- })();
56
- /** Production cadence for the bounded-release clock. A shorter test bound also
57
- * shortens the cadence, so the full-tier regression need not sleep for a minute. */
58
- export const PARK_POLL_MS = Math.min(60_000, UNATTENDED_PARK_MS);
59
35
  /** Condense a tool call into one short line for the activity cue. Picks the most
60
36
  * identifying arg (command / path / pattern / description), collapses whitespace,
61
37
  * and hard-caps the length so a giant bash command can't bloat telemetry.json. */
@@ -115,6 +91,32 @@ function lastAssistantMessage(messages) {
115
91
  }
116
92
  return undefined;
117
93
  }
94
+ /** Review markers present in Pi's current branch. The broker reports only this
95
+ * Pi-owned fact; crtrd compares it with the node's daemon-owned review binding. */
96
+ function currentReviewBoundaryIds(ctx) {
97
+ try {
98
+ const manager = ctx?.sessionManager;
99
+ const entries = typeof manager?.getBranch === 'function'
100
+ ? manager.getBranch()
101
+ : typeof manager?.getEntries === 'function'
102
+ ? manager.getEntries()
103
+ : [];
104
+ if (!Array.isArray(entries))
105
+ return [];
106
+ const ids = new Set();
107
+ for (const entry of entries) {
108
+ if (!isReviewBoundary(entry))
109
+ continue;
110
+ const reviewId = entry.details?.reviewId;
111
+ if (typeof reviewId === 'string')
112
+ ids.add(reviewId);
113
+ }
114
+ return [...ids];
115
+ }
116
+ catch {
117
+ return [];
118
+ }
119
+ }
118
120
  // ---------------------------------------------------------------------------
119
121
  // Context-size steering bands — a single shared schedule of thresholds that
120
122
  // ESCALATE in tone as input context grows. The first band is a gentle
@@ -267,79 +269,28 @@ export function registerCanvasStophook(pi) {
267
269
  // yield --promote only when worthwhile independent work can run in parallel);
268
270
  // a terminal worker to yield-or-push-final.
269
271
  const firedBands = new Set();
270
- // Every broker enters this bounded-release path at session_start, including a
271
- // boot-revived settled node that never produces another agent_settled event.
272
- // Focus, real work, pending inbox delivery, and bounded in-process fault retry
273
- // justify parking; anything else gets at most UNATTENDED_PARK_MS before the
274
- // existing release transition + shutdown path makes it process-free.
275
- let sessionBound = false;
276
- let agentRunning = false;
277
- let parkedSince = null;
278
- let parkTimer = null;
279
- let parkContext = null;
280
- const resetParkClock = () => { parkedSince = null; };
281
- const hasActiveAutoFaultRetry = (now) => {
282
- const fault = readFault(nodeId);
283
- if (fault === null || fault.retry.disposition !== 'auto' || fault.retry.by !== 'daemon')
284
- return false;
285
- if (fault.kind !== 'connection' && fault.kind !== 'rate-limit' && fault.kind !== 'overloaded')
286
- return false;
287
- return fault.retry.nextAt !== undefined || nextFaultRetry(fault, now) !== null;
272
+ const backgroundJobsRunning = () => activeBackgroundBashJobs(contextDir(nodeId)).length > 0;
273
+ const emitDaemonOperationFailure = (operation, error) => {
274
+ emitEvent({
275
+ event: 'broker.daemon.operation.failed',
276
+ level: 'error',
277
+ node_id: nodeId,
278
+ error,
279
+ fields: { operation },
280
+ });
288
281
  };
289
- const pollParkClock = () => {
290
- try {
291
- if (!sessionBound || agentRunning || parkContext === null) {
292
- resetParkClock();
293
- return;
294
- }
295
- const row = getNode(nodeId);
296
- if (row === null || row.intent !== null || row.status === 'done' || row.status === 'canceled' || row.status === 'dead') {
297
- resetParkClock();
298
- return;
299
- }
300
- if (isBusy(nodeId)) {
301
- resetParkClock();
302
- return;
303
- }
304
- if (focusOf(nodeId) !== null) {
305
- resetParkClock();
306
- return;
307
- }
308
- if (readInboxSince(nodeId, readCursor(nodeId)).some((entry) => entry.tier !== 'deferred')) {
309
- resetParkClock();
310
- return;
311
- }
312
- const now = Date.now();
313
- if (hasActiveAutoFaultRetry(now)) {
314
- resetParkClock();
315
- return;
316
- }
317
- parkedSince ??= now;
318
- if (now - parkedSince < UNATTENDED_PARK_MS)
319
- return;
320
- transition(nodeId, 'release');
321
- resetParkClock();
282
+ const enactSettleDirective = (directive, ctx) => {
283
+ if (directive.action === 'reprompt') {
284
+ pi.sendUserMessage(directive.prompt, { deliverAs: 'followUp' });
285
+ return;
286
+ }
287
+ if (directive.action === 'shutdown') {
322
288
  try {
323
- parkContext?.shutdown?.();
289
+ ctx?.shutdown?.();
324
290
  }
325
- catch { /* best-effort */ }
326
- }
327
- catch {
328
- // A policy read failure must stay visible on the next poll rather than
329
- // releasing from incomplete evidence.
330
- resetParkClock();
291
+ catch { /* Pi shutdown is local best-effort */ }
331
292
  }
332
293
  };
333
- const armParkClock = (ctx) => {
334
- sessionBound = true;
335
- parkContext = ctx;
336
- resetParkClock();
337
- if (parkTimer !== null)
338
- return;
339
- parkTimer = setInterval(pollParkClock, PARK_POLL_MS);
340
- if (typeof parkTimer.unref === 'function')
341
- parkTimer.unref();
342
- };
343
294
  // Wedge-heartbeat throttle: message_update/tool_execution_update can fire many
344
295
  // times per second while streaming, and touchBusy is a disk write — rate-limit
345
296
  // it to at most once per HEARTBEAT_THROTTLE_MS. The daemon's wedge grace is
@@ -374,15 +325,11 @@ export function registerCanvasStophook(pi) {
374
325
  // looks identical to a boot. The event reason is delivered fresh on every fire
375
326
  // and is immune to the re-activation.
376
327
  //
377
- // `/new` splits by who ran it: a ROOT relaunches into a genuinely new node
378
- // (relaunchRoot — park the old root `done`, boot a fresh node, re-point this
379
- // pane), a non-root CHILD just refreshes its session id (handleNewSession).
328
+ // `/new` splits by who ran it: crtrd derives rootness from the node row and
329
+ // either directs a root relaunch or resets a child's session coordinates.
380
330
  // ---------------------------------------------------------------------------
381
- pi.on('session_start', (event, ctx) => {
331
+ pi.on('session_start', async (event, ctx) => {
382
332
  try {
383
- // This clock bounds every boot, including one whose durable bookkeeping
384
- // below fails transiently; never leave it behind a swallowed handler error.
385
- armParkClock(ctx);
386
333
  const id = ctx?.sessionManager?.getSessionId?.();
387
334
  if (typeof id !== 'string' || id === '')
388
335
  return;
@@ -391,93 +338,55 @@ export function registerCanvasStophook(pi) {
391
338
  // whereas a bare id is resolved cwd-relative and forks across projects.
392
339
  const filed = ctx?.sessionManager?.getSessionFile?.();
393
340
  const sessionFile = typeof filed === 'string' && filed !== '' ? filed : null;
394
- const existing = getNode(nodeId);
395
- const reviewId = existing?.review_binding?.review_id;
396
- if (reviewId !== undefined) {
397
- let hasBoundary = false;
398
- try {
399
- const manager = ctx?.sessionManager;
400
- const entries = typeof manager?.getBranch === 'function'
401
- ? manager.getBranch()
402
- : typeof manager?.getEntries === 'function'
403
- ? manager.getEntries()
404
- : [];
405
- hasBoundary = entries.some((entry) => isReviewBoundary(entry, reviewId));
406
- }
407
- catch {
408
- hasBoundary = false;
409
- }
410
- if (!hasBoundary) {
411
- try {
412
- ctx?.shutdown?.();
413
- }
414
- catch { /* best-effort */ }
415
- return;
416
- }
417
- }
418
- // `/new` — a brand-new conversation in the same process. The broker already
419
- // drove the engine-side new_session (the viewer's /new → broker
420
- // new_session frame); the runtime side then splits on root-ness: a ROOT
421
- // relaunches into a freshly-minted node (park the old root `done`, boot a
422
- // new broker, re-point the viewer pane), a non-root CHILD just refreshes
423
- // its session id on the SAME node.
424
- if (event?.reason === 'new') {
425
- try {
426
- // A root relaunch LAUNCHES a broker, and launches are daemon-owned
427
- // (fleet-bound) — so the broker never runs relaunchRoot in-process.
428
- // It asks crtrd via POST /v1/nodes/:id/relaunch-root instead; the
429
- // rejection is swallowed here (the enclosing sync catch can't catch
430
- // an async one) to keep `/new` best-effort.
431
- if (existing?.parent == null)
432
- void cliClient().relaunchRoot(nodeId).catch(() => { });
433
- else
434
- handleNewSession(nodeId, id, sessionFile);
435
- }
436
- catch { /* best-effort */ }
437
- // Clear in-memory context-steering so the fresh conversation starts clean.
341
+ const reason = typeof event?.reason === 'string' ? event.reason : null;
342
+ // Pi has already swapped to the fresh conversation. Its local steering
343
+ // counters reset independently of the durable root/child consequence.
344
+ if (reason === 'new') {
438
345
  totalIn = 0;
439
346
  totalOut = 0;
440
347
  firedBands.clear();
441
- return;
442
348
  }
443
- // Boot / startup / resume / reload / fork → (re)bind this process to its
444
- // session id, record our OS pid (the daemon's broker-liveness signal), and
445
- // CONFIRM any pending refresh-yield / pending cycle. Reaching session_start
446
- // proves a fresh engine actually booted, so it is now safe to clear
447
- // intent='refresh' — a refresh shuts the broker down and the daemon
448
- // relaunches it FRESH, which leaves intent='refresh' set until this boot
449
- // clears it (the only proof the relaunch worked; otherwise a failed relaunch
450
- // would look like a success). Clearing `cycle_pending` here is the same
451
- // proof for reviveNode's cycling-attempt marker and the one-shot yield
452
- // note — both remain pending through any pre-session_start failure and are
453
- // safe to clear on any confirmed boot (cycling, resuming, or fresh).
454
- // An ordinary fork is not bound until Pi exposes BOTH the fresh child id
455
- // and its writable session file. Recovery sees either an unbound fork or
456
- // complete child coordinates, never a mixed state that could fork
457
- // provenance twice.
458
- if (existing?.fork_from != null && existing?.pi_session_id == null && sessionFile === null) {
349
+ // crtrd validates the review binding and fork coordinates, derives whether
350
+ // this node is a root, and commits every durable session-start mutation.
351
+ const binding = await bindBrokerSession(nodeId, {
352
+ piSessionId: id,
353
+ sessionFile,
354
+ pid: process.pid,
355
+ reason,
356
+ reviewBoundaryIds: currentReviewBoundaryIds(ctx),
357
+ });
358
+ if (binding.action === 'shutdown') {
459
359
  try {
460
360
  ctx?.shutdown?.();
461
361
  }
462
362
  catch { /* best-effort */ }
463
363
  return;
464
364
  }
465
- // Identity (session id/file) → meta; runtime (pid, intent) → atomic row
466
- // setters. Any confirmed boot owns the one-shot yield note, if any;
467
- // clear it once here so a pre-session_start retry preserves it, but a
468
- // successful revival can still only consume it once.
469
- clearYieldMessage(nodeId);
470
- updateNode(nodeId, {
471
- pi_session_id: id,
472
- pi_session_file: sessionFile,
473
- cycle_pending: false,
474
- });
475
- recordPid(nodeId, process.pid);
476
- if (existing?.intent === 'refresh')
477
- transition(nodeId, 'revive');
365
+ if (binding.action === 'relaunch_root') {
366
+ // The session-bound handler selects this consequence but never calls
367
+ // back into its calling broker. Do not await the operation that tears
368
+ // this broker down from Pi's session-start dispatch.
369
+ void relaunchBrokerRoot(nodeId).catch((error) => {
370
+ emitEvent({
371
+ event: 'broker.daemon.operation.failed',
372
+ level: 'error',
373
+ node_id: nodeId,
374
+ error,
375
+ fields: { operation: 'relaunch_root' },
376
+ });
377
+ });
378
+ }
478
379
  }
479
- catch {
480
- /* best-effort; never surface from an extension handler */
380
+ catch (error) {
381
+ // Binding failure leaves Pi alive; crtrd remains the only process that
382
+ // can retry or reconcile the durable state.
383
+ emitEvent({
384
+ event: 'broker.daemon.operation.failed',
385
+ level: 'error',
386
+ node_id: nodeId,
387
+ error,
388
+ fields: { operation: 'session_bound' },
389
+ });
481
390
  }
482
391
  });
483
392
  // ---------------------------------------------------------------------------
@@ -488,8 +397,6 @@ export function registerCanvasStophook(pi) {
488
397
  pi.on('agent_start', () => {
489
398
  // A fresh turn started. Keep any active fault marker in place so the daemon's
490
399
  // retry accounting survives a failed retry cycle; just mark the turn busy.
491
- agentRunning = true;
492
- resetParkClock();
493
400
  try {
494
401
  markBusy(nodeId);
495
402
  }
@@ -567,56 +474,43 @@ export function registerCanvasStophook(pi) {
567
474
  // intent only flips to 'refresh' via `node yield`, so this can't false-fire.
568
475
  // (A node that somehow boots already carrying intent='refresh' correctly
569
476
  // refreshes on its first tool — the desired outcome.)
570
- pi.on('tool_execution_end', (_event, ctx) => {
477
+ pi.on('tool_execution_end', async (_event, ctx) => {
571
478
  try {
572
479
  touchBusy(nodeId); // wedge heartbeat: the tool returning is a sign of life
573
480
  clearFault(nodeId, { link: 'daemon→node' }); // a tool that was "stuck" just returned — the wedge notice was resolved
574
- if (getNode(nodeId)?.intent === 'refresh') {
481
+ if ((await brokerExtensionState(nodeId)).node.intent === 'refresh') {
482
+ // Stop this turn immediately so the large context does not keep running,
483
+ // but leave the broker alive through agent_settled. Only a successful
484
+ // daemon settle directive may request Pi shutdown.
575
485
  try {
576
486
  ctx?.abort?.();
577
487
  }
578
488
  catch { /* ignore */ }
579
- try {
580
- ctx?.shutdown?.();
581
- }
582
- catch { /* ignore */ }
583
489
  }
584
490
  }
585
491
  catch { /* best-effort */ }
586
492
  });
587
493
  // ---------------------------------------------------------------------------
588
- // session_shutdown — clean exit → done.
589
- //
590
- // pi hands us a reason as a session tears down. Only 'quit' is a node-ending
591
- // event we record (markCleanExitDone guards against clobbering a node
592
- // settlement already routed to done/refresh/idle-release). 'new' is owned by
593
- // the session_start trigger above; reload/resume/fork keep the SAME node id on
594
- // a swapped conversation. A true crash fires NO session_shutdown and falls
595
- // through to the daemon's window-gone 'dead'.
596
- //
597
- // MUST stay synchronous (no await): the synchronous DatabaseSync write then
598
- // lands within pi's awaited shutdown emit, before pi exits.
494
+ // session_shutdown — Pi's clean /quit fact goes to crtrd, which owns the
495
+ // finish transition, focus teardown, presence clear, and fault clear. Other
496
+ // session swaps keep the same node and need no durable settlement.
599
497
  // ---------------------------------------------------------------------------
600
- pi.on('session_shutdown', (event, _ctx) => {
601
- sessionBound = false;
602
- agentRunning = false;
603
- parkContext = null;
604
- resetParkClock();
605
- if (parkTimer !== null) {
606
- clearInterval(parkTimer);
607
- parkTimer = null;
608
- }
498
+ pi.on('session_shutdown', async (event, ctx) => {
499
+ clearBusy(nodeId); // turn marker is meaningless once Pi is exiting
500
+ if (event?.reason !== 'quit')
501
+ return;
609
502
  try {
610
- clearBusy(nodeId); // turn marker is meaningless once pi is exiting
611
- clearFault(nodeId); // ditto the active fault marker
612
- // Clean /quit (reason='quit') resolves the node to done; if it held the
613
- // user's viewport, Q1-close it (tearDownNode kills the frozen focus pane +
614
- // closes the focus row → returns the user to a shell, §1.5/flow (e)). pi is
615
- // already exiting here, so killing its own pane is not a self-saw.
616
- if (markCleanExitDone(nodeId, event?.reason))
617
- tearDownNode(nodeId);
503
+ const directive = await settleBroker(nodeId, {
504
+ stopReason: 'quit',
505
+ backgroundJobsRunning: backgroundJobsRunning(),
506
+ pushedFinal: false,
507
+ askedHuman: false,
508
+ });
509
+ enactSettleDirective(directive, ctx);
510
+ }
511
+ catch (error) {
512
+ emitDaemonOperationFailure('settle_quit', error);
618
513
  }
619
- catch { /* best-effort; never throw out of an extension handler */ }
620
514
  });
621
515
  /** Absorb usage + model from any assistant message (turn or final batch). */
622
516
  const accumulate = (msg) => {
@@ -631,7 +525,7 @@ export function registerCanvasStophook(pi) {
631
525
  // turn_end — live telemetry refresh.
632
526
  // event shape: { message: AssistantMessage, ... }
633
527
  // ---------------------------------------------------------------------------
634
- pi.on('turn_end', (event, ctx) => {
528
+ pi.on('turn_end', async (event, ctx) => {
635
529
  accumulate(event?.message);
636
530
  // The CURRENT context size via ctx.getContextUsage() — the exact figure pi's
637
531
  // footer shows. Captured once here for two consumers: the telemetry flush
@@ -686,13 +580,11 @@ export function registerCanvasStophook(pi) {
686
580
  // is a ~2-token uncached delta each turn), so the bands were unreachable and
687
581
  // the nudge never fired.
688
582
  try {
689
- const node = getNode(nodeId);
690
- const lifecycle = node?.lifecycle ?? 'terminal';
691
- const mode = node?.mode ?? 'base';
583
+ const node = (await brokerExtensionState(nodeId)).node;
692
584
  const at = contextTokens !== null ? steerBand(contextTokens) : null;
693
585
  if (at !== null && !firedBands.has(at)) {
694
586
  firedBands.add(at);
695
- const note = formatContextNudge(steerNote(at, lifecycle, mode));
587
+ const note = formatContextNudge(steerNote(at, node.lifecycle, node.mode));
696
588
  if (runContinues) {
697
589
  pi.sendUserMessage(note, { deliverAs: 'steer' });
698
590
  }
@@ -700,27 +592,17 @@ export function registerCanvasStophook(pi) {
700
592
  pi.sendMessage({ customType: CONTEXT_NUDGE_CUSTOM_TYPE, content: note, display: true }, { deliverAs: 'nextTurn' });
701
593
  }
702
594
  }
703
- }
704
- catch {
705
- /* steering is best-effort */
706
- }
707
- // Persona-transition steering. When this node's mode or lifecycle changed
708
- // since it was last GIVEN guidance (it ran `crtr node promote` / `node
709
- // lifecycle` this turn, or a sibling/human flipped it while the node was
710
- // active), inject the guidance for its NEW persona once, then commit the
711
- // ack so the next turn sees no drift. This is the single delivery site for
712
- // in-session transitions — state-changing commands never hand-emit guidance.
713
- // Delivered as a STEER (like the context nudge): a persona change must
714
- // redirect the node at the turn boundary, not queue behind its next action.
715
- try {
716
- const drift = personaDrift(nodeId);
595
+ // Persona-transition steering. The daemon read snapshots both the
596
+ // expected ack and current persona; its guarded ack below can only commit
597
+ // exactly the transition this broker just described.
598
+ const drift = personaDriftFromBrokerState(node);
717
599
  if (drift !== null) {
718
600
  pi.sendUserMessage(formatPersonaTransition(drift.guidance), { deliverAs: 'steer' });
719
- commitPersonaAck(nodeId, drift.to);
601
+ await commitBrokerPersonaAck(nodeId, { from: drift.from, to: drift.to });
720
602
  }
721
603
  }
722
604
  catch {
723
- /* persona steering is best-effort */
605
+ /* steering is best-effort */
724
606
  }
725
607
  });
726
608
  // Pi may emit several agent_end attempts while it compacts, retries, and
@@ -737,199 +619,35 @@ export function registerCanvasStophook(pi) {
737
619
  catch { /* best-effort */ }
738
620
  });
739
621
  // ---------------------------------------------------------------------------
740
- // agent_settled — whole-run lifecycle commit after recovery and continuations.
622
+ // agent_settled — Pi supplies stop facts; crtrd commits every canvas effect
623
+ // and returns the one Pi-side consequence to enact.
741
624
  // ---------------------------------------------------------------------------
742
- pi.on('agent_settled', (_event, ctx) => {
743
- agentRunning = false;
744
- resetParkClock();
625
+ pi.on('agent_settled', async (_event, ctx) => {
745
626
  const event = stagedAgentEnd;
746
627
  stagedAgentEnd = null;
747
- // Busy and wedge state describe the whole run, so settlement clears them
748
- // even when an abnormal engine path produced no stageable agent_end payload.
628
+ // Busy is a broker-local job marker. The daemon operation below owns the
629
+ // fault marker, stop policy, lifecycle transition, focus, and inbox cursor
630
+ // decision even when Pi had no stageable final agent_end payload.
749
631
  clearBusy(nodeId);
750
- clearFault(nodeId, { link: 'daemon→node' });
751
- if (event === null)
752
- return;
753
- // All routing here is synchronous fs. Provider-fault publication belongs to
754
- // the broker's richer AgentSession event stream and commits at the same
755
- // settlement boundary before its retry/notification scheduling proceeds.
632
+ const messages = Array.isArray(event?.messages) ? event.messages : [];
633
+ const last = lastAssistantMessage(messages);
634
+ const stopReason = typeof last?.stopReason === 'string' ? last.stopReason : '';
635
+ const stopSignals = event === null
636
+ ? { pushedFinal: false, askedHuman: false }
637
+ : consumeStopSignals(nodeId);
756
638
  try {
757
- const messages = Array.isArray(event?.messages) ? event.messages : [];
758
- const last = lastAssistantMessage(messages);
759
- const stopReason = last?.stopReason ?? '';
760
- // Interrupted or errored runs stay alive for re-steering. The broker
761
- // publishes any settled provider fault from its subscriber event stream.
762
- if (stopReason !== 'stop' && stopReason !== 'length') {
763
- // A refresh-yield aborts its OWN turn (the tool_execution_end handler
764
- // above calls ctx.abort() the instant `crtr node yield` returns), so a
765
- // non-'stop' stopReason here is the deliberate refresh, never a failed
766
- // run. Shut down and let the daemon relaunch the node fresh against
767
- // its roadmap; classifying it below would crash the node instead and
768
- // the daemon's exit policy would then forget an already-dead row,
769
- // stranding the yield.
770
- if (getNode(nodeId)?.intent === 'refresh') {
771
- try {
772
- ctx?.shutdown?.();
773
- }
774
- catch { /* ignore */ }
775
- }
776
- return;
777
- }
778
- // TRULY-DONE (pushed `final` this turn). The engine is a detached
779
- // broker, not a pane, so there is no engine to hand off — just close
780
- // this node's VIEWER pane (if any) and shut the broker down. The daemon
781
- // won't revive a done node. tearDownNode closes the viewer focus row +
782
- // pane; ctx.shutdown() exits the broker process.
783
- //
784
- // EVERY step here is best-effort and the shutdown lives in `finally`: the
785
- // `pushedFinal` marker path exists precisely so a broker need not read
786
- // canvas state to know it finished, so a failing local canvas read/write
787
- // (focusOf/setPresence) must not be what keeps a finalized broker alive.
788
- // The enclosing agent_settled catch would swallow the throw and leave the
789
- // process running forever.
790
- const shutDownFinished = () => {
791
- try {
792
- try {
793
- clearFault(nodeId);
794
- }
795
- catch { /* best-effort */ }
796
- try {
797
- if (focusOf(nodeId) !== null)
798
- tearDownNode(nodeId);
799
- }
800
- catch { /* best-effort */ }
801
- try {
802
- setPresence(nodeId, { pane: null, tmux_session: null, window: null });
803
- }
804
- catch { /* best-effort */ }
805
- }
806
- finally {
807
- try {
808
- ctx?.shutdown?.();
809
- }
810
- catch { /* ignore */ }
811
- }
812
- };
813
- // A successful command records its own outcome before it returns to pi.
814
- // Consume that outcome before any canvas read: a broker must not re-read
815
- // state which crtrd just committed in order to decide whether this turn
816
- // can finish or wait for the human.
817
- const stopSignals = consumeStopSignals(nodeId);
818
- if (stopSignals.pushedFinal) {
819
- shutDownFinished();
820
- return;
821
- }
822
- if (stopSignals.askedHuman) {
823
- try {
824
- clearFault(nodeId);
825
- }
826
- catch { /* best-effort */ }
827
- return;
828
- }
829
- // (b) Already done: `crtr push --final` was called this turn, which
830
- // transitions node.status → 'done' synchronously. Shut down cleanly.
831
- const node = getNode(nodeId);
832
- if (node?.status === 'done') {
833
- shutDownFinished();
834
- return;
835
- }
836
- // (b') Refresh-yield BACKSTOP: the node ran `crtr node yield` this turn,
837
- // setting intent='refresh'. The primary exit is the tool_execution_end
838
- // handler above, which shuts down the instant the yield tool returns
839
- // (so the model never burns more context finishing the turn); this
840
- // branch only fires if that shutdown was missed. Either way: shut the
841
- // broker down — the daemon sees the dead pid + intent='refresh' and
842
- // reviveNode relaunches the broker FRESH (no resume) so the node
843
- // re-reads its roadmap. (The daemon also force-recycles a stuck
844
- // refresh whose engine never exits, so a stale in-process stophook
845
- // can't strand the yield — see crtrd.)
846
- if (node?.intent === 'refresh') {
847
- // A yield is SILENT to subscribers: the node keeps its identity and
848
- // subscription edges across the revive and reports only through its own
849
- // explicit `crtr push` calls, so there is no checkpoint push here.
850
- try {
851
- ctx?.shutdown?.();
852
- }
853
- catch { /* ignore */ }
854
- return;
855
- }
856
- // (c) Natural stop — run the stop-guard to classify this stop. Nothing
857
- // is auto-pushed: the node reaches its subscribers only through its
858
- // own explicit `crtr push` calls this turn. The guard decides
859
- // whether the stop is a legitimate dormancy (idle-release, or an
860
- // attended root staying live) or a stall to reprompt.
861
- const decision = evaluateStop(nodeId, stopSignals);
862
- if (decision.action === 'reprompt') {
863
- // Stalled — re-prompt so the node finishes or escalates with an
864
- // explicit `crtr push final` (or `crtr human ask`). Deliver as a
865
- // followUp: the turn just ended but pi may still be flushing, so an
866
- // unqualified sendUserMessage races with 'already processing'.
867
- pi.sendUserMessage(decision.message, { deliverAs: 'followUp' });
868
- try {
869
- clearFault(nodeId);
870
- }
871
- catch { /* best-effort */ }
872
- return;
873
- }
874
- // 'allow' — the node legitimately stopped. The active-fault marker can
875
- // clear now; any report it owed its subscribers was sent by an explicit
876
- // `crtr push` during the turn.
877
- try {
878
- clearFault(nodeId);
879
- }
880
- catch { /* best-effort */ }
881
- if (decision.reason === 'finished') {
882
- // A canonical final can race the in-process watcher just like an
883
- // awaiting stop: keep the broker alive until any non-deferred entry
884
- // beyond the durable cursor has been delivered and committed.
885
- if (readInboxSince(nodeId, readCursor(nodeId)).some((entry) => entry.tier !== 'deferred'))
886
- return;
887
- try {
888
- ctx?.shutdown?.();
889
- }
890
- catch { /* ignore */ }
891
- return;
892
- }
893
- //
894
- // Idle-release: an unfocused node awaiting a subscribed node, controller,
895
- // or background bash job (reason 'awaiting') is holding a live broker for
896
- // nothing. Mark it idle-released and shut pi down; the daemon watches its
897
- // inbox and revives it (resume) when the awaited delivery arrives. A
898
- // resident node never releases: the human is its wake source, so we keep
899
- // its broker live and dormant.
900
- if (decision.reason === 'awaiting' || decision.reason === 'scheduled') {
901
- // AWAITING ≠ done (no manager-takeover). What happens next splits on
902
- // whether the user is WATCHING this node:
903
- // • FOCUSED → it holds the user's viewport, so keep pi LIVE and
904
- // dormant (exactly like a resident root): do NOT release or shut
905
- // down. The in-process inbox-watcher (still alive) wakes it the
906
- // instant a worker pushes — no respawn, no frozen pane, the pane
907
- // stays interactive. When the user later focuses AWAY, placement's
908
- // retarget reclassifies it as a parked terminal viewer and releases
909
- // it then (transition 'release' + pane reaped), so the kept-alive
910
- // pi is reclaimed on focus-away, never held forever.
911
- // • UNFOCUSED → no one is watching, so holding a live pi for a window
912
- // is waste. Release it (idle + idle-release) and shut pi down; its
913
- // backstage pane closes and the daemon revives it (resume) on the
914
- // next unseen inbox entry.
915
- if (focusOf(nodeId) !== null)
916
- return; // focused → stay alive, dormant
917
- // Match the daemon's idle-release wake gate: a resume wake does not
918
- // drainBearings, so a non-deferred entry past the durable cursor must
919
- // keep this broker alive for the watcher to deliver and commit it.
920
- // Deferred entries ride the next natural cycle (#341).
921
- if (readInboxSince(nodeId, readCursor(nodeId)).some((entry) => entry.tier !== 'deferred'))
922
- return;
923
- transition(nodeId, 'release');
924
- try {
925
- ctx?.shutdown?.();
926
- }
927
- catch { /* ignore */ }
928
- return;
929
- }
639
+ const directive = await settleBroker(nodeId, {
640
+ stopReason,
641
+ backgroundJobsRunning: backgroundJobsRunning(),
642
+ pushedFinal: stopSignals.pushedFinal,
643
+ askedHuman: stopSignals.askedHuman,
644
+ });
645
+ enactSettleDirective(directive, ctx);
930
646
  }
931
- catch {
932
- /* agent_settled handler must never throw out of the extension */
647
+ catch (error) {
648
+ // A daemon failure is observable and leaves this broker alive; it must not
649
+ // masquerade as a completed release, teardown, or cursor settlement.
650
+ emitDaemonOperationFailure('settle', error);
933
651
  }
934
652
  });
935
653
  }