@north-light/crouter 0.3.170 → 0.3.172

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 (670) hide show
  1. package/dist/api/client.d.ts +37 -11
  2. package/dist/api/client.js +84 -15
  3. package/dist/api/dto/human.d.ts +53 -39
  4. package/dist/api/dto/human.js +2 -3
  5. package/dist/api/dto/inbox.d.ts +0 -1
  6. package/dist/api/dto/nodes.d.ts +12 -0
  7. package/dist/api/dto/review-comments.d.ts +137 -0
  8. package/dist/api/dto/review-comments.js +5 -0
  9. package/dist/api/dto/reviews.d.ts +109 -0
  10. package/dist/api/dto/reviews.js +5 -0
  11. package/dist/api/index.d.ts +2 -0
  12. package/dist/api/index.js +2 -0
  13. package/dist/api/routes.d.ts +17 -4
  14. package/dist/api/routes.js +21 -5
  15. package/dist/build-root.d.ts +1 -16
  16. package/dist/build-root.js +1 -25
  17. package/dist/builtin-memory/00-runtime-base.md +7 -5
  18. package/dist/builtin-memory/04-base-worker.md +1 -1
  19. package/dist/builtin-memory/04-orchestration-kernel.md +7 -7
  20. package/dist/builtin-memory/05-kinds/design/00-base.md +1 -1
  21. package/dist/builtin-memory/05-kinds/design/01-orchestrator.md +1 -1
  22. package/dist/builtin-memory/05-kinds/developer/00-base.md +1 -1
  23. package/dist/builtin-memory/05-kinds/explore/00-base.md +1 -1
  24. package/dist/builtin-memory/05-kinds/plan/00-base.md +1 -1
  25. package/dist/builtin-memory/05-kinds/plan/01-orchestrator.md +1 -1
  26. package/dist/builtin-memory/05-kinds/review/00-base.md +1 -1
  27. package/dist/builtin-memory/05-kinds/review/companion/00-base.md +20 -0
  28. package/dist/builtin-memory/05-kinds/spec/00-base.md +3 -7
  29. package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +3 -3
  30. package/dist/builtin-memory/05-kinds/spec/requirements.md +3 -3
  31. package/dist/builtin-memory/design.md +2 -2
  32. package/dist/builtin-memory/insights/capture.md +50 -0
  33. package/dist/builtin-memory/insights/init.md +45 -0
  34. package/dist/builtin-memory/insights/listen.md +9 -0
  35. package/dist/builtin-memory/internal/agent-shaping.md +2 -2
  36. package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
  37. package/dist/builtin-memory/internal/plugins.md +12 -11
  38. package/dist/builtin-memory/internal/storage-tiers.md +2 -2
  39. package/dist/builtin-memory/{planning.md → plan/roadmap.md} +3 -3
  40. package/dist/builtin-memory/plan.md +19 -0
  41. package/dist/builtin-memory/spec/guide.md +38 -0
  42. package/dist/builtin-memory/spec/requirements.md +31 -0
  43. package/dist/builtin-memory/spec/roadmap.md +35 -0
  44. package/dist/builtin-memory/spec.md +10 -86
  45. package/dist/builtin-pi-packages/pi-crtr-extensions/README.md +3 -4
  46. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/provider-rotation.test.ts +49 -5
  47. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +56 -0
  48. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +920 -0
  49. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +221 -156
  50. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/statusline.ts +4 -5
  51. package/dist/cli.js +2 -6
  52. package/dist/clients/attach/__tests__/attach-chrome-remote.test.js +7 -35
  53. package/dist/clients/attach/__tests__/attach-keybindings.test.js +32 -16
  54. package/dist/clients/attach/__tests__/context-message.test.js +142 -6
  55. package/dist/clients/attach/__tests__/crtr-output.test.js +29 -45
  56. package/dist/clients/attach/__tests__/diagram.test.js +1 -1
  57. package/dist/clients/attach/__tests__/file-review-focus.test.js +48 -0
  58. package/dist/clients/attach/__tests__/group-activity.test.js +266 -0
  59. package/dist/clients/attach/__tests__/input-controller-extension-command.test.js +32 -0
  60. package/dist/clients/attach/__tests__/session-identity-refresh.test.js +32 -0
  61. package/dist/clients/attach/__tests__/titled-editor-preview.test.js +1 -2
  62. package/dist/clients/attach/chrome/header.d.ts +10 -0
  63. package/dist/clients/attach/chrome/header.js +30 -0
  64. package/dist/clients/attach/chrome/recap.d.ts +7 -0
  65. package/dist/clients/attach/chrome/recap.js +19 -0
  66. package/dist/clients/attach/chrome/status-line.d.ts +3 -0
  67. package/dist/clients/attach/chrome/status-line.js +5 -0
  68. package/dist/clients/attach/chrome/widgets.js +11 -21
  69. package/dist/clients/attach/command.js +11 -7
  70. package/dist/clients/attach/config.d.ts +4 -0
  71. package/dist/clients/attach/config.js +3 -0
  72. package/dist/clients/attach/input/controller.d.ts +19 -0
  73. package/dist/clients/attach/input/controller.js +62 -28
  74. package/dist/clients/attach/input/titled-editor.d.ts +0 -4
  75. package/dist/clients/attach/input/titled-editor.js +2 -10
  76. package/dist/clients/attach/overlays/file-review.d.ts +9 -5
  77. package/dist/clients/attach/overlays/file-review.js +9 -70
  78. package/dist/clients/attach/overlays/help.d.ts +33 -0
  79. package/dist/clients/attach/overlays/help.js +204 -0
  80. package/dist/clients/attach/render/activity-slot.d.ts +4 -0
  81. package/dist/clients/attach/render/activity-slot.js +13 -0
  82. package/dist/clients/attach/render/chat-view.d.ts +117 -12
  83. package/dist/clients/attach/render/chat-view.js +604 -135
  84. package/dist/clients/attach/render/context-message.d.ts +2 -1
  85. package/dist/clients/attach/render/context-message.js +17 -13
  86. package/dist/clients/attach/render/crtr-output.js +1 -3
  87. package/dist/clients/attach/render/diagram.js +2 -2
  88. package/dist/clients/attach/render/edit-diff.d.ts +4 -1
  89. package/dist/clients/attach/render/edit-diff.js +7 -11
  90. package/dist/clients/attach/render/group-activity.d.ts +32 -0
  91. package/dist/clients/attach/render/group-activity.js +206 -0
  92. package/dist/clients/attach/render/group-recap.d.ts +10 -0
  93. package/dist/clients/attach/render/group-recap.js +93 -0
  94. package/dist/clients/attach/render/html-markdown.d.ts +17 -0
  95. package/dist/clients/attach/render/html-markdown.js +228 -0
  96. package/dist/clients/attach/render/measured-container.d.ts +96 -0
  97. package/dist/clients/attach/render/measured-container.js +322 -0
  98. package/dist/clients/attach/render/scroll-animation.d.ts +8 -0
  99. package/dist/clients/attach/render/scroll-animation.js +80 -0
  100. package/dist/clients/attach/render/tool-calls.js +6 -6
  101. package/dist/clients/attach/render/transcript-copy.d.ts +9 -0
  102. package/dist/clients/attach/render/transcript-copy.js +81 -0
  103. package/dist/clients/attach/render/viewport.d.ts +29 -0
  104. package/dist/clients/attach/render/viewport.js +159 -0
  105. package/dist/clients/attach/session/bindings.d.ts +10 -7
  106. package/dist/clients/attach/session/bindings.js +23 -8
  107. package/dist/clients/attach/session/connection.js +4 -5
  108. package/dist/clients/attach/session/context.d.ts +6 -4
  109. package/dist/clients/attach/session/frame.d.ts +34 -0
  110. package/dist/clients/attach/session/frame.js +176 -0
  111. package/dist/clients/attach/session/frames.d.ts +4 -1
  112. package/dist/clients/attach/session/frames.js +14 -1
  113. package/dist/clients/attach/session/identity.js +4 -3
  114. package/dist/clients/attach/session/input-wiring.d.ts +14 -4
  115. package/dist/clients/attach/session/input-wiring.js +15 -13
  116. package/dist/clients/attach/session/invariant.d.ts +9 -0
  117. package/dist/clients/attach/session/invariant.js +15 -0
  118. package/dist/clients/attach/session/keys.d.ts +10 -2
  119. package/dist/clients/attach/session/keys.js +13 -5
  120. package/dist/clients/attach/session/layout.d.ts +10 -8
  121. package/dist/clients/attach/session/layout.js +33 -34
  122. package/dist/clients/attach/session/mouse.d.ts +18 -0
  123. package/dist/clients/attach/session/mouse.js +64 -0
  124. package/dist/clients/attach/session/pane-tag.d.ts +3 -0
  125. package/dist/clients/attach/session/pane-tag.js +51 -8
  126. package/dist/clients/attach/session/reconnect.d.ts +3 -0
  127. package/dist/clients/attach/session/reconnect.js +42 -5
  128. package/dist/clients/attach/session/surface-frame.d.ts +20 -0
  129. package/dist/clients/attach/session/surface-frame.js +73 -0
  130. package/dist/clients/attach/session/surface-host.d.ts +64 -0
  131. package/dist/clients/attach/session/surface-host.js +255 -0
  132. package/dist/clients/attach/session/whip.d.ts +17 -0
  133. package/dist/clients/attach/session/whip.js +334 -0
  134. package/dist/clients/attach/slash/dispatch.d.ts +13 -1
  135. package/dist/clients/attach/slash/dispatch.js +51 -29
  136. package/dist/clients/attach/viewer.js +907 -819
  137. package/dist/clients/conversation/conversation.d.ts +65 -0
  138. package/dist/clients/conversation/conversation.js +318 -0
  139. package/dist/clients/conversation/frames.d.ts +30 -0
  140. package/dist/clients/conversation/frames.js +52 -0
  141. package/dist/clients/conversation/region.d.ts +51 -0
  142. package/dist/clients/conversation/region.js +265 -0
  143. package/dist/clients/conversation/submit.d.ts +38 -0
  144. package/dist/clients/conversation/submit.js +51 -0
  145. package/dist/clients/inbox/__tests__/inbox-controller.test.js +247 -0
  146. package/dist/clients/inbox/__tests__/mount-panel.test.js +776 -0
  147. package/dist/clients/inbox/controller.d.ts +79 -0
  148. package/dist/clients/inbox/controller.js +448 -0
  149. package/dist/clients/inbox/deck-adapter.d.ts +29 -0
  150. package/dist/clients/inbox/deck-adapter.js +62 -0
  151. package/dist/clients/inbox/layout.d.ts +8 -0
  152. package/dist/clients/inbox/layout.js +9 -0
  153. package/dist/clients/inbox/resolve.d.ts +10 -0
  154. package/dist/clients/inbox/resolve.js +34 -0
  155. package/dist/clients/inbox/review/__tests__/editor-roundtrip.test.js +29 -0
  156. package/dist/clients/inbox/review/__tests__/remap.test.js +196 -0
  157. package/dist/clients/inbox/review/__tests__/review-core.test.js +341 -0
  158. package/dist/clients/inbox/review/anchors.d.ts +41 -0
  159. package/dist/clients/inbox/review/anchors.js +89 -0
  160. package/dist/clients/inbox/review/columns.d.ts +22 -0
  161. package/dist/clients/inbox/review/columns.js +40 -0
  162. package/dist/clients/inbox/review/comments-client.d.ts +66 -0
  163. package/dist/clients/inbox/review/comments-client.js +98 -0
  164. package/dist/clients/inbox/review/composition.d.ts +60 -0
  165. package/dist/clients/inbox/review/composition.js +278 -0
  166. package/dist/clients/inbox/review/document-region.d.ts +120 -0
  167. package/dist/clients/inbox/review/document-region.js +902 -0
  168. package/dist/clients/inbox/review/frame.d.ts +45 -0
  169. package/dist/clients/inbox/review/frame.js +215 -0
  170. package/dist/clients/inbox/review/keys.d.ts +67 -0
  171. package/dist/clients/inbox/review/keys.js +130 -0
  172. package/dist/clients/inbox/review/launch.d.ts +10 -0
  173. package/dist/clients/inbox/review/launch.js +129 -0
  174. package/dist/clients/inbox/review/live-source.d.ts +24 -0
  175. package/dist/clients/inbox/review/live-source.js +160 -0
  176. package/dist/clients/inbox/review/nvim.d.ts +13 -0
  177. package/dist/clients/inbox/review/nvim.js +42 -0
  178. package/dist/clients/inbox/review/remap.d.ts +51 -0
  179. package/dist/clients/inbox/review/remap.js +157 -0
  180. package/dist/clients/inbox/review/review-client.d.ts +30 -0
  181. package/dist/clients/inbox/review/review-client.js +107 -0
  182. package/dist/clients/inbox/review/roundtrip.d.ts +5 -0
  183. package/dist/clients/inbox/review/roundtrip.js +36 -0
  184. package/dist/clients/inbox/review/state.d.ts +143 -0
  185. package/dist/clients/inbox/review/state.js +282 -0
  186. package/dist/clients/inbox/review-adapter.d.ts +29 -0
  187. package/dist/clients/inbox/review-adapter.js +92 -0
  188. package/dist/clients/inbox/review-visibility.d.ts +5 -0
  189. package/dist/clients/inbox/review-visibility.js +19 -0
  190. package/dist/clients/inbox/surface.d.ts +19 -0
  191. package/dist/clients/inbox/surface.js +128 -0
  192. package/dist/clients/inbox/tui/ansi.d.ts +66 -0
  193. package/dist/clients/inbox/tui/ansi.js +317 -0
  194. package/dist/clients/inbox/tui/clipboard.d.ts +2 -0
  195. package/dist/clients/inbox/tui/clipboard.js +26 -0
  196. package/dist/clients/inbox/tui/input.d.ts +7 -0
  197. package/dist/clients/inbox/tui/input.js +653 -0
  198. package/dist/clients/inbox/tui/keys.d.ts +28 -0
  199. package/dist/clients/inbox/tui/keys.js +111 -0
  200. package/dist/clients/inbox/tui/panel.d.ts +2 -0
  201. package/dist/clients/inbox/tui/panel.js +217 -0
  202. package/dist/clients/inbox/tui/render.d.ts +37 -0
  203. package/dist/clients/inbox/tui/render.js +476 -0
  204. package/dist/clients/inbox/tui/types.d.ts +57 -0
  205. package/dist/clients/inbox/tui/types.js +1 -0
  206. package/dist/clients/inbox/tui.d.ts +6 -0
  207. package/dist/clients/inbox/tui.js +74 -0
  208. package/dist/clients/surfaces/host.d.ts +66 -0
  209. package/dist/clients/surfaces/host.js +1 -0
  210. package/dist/clients/surfaces/region.d.ts +16 -0
  211. package/dist/clients/surfaces/region.js +1 -0
  212. package/dist/clients/web/__tests__/push-engine.test.js +14 -158
  213. package/dist/clients/web/dev-server.d.ts +3 -3
  214. package/dist/clients/web/dev-server.js +9 -23
  215. package/dist/clients/web/events.js +4 -6
  216. package/dist/clients/web/push-engine.d.ts +2 -66
  217. package/dist/clients/web/push-engine.js +30 -161
  218. package/dist/clients/web/push-registry.d.ts +0 -4
  219. package/dist/clients/web/push-registry.js +2 -7
  220. package/dist/clients/web/server.js +3 -35
  221. package/dist/clients/web/web-client/shared/protocol.d.ts +0 -108
  222. package/dist/clients/web/web-cmd.js +2 -2
  223. package/dist/commands/__tests__/human.test.js +27 -15
  224. package/dist/commands/api-client.js +3 -3
  225. package/dist/commands/canvas-browse.js +1 -1
  226. package/dist/commands/canvas-issue.js +1 -1
  227. package/dist/commands/canvas-use.js +1 -1
  228. package/dist/commands/human/doc.d.ts +2 -0
  229. package/dist/commands/human/doc.js +98 -0
  230. package/dist/commands/human/inbox.d.ts +2 -0
  231. package/dist/commands/human/inbox.js +101 -0
  232. package/dist/commands/human/prompts.d.ts +2 -3
  233. package/dist/commands/human/prompts.js +27 -180
  234. package/dist/commands/human/queue.d.ts +1 -5
  235. package/dist/commands/human/queue.js +54 -216
  236. package/dist/commands/human/review.d.ts +2 -0
  237. package/dist/commands/human/review.js +298 -0
  238. package/dist/commands/human/shared.d.ts +2 -69
  239. package/dist/commands/human/shared.js +1 -181
  240. package/dist/commands/human.js +15 -20
  241. package/dist/commands/memory/__tests__/lint.test.d.ts +1 -0
  242. package/dist/commands/memory/__tests__/lint.test.js +15 -0
  243. package/dist/commands/memory/delete.js +2 -2
  244. package/dist/commands/memory/lint.d.ts +1 -0
  245. package/dist/commands/memory/lint.js +21 -3
  246. package/dist/commands/memory/read.js +4 -4
  247. package/dist/commands/node.js +8 -7
  248. package/dist/commands/pkg/plugin-manage.js +143 -68
  249. package/dist/commands/surface-inspect.js +2 -2
  250. package/dist/commands/surface.js +6 -12
  251. package/dist/commands/sys/__tests__/setup-core.test.js +9 -5
  252. package/dist/commands/sys/__tests__/setup-front-door.test.js +7 -42
  253. package/dist/commands/sys/config.js +29 -3
  254. package/dist/commands/sys/feedback.js +1 -1
  255. package/dist/commands/sys/setup-core.d.ts +12 -11
  256. package/dist/commands/sys/setup-core.js +55 -46
  257. package/dist/commands/sys/setup-wizard.d.ts +4 -1
  258. package/dist/commands/sys/setup-wizard.js +50 -9
  259. package/dist/commands/sys/sync-deps.js +1 -1
  260. package/dist/commands/sys.js +4 -6
  261. package/dist/core/__tests__/broker-sdk-wiring.test.js +6 -1
  262. package/dist/core/__tests__/broker-snapshot-history.test.js +9 -1
  263. package/dist/core/__tests__/dead-node-policy-table.test.js +3 -4
  264. package/dist/core/__tests__/fixtures/fake-engine.d.ts +8 -5
  265. package/dist/core/__tests__/fixtures/fake-engine.js +28 -2
  266. package/dist/core/__tests__/full/broker-provider-retry.test.js +87 -2
  267. package/dist/core/__tests__/full/broker-whip-interrupt.test.d.ts +1 -0
  268. package/dist/core/__tests__/full/broker-whip-interrupt.test.js +39 -0
  269. package/dist/core/__tests__/full/detach-focus.test.js +1 -1
  270. package/dist/core/__tests__/human-deliver-e2e.test.js +64 -64
  271. package/dist/core/__tests__/human-deliver.test.js +71 -345
  272. package/dist/core/__tests__/inline-memory-refs.test.js +2 -12
  273. package/dist/core/__tests__/memory-resolver-precedence.test.js +12 -15
  274. package/dist/core/__tests__/migration.test.js +10 -0
  275. package/dist/core/__tests__/model-pin-durability.test.js +14 -0
  276. package/dist/core/__tests__/phase4-review-migration.test.d.ts +1 -0
  277. package/dist/core/__tests__/phase4-review-migration.test.js +100 -0
  278. package/dist/core/__tests__/phase4-review-store.test.d.ts +1 -0
  279. package/dist/core/__tests__/phase4-review-store.test.js +143 -0
  280. package/dist/core/__tests__/remote-canvas-target.test.js +2 -2
  281. package/dist/core/__tests__/revive.test.js +22 -53
  282. package/dist/core/__tests__/session-cycles.test.js +48 -18
  283. package/dist/core/__tests__/spawn-no-kickoff.test.js +8 -12
  284. package/dist/core/__tests__/stop-guard.test.js +16 -1
  285. package/dist/core/__tests__/tmux-surface.test.js +21 -25
  286. package/dist/core/asset-root.d.ts +7 -0
  287. package/dist/core/asset-root.js +18 -0
  288. package/dist/core/broker-client/client.d.ts +0 -7
  289. package/dist/core/broker-client/client.js +4 -10
  290. package/dist/core/broker-client/transport-relay.d.ts +3 -4
  291. package/dist/core/broker-client/transport-relay.js +3 -4
  292. package/dist/core/canvas/__tests__/attention.test.js +1 -1
  293. package/dist/core/canvas/__tests__/remote-canvas-source.test.js +1 -1
  294. package/dist/core/canvas/__tests__/remote-transport.test.d.ts +1 -0
  295. package/dist/core/{view/__tests__/transport-remote.test.js → canvas/__tests__/remote-transport.test.js} +2 -2
  296. package/dist/core/canvas/__tests__/render-remote.test.js +1 -1
  297. package/dist/core/canvas/attention.js +4 -4
  298. package/dist/core/canvas/canvas.d.ts +6 -11
  299. package/dist/core/canvas/canvas.js +11 -33
  300. package/dist/core/canvas/db.js +207 -38
  301. package/dist/core/canvas/extensions.d.ts +1 -1
  302. package/dist/core/canvas/extensions.js +8 -1
  303. package/dist/core/canvas/index.d.ts +0 -1
  304. package/dist/core/canvas/index.js +0 -1
  305. package/dist/core/canvas/nav-model.d.ts +1 -1
  306. package/dist/core/canvas/nav-model.js +1 -1
  307. package/dist/core/canvas/paths.d.ts +5 -0
  308. package/dist/core/canvas/paths.js +16 -0
  309. package/dist/core/canvas/remote-canvas-source.js +2 -2
  310. package/dist/core/canvas/remote-transport.d.ts +7 -0
  311. package/dist/core/{view/transport-remote.js → canvas/remote-transport.js} +3 -4
  312. package/dist/core/canvas/source.js +1 -1
  313. package/dist/core/canvas/status-glyph.js +4 -12
  314. package/dist/core/canvas/types.d.ts +10 -35
  315. package/dist/core/clipboard-text.d.ts +8 -0
  316. package/dist/core/clipboard-text.js +18 -0
  317. package/dist/core/command-manifests/registry.d.ts +1 -3
  318. package/dist/core/command-plugins/bundle.d.ts +29 -0
  319. package/dist/core/command-plugins/bundle.js +198 -0
  320. package/dist/core/command-plugins/discovery.d.ts +0 -8
  321. package/dist/core/command-plugins/discovery.js +2 -39
  322. package/dist/core/command-plugins/transport/http-fetch.d.ts +4 -30
  323. package/dist/core/command-plugins/transport/http-fetch.js +17 -95
  324. package/dist/core/command.d.ts +1 -13
  325. package/dist/core/command.js +1 -16
  326. package/dist/core/config.d.ts +4 -0
  327. package/dist/core/config.js +28 -3
  328. package/dist/core/document-lines.d.ts +4 -0
  329. package/dist/core/document-lines.js +6 -0
  330. package/dist/core/feed/feed.d.ts +2 -0
  331. package/dist/core/feed/feed.js +11 -7
  332. package/dist/core/human/__tests__/inbox-cancel-worker.d.ts +1 -0
  333. package/dist/core/human/__tests__/inbox-cancel-worker.js +7 -0
  334. package/dist/core/human/__tests__/inbox-claim-worker.d.ts +1 -0
  335. package/dist/core/human/__tests__/inbox-claim-worker.js +17 -0
  336. package/dist/core/human/__tests__/inbox-core.test.d.ts +1 -0
  337. package/dist/core/human/__tests__/inbox-core.test.js +144 -0
  338. package/dist/core/human/__tests__/inbox-stale-claim-worker.d.ts +1 -0
  339. package/dist/core/human/__tests__/inbox-stale-claim-worker.js +8 -0
  340. package/dist/core/human/__tests__/visible-paths.test.d.ts +1 -0
  341. package/dist/{clients/attach → core/human}/__tests__/visible-paths.test.js +9 -0
  342. package/dist/core/human/claim.d.ts +23 -0
  343. package/dist/core/human/claim.js +67 -0
  344. package/dist/core/human/convention.d.ts +30 -0
  345. package/dist/core/human/convention.js +202 -0
  346. package/dist/core/human/deck-factories.d.ts +8 -0
  347. package/dist/core/human/deck-factories.js +15 -0
  348. package/dist/core/human/deck-schema.d.ts +70 -0
  349. package/dist/core/human/deck-schema.js +92 -0
  350. package/dist/core/human/root.d.ts +7 -0
  351. package/dist/core/human/root.js +37 -0
  352. package/dist/core/human/scan.d.ts +3 -0
  353. package/dist/core/human/scan.js +76 -0
  354. package/dist/core/human/summary.d.ts +8 -0
  355. package/dist/core/human/summary.js +44 -0
  356. package/dist/core/human/tickets.d.ts +49 -0
  357. package/dist/core/human/tickets.js +190 -0
  358. package/dist/core/human/types.d.ts +136 -0
  359. package/dist/core/human/types.js +5 -0
  360. package/dist/{clients/attach → core/human}/visible-paths.d.ts +1 -1
  361. package/dist/{clients/attach → core/human}/visible-paths.js +3 -2
  362. package/dist/core/inspector/chrome.d.ts +6 -0
  363. package/dist/core/inspector/chrome.js +14 -0
  364. package/dist/core/inspector/contract.d.ts +105 -0
  365. package/dist/core/inspector/contract.js +1 -0
  366. package/dist/core/inspector/core.d.ts +4 -5
  367. package/dist/core/inspector/core.js +3 -5
  368. package/dist/core/inspector/host.d.ts +46 -0
  369. package/dist/core/{tui → inspector}/host.js +42 -208
  370. package/dist/core/inspector/text.d.ts +2 -2
  371. package/dist/core/inspector/transport.d.ts +6 -0
  372. package/dist/core/inspector/transport.js +36 -0
  373. package/dist/core/inspector/tui.d.ts +2 -2
  374. package/dist/core/inspector/tui.js +15 -15
  375. package/dist/core/keybindings/__tests__/inbox-affordance.test.js +11 -11
  376. package/dist/core/keybindings/__tests__/resolve.test.js +10 -19
  377. package/dist/core/keybindings/attach-control.d.ts +9 -3
  378. package/dist/core/keybindings/attach-control.js +3 -1
  379. package/dist/core/keybindings/catalog.d.ts +6 -5
  380. package/dist/core/keybindings/catalog.js +61 -133
  381. package/dist/core/keybindings/inbox.d.ts +5 -6
  382. package/dist/core/keybindings/inbox.js +9 -10
  383. package/dist/core/keybindings/index.d.ts +3 -3
  384. package/dist/core/keybindings/index.js +3 -3
  385. package/dist/core/keybindings/persistence.d.ts +5 -1
  386. package/dist/core/keybindings/persistence.js +24 -6
  387. package/dist/core/keybindings/resolve.d.ts +6 -0
  388. package/dist/core/keybindings/resolve.js +10 -3
  389. package/dist/core/memory/inline-ref-grammar.js +2 -3
  390. package/dist/core/memory-resolver.d.ts +27 -29
  391. package/dist/core/memory-resolver.js +45 -39
  392. package/dist/core/model-routes.d.ts +33 -0
  393. package/dist/core/model-routes.js +42 -3
  394. package/dist/core/preview-registry.js +17 -55
  395. package/dist/core/profiles/select.js +3 -3
  396. package/dist/core/{view/remote-canvas-target.d.ts → remote-canvas-target.d.ts} +2 -2
  397. package/dist/core/{view/remote-canvas-target.js → remote-canvas-target.js} +4 -4
  398. package/dist/core/review/__tests__/capture-origin.test.d.ts +1 -0
  399. package/dist/core/review/__tests__/capture-origin.test.js +139 -0
  400. package/dist/core/review/__tests__/comments.test.d.ts +1 -0
  401. package/dist/core/review/__tests__/comments.test.js +98 -0
  402. package/dist/core/review/__tests__/project.test.d.ts +1 -0
  403. package/dist/core/review/__tests__/project.test.js +71 -0
  404. package/dist/core/review/__tests__/remap.test.d.ts +1 -0
  405. package/dist/core/review/__tests__/remap.test.js +159 -0
  406. package/dist/core/review/__tests__/stage-identity.test.d.ts +1 -0
  407. package/dist/core/review/__tests__/stage-identity.test.js +140 -0
  408. package/dist/core/review/birth.d.ts +7 -0
  409. package/dist/core/review/birth.js +23 -0
  410. package/dist/core/review/comments.d.ts +69 -0
  411. package/dist/core/review/comments.js +295 -0
  412. package/dist/core/review/companion.d.ts +35 -0
  413. package/dist/core/review/companion.js +205 -0
  414. package/dist/core/review/document.d.ts +27 -0
  415. package/dist/core/review/document.js +138 -0
  416. package/dist/core/review/project.d.ts +13 -0
  417. package/dist/core/review/project.js +58 -0
  418. package/dist/core/review/realize.d.ts +19 -0
  419. package/dist/core/review/realize.js +217 -0
  420. package/dist/core/review/remap.d.ts +24 -0
  421. package/dist/core/review/remap.js +156 -0
  422. package/dist/core/review/signal.d.ts +5 -0
  423. package/dist/core/review/signal.js +31 -0
  424. package/dist/core/review/stage.d.ts +26 -0
  425. package/dist/core/review/stage.js +184 -0
  426. package/dist/core/review/store.d.ts +46 -0
  427. package/dist/core/review/store.js +163 -0
  428. package/dist/core/review/ticket-filter.d.ts +17 -0
  429. package/dist/core/review/ticket-filter.js +32 -0
  430. package/dist/core/review/types.d.ts +130 -0
  431. package/dist/core/review/types.js +23 -0
  432. package/dist/core/runtime/__tests__/session-visibility.test.d.ts +1 -0
  433. package/dist/core/runtime/__tests__/session-visibility.test.js +119 -0
  434. package/dist/core/runtime/bearings.d.ts +5 -17
  435. package/dist/core/runtime/bearings.js +88 -71
  436. package/dist/core/runtime/broker-protocol.d.ts +31 -8
  437. package/dist/core/runtime/broker.d.ts +15 -1
  438. package/dist/core/runtime/broker.js +573 -141
  439. package/dist/core/runtime/canvas-extensions.d.ts +4 -5
  440. package/dist/core/runtime/canvas-extensions.js +5 -5
  441. package/dist/core/runtime/front-door.js +4 -4
  442. package/dist/core/runtime/headless-pi.d.ts +24 -0
  443. package/dist/core/runtime/headless-pi.js +152 -0
  444. package/dist/core/runtime/kickoff.d.ts +1 -5
  445. package/dist/core/runtime/kickoff.js +1 -5
  446. package/dist/core/runtime/model-registry.d.ts +3 -0
  447. package/dist/core/runtime/model-registry.js +13 -0
  448. package/dist/core/runtime/naming-persist.d.ts +4 -0
  449. package/dist/core/runtime/naming-persist.js +27 -1
  450. package/dist/core/runtime/naming.d.ts +17 -12
  451. package/dist/core/runtime/naming.js +91 -140
  452. package/dist/core/runtime/node-read.js +19 -10
  453. package/dist/core/runtime/nodes.d.ts +9 -14
  454. package/dist/core/runtime/nodes.js +3 -53
  455. package/dist/core/runtime/package-health.d.ts +6 -21
  456. package/dist/core/runtime/package-health.js +12 -123
  457. package/dist/core/runtime/placement-tmux.d.ts +2 -1
  458. package/dist/core/runtime/placement-tmux.js +6 -4
  459. package/dist/core/runtime/placement.d.ts +1 -0
  460. package/dist/core/runtime/placement.js +4 -8
  461. package/dist/core/runtime/promote.js +3 -0
  462. package/dist/core/runtime/recap.d.ts +2 -7
  463. package/dist/core/runtime/recap.js +35 -69
  464. package/dist/core/runtime/revive.js +34 -77
  465. package/dist/core/runtime/session-cycles.d.ts +4 -0
  466. package/dist/core/runtime/session-cycles.js +14 -1
  467. package/dist/core/runtime/session-visibility.d.ts +37 -0
  468. package/dist/core/runtime/session-visibility.js +83 -0
  469. package/dist/core/runtime/spawn.js +10 -22
  470. package/dist/core/runtime/stop-guard.d.ts +1 -1
  471. package/dist/core/runtime/stop-guard.js +18 -13
  472. package/dist/core/runtime/surface-bg.js +1 -1
  473. package/dist/core/runtime/tmux-chrome.d.ts +1 -1
  474. package/dist/core/runtime/tmux-chrome.js +1 -1
  475. package/dist/core/runtime/tmux.d.ts +35 -7
  476. package/dist/core/runtime/tmux.js +439 -62
  477. package/dist/core/runtime/tool-group-summary.d.ts +19 -0
  478. package/dist/core/runtime/tool-group-summary.js +88 -0
  479. package/dist/core/scope.d.ts +2 -7
  480. package/dist/core/scope.js +9 -35
  481. package/dist/core/substrate/schema.d.ts +2 -2
  482. package/dist/core/termrender/code-doc.d.ts +12 -0
  483. package/dist/core/termrender/code-doc.js +92 -0
  484. package/dist/core/termrender/display.d.ts +12 -0
  485. package/dist/core/termrender/display.js +19 -0
  486. package/dist/core/termrender/termrender.d.ts +73 -0
  487. package/dist/core/termrender/termrender.js +795 -0
  488. package/dist/core/termrender/version.d.ts +1 -0
  489. package/dist/core/termrender/version.js +1 -0
  490. package/dist/core/tui/terminal.js +1 -2
  491. package/dist/core/user-settings.d.ts +71 -3
  492. package/dist/core/user-settings.js +83 -1
  493. package/dist/daemon/api/__tests__/inbox.test.js +44 -133
  494. package/dist/daemon/api/handlers/human.d.ts +0 -10
  495. package/dist/daemon/api/handlers/human.js +104 -702
  496. package/dist/daemon/api/handlers/inbox.js +113 -142
  497. package/dist/daemon/api/handlers/review-comments.d.ts +2 -0
  498. package/dist/daemon/api/handlers/review-comments.js +500 -0
  499. package/dist/daemon/api/handlers/reviews.d.ts +2 -0
  500. package/dist/daemon/api/handlers/reviews.js +287 -0
  501. package/dist/daemon/api/map.d.ts +22 -7
  502. package/dist/daemon/api/map.js +159 -11
  503. package/dist/daemon/api/server.js +4 -0
  504. package/dist/daemon/cron-run.js +6 -9
  505. package/dist/daemon/crtrd.js +17 -33
  506. package/dist/daemon/fleet.d.ts +1 -8
  507. package/dist/daemon/fleet.js +4 -30
  508. package/dist/daemon/human/finish.d.ts +14 -0
  509. package/dist/daemon/human/finish.js +115 -0
  510. package/dist/daemon/human/sweep.d.ts +6 -0
  511. package/dist/daemon/human/sweep.js +49 -0
  512. package/dist/daemon/messaging/node-message.d.ts +18 -0
  513. package/dist/daemon/messaging/node-message.js +70 -0
  514. package/dist/daemon/review/comment-notify.d.ts +26 -0
  515. package/dist/daemon/review/comment-notify.js +107 -0
  516. package/dist/daemon/review/deliver.d.ts +7 -0
  517. package/dist/daemon/review/deliver.js +56 -0
  518. package/dist/daemon/review/finish.d.ts +22 -0
  519. package/dist/daemon/review/finish.js +254 -0
  520. package/dist/daemon/review/sweep.d.ts +11 -0
  521. package/dist/daemon/review/sweep.js +120 -0
  522. package/dist/index.d.ts +2 -0
  523. package/dist/index.js +2 -2
  524. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +42 -64
  525. package/dist/pi-extensions/__tests__/canvas-recap.test.d.ts +1 -0
  526. package/dist/pi-extensions/__tests__/canvas-recap.test.js +159 -0
  527. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +16 -38
  528. package/dist/pi-extensions/__tests__/canvas-structured-output.test.d.ts +1 -0
  529. package/dist/pi-extensions/__tests__/canvas-structured-output.test.js +63 -0
  530. package/dist/pi-extensions/canvas-context-intro.d.ts +8 -11
  531. package/dist/pi-extensions/canvas-context-intro.js +50 -104
  532. package/dist/pi-extensions/canvas-recap.d.ts +15 -2
  533. package/dist/pi-extensions/canvas-recap.js +192 -69
  534. package/dist/pi-extensions/canvas-review-boundary.d.ts +59 -0
  535. package/dist/pi-extensions/canvas-review-boundary.js +81 -0
  536. package/dist/pi-extensions/canvas-stophook.d.ts +3 -3
  537. package/dist/pi-extensions/canvas-stophook.js +78 -128
  538. package/dist/pi-extensions/canvas-structured-output.js +52 -8
  539. package/dist/shared/generated-context.d.ts +29 -4
  540. package/dist/shared/generated-context.js +122 -7
  541. package/dist/shared/tool-groups.d.ts +23 -0
  542. package/dist/shared/tool-groups.js +60 -0
  543. package/dist/shared/working-activity.d.ts +8 -0
  544. package/dist/shared/working-activity.js +26 -0
  545. package/dist/types.d.ts +36 -2
  546. package/dist/types.js +51 -0
  547. package/dist/web-client/assets/index-CCPaLeW7.css +2 -0
  548. package/dist/web-client/assets/index-kyOWsnZK.js +86 -0
  549. package/dist/web-client/index.html +2 -2
  550. package/dist/web-client/sw.js +1 -1
  551. package/docs/compat/hearth-crtr-v4.md +2 -2
  552. package/docs/compat/hearth-crtr-v5.md +4 -2
  553. package/docs/public-api.md +3 -3
  554. package/package.json +21 -14
  555. package/runtime.lock.json +4661 -1453
  556. package/scripts/postinstall.mjs +15 -2
  557. package/dist/builtin-pi-packages/pi-mode-switch/README.md +0 -36
  558. package/dist/builtin-pi-packages/pi-mode-switch/bin/mode +0 -36
  559. package/dist/builtin-pi-packages/pi-mode-switch/extensions/index.ts +0 -449
  560. package/dist/builtin-pi-packages/pi-mode-switch/package.json +0 -14
  561. package/dist/builtin-pi-packages/pi-mode-switch/tsconfig.json +0 -9
  562. package/dist/builtin-views/_lib/states.mjs +0 -161
  563. package/dist/builtin-views/canvas/core.mjs +0 -657
  564. package/dist/builtin-views/canvas/text.mjs +0 -58
  565. package/dist/builtin-views/canvas/tui.mjs +0 -168
  566. package/dist/builtin-views/canvas/web.jsx +0 -121
  567. package/dist/builtin-views/chat/core.mjs +0 -684
  568. package/dist/builtin-views/chat/text.mjs +0 -101
  569. package/dist/builtin-views/chat/tui.mjs +0 -360
  570. package/dist/builtin-views/chat/web.jsx +0 -362
  571. package/dist/builtin-views/git-pr/core.mjs +0 -673
  572. package/dist/builtin-views/git-pr/text.mjs +0 -84
  573. package/dist/builtin-views/git-pr/tui.mjs +0 -301
  574. package/dist/builtin-views/git-pr/web.jsx +0 -216
  575. package/dist/builtin-views/inbox/_lib/render.mjs +0 -175
  576. package/dist/builtin-views/inbox/core.mjs +0 -1273
  577. package/dist/builtin-views/inbox/text.mjs +0 -73
  578. package/dist/builtin-views/inbox/tui.mjs +0 -314
  579. package/dist/builtin-views/inbox/web.jsx +0 -188
  580. package/dist/builtin-views/linkedin/core.mjs +0 -906
  581. package/dist/builtin-views/linkedin/text.mjs +0 -69
  582. package/dist/builtin-views/linkedin/tui.mjs +0 -413
  583. package/dist/builtin-views/linkedin/web.jsx +0 -206
  584. package/dist/builtin-views/prompt-review/core.mjs +0 -735
  585. package/dist/builtin-views/prompt-review/text.mjs +0 -15
  586. package/dist/builtin-views/prompt-review/tui.mjs +0 -196
  587. package/dist/builtin-views/prompt-review/web.jsx +0 -484
  588. package/dist/builtin-views/workspace-sidebar/__tests__/core.test.js +0 -50
  589. package/dist/builtin-views/workspace-sidebar/__tests__/core.test.ts +0 -53
  590. package/dist/builtin-views/workspace-sidebar/core.mjs +0 -670
  591. package/dist/builtin-views/workspace-sidebar/text.mjs +0 -53
  592. package/dist/builtin-views/workspace-sidebar/tui.mjs +0 -141
  593. package/dist/builtin-views/workspace-sidebar/web.jsx +0 -109
  594. package/dist/clients/attach/session/mode.d.ts +0 -25
  595. package/dist/clients/attach/session/mode.js +0 -97
  596. package/dist/commands/sys/promptstudio.d.ts +0 -2
  597. package/dist/commands/sys/promptstudio.js +0 -65
  598. package/dist/commands/view-cycle.d.ts +0 -2
  599. package/dist/commands/view-cycle.js +0 -130
  600. package/dist/commands/view-list.d.ts +0 -2
  601. package/dist/commands/view-list.js +0 -66
  602. package/dist/commands/view-new.d.ts +0 -2
  603. package/dist/commands/view-new.js +0 -74
  604. package/dist/commands/view-pick.d.ts +0 -6
  605. package/dist/commands/view-pick.js +0 -129
  606. package/dist/commands/view-run.d.ts +0 -2
  607. package/dist/commands/view-run.js +0 -214
  608. package/dist/commands/view.d.ts +0 -2
  609. package/dist/commands/view.js +0 -31
  610. package/dist/commands/workspace.d.ts +0 -2
  611. package/dist/commands/workspace.js +0 -165
  612. package/dist/core/__tests__/chat-view-reconnect.test.js +0 -105
  613. package/dist/core/__tests__/full/consult-startup-failure.test.js +0 -124
  614. package/dist/core/canvas/__tests__/human-work-outbox.test.js +0 -123
  615. package/dist/core/canvas/human-work-outbox.d.ts +0 -73
  616. package/dist/core/canvas/human-work-outbox.js +0 -261
  617. package/dist/core/command-plugins/store.d.ts +0 -16
  618. package/dist/core/command-plugins/store.js +0 -64
  619. package/dist/core/keybindings/__tests__/bespoke-consumers.test.js +0 -40
  620. package/dist/core/runtime/fault-recovery-nudge.d.ts +0 -3
  621. package/dist/core/runtime/fault-recovery-nudge.js +0 -3
  622. package/dist/core/tui/__tests__/host-keybindings.test.js +0 -113
  623. package/dist/core/tui/host.d.ts +0 -66
  624. package/dist/core/view/__tests__/transport-cache.test.js +0 -62
  625. package/dist/core/view/bridge.d.ts +0 -10
  626. package/dist/core/view/bridge.js +0 -31
  627. package/dist/core/view/chrome.d.ts +0 -9
  628. package/dist/core/view/chrome.js +0 -22
  629. package/dist/core/view/contract.d.ts +0 -205
  630. package/dist/core/view/contract.js +0 -23
  631. package/dist/core/view/loader.d.ts +0 -31
  632. package/dist/core/view/loader.js +0 -188
  633. package/dist/core/view/stream-local.d.ts +0 -3
  634. package/dist/core/view/stream-local.js +0 -231
  635. package/dist/core/view/transport-cache.d.ts +0 -8
  636. package/dist/core/view/transport-cache.js +0 -38
  637. package/dist/core/view/transport-local.d.ts +0 -7
  638. package/dist/core/view/transport-local.js +0 -83
  639. package/dist/core/view/transport-remote.d.ts +0 -2
  640. package/dist/core/view/transport.d.ts +0 -10
  641. package/dist/core/view/transport.js +0 -15
  642. package/dist/pi-extensions/naming-tool.d.ts +0 -24
  643. package/dist/pi-extensions/naming-tool.js +0 -67
  644. package/dist/prompts/view.d.ts +0 -7
  645. package/dist/prompts/view.js +0 -172
  646. package/dist/web/ViewChrome.d.ts +0 -7
  647. package/dist/web/ViewChrome.js +0 -28
  648. package/dist/web/ViewPane.d.ts +0 -39
  649. package/dist/web/ViewPane.js +0 -48
  650. package/dist/web/index.d.ts +0 -8
  651. package/dist/web/index.js +0 -22
  652. package/dist/web/runtime.d.ts +0 -39
  653. package/dist/web/runtime.js +0 -232
  654. package/dist/web/states.d.ts +0 -24
  655. package/dist/web/states.js +0 -24
  656. package/dist/web/transport-http.d.ts +0 -5
  657. package/dist/web/transport-http.js +0 -34
  658. package/dist/web/transport-stream.d.ts +0 -3
  659. package/dist/web/transport-stream.js +0 -204
  660. package/dist/web-client/assets/index-U_NZ66VE.js +0 -79
  661. package/dist/web-client/assets/index-aaeu4adv.css +0 -2
  662. /package/dist/{builtin-views/workspace-sidebar/__tests__/core.test.d.ts → clients/attach/__tests__/file-review-focus.test.d.ts} +0 -0
  663. /package/dist/clients/attach/__tests__/{visible-paths.test.d.ts → group-activity.test.d.ts} +0 -0
  664. /package/dist/{core/__tests__/chat-view-reconnect.test.d.ts → clients/attach/__tests__/input-controller-extension-command.test.d.ts} +0 -0
  665. /package/dist/{core/__tests__/full/consult-startup-failure.test.d.ts → clients/attach/__tests__/session-identity-refresh.test.d.ts} +0 -0
  666. /package/dist/{core/canvas/__tests__/human-work-outbox.test.d.ts → clients/inbox/__tests__/inbox-controller.test.d.ts} +0 -0
  667. /package/dist/{core/keybindings/__tests__/bespoke-consumers.test.d.ts → clients/inbox/__tests__/mount-panel.test.d.ts} +0 -0
  668. /package/dist/{core/tui/__tests__/host-keybindings.test.d.ts → clients/inbox/review/__tests__/editor-roundtrip.test.d.ts} +0 -0
  669. /package/dist/{core/view/__tests__/transport-cache.test.d.ts → clients/inbox/review/__tests__/remap.test.d.ts} +0 -0
  670. /package/dist/{core/view/__tests__/transport-remote.test.d.ts → clients/inbox/review/__tests__/review-core.test.d.ts} +0 -0
@@ -0,0 +1,66 @@
1
+ import type { Component } from '@earendil-works/pi-tui';
2
+ /**
3
+ * A surface root: a pi-tui component rendered inside a host-assigned rectangle.
4
+ * The host pushes the rectangle height before every render and on resize; a
5
+ * surface must render exactly that many rows and must not read terminal or
6
+ * process geometry itself. A surface must never place its cursor marker on row
7
+ * 0, which is reserved for host notices.
8
+ */
9
+ export interface SurfaceComponent extends Component {
10
+ /** Set the number of rows assigned by the host for the next render. */
11
+ setRows(rows: number): void;
12
+ /** Consume wheel input at the terminal's 1-based column, when applicable. */
13
+ handleWheel?(direction: 'up' | 'down', lines: number, column: number): boolean;
14
+ }
15
+ /** The identities used for mounted Phase 3 surfaces. */
16
+ export type SurfaceId = 'inbox' | 'review';
17
+ /**
18
+ * The only host boundary available to a surface. Surfaces render only through
19
+ * the mounted component and use {@link notice} as their only output channel;
20
+ * they never write to the terminal, stdout, stderr, or raw input themselves.
21
+ */
22
+ export interface SurfaceHost {
23
+ /**
24
+ * Mount a component into the host-assigned full rectangle. When the focused
25
+ * input component differs from the rendered root, pass it as `focus` so
26
+ * input and cursor ownership remain with that component.
27
+ */
28
+ mount(component: SurfaceComponent, opts?: {
29
+ focus?: Component;
30
+ }): SurfaceHandle;
31
+ /** Report transient output through the host; this is the only surface output channel. */
32
+ notice(text: string): void;
33
+ /**
34
+ * Temporarily release the terminal for a child process and return a resume
35
+ * closure. Callers must invoke the closure in a `finally` block.
36
+ */
37
+ suspendForChild(): () => void;
38
+ /** Bring a node's viewer to the front; failures are reported through notice and never reject. */
39
+ focusNode(nodeId: string): Promise<boolean>;
40
+ /** Mount the shared review-file picker and resolve to its chosen path or null on cancellation. */
41
+ pickReviewFile(spec: {
42
+ candidates: readonly string[];
43
+ cwd: string;
44
+ title?: string;
45
+ }): Promise<string | null>;
46
+ /** Capability facts resolved once by the host for this session. */
47
+ readonly capabilities: {
48
+ /** True when this viewer is attached to a remote session. */
49
+ readonly remote: boolean;
50
+ /** True when focusing another node's viewer is available. */
51
+ readonly canFocusNode: boolean;
52
+ };
53
+ }
54
+ /** A mounted surface's lifecycle controls. */
55
+ export interface SurfaceHandle {
56
+ /** Close this surface and any surfaces mounted above it. Idempotent. */
57
+ close(): void;
58
+ /** Mark the surface dirty; the host schedules a redraw rather than drawing synchronously. */
59
+ invalidate(): void;
60
+ /**
61
+ * Register the only sanctioned teardown hook for timers, watchers, listeners,
62
+ * and poll re-arms. Closing initiates both synchronous and asynchronous
63
+ * cleanup; asynchronous cleanup is not awaited by the host.
64
+ */
65
+ onClose(fn: () => void | Promise<void>): void;
66
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ export interface SurfaceRegion {
2
+ /** Geometry is PUSHED. A region never reads terminal or process geometry. */
3
+ setViewport(cols: number, rows: number): void;
4
+ /** Exactly `rows` lines, each ≤ `cols` display cells. */
5
+ render(): string[];
6
+ /** True when the chunk was consumed. Unconsumed chunks are DROPPED, never re-offered. */
7
+ handleInput(data: string): boolean;
8
+ handleWheel(direction: 'up' | 'down', lines: number): boolean;
9
+ /** Only a focused region may emit CURSOR_MARKER. */
10
+ setFocused(value: boolean): void;
11
+ /** One line of state for the composition's status row. */
12
+ summary(): string;
13
+ /** The region's ONLY repaint channel. */
14
+ onDirty(fn: () => void): void;
15
+ close(): void;
16
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -14,9 +14,6 @@ function makeStores(dir) {
14
14
  lastSeen: new PushLastSeenStore(join(dir, 'last-seen.json')),
15
15
  };
16
16
  }
17
- // A real, allowlisted vendor push-service endpoint shape (Chromium/FCM) —
18
- // endpoints must resolve to one of the small set of known browser-vendor push
19
- // services (see push-registry.ts's PUSH_SERVICE_HOST_ALLOWLIST).
20
17
  function fakeSubscription(id, authScope = 'local') {
21
18
  return {
22
19
  id,
@@ -28,17 +25,11 @@ function fakeSubscription(id, authScope = 'local') {
28
25
  prefs: { doneNotifications: true },
29
26
  };
30
27
  }
31
- /** Seed a registry with one subscription directly (bypassing HTTP validation,
32
- * which is covered in push-registry.test.ts). */
33
- function seedRegistryWithOneSubscription(registry) {
34
- registry.upsert(fakeSubscription('sub-1'));
35
- }
36
28
  function buildHarness(dir, opts = {}) {
37
29
  const { registry, lastSeen } = makeStores(dir);
38
30
  const sent = [];
39
31
  const sentTo = [];
40
32
  const nodes = [];
41
- const asks = [];
42
33
  const clock = { now: 1_000_000 };
43
34
  const defaultSend = async (record, payload) => {
44
35
  sent.push(payload);
@@ -49,26 +40,25 @@ function buildHarness(dir, opts = {}) {
49
40
  registry,
50
41
  lastSeen,
51
42
  readCanvasNodes: () => nodes,
52
- readPendingAsks: () => asks,
53
43
  sendPush: opts.sendPush ?? defaultSend,
54
44
  isTargetScope: opts.isTargetScope ?? (() => true),
55
45
  now: () => clock.now,
56
46
  rateWindowMs: opts.rateWindowMs,
57
47
  });
58
- return { engine, sent, sentTo, registry, lastSeen, nodes, asks, clock };
48
+ return { engine, sent, sentTo, registry, lastSeen, nodes, clock };
59
49
  }
60
- test('seed() sends nothing regardless of current state (no restart storm)', async () => {
50
+ function seedRegistryWithOneSubscription(registry) {
51
+ registry.upsert(fakeSubscription('sub-1'));
52
+ }
53
+ test('seed() sends nothing regardless of current state', async () => {
61
54
  const dir = tmpDir();
62
55
  try {
63
56
  const h = buildHarness(dir);
64
57
  seedRegistryWithOneSubscription(h.registry);
65
58
  h.nodes.push({ node_id: 'root-1', parent: null, status: 'done', attention_count: 0 });
66
- h.asks.push({ id: 'ask-1', jobId: 'job-1', title: 'Pick a color', conversationId: 'root-1', conversationTitle: 'Root One', blockedSince: '2026-01-01T00:00:00.000Z' });
67
59
  await h.engine.seed();
68
60
  assert.equal(h.sent.length, 0);
69
- const snap = h.lastSeen.snapshot();
70
- assert.deepEqual(snap.roots['root-1'], { status: 'done', attention_count: 0 });
71
- assert.deepEqual(snap.asks['ask-1'], { present: true });
61
+ assert.deepEqual(h.lastSeen.snapshot().roots['root-1'], { status: 'done', attention_count: 0 });
72
62
  }
73
63
  finally {
74
64
  rmSync(dir, { recursive: true, force: true });
@@ -81,13 +71,11 @@ test('active -> done emits exactly one done push, and a repeat pass does not dup
81
71
  seedRegistryWithOneSubscription(h.registry);
82
72
  h.nodes.push({ node_id: 'root-1', parent: null, status: 'active', attention_count: 0 });
83
73
  await h.engine.seed();
84
- assert.equal(h.sent.length, 0);
85
74
  h.nodes[0].status = 'done';
86
75
  await h.engine.onNodesInvalidation();
87
76
  assert.equal(h.sent.length, 1);
88
77
  assert.equal(h.sent[0].kind, 'done');
89
78
  assert.equal(h.sent[0].conversationId, 'root-1');
90
- // Repeated invalidation with the same (already-done) status must not re-fire.
91
79
  await h.engine.onNodesInvalidation();
92
80
  assert.equal(h.sent.length, 1);
93
81
  }
@@ -95,71 +83,16 @@ test('active -> done emits exactly one done push, and a repeat pass does not dup
95
83
  rmSync(dir, { recursive: true, force: true });
96
84
  }
97
85
  });
98
- test('a new ask emits exactly one needs-you push, and repeated invalidations do not duplicate it', async () => {
99
- const dir = tmpDir();
100
- try {
101
- const h = buildHarness(dir);
102
- seedRegistryWithOneSubscription(h.registry);
103
- await h.engine.seed(); // no asks yet
104
- h.asks.push({ id: 'ask-1', jobId: 'job-1', title: 'Pick a color', conversationId: 'root-1', conversationTitle: 'Root One', blockedSince: '2026-01-01T00:00:00.000Z' });
105
- await h.engine.onInboxInvalidation();
106
- assert.equal(h.sent.length, 1);
107
- assert.equal(h.sent[0].kind, 'needs-you');
108
- assert.equal(h.sent[0].askId, 'job-1');
109
- // Same ask still pending on a second invalidation — no duplicate.
110
- await h.engine.onInboxInvalidation();
111
- assert.equal(h.sent.length, 1);
112
- }
113
- finally {
114
- rmSync(dir, { recursive: true, force: true });
115
- }
116
- });
117
- test('a resolved/missing ask never notifies', async () => {
86
+ test('push targeting is scope-filtered', async () => {
118
87
  const dir = tmpDir();
119
88
  try {
120
- const h = buildHarness(dir);
121
- seedRegistryWithOneSubscription(h.registry);
122
- await h.engine.seed();
123
- h.asks.push({ id: 'ask-1', jobId: 'job-1', title: 'Pick a color', conversationId: 'root-1', conversationTitle: 'Root One', blockedSince: '2026-01-01T00:00:00.000Z' });
124
- await h.engine.onInboxInvalidation();
125
- assert.equal(h.sent.length, 1);
126
- // The ask resolves — it disappears from the pending list.
127
- h.asks.length = 0;
128
- await h.engine.onInboxInvalidation();
129
- assert.equal(h.sent.length, 1); // no new push
130
- assert.deepEqual(h.lastSeen.snapshot().asks, {});
131
- }
132
- finally {
133
- rmSync(dir, { recursive: true, force: true });
134
- }
135
- });
136
- test('multiple new asks in the same conversation within the rate window coalesce into one push', async () => {
137
- const dir = tmpDir();
138
- try {
139
- const h = buildHarness(dir, { rateWindowMs: 30_000 });
140
- seedRegistryWithOneSubscription(h.registry);
141
- await h.engine.seed();
142
- h.asks.push({ id: 'ask-1', jobId: 'job-1', title: 'Pick a color', conversationId: 'root-1', conversationTitle: 'Root One', blockedSince: '2026-01-01T00:00:00.000Z' }, { id: 'ask-2', jobId: 'job-2', title: 'Approve deploy', conversationId: 'root-1', conversationTitle: 'Root One', blockedSince: '2026-01-01T00:00:01.000Z' });
143
- await h.engine.onInboxInvalidation();
144
- assert.equal(h.sent.length, 1);
145
- assert.match(h.sent[0].snippet, /\+1 more/);
146
- }
147
- finally {
148
- rmSync(dir, { recursive: true, force: true });
149
- }
150
- });
151
- test('push targeting is scope-filtered: only subscriptions on the watched auth boundary are sent to', async () => {
152
- const dir = tmpDir();
153
- try {
154
- const h = buildHarness(dir, { isTargetScope: (s) => s === 'token:abc' });
155
- // One local-scope sub and one token-scope sub in the SAME registry.
89
+ const h = buildHarness(dir, { isTargetScope: (scope) => scope === 'token:abc' });
156
90
  h.registry.upsert(fakeSubscription('sub-local', 'local'));
157
91
  h.registry.upsert(fakeSubscription('sub-token', 'token:abc'));
158
92
  h.nodes.push({ node_id: 'root-1', parent: null, status: 'active', attention_count: 0 });
159
93
  await h.engine.seed();
160
94
  h.nodes[0].status = 'done';
161
95
  await h.engine.onNodesInvalidation();
162
- // Exactly one send, and it went to the token-scoped endpoint only.
163
96
  assert.equal(h.sent.length, 1);
164
97
  assert.deepEqual(h.sentTo, ['https://fcm.googleapis.com/fcm/send/sub-token']);
165
98
  }
@@ -174,7 +107,7 @@ test('a transient send failure does not advance last-seen and is retried next pa
174
107
  const attempts = [];
175
108
  const h = buildHarness(dir, {
176
109
  rateWindowMs: 30_000,
177
- sendPush: async (_r, payload) => {
110
+ sendPush: async (_record, payload) => {
178
111
  attempts.push(payload);
179
112
  call += 1;
180
113
  return call === 1 ? 'error' : 'sent';
@@ -185,40 +118,27 @@ test('a transient send failure does not advance last-seen and is retried next pa
185
118
  await h.engine.seed();
186
119
  h.nodes[0].status = 'done';
187
120
  await h.engine.onNodesInvalidation();
188
- // The send was attempted but failed transiently — last-seen root must stay
189
- // pre-transition ('active') so the edge is re-detected next pass.
190
121
  assert.equal(attempts.length, 1);
191
122
  assert.equal(h.lastSeen.snapshot().roots['root-1'].status, 'active');
192
- // Advance past the rate window (the failed pass set lastPushAt) and retry.
193
123
  h.clock.now += 60_000;
194
124
  await h.engine.onNodesInvalidation();
195
125
  assert.equal(attempts.length, 2);
196
126
  assert.equal(h.lastSeen.snapshot().roots['root-1'].status, 'done');
197
- // A further pass does not re-fire.
198
- h.clock.now += 60_000;
199
- await h.engine.onNodesInvalidation();
200
- assert.equal(attempts.length, 2);
201
127
  }
202
128
  finally {
203
129
  rmSync(dir, { recursive: true, force: true });
204
130
  }
205
131
  });
206
- test('a transient failure on one subscription does not cause a retry to re-send to an already-delivered subscription', async () => {
132
+ test('a transient failure on one subscription does not re-send to an already-delivered subscription', async () => {
207
133
  const dir = tmpDir();
208
134
  try {
209
- // Keyed by endpoint, not `record.id` — upsert() derives the persisted id
210
- // from `subscriptionIdForEndpoint(endpoint)`, discarding the fixture's
211
- // caller-supplied id, so the endpoint is the stable fixture identity here.
212
135
  const attemptsBySub = new Map();
213
136
  const h = buildHarness(dir, {
214
137
  rateWindowMs: 30_000,
215
- sendPush: async (record, _payload) => {
216
- const n = (attemptsBySub.get(record.endpoint) ?? 0) + 1;
217
- attemptsBySub.set(record.endpoint, n);
218
- // sub-ok always succeeds; sub-fail fails transiently on its first
219
- // attempt only, then succeeds on retry — so the second pass proves
220
- // sub-ok is never touched again while sub-fail finally lands.
221
- return record.endpoint.includes('sub-fail') && n === 1 ? 'error' : 'sent';
138
+ sendPush: async (record) => {
139
+ const attempts = (attemptsBySub.get(record.endpoint) ?? 0) + 1;
140
+ attemptsBySub.set(record.endpoint, attempts);
141
+ return record.endpoint.includes('sub-fail') && attempts === 1 ? 'error' : 'sent';
222
142
  },
223
143
  });
224
144
  h.registry.upsert(fakeSubscription('sub-ok'));
@@ -227,19 +147,6 @@ test('a transient failure on one subscription does not cause a retry to re-send
227
147
  await h.engine.seed();
228
148
  h.nodes[0].status = 'done';
229
149
  await h.engine.onNodesInvalidation();
230
- // Both subscriptions were attempted once; the event is not fully delivered
231
- // (sub-fail errored), so last-seen must stay pre-transition.
232
- assert.equal(attemptsBySub.get('https://fcm.googleapis.com/fcm/send/sub-ok'), 1);
233
- assert.equal(attemptsBySub.get('https://fcm.googleapis.com/fcm/send/sub-fail'), 1);
234
- assert.equal(h.lastSeen.snapshot().roots['root-1'].status, 'active');
235
- // Retry next pass (past the rate window): sub-ok must NOT be re-sent to —
236
- // only sub-fail, which never succeeded, is retried.
237
- h.clock.now += 60_000;
238
- await h.engine.onNodesInvalidation();
239
- assert.equal(attemptsBySub.get('https://fcm.googleapis.com/fcm/send/sub-ok'), 1, 'an already-delivered subscription must not be re-sent to on retry');
240
- assert.equal(attemptsBySub.get('https://fcm.googleapis.com/fcm/send/sub-fail'), 2);
241
- assert.equal(h.lastSeen.snapshot().roots['root-1'].status, 'done');
242
- // Fully delivered now — a further pass does not re-fire for anyone.
243
150
  h.clock.now += 60_000;
244
151
  await h.engine.onNodesInvalidation();
245
152
  assert.equal(attemptsBySub.get('https://fcm.googleapis.com/fcm/send/sub-ok'), 1);
@@ -249,54 +156,3 @@ test('a transient failure on one subscription does not cause a retry to re-send
249
156
  rmSync(dir, { recursive: true, force: true });
250
157
  }
251
158
  });
252
- test('overlapping inbox invalidations serialize — each distinct ask notifies exactly once', async () => {
253
- const dir = tmpDir();
254
- try {
255
- const h = buildHarness(dir);
256
- seedRegistryWithOneSubscription(h.registry);
257
- await h.engine.seed();
258
- // First invalidation kicked off but NOT awaited; a second ask + invalidation
259
- // land while the first pass is in-flight. The drain queue must serialize
260
- // them so neither ask is notified twice.
261
- h.asks.push({ id: 'ask-1', jobId: 'job-1', title: 'Pick a color', conversationId: 'root-1', conversationTitle: 'Root One', blockedSince: '2026-01-01T00:00:00.000Z' });
262
- const p1 = h.engine.onInboxInvalidation();
263
- h.asks.push({ id: 'ask-2', jobId: 'job-2', title: 'Approve deploy', conversationId: 'root-2', conversationTitle: 'Root Two', blockedSince: '2026-01-01T00:00:01.000Z' });
264
- const p2 = h.engine.onInboxInvalidation();
265
- await Promise.all([p1, p2]);
266
- const askIds = h.sent.map((p) => p.askId).sort();
267
- assert.deepEqual(askIds, ['job-1', 'job-2']);
268
- assert.deepEqual(Object.keys(h.lastSeen.snapshot().asks).sort(), ['ask-1', 'ask-2']);
269
- }
270
- finally {
271
- rmSync(dir, { recursive: true, force: true });
272
- }
273
- });
274
- test('a rate-capped ask is suppressed within the window then retried once it clears — never lost, never duplicated', async () => {
275
- const dir = tmpDir();
276
- try {
277
- const h = buildHarness(dir, { rateWindowMs: 30_000 });
278
- seedRegistryWithOneSubscription(h.registry);
279
- await h.engine.seed();
280
- h.asks.push({ id: 'ask-1', jobId: 'job-1', title: 'Pick a color', conversationId: 'root-1', conversationTitle: 'Root One', blockedSince: '2026-01-01T00:00:00.000Z' });
281
- await h.engine.onInboxInvalidation();
282
- assert.equal(h.sent.length, 1); // first ask fires immediately
283
- // A second, distinct ask lands in the same conversation moments later —
284
- // still inside the rate window, so it must be suppressed, not sent.
285
- h.asks.push({ id: 'ask-2', jobId: 'job-2', title: 'Approve deploy', conversationId: 'root-1', conversationTitle: 'Root One', blockedSince: '2026-01-01T00:00:05.000Z' });
286
- h.clock.now += 5_000;
287
- await h.engine.onInboxInvalidation();
288
- assert.equal(h.sent.length, 1); // still suppressed
289
- assert.equal(h.lastSeen.snapshot().asks['ask-2'], undefined); // left untracked so it retries
290
- // Once the rate window clears, the still-pending ask-2 is retried exactly once.
291
- h.clock.now += 30_000;
292
- await h.engine.onInboxInvalidation();
293
- assert.equal(h.sent.length, 2);
294
- assert.equal(h.sent[1].askId, 'job-2');
295
- // And it never fires a third time on a further no-op pass.
296
- await h.engine.onInboxInvalidation();
297
- assert.equal(h.sent.length, 2);
298
- }
299
- finally {
300
- rmSync(dir, { recursive: true, force: true });
301
- }
302
- });
@@ -1,7 +1,7 @@
1
1
  import type { Server as HttpServer } from 'node:http';
2
2
  import type { ViteDevServer } from 'vite';
3
3
  /** Create a Vite dev server in middleware mode, HMR bound to `httpServer`.
4
- * Mirrors the old `view serve` resolve setup so the shell's bare imports
5
- * (react, the `@north-light/crouter/web` self-subpath) resolve from the
6
- * generated/shell root. Lazily imports vite so the shipped path never loads it. */
4
+ * It loads the shell's Vite config rather than duplicating its plugins: that
5
+ * config supplies the PWA virtual-module resolver as well as the production
6
+ * build settings. Lazily imports vite so the shipped path never loads it. */
7
7
  export declare function createDevServer(httpServer: HttpServer): Promise<ViteDevServer>;
@@ -1,8 +1,8 @@
1
1
  // dev-server.ts — `crtr web serve --dev` Vite middleware mode.
2
2
  //
3
3
  // The shipped server serves a prebuilt static shell bundle from dist/web-client/
4
- // (§11). In --dev a contributor iterating on the shell or a builtin view gets
5
- // HMR instead: a Vite dev server in MIDDLEWARE mode mounted on the SAME HTTP
4
+ // (§11). In --dev a contributor iterating on the shell gets HMR instead: a Vite
5
+ // dev server in MIDDLEWARE mode mounted on the SAME HTTP
6
6
  // server as the crtrd proxy + attach tunnel. This is the one place Vite runs at
7
7
  // runtime — the mainstream "Vite middleware in dev, static dist in prod" split.
8
8
  //
@@ -22,32 +22,18 @@ function resolveShellRoot(packageRoot) {
22
22
  return join(packageRoot, 'src', 'clients', 'web', 'web-client');
23
23
  }
24
24
  /** Create a Vite dev server in middleware mode, HMR bound to `httpServer`.
25
- * Mirrors the old `view serve` resolve setup so the shell's bare imports
26
- * (react, the `@north-light/crouter/web` self-subpath) resolve from the
27
- * generated/shell root. Lazily imports vite so the shipped path never loads it. */
25
+ * It loads the shell's Vite config rather than duplicating its plugins: that
26
+ * config supplies the PWA virtual-module resolver as well as the production
27
+ * build settings. Lazily imports vite so the shipped path never loads it. */
28
28
  export async function createDevServer(httpServer) {
29
29
  const packageRoot = resolve(HERE, '../../..');
30
- const nodeModules = join(packageRoot, 'node_modules');
31
30
  const shellRoot = resolveShellRoot(packageRoot);
32
31
  const { createServer } = await import('vite');
33
- const react = (await import('@vitejs/plugin-react')).default;
34
- const tailwindcss = (await import('@tailwindcss/vite')).default;
35
32
  return createServer({
36
- configFile: false,
37
- root: shellRoot,
38
- plugins: [react(), tailwindcss()],
39
- appType: 'spa',
40
- resolve: {
41
- alias: {
42
- react: join(nodeModules, 'react'),
43
- 'react-dom': join(nodeModules, 'react-dom'),
44
- '@': shellRoot,
45
- // The crtr web runtime is a self-subpath of crouter's own package;
46
- // pin it to the built barrel so the shell can import it from any root.
47
- '@north-light/crouter/web': join(packageRoot, 'dist', 'web', 'index.js'),
48
- },
49
- dedupe: ['react', 'react-dom'],
50
- },
33
+ configFile: join(shellRoot, 'vite.config.ts'),
34
+ // The integrated middleware already owns /node, /v1, and /__crtr. The
35
+ // shell config uses this mode to omit its standalone-server proxies.
36
+ mode: 'middleware',
51
37
  server: {
52
38
  middlewareMode: true,
53
39
  // Share our HTTP server for HMR; server.ts's upgrade handler hands every
@@ -1,10 +1,8 @@
1
- // events.ts — the `crtr web` realtime push lane.
1
+ // events.ts — the browser shell's realtime invalidation lane.
2
2
  //
3
- // ONE server-sent-events stream, `GET /__crtr/events`, that carries change
4
- // invalidations — never data. The shell and built-in views subscribe and, on an
5
- // event, re-pull through their existing bridge reads instead of waiting on a
6
- // fixed poll tick. SSE carries "something in this class changed"; the consumer
7
- // decides what to re-read.
3
+ // One server-sent-events stream, `GET /__crtr/events`, carries change
4
+ // invalidations, never data. On an event the shell re-reads through the REST
5
+ // proxy rather than waiting for its fixed polling interval.
8
6
  //
9
7
  // Event vocabulary (deliberately minimal): { kind: 'nodes' | 'inbox', ts }.
10
8
  // - 'nodes' — the node graph changed (topology, status/intent transitions,
@@ -1,49 +1,23 @@
1
1
  import type { NodeLifeStatus } from './web-client/shared/protocol.js';
2
2
  import type { PushLastSeenStore, PushRegistryStore, PushSubscriptionRecord } from './push-registry.js';
3
- /** The subset of `NodeSummary` the diff engine needs — kept minimal and
4
- * decoupled from the full wire type so the engine can be fed by any canvas
5
- * reader (production: `canvas snapshot`; tests: a fixture array). */
6
3
  export interface CanvasNodeRow {
7
4
  node_id: string;
8
5
  parent: string | null;
9
6
  status: NodeLifeStatus;
10
7
  attention_count: number;
11
8
  }
12
- /** A pending human ask with just the `DeckSummary` provenance the payload/dedupe
13
- * logic needs (design: "ask provenance comes from DeckSummary"). */
14
- export interface PendingAsk {
15
- /** Opaque, stable inbox-entry id — the dedupe key (never re-notify the same
16
- * unresolved ask). */
17
- id: string;
18
- /** The interaction job id — carried in the payload as `askId` for the deep-link. */
19
- jobId: string;
20
- title: string;
21
- conversationId: string;
22
- conversationTitle: string;
23
- blockedSince: string;
24
- }
25
9
  export type PushSendResult = 'sent' | 'gone' | 'error';
26
10
  export interface PushPayload {
27
11
  conversationId: string;
28
- kind: 'needs-you' | 'done';
29
- askId?: string;
12
+ kind: 'done';
30
13
  title: string;
31
14
  snippet: string;
32
15
  }
33
16
  export interface PushEngineDeps {
34
17
  registry: PushRegistryStore;
35
18
  lastSeen: PushLastSeenStore;
36
- /** Re-read the live canvas roster. */
37
19
  readCanvasNodes: () => Promise<CanvasNodeRow[]> | CanvasNodeRow[];
38
- /** Re-read every currently pending ask (deck provenance). */
39
- readPendingAsks: () => Promise<PendingAsk[]> | PendingAsk[];
40
- /** Deliver one push to one subscription. Implementations classify a
41
- * service-side 404/410 as `'gone'` so the engine can prune the record. */
42
20
  sendPush: (record: PushSubscriptionRecord, payload: PushPayload) => Promise<PushSendResult>;
43
- /** True iff a subscription's persisted authScope matches the canvas/user this
44
- * engine is watching (design line 252: push is sent ONLY to subscriptions
45
- * whose authScope is on the identical boundary that gates the /v1 proxy).
46
- * Required — no lenient default — so a foreign scope can never be targeted. */
47
21
  isTargetScope: (authScope: string) => boolean;
48
22
  now?: () => number;
49
23
  rateWindowMs?: number;
@@ -52,57 +26,19 @@ export declare class PushDiffEngine {
52
26
  private readonly registry;
53
27
  private readonly lastSeen;
54
28
  private readonly readCanvasNodes;
55
- private readonly readPendingAsks;
56
29
  private readonly sendPush;
57
30
  private readonly isTargetScope;
58
31
  private readonly now;
59
32
  private readonly rateWindowMs;
60
- /** Drain-queue state: only one diff pass mutates last-seen at a time. An
61
- * invalidation arriving mid-pass sets its pending flag and is reprocessed
62
- * when the current pass finishes — no two passes race the same snapshot. */
63
33
  private draining;
64
34
  private pendingNodes;
65
- private pendingInbox;
66
- /** Per-conversation rate-cap clock. Deliberately in-memory/process-lifetime
67
- * only (not persisted) — a restart re-seeding silently is already the
68
- * no-storm guarantee; the rate cap only smooths a live process's bursts. */
69
35
  private readonly lastPushAt;
70
- /** Per-(conversationId+kind) set of subscription ids already delivered for
71
- * the CURRENT still-pending notification. A transient failure on one
72
- * subscription must never cause a later retry to re-send to subscriptions
73
- * that already got `'sent'` — this is exactly what remembers them across
74
- * passes. Cleared the moment the event fully succeeds (or has no eligible
75
- * subscriber left), since a later, distinct event reusing the same key
76
- * must start fresh. */
77
36
  private readonly deliveredForKey;
78
37
  constructor(deps: PushEngineDeps);
79
- /** Seed last-seen from a fresh canvas+deck read and send nothing. Call once
80
- * on server start — a restart must never be an attention event. */
38
+ /** Record the current canvas state without sending notifications. */
81
39
  seed(): Promise<void>;
82
- /** 'nodes' invalidation: re-read the canvas roster, emit a 'done' push for
83
- * every conversation root that just crossed into a done|dead|canceled
84
- * status from a non-done status. */
85
40
  onNodesInvalidation(): Promise<void>;
86
- onInboxInvalidation(): Promise<void>;
87
- /** Serialize passes: if a pass is already running, just set the pending flag
88
- * and return — the running drain loop will pick it up. Otherwise run pending
89
- * passes until none remain. */
90
41
  private drain;
91
42
  private runNodesPass;
92
- /** 'inbox' invalidation: re-read pending asks, emit exactly one 'needs-you'
93
- * push per conversation for its NEW (not-yet-notified) asks, coalesced. An
94
- * ask no longer present (resolved/missing) is simply dropped, never
95
- * notified. */
96
- private runInboxPass;
97
- /** Send one push per ELIGIBLE subscription — one whose authScope is on the
98
- * watched boundary (`isTargetScope`) AND that opted in for this payload kind.
99
- * Respects the per-conversation rate cap; prunes any subscription the push
100
- * service reports gone (404/410) or whose endpoint fails the push-service
101
- * allowlist re-check. Tracks per-subscription delivery for this notification
102
- * (`deliveredForKey`) so a retry after a transient failure on one
103
- * subscription never re-sends to a subscription that already got `'sent'`.
104
- * Returns true iff last-seen may advance: false when suppressed by the rate
105
- * cap OR when a transient send error means the item must be retried next
106
- * pass. A no-eligible pass returns true (nothing to retry). */
107
43
  private emit;
108
44
  }