@north-light/crouter 0.3.172 → 0.3.174

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 (673) 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} +106 -177
  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 +55 -0
  46. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +60 -0
  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/node/bash.d.ts +1 -0
  138. package/dist/commands/node/bash.js +198 -0
  139. package/dist/commands/node/create.d.ts +23 -0
  140. package/dist/commands/node/create.js +207 -0
  141. package/dist/commands/node/inspect.d.ts +2 -0
  142. package/dist/commands/node/inspect.js +302 -0
  143. package/dist/commands/node/lifecycle.d.ts +4 -0
  144. package/dist/commands/node/lifecycle.js +415 -0
  145. package/dist/commands/node/message.d.ts +1 -0
  146. package/dist/commands/node/message.js +164 -0
  147. package/dist/commands/node/pyramid.d.ts +2 -0
  148. package/dist/commands/node/pyramid.js +79 -0
  149. package/dist/commands/node/subscription.d.ts +1 -0
  150. package/dist/commands/node/subscription.js +82 -0
  151. package/dist/commands/node/wait.d.ts +1 -0
  152. package/dist/commands/node/wait.js +159 -0
  153. package/dist/commands/node-lifecycle-revive.js +10 -57
  154. package/dist/commands/node.d.ts +0 -42
  155. package/dist/commands/node.js +11 -2065
  156. package/dist/commands/search.js +1 -1
  157. package/dist/commands/surface/node/cycle.d.ts +1 -0
  158. package/dist/commands/surface/node/cycle.js +83 -0
  159. package/dist/commands/surface/node/focus.d.ts +1 -0
  160. package/dist/commands/surface/node/focus.js +67 -0
  161. package/dist/commands/surface/node/id.d.ts +1 -0
  162. package/dist/commands/surface/node/id.js +38 -0
  163. package/dist/commands/surface/node/pin.d.ts +1 -0
  164. package/dist/commands/surface/node/pin.js +42 -0
  165. package/dist/commands/surface/node/placement.d.ts +46 -0
  166. package/dist/commands/surface/node/placement.js +124 -0
  167. package/dist/commands/surface-node.js +4 -1
  168. package/dist/commands/surface-reload.js +1 -2
  169. package/dist/commands/surface-tmux-spread.js +1 -1
  170. package/dist/commands/surface.js +5 -20
  171. package/dist/commands/sys/__tests__/setup-core.test.js +18 -271
  172. package/dist/commands/sys/config.js +6 -6
  173. package/dist/commands/sys/logs.js +1 -1
  174. package/dist/commands/sys/panels/broker-limits-panel.d.ts +17 -0
  175. package/dist/commands/sys/panels/broker-limits-panel.js +104 -0
  176. package/dist/commands/sys/panels/dependencies-panel.d.ts +14 -0
  177. package/dist/commands/sys/panels/dependencies-panel.js +80 -0
  178. package/dist/commands/sys/panels/keybindings-panel.d.ts +56 -0
  179. package/dist/commands/sys/panels/keybindings-panel.js +703 -0
  180. package/dist/commands/sys/panels/keys-panel.d.ts +16 -0
  181. package/dist/commands/sys/panels/keys-panel.js +60 -0
  182. package/dist/commands/sys/panels/models-panel.d.ts +77 -0
  183. package/dist/commands/sys/panels/models-panel.js +647 -0
  184. package/dist/commands/sys/panels/panel.d.ts +45 -0
  185. package/dist/commands/sys/panels/panel.js +137 -0
  186. package/dist/commands/sys/panels/plugins-panel.d.ts +16 -0
  187. package/dist/commands/sys/panels/plugins-panel.js +80 -0
  188. package/dist/commands/sys/panels/prefs-panel.d.ts +21 -0
  189. package/dist/commands/sys/panels/prefs-panel.js +85 -0
  190. package/dist/commands/sys/panels/provider-panel.d.ts +62 -0
  191. package/dist/commands/sys/panels/provider-panel.js +538 -0
  192. package/dist/commands/sys/settings-shell.d.ts +55 -0
  193. package/dist/commands/sys/settings-shell.js +400 -0
  194. package/dist/commands/sys/settings.d.ts +2 -0
  195. package/dist/commands/sys/settings.js +31 -0
  196. package/dist/commands/sys/setup-core.d.ts +3 -33
  197. package/dist/commands/sys/setup-core.js +27 -78
  198. package/dist/commands/sys/setup-settings-runner.d.ts +24 -0
  199. package/dist/commands/sys/setup-settings-runner.js +63 -0
  200. package/dist/commands/sys/setup-wizard.d.ts +26 -125
  201. package/dist/commands/sys/setup-wizard.js +209 -2473
  202. package/dist/commands/sys/setup.js +5 -7
  203. package/dist/commands/sys.js +3 -2
  204. package/dist/core/__tests__/broker-extension-canvas-db-boundary.test.js +50 -0
  205. package/dist/core/__tests__/broker-launch-candidates.test.js +20 -9
  206. package/dist/core/__tests__/broker-preflight.test.js +1 -1
  207. package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +108 -27
  208. package/dist/core/__tests__/canvas-inbox-watcher.test.js +14 -0
  209. package/dist/core/__tests__/canvas.test.js +2 -36
  210. package/dist/core/__tests__/close.test.js +14 -3
  211. package/dist/core/__tests__/context-intro.test.js +32 -143
  212. package/dist/core/__tests__/cron-broker-capacity.test.js +22 -3
  213. package/dist/core/__tests__/daemon-boot.test.js +2 -20
  214. package/dist/core/__tests__/daemon-wedge.test.js +1 -1
  215. package/dist/core/__tests__/dead-node-policy-table.test.js +1 -18
  216. package/dist/core/__tests__/fixtures/fake-engine.d.ts +1 -1
  217. package/dist/core/__tests__/fixtures/fake-engine.js +2 -2
  218. package/dist/core/__tests__/fixtures/fake-pi-host.js +2 -2
  219. package/dist/core/__tests__/focuses.test.js +4 -98
  220. package/dist/core/__tests__/helpers/broker-clients.d.ts +0 -3
  221. package/dist/core/__tests__/helpers/broker-clients.js +0 -14
  222. package/dist/core/__tests__/helpers/harness.d.ts +0 -8
  223. package/dist/core/__tests__/helpers/harness.js +7 -87
  224. package/dist/core/__tests__/helpers/viewer-panes.js +1 -1
  225. package/dist/core/__tests__/inline-memory-refs.test.js +5 -134
  226. package/dist/core/__tests__/kickoff.test.js +1 -1
  227. package/dist/core/__tests__/memory-resolver-precedence.test.js +29 -1
  228. package/dist/core/__tests__/migration.test.js +35 -48
  229. package/dist/core/__tests__/on-read-dedup-resume.test.js +22 -12
  230. package/dist/core/__tests__/passive-subscription.test.js +26 -49
  231. package/dist/core/__tests__/preview-registry-sync.test.js +1 -2
  232. package/dist/core/__tests__/prune.test.js +94 -1
  233. package/dist/core/__tests__/review-model-floor.test.js +0 -32
  234. package/dist/core/__tests__/seam/broker-attach-multiclient.test.js +255 -0
  235. package/dist/core/__tests__/{full → seam}/broker-attach-stream.test.js +39 -7
  236. package/dist/core/__tests__/{full → seam}/broker-crash-teardown.test.js +30 -29
  237. package/dist/core/__tests__/{full → seam}/broker-pane-resolution.test.js +54 -5
  238. package/dist/core/__tests__/{full → seam}/broker-provider-retry.test.js +134 -82
  239. package/dist/core/__tests__/{full → seam}/broker-whip-interrupt.test.js +15 -4
  240. package/dist/core/__tests__/{full/idle-release-settlement.test.js → seam/dormancy-release.test.js} +69 -17
  241. package/dist/core/__tests__/{full/yield-message-transaction.test.js → seam/yield-refresh-transaction.test.js} +31 -9
  242. package/dist/core/__tests__/secrets.test.js +1 -7
  243. package/dist/core/__tests__/{broker-fork-seam.test.js → serial/broker-fork-seam.test.js} +58 -7
  244. package/dist/core/__tests__/{broker-sdk-wiring.test.js → serial/broker-sdk-wiring.test.js} +18 -162
  245. package/dist/core/__tests__/{broker-snapshot-history.test.js → serial/broker-snapshot-history.test.js} +9 -9
  246. package/dist/core/__tests__/{command-plugins.test.js → serial/command-plugins.test.js} +105 -15
  247. package/dist/core/__tests__/{deferred-no-wake.test.js → serial/deferred-no-wake.test.js} +23 -20
  248. package/dist/core/__tests__/{flagship-lifecycle.test.js → serial/flagship-lifecycle.test.js} +7 -7
  249. package/dist/core/__tests__/{host-teardown-process-group.test.js → serial/host-teardown-process-group.test.js} +6 -6
  250. package/dist/core/__tests__/{human-deliver-e2e.test.js → serial/human-deliver-e2e.test.js} +12 -12
  251. package/dist/core/__tests__/{live-mutation.test.js → serial/live-mutation.test.js} +5 -5
  252. package/dist/core/__tests__/{refresh-stall-recycle.test.js → serial/refresh-stall-recycle.test.js} +5 -14
  253. package/dist/core/__tests__/{revive.test.js → serial/revive.test.js} +15 -100
  254. package/dist/core/__tests__/{spawn-root.test.js → serial/spawn-root.test.js} +32 -15
  255. package/dist/core/__tests__/serial/subscription-delivery.test.js +126 -0
  256. package/dist/core/__tests__/serial/tmux-surface.test.js +256 -0
  257. package/dist/core/__tests__/{worktree.test.js → serial/worktree.test.js} +15 -15
  258. package/dist/core/__tests__/session-model.test.js +0 -18
  259. package/dist/core/__tests__/spawn-worktree-id-conflict.test.js +9 -0
  260. package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +50 -0
  261. package/dist/core/broker-client/__tests__/transport-relay.test.js +15 -16
  262. package/dist/core/broker-client/__tests__/transport-socket.test.js +28 -0
  263. package/dist/core/broker-client/client.d.ts +2 -2
  264. package/dist/core/broker-client/client.js +4 -7
  265. package/dist/core/broker-client/transport-relay.d.ts +13 -19
  266. package/dist/core/broker-client/transport-relay.js +19 -34
  267. package/dist/core/broker-client/transport-socket.d.ts +2 -2
  268. package/dist/core/broker-client/transport-socket.js +9 -2
  269. package/dist/core/broker-client/transport.d.ts +7 -3
  270. package/dist/core/broker-client/transport.js +4 -4
  271. package/dist/core/canvas/__tests__/attention.test.js +1 -18
  272. package/dist/core/canvas/__tests__/remote-canvas-source.test.js +7 -64
  273. package/dist/core/canvas/__tests__/remote-transport.test.js +2 -3
  274. package/dist/core/canvas/__tests__/render-remote.test.js +7 -52
  275. package/dist/core/canvas/browse/app.d.ts +2 -17
  276. package/dist/core/canvas/browse/app.js +16 -88
  277. package/dist/core/canvas/browse/model.d.ts +0 -4
  278. package/dist/core/canvas/browse/model.js +1 -12
  279. package/dist/core/canvas/browse/render.js +6 -3
  280. package/dist/core/canvas/crons.d.ts +8 -5
  281. package/dist/core/canvas/crons.js +7 -6
  282. package/dist/core/canvas/extensions.d.ts +7 -3
  283. package/dist/core/canvas/extensions.js +16 -4
  284. package/dist/core/canvas/nav-model.d.ts +0 -4
  285. package/dist/core/canvas/nav-model.js +2 -14
  286. package/dist/core/canvas/node-order.d.ts +3 -0
  287. package/dist/core/canvas/node-order.js +12 -0
  288. package/dist/core/canvas/remote-canvas-source.d.ts +3 -6
  289. package/dist/core/canvas/remote-canvas-source.js +8 -15
  290. package/dist/core/command.js +11 -4
  291. package/dist/core/config.js +3 -1
  292. package/dist/core/events/envelope.js +1 -1
  293. package/dist/core/events/read.js +7 -21
  294. package/dist/core/events/source.d.ts +0 -2
  295. package/dist/core/events/source.js +0 -16
  296. package/dist/core/events/types.d.ts +1 -1
  297. package/dist/core/fault-classifier.d.ts +1 -1
  298. package/dist/core/feed/passive.d.ts +0 -11
  299. package/dist/core/feed/passive.js +1 -62
  300. package/dist/core/human/__tests__/{inbox-core.test.js → serial/inbox-core.test.js} +6 -6
  301. package/dist/core/keybindings/__tests__/resolve.test.js +1 -96
  302. package/dist/core/keybindings/background-bash.js +3 -4
  303. package/dist/core/keybindings/catalog.js +1 -1
  304. package/dist/core/memory/inline-ref-grammar.js +3 -3
  305. package/dist/core/memory-resolver.d.ts +11 -25
  306. package/dist/core/memory-resolver.js +51 -33
  307. package/dist/core/model-routes.d.ts +15 -0
  308. package/dist/core/model-routes.js +12 -0
  309. package/dist/core/pool-credential-store.js +1 -1
  310. package/dist/core/preview-registry.js +8 -9
  311. package/dist/core/profiles/__tests__/root-profile.test.js +4 -14
  312. package/dist/core/review/realize.d.ts +0 -13
  313. package/dist/core/review/realize.js +0 -40
  314. package/dist/core/review/types.d.ts +1 -1
  315. package/dist/core/runtime/__tests__/engine-route.test.js +2 -2
  316. package/dist/core/runtime/bearings.js +1 -11
  317. package/dist/core/runtime/broker/client-registry.d.ts +33 -0
  318. package/dist/core/runtime/broker/client-registry.js +164 -0
  319. package/dist/core/runtime/broker/daemon-ops.d.ts +19 -0
  320. package/dist/core/runtime/broker/daemon-ops.js +49 -0
  321. package/dist/core/runtime/broker/event-projection.d.ts +42 -0
  322. package/dist/core/runtime/broker/event-projection.js +178 -0
  323. package/dist/core/runtime/broker/fault-retry.d.ts +39 -0
  324. package/dist/core/runtime/broker/fault-retry.js +277 -0
  325. package/dist/core/runtime/broker/frame-dispatch.d.ts +238 -0
  326. package/dist/core/runtime/broker/frame-dispatch.js +1537 -0
  327. package/dist/core/runtime/broker/inbox.d.ts +22 -0
  328. package/dist/core/runtime/broker/inbox.js +167 -0
  329. package/dist/core/runtime/broker/passive.d.ts +16 -0
  330. package/dist/core/runtime/broker/passive.js +44 -0
  331. package/dist/core/runtime/broker/read-ops.d.ts +23 -0
  332. package/dist/core/runtime/broker/read-ops.js +150 -0
  333. package/dist/core/runtime/broker/rebind.d.ts +74 -0
  334. package/dist/core/runtime/broker/rebind.js +211 -0
  335. package/dist/core/runtime/broker/tool-groups.d.ts +39 -0
  336. package/dist/core/runtime/broker/tool-groups.js +244 -0
  337. package/dist/core/runtime/broker-extension-render.d.ts +11 -0
  338. package/dist/core/runtime/broker-extension-render.js +181 -0
  339. package/dist/core/runtime/broker-persona-guidance.d.ts +13 -0
  340. package/dist/core/runtime/broker-persona-guidance.js +58 -0
  341. package/dist/core/runtime/broker-protocol.d.ts +1 -1
  342. package/dist/core/runtime/broker-protocol.js +1 -1
  343. package/dist/core/runtime/broker.d.ts +5 -196
  344. package/dist/core/runtime/broker.js +276 -3059
  345. package/dist/core/runtime/canvas-extensions.js +11 -2
  346. package/dist/core/runtime/fault.js +1 -1
  347. package/dist/core/runtime/model-selection.d.ts +9 -0
  348. package/dist/core/runtime/model-selection.js +12 -0
  349. package/dist/core/runtime/model-swap.d.ts +3 -3
  350. package/dist/core/runtime/model-swap.js +33 -25
  351. package/dist/core/runtime/placement-tmux.d.ts +3 -14
  352. package/dist/core/runtime/placement-tmux.js +11 -80
  353. package/dist/core/runtime/placement.d.ts +4 -2
  354. package/dist/core/runtime/placement.js +7 -12
  355. package/dist/core/runtime/promote.d.ts +14 -1
  356. package/dist/core/runtime/promote.js +1 -1
  357. package/dist/core/runtime/reset.d.ts +1 -1
  358. package/dist/core/runtime/roadmap.js +1 -1
  359. package/dist/core/runtime/spawn.d.ts +8 -0
  360. package/dist/core/runtime/spawn.js +36 -6
  361. package/dist/core/runtime/stop-guard.d.ts +4 -3
  362. package/dist/core/runtime/stop-guard.js +36 -18
  363. package/dist/core/runtime/stop-signals.d.ts +4 -1
  364. package/dist/core/runtime/stream-watchdog.js +4 -5
  365. package/dist/core/runtime/structured-output.d.ts +15 -2
  366. package/dist/core/runtime/structured-output.js +35 -12
  367. package/dist/core/runtime/tmux-bindings.d.ts +25 -0
  368. package/dist/core/runtime/tmux-bindings.js +682 -0
  369. package/dist/core/runtime/tmux-chrome.d.ts +2 -1
  370. package/dist/core/runtime/tmux-chrome.js +3 -2
  371. package/dist/core/runtime/{tmux.d.ts → tmux-driver.d.ts} +18 -26
  372. package/dist/core/runtime/tmux-driver.js +598 -0
  373. package/dist/core/runtime/view-socket.d.ts +14 -0
  374. package/dist/core/runtime/view-socket.js +83 -0
  375. package/dist/core/session-model/session-state.d.ts +1 -2
  376. package/dist/core/session-model/session-state.js +5 -8
  377. package/dist/core/spawn.d.ts +1 -1
  378. package/dist/core/spawn.js +2 -2
  379. package/dist/core/substrate/gate.d.ts +1 -1
  380. package/dist/core/substrate/on-read-pure.d.ts +7 -0
  381. package/dist/core/substrate/on-read-pure.js +272 -0
  382. package/dist/core/termrender/termrender.js +32 -2
  383. package/dist/core/user-settings.d.ts +23 -1
  384. package/dist/core/user-settings.js +18 -1
  385. package/dist/daemon/api/__tests__/node-model-validation.test.js +134 -0
  386. package/dist/daemon/api/__tests__/review-terminal-conflict.test.js +98 -0
  387. package/dist/daemon/api/__tests__/{full → seam}/api-server.test.js +6 -48
  388. package/dist/daemon/api/__tests__/{full → seam}/b10-attach-modelauth.test.js +17 -44
  389. package/dist/daemon/api/__tests__/{full/push-parity.test.js → seam/leaf-api-parity.test.js} +61 -42
  390. package/dist/daemon/api/bridge.js +40 -81
  391. package/dist/daemon/api/handlers/broker-ops.d.ts +2 -0
  392. package/dist/daemon/api/handlers/broker-ops.js +383 -0
  393. package/dist/daemon/api/handlers/crons.js +9 -4
  394. package/dist/daemon/api/handlers/files.js +6 -7
  395. package/dist/daemon/api/handlers/inbox.js +2 -340
  396. package/dist/daemon/api/handlers/nodes.d.ts +10 -1
  397. package/dist/daemon/api/handlers/nodes.js +74 -39
  398. package/dist/daemon/api/handlers/review-comments.js +5 -1
  399. package/dist/daemon/api/handlers/reviews.js +0 -19
  400. package/dist/daemon/api/map.js +25 -4
  401. package/dist/daemon/api/router.js +2 -3
  402. package/dist/daemon/api/server.js +5 -7
  403. package/dist/daemon/cron-run.d.ts +4 -0
  404. package/dist/daemon/cron-run.js +30 -13
  405. package/dist/daemon/crtrd.d.ts +3 -58
  406. package/dist/daemon/crtrd.js +28 -1244
  407. package/dist/daemon/manage.js +0 -1
  408. package/dist/daemon/reconcilers/broker-supervision.d.ts +50 -0
  409. package/dist/daemon/reconcilers/broker-supervision.js +549 -0
  410. package/dist/daemon/reconcilers/cron-lane.d.ts +10 -0
  411. package/dist/daemon/reconcilers/cron-lane.js +32 -0
  412. package/dist/daemon/reconcilers/dormant-inbox.d.ts +18 -0
  413. package/dist/daemon/reconcilers/dormant-inbox.js +143 -0
  414. package/dist/daemon/reconcilers/storage-maintenance.d.ts +22 -0
  415. package/dist/daemon/reconcilers/storage-maintenance.js +213 -0
  416. package/dist/daemon/review/finish.js +2 -5
  417. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +34 -53
  418. package/dist/pi-extensions/__tests__/canvas-recap.test.js +16 -113
  419. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +72 -99
  420. package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.js +29 -12
  421. package/dist/pi-extensions/broker-local.d.ts +20 -0
  422. package/dist/pi-extensions/broker-local.js +89 -0
  423. package/dist/pi-extensions/canvas-context-intro.d.ts +3 -3
  424. package/dist/pi-extensions/canvas-context-intro.js +22 -11
  425. package/dist/pi-extensions/canvas-doc-substrate.js +17 -34
  426. package/dist/pi-extensions/canvas-goal-capture.js +7 -12
  427. package/dist/pi-extensions/canvas-inbox-watcher.js +124 -139
  428. package/dist/pi-extensions/canvas-passive-context.d.ts +3 -3
  429. package/dist/pi-extensions/canvas-passive-context.js +22 -18
  430. package/dist/pi-extensions/canvas-recap.d.ts +2 -2
  431. package/dist/pi-extensions/canvas-recap.js +48 -21
  432. package/dist/pi-extensions/canvas-review-boundary.js +10 -4
  433. package/dist/pi-extensions/canvas-stophook.d.ts +0 -5
  434. package/dist/pi-extensions/canvas-stophook.js +149 -431
  435. package/dist/pi-extensions/canvas-structured-output.js +52 -30
  436. package/dist/pi-extensions/envelope-merge.d.ts +13 -0
  437. package/dist/pi-extensions/envelope-merge.js +29 -0
  438. package/dist/shared/working-activity.d.ts +3 -2
  439. package/dist/shared/working-activity.js +3 -2
  440. package/dist/types.d.ts +6 -5
  441. package/dist/types.js +2 -2
  442. package/docs/compat/hearth-crtr-v1.md +4 -12
  443. package/docs/compat/hearth-crtr-v2.md +3 -11
  444. package/docs/compat/hearth-crtr-v3.md +4 -12
  445. package/docs/compat/hearth-crtr-v4.md +3 -11
  446. package/docs/compat/hearth-crtr-v5.md +3 -11
  447. package/docs/public-api.md +3 -7
  448. package/package.json +7 -49
  449. package/runtime.lock.json +2766 -14533
  450. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/claude-plugin-commands.test.ts +0 -49
  451. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/memory-slash-commands.test.ts +0 -194
  452. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/statusline.test.ts +0 -68
  453. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/frontmatter-rules/test.ts +0 -119
  454. package/dist/clients/attach/__tests__/attach-chrome-remote.test.js +0 -439
  455. package/dist/clients/attach/__tests__/attach-keybindings.test.js +0 -170
  456. package/dist/clients/attach/__tests__/crtr-output-coverage.test.js +0 -57
  457. package/dist/clients/attach/__tests__/editor-frame-title.test.js +0 -19
  458. package/dist/clients/attach/__tests__/input-controller-extension-command.test.js +0 -32
  459. package/dist/clients/attach/__tests__/markdown-headings.test.js +0 -35
  460. package/dist/clients/attach/__tests__/session-identity-refresh.test.js +0 -32
  461. package/dist/clients/conversation/conversation.d.ts +0 -65
  462. package/dist/clients/conversation/conversation.js +0 -318
  463. package/dist/clients/conversation/frames.d.ts +0 -30
  464. package/dist/clients/conversation/frames.js +0 -52
  465. package/dist/clients/conversation/region.d.ts +0 -51
  466. package/dist/clients/conversation/region.js +0 -265
  467. package/dist/clients/inbox/__tests__/inbox-controller.test.js +0 -247
  468. package/dist/clients/inbox/__tests__/mount-panel.test.js +0 -776
  469. package/dist/clients/inbox/review/__tests__/remap.test.js +0 -196
  470. package/dist/clients/inbox/review/columns.d.ts +0 -22
  471. package/dist/clients/inbox/review/columns.js +0 -40
  472. package/dist/clients/inbox/review/composition.d.ts +0 -60
  473. package/dist/clients/inbox/review/composition.js +0 -278
  474. package/dist/clients/inbox/review/document-region.d.ts +0 -120
  475. package/dist/clients/surfaces/region.d.ts +0 -16
  476. package/dist/clients/web/__tests__/push-engine.test.js +0 -158
  477. package/dist/clients/web/__tests__/push-registry.test.d.ts +0 -1
  478. package/dist/clients/web/__tests__/push-registry.test.js +0 -177
  479. package/dist/clients/web/dev-server.d.ts +0 -7
  480. package/dist/clients/web/dev-server.js +0 -46
  481. package/dist/clients/web/events.d.ts +0 -19
  482. package/dist/clients/web/events.js +0 -163
  483. package/dist/clients/web/push-engine.d.ts +0 -44
  484. package/dist/clients/web/push-engine.js +0 -125
  485. package/dist/clients/web/push-registry.d.ts +0 -85
  486. package/dist/clients/web/push-registry.js +0 -373
  487. package/dist/clients/web/server.d.ts +0 -19
  488. package/dist/clients/web/server.js +0 -661
  489. package/dist/clients/web/web-client/shared/protocol.d.ts +0 -214
  490. package/dist/clients/web/web-client/shared/protocol.js +0 -8
  491. package/dist/clients/web/web-cmd.d.ts +0 -2
  492. package/dist/clients/web/web-cmd.js +0 -141
  493. package/dist/commands/__tests__/api-canvas-source.test.d.ts +0 -1
  494. package/dist/commands/__tests__/api-canvas-source.test.js +0 -37
  495. package/dist/commands/__tests__/canvas-config.test.d.ts +0 -1
  496. package/dist/commands/__tests__/canvas-config.test.js +0 -107
  497. package/dist/commands/__tests__/node-no-kickoff-flag.test.d.ts +0 -1
  498. package/dist/commands/__tests__/node-no-kickoff-flag.test.js +0 -73
  499. package/dist/commands/__tests__/node-worktree-flag.test.d.ts +0 -1
  500. package/dist/commands/__tests__/node-worktree-flag.test.js +0 -49
  501. package/dist/commands/__tests__/search-contents.test.d.ts +0 -1
  502. package/dist/commands/__tests__/search-contents.test.js +0 -52
  503. package/dist/commands/memory/__tests__/lint.test.d.ts +0 -1
  504. package/dist/commands/memory/__tests__/lint.test.js +0 -15
  505. package/dist/commands/sys/__tests__/config-broker-thresholds.test.d.ts +0 -1
  506. package/dist/commands/sys/__tests__/config-broker-thresholds.test.js +0 -95
  507. package/dist/commands/sys/__tests__/config-keybindings.test.d.ts +0 -1
  508. package/dist/commands/sys/__tests__/config-keybindings.test.js +0 -55
  509. package/dist/commands/sys/__tests__/helpers/setup-runtime.d.ts +0 -5
  510. package/dist/commands/sys/__tests__/helpers/setup-runtime.js +0 -19
  511. package/dist/commands/sys/__tests__/setup-front-door.test.d.ts +0 -1
  512. package/dist/commands/sys/__tests__/setup-front-door.test.js +0 -102
  513. package/dist/commands/sys/__tests__/setup-models.test.d.ts +0 -1
  514. package/dist/commands/sys/__tests__/setup-models.test.js +0 -205
  515. package/dist/commands/sys/__tests__/setup-providers-viewport.test.d.ts +0 -1
  516. package/dist/commands/sys/__tests__/setup-providers-viewport.test.js +0 -155
  517. package/dist/commands/sys/__tests__/sync-deps.test.d.ts +0 -1
  518. package/dist/commands/sys/__tests__/sync-deps.test.js +0 -179
  519. package/dist/commands/sys/__tests__/sync-import.test.d.ts +0 -1
  520. package/dist/commands/sys/__tests__/sync-import.test.js +0 -315
  521. package/dist/core/__tests__/base-worker-prompt.test.d.ts +0 -1
  522. package/dist/core/__tests__/base-worker-prompt.test.js +0 -57
  523. package/dist/core/__tests__/command-plugins-surfaces.test.d.ts +0 -1
  524. package/dist/core/__tests__/command-plugins-surfaces.test.js +0 -359
  525. package/dist/core/__tests__/connection-reconnect-resume.test.d.ts +0 -1
  526. package/dist/core/__tests__/connection-reconnect-resume.test.js +0 -36
  527. package/dist/core/__tests__/finalization-migration.test.d.ts +0 -1
  528. package/dist/core/__tests__/finalization-migration.test.js +0 -38
  529. package/dist/core/__tests__/fixtures/extra-extension.d.ts +0 -1
  530. package/dist/core/__tests__/fixtures/extra-extension.js +0 -3
  531. package/dist/core/__tests__/fixtures/spawn-proof-target.test.d.ts +0 -1
  532. package/dist/core/__tests__/fixtures/spawn-proof-target.test.js +0 -15
  533. package/dist/core/__tests__/fork.test.d.ts +0 -1
  534. package/dist/core/__tests__/fork.test.js +0 -108
  535. package/dist/core/__tests__/full/broker-attach-limits.test.d.ts +0 -1
  536. package/dist/core/__tests__/full/broker-attach-limits.test.js +0 -147
  537. package/dist/core/__tests__/full/broker-deliver-ack.test.d.ts +0 -1
  538. package/dist/core/__tests__/full/broker-deliver-ack.test.js +0 -73
  539. package/dist/core/__tests__/full/broker-dialogs.test.d.ts +0 -1
  540. package/dist/core/__tests__/full/broker-dialogs.test.js +0 -180
  541. package/dist/core/__tests__/full/broker-display-snapshot.test.d.ts +0 -1
  542. package/dist/core/__tests__/full/broker-display-snapshot.test.js +0 -75
  543. package/dist/core/__tests__/full/broker-dormant-wake.test.d.ts +0 -1
  544. package/dist/core/__tests__/full/broker-dormant-wake.test.js +0 -130
  545. package/dist/core/__tests__/full/broker-model-changed-broadcast.test.d.ts +0 -1
  546. package/dist/core/__tests__/full/broker-model-changed-broadcast.test.js +0 -57
  547. package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.d.ts +0 -1
  548. package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.js +0 -80
  549. package/dist/core/__tests__/full/cascade-close.test.d.ts +0 -1
  550. package/dist/core/__tests__/full/cascade-close.test.js +0 -240
  551. package/dist/core/__tests__/full/detach-focus.test.d.ts +0 -1
  552. package/dist/core/__tests__/full/detach-focus.test.js +0 -126
  553. package/dist/core/__tests__/full/idle-release-settlement.test.d.ts +0 -1
  554. package/dist/core/__tests__/full/issue-146-yield-spawn-focus.test.d.ts +0 -1
  555. package/dist/core/__tests__/full/issue-146-yield-spawn-focus.test.js +0 -107
  556. package/dist/core/__tests__/full/park-clock-release.test.d.ts +0 -1
  557. package/dist/core/__tests__/full/park-clock-release.test.js +0 -56
  558. package/dist/core/__tests__/full/yield-message-transaction.test.d.ts +0 -1
  559. package/dist/core/__tests__/memory-index-render.test.d.ts +0 -1
  560. package/dist/core/__tests__/memory-index-render.test.js +0 -60
  561. package/dist/core/__tests__/model-routes.test.d.ts +0 -1
  562. package/dist/core/__tests__/model-routes.test.js +0 -41
  563. package/dist/core/__tests__/on-read-identity.test.d.ts +0 -1
  564. package/dist/core/__tests__/on-read-identity.test.js +0 -61
  565. package/dist/core/__tests__/phase4-review-migration.test.d.ts +0 -1
  566. package/dist/core/__tests__/phase4-review-migration.test.js +0 -100
  567. package/dist/core/__tests__/prune-to-limit.test.d.ts +0 -1
  568. package/dist/core/__tests__/prune-to-limit.test.js +0 -126
  569. package/dist/core/__tests__/reset.test.d.ts +0 -1
  570. package/dist/core/__tests__/reset.test.js +0 -69
  571. package/dist/core/__tests__/spawn-no-kickoff.test.d.ts +0 -1
  572. package/dist/core/__tests__/spawn-no-kickoff.test.js +0 -115
  573. package/dist/core/__tests__/steer-note.test.d.ts +0 -1
  574. package/dist/core/__tests__/steer-note.test.js +0 -41
  575. package/dist/core/__tests__/subcommand-tier.test.d.ts +0 -1
  576. package/dist/core/__tests__/subcommand-tier.test.js +0 -99
  577. package/dist/core/__tests__/subscription-delivery.test.js +0 -211
  578. package/dist/core/__tests__/test-runner-cheap-sharding.test.d.ts +0 -1
  579. package/dist/core/__tests__/test-runner-cheap-sharding.test.js +0 -97
  580. package/dist/core/__tests__/tmux-surface.test.js +0 -484
  581. package/dist/core/__tests__/wake-bearings.test.d.ts +0 -1
  582. package/dist/core/__tests__/wake-bearings.test.js +0 -102
  583. package/dist/core/canvas/__tests__/remote-event-stream.test.d.ts +0 -1
  584. package/dist/core/canvas/__tests__/remote-event-stream.test.js +0 -146
  585. package/dist/core/canvas/__tests__/source-resolve.test.d.ts +0 -1
  586. package/dist/core/canvas/__tests__/source-resolve.test.js +0 -77
  587. package/dist/core/canvas/browse/__tests__/model.test.d.ts +0 -1
  588. package/dist/core/canvas/browse/__tests__/model.test.js +0 -290
  589. package/dist/core/canvas/browse/__tests__/rebuild-coalescer.test.d.ts +0 -1
  590. package/dist/core/canvas/browse/__tests__/rebuild-coalescer.test.js +0 -134
  591. package/dist/core/canvas/browse/__tests__/render.test.d.ts +0 -1
  592. package/dist/core/canvas/browse/__tests__/render.test.js +0 -111
  593. package/dist/core/canvas/browse/rebuild-coalescer.d.ts +0 -7
  594. package/dist/core/canvas/browse/rebuild-coalescer.js +0 -61
  595. package/dist/core/canvas/remote-event-stream.d.ts +0 -24
  596. package/dist/core/canvas/remote-event-stream.js +0 -94
  597. package/dist/core/feed/__tests__/coalesce-human.test.d.ts +0 -1
  598. package/dist/core/feed/__tests__/coalesce-human.test.js +0 -36
  599. package/dist/core/feed/__tests__/empty-node-guard.test.d.ts +0 -1
  600. package/dist/core/feed/__tests__/empty-node-guard.test.js +0 -45
  601. package/dist/core/host-exports/__tests__/export-prunes-boot-skill.test.d.ts +0 -1
  602. package/dist/core/host-exports/__tests__/export-prunes-boot-skill.test.js +0 -84
  603. package/dist/core/human/__tests__/visible-paths.test.d.ts +0 -1
  604. package/dist/core/human/__tests__/visible-paths.test.js +0 -28
  605. package/dist/core/keybindings/__tests__/inbox-affordance.test.d.ts +0 -1
  606. package/dist/core/keybindings/__tests__/inbox-affordance.test.js +0 -38
  607. package/dist/core/review/__tests__/project.test.d.ts +0 -1
  608. package/dist/core/review/__tests__/project.test.js +0 -71
  609. package/dist/core/runtime/__tests__/command-expansion.test.d.ts +0 -1
  610. package/dist/core/runtime/__tests__/command-expansion.test.js +0 -25
  611. package/dist/core/runtime/__tests__/session-visibility.test.d.ts +0 -1
  612. package/dist/core/runtime/__tests__/session-visibility.test.js +0 -119
  613. package/dist/core/runtime/__tests__/spawn-at-given-id.test.d.ts +0 -1
  614. package/dist/core/runtime/__tests__/spawn-at-given-id.test.js +0 -34
  615. package/dist/core/runtime/tmux.js +0 -1314
  616. package/dist/daemon/api/__tests__/full/push-parity.test.d.ts +0 -1
  617. package/dist/daemon/api/__tests__/full/worktree-parity.test.d.ts +0 -1
  618. package/dist/daemon/api/__tests__/full/worktree-parity.test.js +0 -160
  619. package/dist/daemon/api/__tests__/inbox.test.d.ts +0 -1
  620. package/dist/daemon/api/__tests__/inbox.test.js +0 -489
  621. package/dist/web-client/apple-touch-icon.png +0 -0
  622. package/dist/web-client/assets/fragment-mono-latin-400-normal-BYwT3kSJ.woff +0 -0
  623. package/dist/web-client/assets/fragment-mono-latin-400-normal-yxdJ5AmL.woff2 +0 -0
  624. package/dist/web-client/assets/fragment-mono-latin-ext-400-normal-BbKYyvR9.woff2 +0 -0
  625. package/dist/web-client/assets/fragment-mono-latin-ext-400-normal-CT4YFKeK.woff +0 -0
  626. package/dist/web-client/assets/index-CCPaLeW7.css +0 -2
  627. package/dist/web-client/assets/index-kyOWsnZK.js +0 -86
  628. package/dist/web-client/assets/martian-mono-cyrillic-wght-normal-B84CD5C_.woff2 +0 -0
  629. package/dist/web-client/assets/martian-mono-latin-ext-wght-normal-DlL6xMw5.woff2 +0 -0
  630. package/dist/web-client/assets/martian-mono-latin-wght-normal-5W32yIyr.woff2 +0 -0
  631. package/dist/web-client/assets/workbox-window.prod.es5-Bd17z0YL.js +0 -2
  632. package/dist/web-client/icon-192.png +0 -0
  633. package/dist/web-client/icon-512.png +0 -0
  634. package/dist/web-client/icon-maskable-512.png +0 -0
  635. package/dist/web-client/index.html +0 -17
  636. package/dist/web-client/manifest.webmanifest +0 -1
  637. package/dist/web-client/sw.js +0 -1
  638. /package/dist/api/__tests__/{client.test.d.ts → serial/client.test.d.ts} +0 -0
  639. /package/dist/clients/inbox/__tests__/{inbox-controller.test.d.ts → serial/inbox-controller.test.d.ts} +0 -0
  640. /package/dist/clients/inbox/__tests__/{mount-panel.test.d.ts → serial/mount-panel.test.d.ts} +0 -0
  641. /package/dist/clients/{attach/__tests__/attach-chrome-remote.test.d.ts → inbox/review/__tests__/teardown-notice.test.d.ts} +0 -0
  642. /package/dist/{clients/attach/__tests__/attach-keybindings.test.d.ts → core/__tests__/broker-extension-canvas-db-boundary.test.d.ts} +0 -0
  643. /package/dist/{clients/attach/__tests__/crtr-output-coverage.test.d.ts → core/__tests__/seam/broker-attach-multiclient.test.d.ts} +0 -0
  644. /package/dist/core/__tests__/{full → seam}/broker-attach-stream.test.d.ts +0 -0
  645. /package/dist/core/__tests__/{full → seam}/broker-crash-teardown.test.d.ts +0 -0
  646. /package/dist/core/__tests__/{full → seam}/broker-pane-resolution.test.d.ts +0 -0
  647. /package/dist/core/__tests__/{full → seam}/broker-provider-retry.test.d.ts +0 -0
  648. /package/dist/core/__tests__/{full → seam}/broker-whip-interrupt.test.d.ts +0 -0
  649. /package/dist/{clients/attach/__tests__/editor-frame-title.test.d.ts → core/__tests__/seam/dormancy-release.test.d.ts} +0 -0
  650. /package/dist/{clients/attach/__tests__/input-controller-extension-command.test.d.ts → core/__tests__/seam/yield-refresh-transaction.test.d.ts} +0 -0
  651. /package/dist/core/__tests__/{broker-fork-seam.test.d.ts → serial/broker-fork-seam.test.d.ts} +0 -0
  652. /package/dist/core/__tests__/{broker-sdk-wiring.test.d.ts → serial/broker-sdk-wiring.test.d.ts} +0 -0
  653. /package/dist/core/__tests__/{broker-snapshot-history.test.d.ts → serial/broker-snapshot-history.test.d.ts} +0 -0
  654. /package/dist/core/__tests__/{command-plugins.test.d.ts → serial/command-plugins.test.d.ts} +0 -0
  655. /package/dist/core/__tests__/{deferred-no-wake.test.d.ts → serial/deferred-no-wake.test.d.ts} +0 -0
  656. /package/dist/core/__tests__/{flagship-lifecycle.test.d.ts → serial/flagship-lifecycle.test.d.ts} +0 -0
  657. /package/dist/core/__tests__/{host-teardown-process-group.test.d.ts → serial/host-teardown-process-group.test.d.ts} +0 -0
  658. /package/dist/core/__tests__/{human-deliver-e2e.test.d.ts → serial/human-deliver-e2e.test.d.ts} +0 -0
  659. /package/dist/core/__tests__/{live-mutation.test.d.ts → serial/live-mutation.test.d.ts} +0 -0
  660. /package/dist/core/__tests__/{refresh-stall-recycle.test.d.ts → serial/refresh-stall-recycle.test.d.ts} +0 -0
  661. /package/dist/core/__tests__/{revive.test.d.ts → serial/revive.test.d.ts} +0 -0
  662. /package/dist/core/__tests__/{spawn-root.test.d.ts → serial/spawn-root.test.d.ts} +0 -0
  663. /package/dist/core/__tests__/{subscription-delivery.test.d.ts → serial/subscription-delivery.test.d.ts} +0 -0
  664. /package/dist/core/__tests__/{tmux-surface.test.d.ts → serial/tmux-surface.test.d.ts} +0 -0
  665. /package/dist/core/__tests__/{worktree.test.d.ts → serial/worktree.test.d.ts} +0 -0
  666. /package/dist/{clients/attach/__tests__/markdown-headings.test.d.ts → core/__tests__/watchdog-abort-arms-retry.test.d.ts} +0 -0
  667. /package/dist/{clients/attach/__tests__/session-identity-refresh.test.d.ts → core/broker-client/__tests__/transport-socket.test.d.ts} +0 -0
  668. /package/dist/core/human/__tests__/{inbox-core.test.d.ts → serial/inbox-core.test.d.ts} +0 -0
  669. /package/dist/{clients/inbox/review/__tests__/remap.test.d.ts → daemon/api/__tests__/node-model-validation.test.d.ts} +0 -0
  670. /package/dist/{clients/surfaces/region.js → daemon/api/__tests__/review-terminal-conflict.test.d.ts} +0 -0
  671. /package/dist/daemon/api/__tests__/{full → seam}/api-server.test.d.ts +0 -0
  672. /package/dist/daemon/api/__tests__/{full → seam}/b10-attach-modelauth.test.d.ts +0 -0
  673. /package/dist/{clients/web/__tests__/push-engine.test.d.ts → daemon/api/__tests__/seam/leaf-api-parity.test.d.ts} +0 -0
@@ -11,19 +11,17 @@ import { defineLeaf } from '../../core/command.js';
11
11
  export const BROKER_LIMIT_OVERRIDE_PRECEDENCE = 'Valid CRTR_WARN_LIVE_BROKERS and CRTR_MAX_LIVE_BROKERS environment overrides take precedence over their corresponding configured limits.';
12
12
  export const sysSetupLeaf = defineLeaf({
13
13
  name: 'setup',
14
- description: 'manage providers, setup dependencies and keys, crouter keybindings, and broker limits',
15
- whenToUse: 'you want to bootstrap this machine or change setup-owned settings: manage configured model providers, install vendored pi plugins or system dependencies, save an Exa API key, edit crouter-owned keybindings, or set broker warning and automatic-revive limits.',
14
+ description: 'bootstrap a fresh machine — provider login, companion packages, system dependencies, Exa key',
15
+ whenToUse: 'you are setting up crouter on a machine for the first time and need credentials and installs in place. Use sys settings to change configuration on an installed machine, and sys config set for scriptable edits.',
16
16
  help: {
17
17
  name: 'sys setup',
18
- summary: 'open the multi-tab setup wizard for providers, dependencies, keys, keybindings, and broker limits',
18
+ summary: 'run the first-run installer: provider login, companion packages, system dependencies, Exa key',
19
19
  inputNote: 'No input parameters.',
20
20
  output: [],
21
21
  outputKind: 'object',
22
22
  effects: [
23
- 'Opens a pi-tui wizard whose first tab logs in to a model provider (pi\'s real OAuth/API-key flow, same as in-app /login) so a fresh install has credentials before running any node.',
24
- 'Collects companion package installs, system dependency installs, API keys, sparse user overrides for crouter-owned keybindings, and user-scope broker limits across the remaining tabs.',
25
- 'Saves validated keybinding changes atomically in the user config and refreshes crouter-owned tmux bindings without overwriting occupied user keys.',
26
- `Saves positive-integer broker warning and automatic-revive hard-cap values under user config brokerThresholds; crtrd reads them on its next supervision tick. ${BROKER_LIMIT_OVERRIDE_PRECEDENCE}`,
23
+ 'Opens a four-step pi-tui installer. Step one logs in to a model provider (pi\'s real OAuth/API-key flow, same as in-app /login) so a fresh install has credentials before running any node.',
24
+ 'The remaining steps collect companion package installs, system dependency installs, and an Exa API key, then confirm them all at once.',
27
25
  'Runs the bundled pi CLI to install the selected companion packages, writes EXA_API_KEY to ~/.crouter/exa.key when provided, and prints a summary.',
28
26
  'The companion-package list includes crtr marketplace plugins (currently `capture`), checked by default and installed into the user scope when left checked. An unreachable marketplace is reported as skipped rather than failing setup.',
29
27
  'On every invocation (best-effort, idempotent), refreshes crouter-owned tmux bindings and registers known nodes\' interaction roots so resolved tickets can call back into the asking node. The inbox popup toggle is a crouter-owned keybinding, editable on the keybindings tab.',
@@ -5,6 +5,7 @@ import { daemonBranch } from './sys/daemon.js';
5
5
  import { sysDoctorLeaf } from './sys/doctor.js';
6
6
  import { sysFeedbackLeaf } from './sys/feedback.js';
7
7
  import { sysLogsLeaf } from './sys/logs.js';
8
+ import { sysSettingsLeaf } from './sys/settings.js';
8
9
  import { sysSetupLeaf } from './sys/setup.js';
9
10
  import { supportBranch } from './sys/support.js';
10
11
  import { sysSyspromptLeaf } from './sys/sysprompt.js';
@@ -16,13 +17,13 @@ export function registerSys() {
16
17
  name: 'sys',
17
18
  rootEntry: {
18
19
  concept: 'crtr configuration, diagnostics, and self-management',
19
- desc: 'config, setup, doctor, sysprompt, prompt-review, sync, update, version, feedback, logs, support, daemon',
20
+ desc: 'settings, config, setup, doctor, sysprompt, prompt-review, sync, update, version, feedback, logs, support, daemon',
20
21
  useWhen: 'managing the crtr installation, inspecting diagnostics, or operating the crtrd supervisor process',
21
22
  },
22
23
  help: {
23
24
  name: 'sys',
24
25
  summary: 'crtr system configuration, settings, diagnostics, and self-management',
25
26
  },
26
- children: [configBranch, sysSetupLeaf, sysDoctorLeaf, sysSyspromptLeaf, promptReviewLeaf, sysFeedbackLeaf, sysLogsLeaf, supportBranch, sysUpdateLeaf, sysVersionLeaf, sysSyncBranch, daemonBranch],
27
+ children: [sysSettingsLeaf, configBranch, sysSetupLeaf, sysDoctorLeaf, sysSyspromptLeaf, promptReviewLeaf, sysFeedbackLeaf, sysLogsLeaf, supportBranch, sysUpdateLeaf, sysVersionLeaf, sysSyncBranch, daemonBranch],
27
28
  });
28
29
  }
@@ -0,0 +1,50 @@
1
+ // The shipped Pi extensions execute in broker processes, which must never load
2
+ // canvas.db code. This walks each shipped extension's local static import graph
3
+ // and rejects any reach to the single DB accessor module.
4
+ import { test } from 'node:test';
5
+ import assert from 'node:assert/strict';
6
+ import { existsSync, readFileSync } from 'node:fs';
7
+ import { dirname, join, normalize, resolve } from 'node:path';
8
+ import ts from 'typescript';
9
+ import { CANVAS_EXTENSION_NAMES } from '../canvas/extensions.js';
10
+ const SOURCE_ROOT = resolve(process.cwd(), 'src');
11
+ const DB_MODULE = normalize(join(SOURCE_ROOT, 'core/canvas/db.ts'));
12
+ function resolveLocalImport(from, specifier) {
13
+ if (!specifier.startsWith('.'))
14
+ return null;
15
+ const stem = resolve(dirname(from), specifier).replace(/\.js$/, '');
16
+ for (const candidate of [`${stem}.ts`, join(stem, 'index.ts')]) {
17
+ if (existsSync(candidate))
18
+ return normalize(candidate);
19
+ }
20
+ return null;
21
+ }
22
+ function importsOf(file) {
23
+ const source = readFileSync(file, 'utf8');
24
+ return ts.preProcessFile(source, true, true).importedFiles
25
+ .map((reference) => resolveLocalImport(file, reference.fileName))
26
+ .filter((target) => target !== null);
27
+ }
28
+ function dbReach(root) {
29
+ const pending = [{ file: root, path: [root] }];
30
+ const seen = new Set([root]);
31
+ while (pending.length > 0) {
32
+ const current = pending.pop();
33
+ if (current.file === DB_MODULE)
34
+ return current.path;
35
+ for (const imported of importsOf(current.file)) {
36
+ if (seen.has(imported))
37
+ continue;
38
+ seen.add(imported);
39
+ pending.push({ file: imported, path: [...current.path, imported] });
40
+ }
41
+ }
42
+ return null;
43
+ }
44
+ test('every shipped broker extension is transitively canvas.db-free', () => {
45
+ for (const name of CANVAS_EXTENSION_NAMES) {
46
+ const root = join(SOURCE_ROOT, 'pi-extensions', `${name}.ts`);
47
+ const reach = dbReach(root);
48
+ assert.equal(reach, null, `${name} reaches canvas.db through:\n${reach?.join('\n')}`);
49
+ }
50
+ });
@@ -5,7 +5,9 @@ import { tmpdir } from 'node:os';
5
5
  import { dirname, join } from 'node:path';
6
6
  import { fileURLToPath } from 'node:url';
7
7
  import { createAgentSessionFromServices, createAgentSessionServices, SessionManager, VERSION } from '../runtime/broker-sdk.js';
8
- import { buildBrokerSession, isUnknownModel } from '../runtime/broker.js';
8
+ import { buildBrokerSession } from '../runtime/broker.js';
9
+ import { unregisteredConcreteModel } from '../model-routes.js';
10
+ import { isUnknownModel } from '../runtime/model-selection.js';
9
11
  import { resolveProviderCandidates } from '../subscription-state.js';
10
12
  const realEngine = { createAgentSessionServices, createAgentSessionFromServices, SessionManager, VERSION };
11
13
  const C3_EXT = join(dirname(fileURLToPath(import.meta.url)), 'fixtures', 'c3-custom-provider-ext.ts');
@@ -89,6 +91,21 @@ function resolve(options) {
89
91
  })),
90
92
  };
91
93
  }
94
+ test('an unregistered concrete recipe is a permanent failure, but missing auth is not', () => {
95
+ // The two outcomes route differently at launch: an unregistered model can
96
+ // never boot and must fault, while a registered model with no configured auth
97
+ // is recoverable once credentials arrive.
98
+ const known = { provider: 'openai-codex', id: 'o-strong' };
99
+ const registry = {
100
+ find: (providerId, modelId) => providerId === known.provider && modelId === known.id ? known : undefined,
101
+ hasConfiguredAuth: () => false,
102
+ };
103
+ const unknown = unregisteredConcreteModel({ kind: 'concrete', spec: 'openai-codex/fast' }, registry, { profileId: null });
104
+ assert.equal(unknown?.reason, 'unregistered');
105
+ assert.equal(unknown?.candidate.providerId, 'openai-codex');
106
+ assert.equal(unknown?.candidate.modelId, 'fast');
107
+ assert.equal(unregisteredConcreteModel({ kind: 'concrete', spec: 'openai-codex/o-strong' }, registry, { profileId: null }), undefined, 'a registered model remains recoverable even when it has no configured auth');
108
+ });
92
109
  test('launch candidate resolver keeps a healthy explicit provider pin ahead of authenticated alternatives', () => {
93
110
  const result = resolve({ requested: 'anthropic/requested', available: [alternative, requested], modelProviderPinned: true });
94
111
  assert.equal(result.model, requested);
@@ -102,7 +119,7 @@ test('launch candidate resolver selects a non-managed candidate as automatic fal
102
119
  { spec: 'missing/missing', reason: 'not registered' },
103
120
  ]);
104
121
  });
105
- test('broker launch keeps an unregistered concrete model pinned even when a non-managed provider is available', async () => {
122
+ test('broker launch rejects an unregistered concrete model even when a non-managed provider is available', async () => {
106
123
  const cwd = mkdtempSync(join(tmpdir(), 'crtr-launch-candidate-'));
107
124
  try {
108
125
  const engine = {
@@ -119,13 +136,7 @@ test('broker launch keeps an unregistered concrete model pinned even when a non-
119
136
  return { ...services, modelRuntime };
120
137
  },
121
138
  };
122
- const { session } = await buildBrokerSession(engine, { cwd, extensionPaths: [C3_EXT], model: 'missing/missing' });
123
- try {
124
- assert.equal(`${session.model?.provider}/${session.model?.id}`, 'unknown/unknown');
125
- }
126
- finally {
127
- session.dispose();
128
- }
139
+ await assert.rejects(buildBrokerSession(engine, { cwd, extensionPaths: [C3_EXT], model: 'missing/missing' }), /FATAL: model 'missing\/missing' is not registered/);
129
140
  }
130
141
  finally {
131
142
  rmSync(cwd, { recursive: true, force: true });
@@ -62,7 +62,7 @@ test('preflightBrokerLaunch rejects missing or duplicate mandatory canvas hooks
62
62
  const missing = { argv: ['hello'], env: { CRTR_BROKER_ENGINE: FAKE_ENGINE } };
63
63
  assert.throws(() => preflightBrokerLaunch('preflight-missing-hook', missing, '/tmp/work'), /canvas extension.*found 0/i);
64
64
  const duplicate = { argv: [...validArgv(), '-e', CANVAS_EXTENSIONS[0], 'hello'], env: { CRTR_BROKER_ENGINE: FAKE_ENGINE } };
65
- assert.throws(() => preflightBrokerLaunch('preflight-duplicate-hook', duplicate, '/tmp/work'), /canvas extension.*found 2/i);
65
+ assert.throws(() => preflightBrokerLaunch('preflight-duplicate-hook', duplicate, '/tmp/work'), /duplicate mandatory canvas extension basename canvas-inbox-watcher/i);
66
66
  });
67
67
  test('preflightBrokerLaunch validates the exact broker engine env passed to the detached broker', () => {
68
68
  const nodeId = 'preflight-empty-engine';
@@ -13,8 +13,11 @@ import registerCanvasInboxWatcher from '../../pi-extensions/canvas-inbox-watcher
13
13
  import { appendInbox, readCursor } from '../feed/inbox.js';
14
14
  import { drainBearings } from '../runtime/kickoff.js';
15
15
  import { appendSituationalContext } from '../runtime/situational-context.js';
16
- import { createNode, getNode, setIntent } from '../canvas/canvas.js';
16
+ import { createNode, getNode, recordPid, setIntent } from '../canvas/canvas.js';
17
17
  import { closeDb } from '../canvas/db.js';
18
+ import { createApiServer } from '../../daemon/api/server.js';
19
+ import { CrtrClient } from '../../api/client.js';
20
+ import { ApiError } from '../../api/errors.js';
18
21
  // Drive the watcher's injectable cadence seam (CRTR_WATCHER_TICK_MS /
19
22
  // CRTR_WATCHER_DEBOUNCE_MS) at a fast tempo so the test sleeps milliseconds, not
20
23
  // seconds. SETTLE_MS still allows a resolve+seed tick, a read tick, and the
@@ -26,13 +29,15 @@ let origHome;
26
29
  let origNode;
27
30
  const homes = [];
28
31
  const disposers = [];
32
+ let server;
29
33
  /** Point CRTR_HOME at a fresh temp canvas root and bind CRTR_NODE_ID. */
30
34
  function freshNode(nodeId) {
31
- const home = join(tmpdir(), `crtr-canvas-watcher-${Date.now()}-${Math.random().toString(36).slice(2)}`);
35
+ const home = join(tmpdir(), `crtr-w-${Math.random().toString(36).slice(2, 8)}`);
32
36
  mkdirSync(home, { recursive: true });
33
37
  homes.push(home);
34
38
  process.env['CRTR_HOME'] = home;
35
39
  process.env['CRTR_NODE_ID'] = nodeId;
40
+ server = createApiServer();
36
41
  }
37
42
  function makeFakePi() {
38
43
  const handlers = {};
@@ -42,7 +47,7 @@ function makeFakePi() {
42
47
  on(e, h) { handlers[e] = h; },
43
48
  sendUserMessage(content, options) { this.injected.push({ content, deliverAs: options?.deliverAs }); },
44
49
  sendMessage(message) { this.sentMessages.push(message); },
45
- fire(e, ev, ctx) { handlers[e]?.(ev, ctx); },
50
+ async fire(e, ev, ctx) { await handlers[e]?.(ev, ctx); },
46
51
  };
47
52
  }
48
53
  // Fire agent_settled — the authoritative durable-commit boundary in the
@@ -51,9 +56,9 @@ function makeFakePi() {
51
56
  // unconditionally regardless of queue state, so `pending: true` exercises that
52
57
  // the commit still lands rather than being vetoed. See `shutdown()` below for
53
58
  // the one boundary where `hasPendingMessages()` still gates a commit.
54
- function settle(pi, opts = {}) {
59
+ async function settle(pi, opts = {}) {
55
60
  const pending = opts.pending === true;
56
- pi.fire('agent_settled', { type: 'agent_settled' }, { isIdle: () => true, hasPendingMessages: () => pending });
61
+ await pi.fire('agent_settled', { type: 'agent_settled' }, { isIdle: () => true, hasPendingMessages: () => pending });
57
62
  }
58
63
  // Fire session_shutdown — pi's graceful-teardown safety net for a settle that
59
64
  // never fired before exit. The real handler takes NO event ctx of its own; it
@@ -65,19 +70,37 @@ function settle(pi, opts = {}) {
65
70
  // itself. `pending` maps to pi's `hasPendingMessages()`: true exercises the
66
71
  // retained HOLD (an unconsumed queued send would die with the process, so the
67
72
  // commit is declined); false (default) commits normally.
68
- function shutdown(pi, opts = {}) {
73
+ async function shutdown(pi, opts = {}) {
69
74
  const pending = opts.pending === true;
70
- pi.fire('agent_end', { type: 'agent_end', messages: [] }, { isIdle: () => false, hasPendingMessages: () => pending });
71
- pi.fire('session_shutdown', {}, undefined);
75
+ await pi.fire('agent_end', { type: 'agent_end', messages: [] }, { isIdle: () => false, hasPendingMessages: () => pending });
76
+ await pi.fire('session_shutdown', {}, undefined);
72
77
  }
73
78
  const wait = (ms) => new Promise((r) => setTimeout(r, ms));
74
79
  // Register the watcher, then fire session_start — the real lifecycle gate
75
80
  // that arms its poll interval and initial tick (see canvas-inbox-watcher.ts).
76
81
  // registerCanvasInboxWatcher() alone only wires up handlers; without this the
77
82
  // watcher never polls or sends anything.
83
+ function ensureWatcherNode() {
84
+ const nodeId = process.env['CRTR_NODE_ID'];
85
+ if (nodeId === undefined || getNode(nodeId) !== null)
86
+ return;
87
+ createNode({
88
+ node_id: nodeId,
89
+ name: nodeId,
90
+ created: new Date().toISOString(),
91
+ cwd: '/tmp',
92
+ kind: 'general',
93
+ mode: 'base',
94
+ lifecycle: 'terminal',
95
+ status: 'active',
96
+ });
97
+ recordPid(nodeId, process.pid);
98
+ }
78
99
  function registerWatcher(pi) {
100
+ ensureWatcherNode();
101
+ recordPid(process.env['CRTR_NODE_ID'], process.pid);
79
102
  const dispose = registerCanvasInboxWatcher(pi);
80
- pi.fire('session_start', { type: 'session_start' }, undefined);
103
+ void pi.fire('session_start', { type: 'session_start' }, undefined);
81
104
  return dispose;
82
105
  }
83
106
  let origTick;
@@ -90,9 +113,12 @@ before(() => {
90
113
  process.env['CRTR_WATCHER_TICK_MS'] = String(TICK_MS);
91
114
  process.env['CRTR_WATCHER_DEBOUNCE_MS'] = String(DEBOUNCE_MS);
92
115
  });
93
- afterEach(() => {
116
+ afterEach(async () => {
94
117
  while (disposers.length > 0)
95
118
  disposers.pop()();
119
+ await server?.close();
120
+ server = undefined;
121
+ closeDb();
96
122
  });
97
123
  after(() => {
98
124
  if (origHome === undefined)
@@ -119,7 +145,7 @@ after(() => {
119
145
  }
120
146
  });
121
147
  describe('canvas inbox watcher — hold + idle delivery', () => {
122
- test('refresh-yield in flight: inbox entries are HELD, then delivered once intent clears (no loss)', async () => {
148
+ test('refresh-yield in flight: a handoff remains uncommitted for the replacement conversation', async () => {
123
149
  freshNode('node-refresh');
124
150
  closeDb(); // rebind the canvas db to this test's fresh home
125
151
  const meta = {
@@ -135,12 +161,66 @@ describe('canvas inbox watcher — hold + idle delivery', () => {
135
161
  await wait(TICK_MS + 100);
136
162
  appendInbox('node-refresh', { from: 'child-x', tier: 'urgent', kind: 'final', label: 'done' });
137
163
  await wait(SETTLE_MS);
138
- assert.equal(pi.injected.length, 0, 'entries are held while a refresh-yield is in flight (no steer-hijack)');
139
- // The fresh pi clears intent on boot; the held entry must then be delivered
140
- // — the cursor was never advanced, so nothing is lost.
164
+ assert.equal(pi.injected.length, 1, 'the live broker receives the handoff before its durable cursor boundary');
165
+ // The cursor operation decides the refresh hold at its durable commit
166
+ // boundary; clearing intent does not manufacture a second handoff.
141
167
  setIntent('node-refresh', null);
142
168
  await wait(SETTLE_MS);
143
- assert.equal(pi.injected.length, 1, 'the held entry is delivered once the refresh clears');
169
+ assert.equal(pi.injected.length, 1, 'the same handoff is not delivered twice');
170
+ });
171
+ test('replacement session binding holds a late old-broker cursor commit', async () => {
172
+ freshNode('node-refresh-replacement');
173
+ closeDb();
174
+ const meta = {
175
+ node_id: 'node-refresh-replacement', name: 'r', created: new Date().toISOString(),
176
+ cwd: '/tmp', kind: 'general', mode: 'base', lifecycle: 'resident',
177
+ status: 'active', intent: 'refresh',
178
+ };
179
+ createNode(meta);
180
+ const entry = appendInbox(meta.node_id, { from: 'child-x', tier: 'normal', kind: 'update', label: 'handoff before replacement' });
181
+ recordPid(meta.node_id, 101);
182
+ const client = CrtrClient.forLocalSocket({ autostart: false });
183
+ // The replacement binds first, consuming refresh and recording its own
184
+ // process generation. The old broker's delayed request must still hold.
185
+ await client.bindBrokerSession(meta.node_id, {
186
+ piSessionId: 'replacement-session', sessionFile: '/tmp/replacement.jsonl',
187
+ pid: 202, reason: 'startup', reviewBoundaryIds: [],
188
+ });
189
+ const oldResult = await client.advanceBrokerInboxCursor(meta.node_id, {
190
+ throughEntryId: entry.entry_id, brokerPid: 101,
191
+ });
192
+ assert.deepEqual(oldResult, { action: 'hold_refresh' });
193
+ assert.equal(readCursor(meta.node_id), undefined, 'the stale broker cannot consume the replacement replay');
194
+ const replacementResult = await client.advanceBrokerInboxCursor(meta.node_id, {
195
+ throughEntryId: entry.entry_id, brokerPid: 202,
196
+ });
197
+ assert.deepEqual(replacementResult, { action: 'advanced' });
198
+ assert.equal(readCursor(meta.node_id), entry.entry_id, 'only the replacement broker advances the durable cursor');
199
+ });
200
+ test('cursor rejects a nonexistent or backward physical entry', async () => {
201
+ freshNode('node-cursor-physical-boundary');
202
+ closeDb();
203
+ const meta = {
204
+ node_id: 'node-cursor-physical-boundary', name: 'r', created: new Date().toISOString(),
205
+ cwd: '/tmp', kind: 'general', mode: 'base', lifecycle: 'resident', status: 'active',
206
+ };
207
+ createNode(meta);
208
+ recordPid(meta.node_id, 303);
209
+ const first = appendInbox(meta.node_id, { from: 'child-x', tier: 'normal', kind: 'update', label: 'first' });
210
+ const second = appendInbox(meta.node_id, { from: 'child-x', tier: 'normal', kind: 'update', label: 'second' });
211
+ const client = CrtrClient.forLocalSocket({ autostart: false });
212
+ const rejected = (request) => client
213
+ .advanceBrokerInboxCursor(meta.node_id, request)
214
+ .then(() => assert.fail('cursor request should fail'))
215
+ .catch((error) => {
216
+ assert.ok(error instanceof ApiError);
217
+ assert.equal(error.status, 400);
218
+ });
219
+ await rejected({ throughEntryId: 'f'.repeat(32), brokerPid: 303 });
220
+ assert.equal(readCursor(meta.node_id), undefined, 'a well-shaped unknown id cannot poison the cursor');
221
+ await client.advanceBrokerInboxCursor(meta.node_id, { throughEntryId: second.entry_id, brokerPid: 303 });
222
+ await rejected({ throughEntryId: first.entry_id, brokerPid: 303 });
223
+ assert.equal(readCursor(meta.node_id), second.entry_id, 'a late commit cannot move the durable cursor backward');
144
224
  });
145
225
  test('refresh-yield replays a handoff that reached the discarded conversation', async () => {
146
226
  freshNode('node-refresh-handoff');
@@ -161,7 +241,7 @@ describe('canvas inbox watcher — hold + idle delivery', () => {
161
241
  // Yield discards that conversation before it can act on the queued handoff.
162
242
  // Its settle must leave the entry durable for the fresh revive's kickoff.
163
243
  setIntent(meta.node_id, 'refresh');
164
- settle(pi);
244
+ await settle(pi);
165
245
  assert.equal(readCursor(meta.node_id), undefined, 'the discarded conversation cannot commit its inbox handoff');
166
246
  const bearings = drainBearings(getNode(meta.node_id));
167
247
  assert.match(bearings.unreadDigest ?? '', /handoff at yield/, 'the fresh revive receives the uncommitted handoff');
@@ -205,6 +285,7 @@ describe('canvas inbox watcher — action-gated startup (session_start arm)', ()
205
285
  // Registration alone (the extension factory, before Pi has bound actions)
206
286
  // must be side-effect-free: no timer armed, no tick run, no action attempted
207
287
  // — even across several tick+debounce windows.
288
+ ensureWatcherNode();
208
289
  disposers.push(registerCanvasInboxWatcher(pi));
209
290
  await wait(TICK_MS * 5 + DEBOUNCE_MS + 50);
210
291
  assert.equal(sendAttempts, 0, 'no action call is attempted before session_start arms the watcher');
@@ -218,7 +299,7 @@ describe('canvas inbox watcher — action-gated startup (session_start arm)', ()
218
299
  assert.equal(sendAttempts, 1, 'exactly one action attempt once session_start arms the watcher');
219
300
  assert.equal(pi.injected.length, 1, 'exactly one handoff once actions are bound');
220
301
  assert.equal(readCursor('node-action-gate'), undefined, 'still uncommitted until agent_settled');
221
- settle(pi);
302
+ await settle(pi);
222
303
  assert.equal(readCursor('node-action-gate'), entry.entry_id, 'cursor committed at agent_settled');
223
304
  // A repeated session_start (e.g. a resume) must not re-arm a second
224
305
  // interval or re-run the initial tick — no duplicate delivery.
@@ -302,7 +383,7 @@ describe('canvas inbox watcher — durable cursor (at-least-once)', () => {
302
383
  assert.equal(readCursor('node-cursor-committed'), undefined, 'not yet committed before the settle');
303
384
  // The turn settles with pi's queue drained (the followUp was consumed) —
304
385
  // THAT commits the cursor.
305
- settle(pi1);
386
+ await settle(pi1);
306
387
  assert.equal(readCursor('node-cursor-committed'), entry.entry_id, 'cursor committed to disk at agent_settled');
307
388
  const pi2 = makeFakePi();
308
389
  disposers.push(registerWatcher(pi2));
@@ -323,7 +404,7 @@ describe('canvas inbox watcher — durable cursor (at-least-once)', () => {
323
404
  // of acceptance — the cursor stays put until the turn settles. (One rule: no
324
405
  // immediate idle-path commit.)
325
406
  assert.equal(readCursor('node-cursor-idle'), undefined, 'idle send does not commit on the fire-and-forget return');
326
- settle(pi);
407
+ await settle(pi);
327
408
  assert.equal(readCursor('node-cursor-idle'), entry.entry_id, 'idle-path delivery commits at the turn it started settling');
328
409
  });
329
410
  test('synchronous send throw then agent_settled: durable cursor NOT advanced past the re-buffered entry, fresh watcher re-delivers', async () => {
@@ -339,7 +420,7 @@ describe('canvas inbox watcher — durable cursor (at-least-once)', () => {
339
420
  await wait(SETTLE_MS);
340
421
  assert.equal(pi1.injected.length, 0, 'the failing send delivered nothing');
341
422
  // agent_settled must NOT commit past the still-re-buffered (never-handed-off) entry.
342
- settle(pi1);
423
+ await settle(pi1);
343
424
  assert.equal(readCursor('node-cursor-failsend'), undefined, 'durable cursor not advanced past a re-buffered, never-delivered entry');
344
425
  const pi2 = makeFakePi();
345
426
  disposers.push(registerWatcher(pi2));
@@ -363,7 +444,7 @@ describe('canvas inbox watcher — durable cursor (at-least-once)', () => {
363
444
  // The abort-generated agent_end/settle must not commit the pending critical
364
445
  // entry (it is re-buffered, never handed off).
365
446
  pi1.fire('agent_end', { type: 'agent_end', messages: [] }, { isIdle: () => true });
366
- settle(pi1);
447
+ await settle(pi1);
367
448
  assert.equal(readCursor('node-cursor-critical'), undefined, 'abort-generated settle does not commit the pending critical entry before its retry');
368
449
  const pi2 = makeFakePi();
369
450
  disposers.push(registerWatcher(pi2));
@@ -390,7 +471,7 @@ describe('canvas inbox watcher — durable cursor (at-least-once)', () => {
390
471
  await wait(70); // B read into the buffer but < 200ms debounce → not yet flushed
391
472
  // A's turn settles while B is still debouncing in the buffer. The commit must
392
473
  // clamp below the still-buffered B and land on A only.
393
- settle(pi1);
474
+ await settle(pi1);
394
475
  assert.equal(readCursor('node-cursor-batchB'), a.entry_id, 'commit lands on handed-off batch A');
395
476
  assert.notEqual(readCursor('node-cursor-batchB'), b.entry_id, 'commit does not cross the still-buffered batch B');
396
477
  const pi2 = makeFakePi();
@@ -423,7 +504,7 @@ describe('canvas inbox watcher — durable cursor (at-least-once)', () => {
423
504
  assert.equal(readCursor('node-cursor-failhold'), undefined, 'a failure agent_end does not commit');
424
505
  // The settle commits even though the context reports pending sends —
425
506
  // agent_settled no longer declines on hasPendingMessages().
426
- settle(pi1, { pending: true });
507
+ await settle(pi1, { pending: true });
427
508
  assert.equal(readCursor('node-cursor-failhold'), entry.entry_id, 'agent_settled commits unconditionally, even when hasPendingMessages() reports pending');
428
509
  const pi2 = makeFakePi();
429
510
  disposers.push(registerWatcher(pi2));
@@ -452,7 +533,7 @@ describe('canvas inbox watcher — durable cursor (at-least-once)', () => {
452
533
  await wait(SETTLE_MS);
453
534
  assert.equal(pi.injected.length, 1, 'the active conversation received the handoff before refresh');
454
535
  setIntent(meta.node_id, 'refresh');
455
- shutdown(pi, { pending: false });
536
+ await shutdown(pi, { pending: false });
456
537
  assert.equal(readCursor(meta.node_id), undefined, 'a refresh keeps the shutdown handoff uncommitted for replay');
457
538
  });
458
539
  test('session_shutdown still holds while hasPendingMessages() reports pending (no agent_settled fired)', async () => {
@@ -466,7 +547,7 @@ describe('canvas inbox watcher — durable cursor (at-least-once)', () => {
466
547
  assert.equal(pi1.injected.length, 1, 'delivered mid-turn as a followUp');
467
548
  // session_shutdown fires with no prior agent_settled, and the context
468
549
  // reports an unconsumed queued send — the hold declines the commit.
469
- shutdown(pi1, { pending: true });
550
+ await shutdown(pi1, { pending: true });
470
551
  assert.equal(readCursor('node-cursor-shutdownhold'), undefined, 'session_shutdown declines to commit while pi reports pending sends');
471
552
  dispose();
472
553
  // A fresh watcher re-reads and re-delivers, then a drained settle commits.
@@ -475,7 +556,7 @@ describe('canvas inbox watcher — durable cursor (at-least-once)', () => {
475
556
  await wait(SETTLE_MS);
476
557
  assert.equal(pi2.injected.length, 1, 'a fresh watcher re-reads and re-delivers the never-committed entry');
477
558
  assert.match(pi2.injected[0].content, /still queued at shutdown/);
478
- settle(pi2);
559
+ await settle(pi2);
479
560
  assert.equal(readCursor('node-cursor-shutdownhold'), entry.entry_id, 'the redelivered entry commits once the fresh watcher settles cleanly');
480
561
  });
481
562
  // Situational custom sends do not enter pi's user steer/followUp queue, so
@@ -496,7 +577,7 @@ describe('canvas inbox watcher — durable cursor (at-least-once)', () => {
496
577
  await wait(SETTLE_MS);
497
578
  assert.equal(pi1.sentMessages.length, 1, 'the hidden custom message was sent');
498
579
  assert.equal(readCursor('node-cursor-situational'), undefined, 'not committed before the settle');
499
- settle(pi1);
580
+ await settle(pi1);
500
581
  assert.equal(readCursor('node-cursor-situational'), entry.entry_id, 'the situational handoff commits at the drained settle');
501
582
  });
502
583
  });
@@ -109,6 +109,20 @@ test('coalesce inlines short report bodies with a trailing artifact pointer and
109
109
  assert.doesNotMatch(spilled, /Dereference a ref with/);
110
110
  closeDb();
111
111
  });
112
+ test('a human message coalesces verbatim — a conversation turn, not a digest', () => {
113
+ // A human typing directly into a node's box is a CONVERSATION TURN, so the
114
+ // dormant wake path must read identically to the live path: no "From … — N
115
+ // updates" header, no `[message]` kind tag. Every other sender keeps framing.
116
+ const body = 'first line\n\nsecond paragraph';
117
+ const human = coalesce([
118
+ finalizeInboxEntry({ from: 'human', tier: 'normal', kind: 'message', label: 'first line', data: { body } }),
119
+ ]);
120
+ assert.equal(human, body);
121
+ const agent = coalesce([
122
+ finalizeInboxEntry({ from: 'mqifzplr-0753bde3', tier: 'normal', kind: 'message', label: 'go', data: { body: 'go' } }),
123
+ ]);
124
+ assert.match(agent, /^From mqifzplr-0753bde3 — 1 update:/);
125
+ });
112
126
  let origTick;
113
127
  let origDebounce;
114
128
  before(() => {
@@ -3,9 +3,9 @@ import assert from 'node:assert/strict';
3
3
  import { mkdtempSync, rmSync, existsSync, readFileSync, writeFileSync, statSync } from 'node:fs';
4
4
  import { tmpdir } from 'node:os';
5
5
  import { join } from 'node:path';
6
- import { createNode, getNode, getRow, updateNode, setStatus, listNodes, subscribe, unsubscribe, setSubscriptionActive, recordSpawn, subscribersOf, subscriptionsOf, view, hasActiveLiveSubscription, rebuildIndex, } from '../canvas/canvas.js';
6
+ import { createNode, getNode, getRow, updateNode, setStatus, subscribe, unsubscribe, setSubscriptionActive, recordSpawn, subscribersOf, subscriptionsOf, view, hasActiveLiveSubscription, rebuildIndex, } from '../canvas/canvas.js';
7
7
  import { closeDb } from '../canvas/db.js';
8
- import { contextDir, reportsDir, jobDir, nodeMetaPath, } from '../canvas/paths.js';
8
+ import { nodeMetaPath } from '../canvas/paths.js';
9
9
  let home;
10
10
  function node(id, over = {}) {
11
11
  return {
@@ -34,32 +34,11 @@ after(() => {
34
34
  rmSync(home, { recursive: true, force: true });
35
35
  delete process.env['CRTR_HOME'];
36
36
  });
37
- test('createNode scaffolds dirs, writes meta, indexes the row', () => {
38
- createNode(node('a'));
39
- assert.ok(existsSync(contextDir('a')));
40
- assert.ok(existsSync(reportsDir('a')));
41
- assert.ok(existsSync(jobDir('a')));
42
- assert.ok(existsSync(nodeMetaPath('a')));
43
- const meta = getNode('a');
44
- assert.equal(meta?.node_id, 'a');
45
- assert.equal(meta?.kind, 'general');
46
- const row = getRow('a');
47
- assert.equal(row?.node_id, 'a');
48
- assert.equal(row?.status, 'active');
49
- });
50
37
  test('meta.json is the source of truth on disk', () => {
51
38
  createNode(node('a', { kind: 'developer' }));
52
39
  const raw = JSON.parse(readFileSync(nodeMetaPath('a'), 'utf8'));
53
40
  assert.equal(raw.kind, 'developer');
54
41
  });
55
- test('updateNode merges meta and re-indexes the row', () => {
56
- createNode(node('a'));
57
- updateNode('a', { mode: 'orchestrator', lifecycle: 'resident' });
58
- assert.equal(getNode('a')?.mode, 'orchestrator');
59
- assert.equal(getRow('a')?.lifecycle, 'resident');
60
- // unspecified fields preserved
61
- assert.equal(getNode('a')?.kind, 'general');
62
- });
63
42
  // Regression: cycle_pending is an IDENTITY field (meta.json-only, no db
64
43
  // column — like pi_session_file) written by reviveNode/canvas-stophook and
65
44
  // read back by reviveNode's locked launch arbitration. writeMeta only persists
@@ -73,19 +52,6 @@ test('cycle_pending survives the updateNode/getNode meta.json round-trip', () =>
73
52
  updateNode('a', { cycle_pending: false });
74
53
  assert.equal(getNode('a')?.cycle_pending, false);
75
54
  });
76
- test('setStatus updates both meta and row', () => {
77
- createNode(node('a'));
78
- setStatus('a', 'done');
79
- assert.equal(getNode('a')?.status, 'done');
80
- assert.equal(getRow('a')?.status, 'done');
81
- });
82
- test('listNodes filters by status', () => {
83
- createNode(node('a', { status: 'active' }));
84
- createNode(node('b', { status: 'idle' }));
85
- createNode(node('c', { status: 'done' }));
86
- assert.equal(listNodes().length, 3);
87
- assert.deepEqual(listNodes({ status: ['active', 'idle'] }).map((n) => n.node_id).sort(), ['a', 'b']);
88
- });
89
55
  test('subscription spine: subscribersOf / subscriptionsOf', () => {
90
56
  createNode(node('mgr'));
91
57
  createNode(node('w1'));
@@ -3,7 +3,7 @@ import assert from 'node:assert/strict';
3
3
  import { mkdtempSync, rmSync, mkdirSync, writeFileSync, existsSync, readdirSync } from 'node:fs';
4
4
  import { tmpdir } from 'node:os';
5
5
  import { join } from 'node:path';
6
- import { createNode, getNode, subscribe } from '../canvas/canvas.js';
6
+ import { createNode, getNode, subscribe, subscriptionsOf } from '../canvas/canvas.js';
7
7
  import { nodeDir } from '../canvas/paths.js';
8
8
  import { closeDb } from '../canvas/db.js';
9
9
  import { closeNode } from '../runtime/close.js';
@@ -69,7 +69,7 @@ test('closes the root and its exclusive descendants; spares a shared node', () =
69
69
  // Closed nodes → canceled + intent cleared. (Broker-host cut: nodes carry NO
70
70
  // engine pane/window/session — the viewer lives in the focuses table and is
71
71
  // torn down asynchronously when the broker socket drops, so close no longer
72
- // nulls a meta `pane`; viewer teardown is covered in the full-tier broker
72
+ // nulls a meta `pane`; viewer teardown is covered in the compiled-seam broker
73
73
  // lifecycle suite.)
74
74
  for (const id of ['N', 'A', 'C']) {
75
75
  const m = getNode(id);
@@ -80,6 +80,17 @@ test('closes the root and its exclusive descendants; spares a shared node', () =
80
80
  assert.equal(getNode('B').status, 'active');
81
81
  assert.equal(getNode('M').status, 'active');
82
82
  });
83
+ test('closing a middle node preserves its subscription edge and child provenance', () => {
84
+ createNode(node('A'));
85
+ createNode(node('B', { parent: 'A' }));
86
+ createNode(node('C', { parent: 'B' }));
87
+ spawnEdge('A', 'B');
88
+ spawnEdge('B', 'C');
89
+ closeNode('B');
90
+ assert.deepEqual(subscriptionsOf('B').map(({ node_id, active }) => ({ node_id, active })), [{ node_id: 'C', active: true }]);
91
+ assert.equal(getNode('B')?.parent, 'A');
92
+ assert.equal(getNode('C')?.parent, 'B');
93
+ });
83
94
  test('kill order is leaves-first, root-last ("cascades up")', () => {
84
95
  for (const id of ['N', 'A', 'C'])
85
96
  createNode(node(id));
@@ -249,6 +260,6 @@ test('reaping an empty child still notifies a surviving external manager', () =>
249
260
  // routes through the synchronous tearDownNode — it sends the broker `shutdown`
250
261
  // frame (headlessBrokerHost.teardown) and the viewer pane/focus row close on
251
262
  // their own when the broker socket drops (GC'd by the daemon + focusOf prune).
252
- // That async viewer teardown is covered by the full-tier broker-crash-teardown /
263
+ // That async viewer teardown is covered by the compiled-seam broker-crash-teardown /
253
264
  // broker-lifecycle suite, which runs a real broker; it cannot be unit-tested
254
265
  // without one.