@north-light/crouter 0.3.173 → 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} +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/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
@@ -1,661 +0,0 @@
1
- // server.ts — the `surface web serve` dev shell: a thin reverse proxy in front
2
- // of crtrd (spec §7.5, C-1). It hosts NO canvas writer of its own — crtrd is the
3
- // sole writer. This process opens NO `canvas.db`, spawns NO subprocess bridge,
4
- // and terminates NO WebSocket. It serves, on one origin:
5
- // • /v1/* → REVERSE PROXY to crtrd's unix socket. The SPA (and
6
- // any /v1 client) reaches the REST API THROUGH this
7
- // shell; the shell owns the auth boundary (crtrd
8
- // applies none), then streams the request/response
9
- // verbatim to/from the socket.
10
- // • WS /node/<id> → TRANSPARENT TUNNEL to crtrd's
11
- // `GET /v1/nodes/{id}/attach`. The shell does NOT
12
- // terminate the WebSocket — it forwards the upgrade
13
- // rewritten to the attach path and pipes bytes both
14
- // directions. crtrd owns the handshake and
15
- // attach-implies-revive; the browser is the SAME
16
- // protocol peer as `crtr surface attach`.
17
- // • GET /* → the shell SPA (static dist/web-client/, or Vite
18
- // middleware in --dev) + SPA fallback.
19
- // • GET /__crtr/events → the SSE change-invalidation lane (events.ts).
20
- // canvas.db-free; explicitly out of P1 scope, kept.
21
- // • Web push (§push) → GET /__crtr/push/vapid-public-key, POST/DELETE
22
- // /__crtr/push/subscribe. A server-side diff engine
23
- // (push-engine.ts) watches the SAME SSE invalidations
24
- // above and sends web-push to a persisted, auth-scoped
25
- // registry (push-registry.ts). Its canvas reads go
26
- // through the crtrd API (via `cliClient()` command
27
- // leaves), never `canvas.db`. Out of P1 scope, kept.
28
- //
29
- // §0 ONE-WRITER INVARIANT: this process never mutates the canvas. Every write
30
- // and every canvas read flows to crtrd — the `/v1/*` proxy and the `/node/<id>`
31
- // attach tunnel both terminate at crtrd's unix socket, and the push engine's
32
- // reads route through the crtrd-backed command leaves. There is no local
33
- // transport, no `canvas.db` handle, and no direct broker socket here.
34
- import { createServer as createHttpServer, request as httpRequest } from 'node:http';
35
- import { createConnection, isIP } from 'node:net';
36
- import { createHash } from 'node:crypto';
37
- import { createReadStream, existsSync, statSync } from 'node:fs';
38
- import { fileURLToPath } from 'node:url';
39
- import { dirname, extname, join, normalize, resolve } from 'node:path';
40
- import webpush from 'web-push';
41
- import { apiSocketPath, isSafeNodeId } from '../../core/canvas/paths.js';
42
- import { emitEvent } from '../../core/events/emit.js';
43
- import { bindWebEventSource } from '../../core/events/source.js';
44
- import { canvasRosterLeaf } from '../../commands/canvas-roster.js';
45
- import { startEventHub } from './events.js';
46
- import { createDevServer } from './dev-server.js';
47
- import { PushLastSeenStore, PushRegistryStore, PushRequestError, loadOrCreateVapidKeypair, parsePushDeleteBody, parsePushSubscriptionBody, pushBodyMaxBytes, } from './push-registry.js';
48
- import { PushDiffEngine } from './push-engine.js';
49
- const HERE = dirname(fileURLToPath(import.meta.url));
50
- /** Candidate dirs to serve the shell SPA bundle from, in priority order: an
51
- * explicit override, the compiled-module-relative `dist/web-client/` (what
52
- * `vite build` emits and what we serve in production), and the placeholder
53
- * copied from source. The first that exists wins. (--dev bypasses this entirely
54
- * — Vite middleware owns asset serving in that mode.) */
55
- function resolveClientDir() {
56
- const candidates = [
57
- process.env['CRTR_WEB_CLIENT_DIR'],
58
- join(HERE, '../../web-client'),
59
- resolve(HERE, '../../../dist/web-client'),
60
- ].filter((p) => p !== undefined && p !== '');
61
- for (const dir of candidates) {
62
- if (existsSync(dir))
63
- return dir;
64
- }
65
- // Fall back to the module-relative path even if absent; missing-file handling
66
- // below returns a clear 503 so a not-yet-built shell is diagnosable.
67
- return join(HERE, '../../web-client');
68
- }
69
- const CONTENT_TYPES = {
70
- '.html': 'text/html; charset=utf-8',
71
- '.js': 'text/javascript; charset=utf-8',
72
- '.mjs': 'text/javascript; charset=utf-8',
73
- '.css': 'text/css; charset=utf-8',
74
- '.json': 'application/json; charset=utf-8',
75
- '.webmanifest': 'application/manifest+json',
76
- '.svg': 'image/svg+xml',
77
- '.png': 'image/png',
78
- '.jpg': 'image/jpeg',
79
- '.jpeg': 'image/jpeg',
80
- '.gif': 'image/gif',
81
- '.webp': 'image/webp',
82
- '.ico': 'image/x-icon',
83
- '.woff': 'font/woff',
84
- '.woff2': 'font/woff2',
85
- '.map': 'application/json; charset=utf-8',
86
- };
87
- function contentTypeFor(path) {
88
- return CONTENT_TYPES[extname(path).toLowerCase()] ?? 'application/octet-stream';
89
- }
90
- /** Match a WS/GET path of the shape `/node/<id>` (with any number of leading
91
- * segments, future-proofing a mount prefix). Returns the decoded node id, or
92
- * null if the path doesn't match or the id is undecodable (malformed `%`). The
93
- * caller must still validate the decoded id with the shared persisted-node-ID
94
- * predicate before building a filesystem path — see {@link isSafeNodeId}. */
95
- function nodeIdFromPath(pathname) {
96
- const m = /\/node\/([^/?#]+)\/?$/.exec(pathname);
97
- if (m === null)
98
- return null;
99
- try {
100
- return decodeURIComponent(m[1]);
101
- }
102
- catch {
103
- return null; // malformed percent-encoding — treat as no match
104
- }
105
- }
106
- function isLoopbackHost(host) {
107
- const lower = host.toLowerCase();
108
- const ipVersion = isIP(host);
109
- if (lower === 'localhost' || lower === '::1')
110
- return true;
111
- if (ipVersion === 4 && host.startsWith('127.'))
112
- return true;
113
- if (lower === '::ffff:127.0.0.1')
114
- return true;
115
- if (ipVersion === 6 && lower.startsWith('::ffff:127.'))
116
- return true;
117
- return false;
118
- }
119
- function hostForUrl(host) {
120
- return host.includes(':') ? `[${host}]` : host;
121
- }
122
- function requestTokens(req) {
123
- const url = new URL(req.url ?? '/', 'http://127.0.0.1');
124
- const tokens = [];
125
- const queryToken = url.searchParams.get('token');
126
- if (queryToken !== null && queryToken !== '')
127
- tokens.push(queryToken);
128
- const authorization = req.headers.authorization;
129
- if (typeof authorization === 'string') {
130
- const match = /^Bearer\s+(.+)$/.exec(authorization);
131
- if (match !== null && match[1] !== '')
132
- tokens.push(match[1]);
133
- }
134
- return tokens;
135
- }
136
- function requestTokenMatches(req, secret) {
137
- if (secret === undefined)
138
- return false;
139
- return requestTokens(req).some((token) => token === secret);
140
- }
141
- /** Read a request body into a string, aborting the moment the accumulated body exceeds
142
- * `maxBytes` — so a push endpoint never buffers arbitrary attacker memory
143
- * before validation rejects it. Rejects with PushRequestError(413), which the
144
- * push error handler maps to a 413 response. */
145
- function readBodyCapped(req, maxBytes) {
146
- return new Promise((resolve, reject) => {
147
- const chunks = [];
148
- let total = 0;
149
- req.on('data', (c) => {
150
- total += c.length;
151
- if (total > maxBytes) {
152
- reject(new PushRequestError(413, 'push subscription body is too large'));
153
- req.destroy();
154
- return;
155
- }
156
- chunks.push(c);
157
- });
158
- req.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
159
- req.on('error', reject);
160
- });
161
- }
162
- /** Derive the persisted auth scope from a bearer token: a short, stable hash so
163
- * the raw secret never touches disk. */
164
- function scopeForToken(secret) {
165
- return `token:${createHash('sha256').update(secret).digest('base64url').slice(0, 16)}`;
166
- }
167
- /** Serve a static file from the client dir, with SPA fallback to index.html for
168
- * any unmatched (non-asset) GET — so `/` and `/node/<id>` both boot the app
169
- * shell. Returns true if it wrote a response. */
170
- function serveStatic(clientDir, req, res) {
171
- const url = new URL(req.url ?? '/', 'http://127.0.0.1');
172
- let pathname;
173
- try {
174
- pathname = decodeURIComponent(url.pathname);
175
- }
176
- catch {
177
- // Malformed percent-encoding (e.g. `GET /%`) — never let it throw out of
178
- // the request listener and crash the whole multiplexing server (C1).
179
- res.writeHead(400, { 'content-type': 'text/plain; charset=utf-8' });
180
- res.end('bad request\n');
181
- return;
182
- }
183
- // Resolve within clientDir; reject traversal.
184
- const rel = normalize(pathname).replace(/^(\.\.(\/|\\|$))+/, '');
185
- let filePath = join(clientDir, rel);
186
- if (!filePath.startsWith(clientDir)) {
187
- res.writeHead(403, { 'content-type': 'text/plain; charset=utf-8' });
188
- res.end('forbidden\n');
189
- return;
190
- }
191
- // Directory or root → index.html. A path with no file extension that does not
192
- // exist → SPA fallback to index.html (so deep links like /node/<id> boot).
193
- const isFile = existsSync(filePath) && statSync(filePath).isFile();
194
- if (!isFile) {
195
- filePath = join(clientDir, 'index.html');
196
- }
197
- if (!existsSync(filePath)) {
198
- res.writeHead(503, { 'content-type': 'text/plain; charset=utf-8' });
199
- res.end('crtr surface web shell bundle not found — run `npm run build` to emit it into ' +
200
- `${clientDir} (or pass --dev for Vite middleware)\n`);
201
- return;
202
- }
203
- res.writeHead(200, { 'content-type': contentTypeFor(filePath), 'cache-control': 'no-cache' });
204
- if (req.method === 'HEAD') {
205
- res.end();
206
- return;
207
- }
208
- const stream = createReadStream(filePath);
209
- stream.on('error', () => {
210
- if (!res.headersSent)
211
- res.writeHead(500);
212
- res.end();
213
- });
214
- stream.pipe(res);
215
- }
216
- /** RFC 7230 §6.1 hop-by-hop headers: meaningful only for a single transport hop,
217
- * never forwarded through a proxy. Stripping them keeps this shell's browser↔shell
218
- * and shell↔crtrd connection lifetimes independent instead of leaning on Node's
219
- * re-framing to paper over a forwarded `Transfer-Encoding`/`Connection` (m5). */
220
- const HOP_BY_HOP_HEADERS = new Set([
221
- 'connection',
222
- 'keep-alive',
223
- 'proxy-authenticate',
224
- 'proxy-authorization',
225
- 'te',
226
- 'trailer',
227
- 'transfer-encoding',
228
- 'upgrade',
229
- ]);
230
- /** Copy incoming headers minus the hop-by-hop set. Node lowercases incoming
231
- * header names, so a lowercase-keyed delete is exhaustive. */
232
- function withoutHopByHop(headers) {
233
- const out = { ...headers };
234
- for (const key of HOP_BY_HOP_HEADERS)
235
- delete out[key];
236
- return out;
237
- }
238
- /** Parse a request URL and strip the `token` auth param — it authorizes THIS
239
- * shell hop only; forwarding it into crtrd's request path would leak the secret
240
- * into crtrd's (loggable) request line, and crtrd doesn't consume it (m4). Any
241
- * OTHER query survives (e.g. crtrd's browser-only `?revive=0` opt-out). */
242
- function stripTokenParam(rawUrl) {
243
- const url = new URL(rawUrl, 'http://127.0.0.1');
244
- url.searchParams.delete('token');
245
- return url;
246
- }
247
- /** Proxy a `/v1/*` REST request to crtrd's unix socket. The dev shell adds only
248
- * its auth boundary (crtrd applies none) then streams the request body up and
249
- * the response back verbatim. No `canvas.db`, no subprocess: pure reverse proxy. */
250
- function proxyToCrtrd(req, res) {
251
- const target = stripTokenParam(req.url ?? '/');
252
- const upstream = httpRequest({
253
- socketPath: apiSocketPath(),
254
- method: req.method,
255
- path: `${target.pathname}${target.search}`,
256
- headers: withoutHopByHop(req.headers),
257
- }, (upstreamRes) => {
258
- res.writeHead(upstreamRes.statusCode ?? 502, withoutHopByHop(upstreamRes.headers));
259
- upstreamRes.pipe(res);
260
- });
261
- upstream.on('error', () => {
262
- // Once headers are on the wire we can no longer signal an error in-band —
263
- // appending a JSON error to a partially-streamed body would corrupt it, so
264
- // truncate the response instead (m1). Before headersSent, a clean 502.
265
- if (res.headersSent) {
266
- res.destroy();
267
- return;
268
- }
269
- res.writeHead(502, { 'content-type': 'application/json; charset=utf-8' });
270
- res.end(JSON.stringify({ error: { code: 'daemon_unavailable', message: 'crtrd is not reachable' } }));
271
- });
272
- // Propagate a browser abort/response-close upstream: without this an aborted
273
- // request leaves the crtrd response paused and its in-flight work pinned until
274
- // upstream completes on its own (M1). `destroy` on a finished exchange no-ops.
275
- res.on('close', () => upstream.destroy());
276
- req.pipe(upstream);
277
- }
278
- /** Transparently tunnel a browser `/node/<id>` WS upgrade to crtrd's
279
- * `GET /v1/nodes/{id}/attach`. The dev shell does NOT terminate the WebSocket:
280
- * it opens a raw connection to crtrd's unix socket, forwards the upgrade request
281
- * rewritten to the attach path (headers verbatim), and pipes bytes both
282
- * directions. crtrd performs the 101 handshake (which flows back through the
283
- * tunnel) and owns attach-implies-revive — so the browser is the SAME protocol
284
- * peer as `crtr surface attach` and this process only relays. Idempotent
285
- * teardown; the tunneled socket is tracked so shutdown can drop it. */
286
- function tunnelAttachUpgrade(req, socket, head, nodeId, track) {
287
- if (!isSafeNodeId(nodeId)) {
288
- try {
289
- socket.write('HTTP/1.1 400 Bad Request\r\n\r\n');
290
- socket.destroy();
291
- }
292
- catch {
293
- /* ignore */
294
- }
295
- return;
296
- }
297
- const upstream = createConnection(apiSocketPath());
298
- track.add(socket);
299
- let tornDown = false;
300
- let relayStarted = false;
301
- const teardown = () => {
302
- if (tornDown)
303
- return;
304
- tornDown = true;
305
- track.delete(socket);
306
- if (!socket.destroyed)
307
- socket.destroy();
308
- if (!upstream.destroyed)
309
- upstream.destroy();
310
- };
311
- upstream.on('connect', () => {
312
- // Preserve any non-token query (crtrd honors a browser-only `?revive=0`
313
- // opt-out here — a WS handshake can't set the equivalent request header, so
314
- // this query is the browser's ONLY channel for it); the token is stripped
315
- // for the same reason as the REST proxy (m2/m4).
316
- const path = `/v1/nodes/${encodeURIComponent(nodeId)}/attach${stripTokenParam(req.url ?? '/').search}`;
317
- const lines = [`GET ${path} HTTP/1.1`];
318
- for (let i = 0; i + 1 < req.rawHeaders.length; i += 2) {
319
- lines.push(`${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}`);
320
- }
321
- try {
322
- upstream.write(lines.join('\r\n') + '\r\n\r\n');
323
- if (head.length > 0)
324
- upstream.write(head);
325
- }
326
- catch {
327
- teardown();
328
- return;
329
- }
330
- relayStarted = true;
331
- socket.pipe(upstream);
332
- upstream.pipe(socket);
333
- });
334
- upstream.on('error', () => {
335
- // A pre-handshake upstream failure (crtrd down) leaves the browser with a
336
- // bare TCP reset, indistinguishable from any other failure. Before any byte
337
- // has been relayed, answer a 502 so the browser sees a distinct gateway
338
- // error; once relaying is underway a bare reset is the correct WS signal (m3).
339
- if (!relayStarted && !tornDown && !socket.destroyed) {
340
- try {
341
- socket.write('HTTP/1.1 502 Bad Gateway\r\n\r\n');
342
- }
343
- catch {
344
- /* ignore */
345
- }
346
- }
347
- teardown();
348
- });
349
- socket.on('error', teardown);
350
- upstream.on('close', teardown);
351
- socket.on('close', teardown);
352
- }
353
- /** Build + start the unified web server. Binds the requested host/port and
354
- * resolves once the server is listening. Async because --dev awaits a Vite
355
- * middleware server before listening. */
356
- export async function startWebServer(opts) {
357
- const host = opts.host ?? '127.0.0.1';
358
- const token = opts.token !== undefined && opts.token !== '' ? opts.token : undefined;
359
- const dev = opts.dev ?? false;
360
- const tokenRequired = !isLoopbackHost(host);
361
- if (tokenRequired && (token === undefined || token === '')) {
362
- throw new Error(`crtr surface web serve --host ${host} requires --token for remote-capable endpoints`);
363
- }
364
- const clientDir = resolveClientDir();
365
- // The SSE change lane — one hub, fanned to every connected EventSource.
366
- const eventHub = startEventHub();
367
- // Live `/node/<id>` attach tunnels to crtrd — tracked so shutdown drops them.
368
- const activeTunnels = new Set();
369
- // Same-origin allowlist: tokenless localhost pages are implicitly allowed,
370
- // while a valid relay token can authorize remote/guest route origins that would
371
- // otherwise be rejected by originAllowed().
372
- let allowedOrigins = new Set();
373
- const originAllowed = (origin) => {
374
- if (origin === undefined || origin === '')
375
- return true;
376
- return allowedOrigins.has(origin);
377
- };
378
- const authorizeRequest = (req) => {
379
- if (token !== undefined && requestTokenMatches(req, token)) {
380
- return { allowed: true, scope: scopeForToken(token) };
381
- }
382
- if (tokenRequired)
383
- return { allowed: false };
384
- if (!originAllowed(req.headers.origin))
385
- return { allowed: false };
386
- return { allowed: true, scope: 'local' };
387
- };
388
- // The set of auth scopes this server actually authorizes — the push diff
389
- // engine sends ONLY to subscriptions whose authScope is in this set (the same
390
- // auth boundary that gates the /v1 proxy, SSE, and attach tunnel). Mirrors authorizeRequest:
391
- // a token authorizes scopeForToken(token); a tokenless request is authorized
392
- // only when !tokenRequired, as scope 'local'. A record left by a rotated/old
393
- // token has a different digest and is therefore excluded.
394
- const targetScopes = new Set();
395
- if (token !== undefined)
396
- targetScopes.add(scopeForToken(token));
397
- if (!tokenRequired)
398
- targetScopes.add('local');
399
- // §push — the server-side web-push registry + diff engine (design D8). One
400
- // persisted, auth-scoped subscription registry; one locally-generated VAPID
401
- // identity signing every send; one diff engine that re-reads the canvas on
402
- // node invalidations received through eventHub.subscribe (no HTTP self-loop)
403
- // and pushes done-transition notifications.
404
- const pushRegistry = new PushRegistryStore();
405
- const pushLastSeen = new PushLastSeenStore();
406
- const vapid = loadOrCreateVapidKeypair();
407
- webpush.setVapidDetails(vapid.subject, vapid.publicKey, vapid.privateKey);
408
- const pushEngine = new PushDiffEngine({
409
- registry: pushRegistry,
410
- lastSeen: pushLastSeen,
411
- // The lean roster (node_id/parent/status/attention_count is exactly the
412
- // CanvasNodeRow subset this diff engine needs) instead of the enriched
413
- // snapshot — this fires on every 'nodes' invalidation, not on a bounded
414
- // interval, so it must never force the enrichRows/per-row getNode pass.
415
- readCanvasNodes: async () => {
416
- const snap = (await canvasRosterLeaf.run({}));
417
- return snap.nodes;
418
- },
419
- isTargetScope: (s) => targetScopes.has(s),
420
- sendPush: async (record, payload) => {
421
- try {
422
- await webpush.sendNotification({ endpoint: record.endpoint, keys: record.keys }, JSON.stringify(payload));
423
- return 'sent';
424
- }
425
- catch (err) {
426
- const statusCode = err.statusCode;
427
- return statusCode === 404 || statusCode === 410 ? 'gone' : 'error';
428
- }
429
- },
430
- });
431
- // A restart is not an attention event — record current state, send nothing.
432
- await pushEngine.seed();
433
- const unsubscribePush = eventHub.subscribe((kind) => {
434
- if (kind === 'nodes')
435
- void pushEngine.onNodesInvalidation();
436
- });
437
- // Assigned before listen() when --dev; the request handler closes over it.
438
- let vite;
439
- const httpServer = createHttpServer((req, res) => {
440
- try {
441
- const url = new URL(req.url ?? '/', 'http://127.0.0.1');
442
- const pathname = url.pathname;
443
- // The crtrd REST proxy: /v1/* → reverse-proxy to crtrd's unix socket. The
444
- // SPA (and any /v1 client) reaches the API THROUGH this dev shell. The
445
- // shell owns the auth boundary (crtrd applies none); token-or-origin gated
446
- // like the SSE lane and the attach tunnel. No canvas.db, no subprocess.
447
- if (pathname === '/v1' || pathname.startsWith('/v1/')) {
448
- if (!authorizeRequest(req).allowed) {
449
- res.writeHead(403, { 'content-type': 'text/plain; charset=utf-8' });
450
- res.end('forbidden\n');
451
- return;
452
- }
453
- proxyToCrtrd(req, res);
454
- return;
455
- }
456
- // The SSE change-invalidation lane: GET /__crtr/events. Token-or-origin
457
- // gated too — a foreign page should not even learn the user's graph is
458
- // mutating.
459
- if (pathname === '/__crtr/events') {
460
- if (req.method !== 'GET') {
461
- res.writeHead(405, { 'content-type': 'text/plain; charset=utf-8', allow: 'GET' });
462
- res.end('method not allowed\n');
463
- return;
464
- }
465
- if (!authorizeRequest(req).allowed) {
466
- res.writeHead(403, { 'content-type': 'text/plain; charset=utf-8' });
467
- res.end('forbidden\n');
468
- return;
469
- }
470
- eventHub.addClient(res);
471
- return;
472
- }
473
- // §push — the VAPID public key a browser needs to subscribe. Read-only,
474
- // non-secret, but behind the same auth boundary as everything else so a
475
- // foreign page can't even enumerate the surface.
476
- if (pathname === '/__crtr/push/vapid-public-key') {
477
- if (req.method !== 'GET') {
478
- res.writeHead(405, { 'content-type': 'text/plain; charset=utf-8', allow: 'GET' });
479
- res.end('method not allowed\n');
480
- return;
481
- }
482
- if (!authorizeRequest(req).allowed) {
483
- res.writeHead(403, { 'content-type': 'text/plain; charset=utf-8' });
484
- res.end('forbidden\n');
485
- return;
486
- }
487
- res.writeHead(200, { 'content-type': 'application/json' });
488
- res.end(JSON.stringify({ publicKey: vapid.publicKey }));
489
- return;
490
- }
491
- // §push — subscribe (POST) / unsubscribe (DELETE). Validation lives in
492
- // parsePush*Body, which rejects oversized/malformed/private/http/file
493
- // shapes BEFORE any persistence, throwing PushRequestError with a status.
494
- if (pathname === '/__crtr/push/subscribe') {
495
- const auth = authorizeRequest(req);
496
- if (!auth.allowed) {
497
- res.writeHead(403, { 'content-type': 'text/plain; charset=utf-8' });
498
- res.end('forbidden\n');
499
- return;
500
- }
501
- const handlePushError = (e) => {
502
- if (e instanceof PushRequestError) {
503
- res.writeHead(e.statusCode, { 'content-type': 'application/json' });
504
- res.end(JSON.stringify({ ok: false, error: e.message }));
505
- return;
506
- }
507
- res.writeHead(500, { 'content-type': 'application/json' });
508
- res.end(JSON.stringify({ ok: false, error: e instanceof Error ? e.message : String(e) }));
509
- };
510
- if (req.method === 'POST') {
511
- void readBodyCapped(req, pushBodyMaxBytes())
512
- .then((body) => {
513
- const record = parsePushSubscriptionBody(body, auth.scope);
514
- const stored = pushRegistry.upsert(record);
515
- res.writeHead(200, { 'content-type': 'application/json' });
516
- res.end(JSON.stringify({ ok: true, id: stored.id, authScope: stored.authScope }));
517
- })
518
- .catch(handlePushError);
519
- return;
520
- }
521
- if (req.method === 'DELETE') {
522
- void readBodyCapped(req, pushBodyMaxBytes())
523
- .then((body) => {
524
- const { endpoint } = parsePushDeleteBody(body);
525
- // Scoped: a caller may only delete a subscription it owns.
526
- const deleted = pushRegistry.deleteByEndpoint(endpoint, auth.scope);
527
- res.writeHead(200, { 'content-type': 'application/json' });
528
- res.end(JSON.stringify({ ok: true, deleted }));
529
- })
530
- .catch(handlePushError);
531
- return;
532
- }
533
- res.writeHead(405, { 'content-type': 'text/plain; charset=utf-8', allow: 'POST, DELETE' });
534
- res.end('method not allowed\n');
535
- return;
536
- }
537
- // --dev: Vite middleware owns all remaining asset/HTML serving (incl. its
538
- // own SPA fallback). It is mounted AFTER the bridge + SSE checks above, so
539
- // those never fall through to Vite.
540
- if (vite !== undefined) {
541
- vite.middlewares(req, res);
542
- return;
543
- }
544
- // Shipped: static shell bundle + SPA fallback.
545
- if (req.method !== 'GET' && req.method !== 'HEAD') {
546
- res.writeHead(405, { 'content-type': 'text/plain; charset=utf-8', allow: 'GET, HEAD' });
547
- res.end('method not allowed\n');
548
- return;
549
- }
550
- serveStatic(clientDir, req, res);
551
- }
552
- catch {
553
- // Belt-and-suspenders: nothing in the handler should throw now (C1), but a
554
- // request listener that throws crashes the whole daemon — never allow it.
555
- if (!res.headersSent)
556
- res.writeHead(500, { 'content-type': 'text/plain; charset=utf-8' });
557
- res.end('internal error\n');
558
- }
559
- });
560
- httpServer.on('upgrade', (req, socket, head) => {
561
- // A raw upgrade socket with no 'error' listener throws on a write to a reset
562
- // peer — attach one before we ever write/destroy it (n8).
563
- socket.on('error', () => {
564
- /* peer reset mid-handshake — destroy below or already destroyed */
565
- });
566
- try {
567
- const url = new URL(req.url ?? '/', 'http://127.0.0.1');
568
- const nodeId = nodeIdFromPath(url.pathname);
569
- if (nodeId === null) {
570
- // --dev: Vite's HMR WebSocket shares this HTTP server. Vite registers its
571
- // OWN 'upgrade' listener (via server.hmr.server); leave every non-`/node/`
572
- // upgrade for it instead of destroying the socket.
573
- if (vite !== undefined)
574
- return;
575
- socket.write('HTTP/1.1 404 Not Found\r\n\r\n');
576
- socket.destroy();
577
- return;
578
- }
579
- if (!authorizeRequest(req).allowed) {
580
- socket.write('HTTP/1.1 403 Forbidden\r\n\r\n');
581
- socket.destroy();
582
- return;
583
- }
584
- // Transparent tunnel to crtrd's attach endpoint — the shell never
585
- // terminates the WS; crtrd owns the handshake and attach-implies-revive.
586
- tunnelAttachUpgrade(req, socket, head, nodeId, activeTunnels);
587
- }
588
- catch {
589
- // Never let an upgrade-handler throw escape and crash the daemon (C1).
590
- try {
591
- socket.destroy();
592
- }
593
- catch {
594
- /* ignore */
595
- }
596
- }
597
- });
598
- // --dev: create the Vite middleware server BEFORE listen so the request
599
- // handler's `vite` is set and Vite's HMR upgrade listener is attached (ours
600
- // was added first, so a vite-hmr upgrade hits ours → nodeId null → returns →
601
- // Vite's listener handles it).
602
- if (dev) {
603
- vite = await createDevServer(httpServer);
604
- }
605
- return new Promise((resolveListening, rejectListening) => {
606
- httpServer.once('error', rejectListening);
607
- httpServer.listen(opts.port, host, () => {
608
- let port;
609
- try {
610
- const addr = httpServer.address();
611
- if (typeof addr !== 'object' || addr === null) {
612
- throw new Error('web server address is unavailable after listen');
613
- }
614
- port = addr.port;
615
- bindWebEventSource(host, port);
616
- }
617
- catch (error) {
618
- httpServer.close(() => {
619
- httpServer.off('error', rejectListening);
620
- rejectListening(error);
621
- });
622
- httpServer.closeAllConnections();
623
- return;
624
- }
625
- httpServer.off('error', rejectListening);
626
- // A server error AFTER listen (e.g. an accept failure) must not be an
627
- // unhandled 'error' that crashes the process (n9) — emit + carry on.
628
- httpServer.on('error', (err) => {
629
- emitEvent({ event: 'web.server.failed', level: 'error', error: err });
630
- });
631
- const hostUrl = hostForUrl(host);
632
- const url = `http://${hostUrl}:${port}`;
633
- allowedOrigins = new Set([
634
- `http://${hostUrl}:${port}`,
635
- `http://127.0.0.1:${port}`,
636
- `http://localhost:${port}`,
637
- ]);
638
- const close = () => new Promise((done) => {
639
- unsubscribePush();
640
- eventHub.close();
641
- void vite?.close().catch(() => {
642
- /* best-effort */
643
- });
644
- for (const s of activeTunnels) {
645
- try {
646
- s.destroy();
647
- }
648
- catch {
649
- /* ignore */
650
- }
651
- }
652
- activeTunnels.clear();
653
- httpServer.close(() => done());
654
- // Idle keep-alive HTTP connections would otherwise keep close()'s
655
- // callback from ever firing — drop them so shutdown completes (m4).
656
- httpServer.closeAllConnections();
657
- });
658
- resolveListening({ url, port, clientDir, close });
659
- });
660
- });
661
- }