@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
@@ -1,111 +1,56 @@
1
- // push-engine.ts — the server-side web-push DIFF ENGINE (design D8/push
2
- // contract). SSE (`events.ts`) is a TRIGGER ONLY (`{kind, ts}`, never data);
3
- // this module is the one authority that re-reads canvas + decks on that
4
- // trigger, diffs against persisted last-seen state, and decides what (if
5
- // anything) to push. It never invents a second attention signal — decks/canvas
6
- // stay the truth.
1
+ // push-engine.ts — the server-side web-push diff engine. SSE (`events.ts`) is
2
+ // a trigger only (`{kind, ts}`, never data); this module re-reads the canvas,
3
+ // diffs persisted last-seen state, and emits done-transition notifications.
7
4
  //
8
- // Two invalidation kinds drive two independent diff passes:
9
- // - 'nodes' -> re-read the canvas roster, detect a conversation ROOT
10
- // (parent === null) crossing into a done|dead|canceled status
11
- // from a non-done status, emit one 'done' push per transition.
12
- // - 'inbox' -> re-read pending asks (deck provenance), detect an ask id that
13
- // is present now but was not known-notified before, emit one
14
- // 'needs-you' push per NEW ask, coalesced per conversation.
15
- //
16
- // On server start, `seed()` records the current state and sends NOTHING — a
17
- // restart is not an attention event.
18
- //
19
- // Last-seen state is only advanced past a suppressed (rate-capped) item when
20
- // that item was not actually the reason for suppression; a rate-capped
21
- // transition/ask is deliberately left out of the persisted state so the NEXT
22
- // invalidation retries it rather than silently losing it forever.
5
+ // A `nodes` invalidation detects a conversation root (`parent === null`) crossing
6
+ // from a nonterminal state into done, dead, or canceled. On server start,
7
+ // `seed()` records the current state and sends nothing.
23
8
  import { isAllowedPushEndpoint } from './push-registry.js';
24
9
  const DONE_STATUSES = new Set(['done', 'dead', 'canceled']);
25
- /** Minimum interval between pushes for the same conversation root — coalesces
26
- * a burst of distinct events (several new asks, or an ask+done in close
27
- * succession) into at most one send per window, never a storm. */
28
10
  const DEFAULT_RATE_WINDOW_MS = 30_000;
29
11
  export class PushDiffEngine {
30
12
  registry;
31
13
  lastSeen;
32
14
  readCanvasNodes;
33
- readPendingAsks;
34
15
  sendPush;
35
16
  isTargetScope;
36
17
  now;
37
18
  rateWindowMs;
38
- /** Drain-queue state: only one diff pass mutates last-seen at a time. An
39
- * invalidation arriving mid-pass sets its pending flag and is reprocessed
40
- * when the current pass finishes — no two passes race the same snapshot. */
41
19
  draining = false;
42
20
  pendingNodes = false;
43
- pendingInbox = false;
44
- /** Per-conversation rate-cap clock. Deliberately in-memory/process-lifetime
45
- * only (not persisted) — a restart re-seeding silently is already the
46
- * no-storm guarantee; the rate cap only smooths a live process's bursts. */
47
21
  lastPushAt = new Map();
48
- /** Per-(conversationId+kind) set of subscription ids already delivered for
49
- * the CURRENT still-pending notification. A transient failure on one
50
- * subscription must never cause a later retry to re-send to subscriptions
51
- * that already got `'sent'` — this is exactly what remembers them across
52
- * passes. Cleared the moment the event fully succeeds (or has no eligible
53
- * subscriber left), since a later, distinct event reusing the same key
54
- * must start fresh. */
55
22
  deliveredForKey = new Map();
56
23
  constructor(deps) {
57
24
  this.registry = deps.registry;
58
25
  this.lastSeen = deps.lastSeen;
59
26
  this.readCanvasNodes = deps.readCanvasNodes;
60
- this.readPendingAsks = deps.readPendingAsks;
61
27
  this.sendPush = deps.sendPush;
62
28
  this.isTargetScope = deps.isTargetScope;
63
29
  this.now = deps.now ?? (() => Date.now());
64
30
  this.rateWindowMs = deps.rateWindowMs ?? DEFAULT_RATE_WINDOW_MS;
65
31
  }
66
- /** Seed last-seen from a fresh canvas+deck read and send nothing. Call once
67
- * on server start — a restart must never be an attention event. */
32
+ /** Record the current canvas state without sending notifications. */
68
33
  async seed() {
69
- const [nodes, asks] = await Promise.all([this.readCanvasNodes(), this.readPendingAsks()]);
34
+ const nodes = await this.readCanvasNodes();
70
35
  const roots = {};
71
- for (const n of nodes) {
72
- if (n.parent !== null)
73
- continue;
74
- roots[n.node_id] = { status: n.status, attention_count: n.attention_count };
36
+ for (const node of nodes) {
37
+ if (node.parent === null)
38
+ roots[node.node_id] = { status: node.status, attention_count: node.attention_count };
75
39
  }
76
- const askState = {};
77
- for (const a of asks)
78
- askState[a.id] = { present: true };
79
- this.lastSeen.replace({ schemaVersion: 1, updatedAt: this.now(), roots, asks: askState });
40
+ this.lastSeen.replace({ schemaVersion: 1, updatedAt: this.now(), roots });
80
41
  }
81
- /** 'nodes' invalidation: re-read the canvas roster, emit a 'done' push for
82
- * every conversation root that just crossed into a done|dead|canceled
83
- * status from a non-done status. */
84
42
  async onNodesInvalidation() {
85
43
  this.pendingNodes = true;
86
44
  await this.drain();
87
45
  }
88
- async onInboxInvalidation() {
89
- this.pendingInbox = true;
90
- await this.drain();
91
- }
92
- /** Serialize passes: if a pass is already running, just set the pending flag
93
- * and return — the running drain loop will pick it up. Otherwise run pending
94
- * passes until none remain. */
95
46
  async drain() {
96
47
  if (this.draining)
97
48
  return;
98
49
  this.draining = true;
99
50
  try {
100
- while (this.pendingNodes || this.pendingInbox) {
101
- if (this.pendingNodes) {
102
- this.pendingNodes = false;
103
- await this.runNodesPass();
104
- }
105
- if (this.pendingInbox) {
106
- this.pendingInbox = false;
107
- await this.runInboxPass();
108
- }
51
+ while (this.pendingNodes) {
52
+ this.pendingNodes = false;
53
+ await this.runNodesPass();
109
54
  }
110
55
  }
111
56
  finally {
@@ -114,93 +59,30 @@ export class PushDiffEngine {
114
59
  }
115
60
  async runNodesPass() {
116
61
  const nodes = await this.readCanvasNodes();
117
- const prev = this.lastSeen.snapshot();
118
- const nextRoots = {};
119
- for (const n of nodes) {
120
- if (n.parent !== null)
62
+ const previous = this.lastSeen.snapshot();
63
+ const roots = {};
64
+ for (const node of nodes) {
65
+ if (node.parent !== null)
121
66
  continue;
122
- const before = prev.roots[n.node_id];
123
- const isTransition = before !== undefined && !DONE_STATUSES.has(before.status) && DONE_STATUSES.has(n.status);
124
- if (!isTransition) {
125
- nextRoots[n.node_id] = { status: n.status, attention_count: n.attention_count };
67
+ const before = previous.roots[node.node_id];
68
+ const transitioned = before !== undefined && !DONE_STATUSES.has(before.status) && DONE_STATUSES.has(node.status);
69
+ if (!transitioned) {
70
+ roots[node.node_id] = { status: node.status, attention_count: node.attention_count };
126
71
  continue;
127
72
  }
128
- const sent = await this.emit(n.node_id, {
129
- conversationId: n.node_id,
73
+ const sent = await this.emit(node.node_id, {
74
+ conversationId: node.node_id,
130
75
  kind: 'done',
131
76
  title: 'Conversation finished',
132
- snippet: `This conversation is now ${n.status}.`,
133
- });
134
- // Rate-capped: keep the PRE-transition state so the next 'nodes'
135
- // invalidation still sees a non-done -> done edge and retries.
136
- nextRoots[n.node_id] = sent ? { status: n.status, attention_count: n.attention_count } : before;
137
- }
138
- this.lastSeen.replace({ schemaVersion: prev.schemaVersion, updatedAt: this.now(), roots: nextRoots, asks: prev.asks });
139
- }
140
- /** 'inbox' invalidation: re-read pending asks, emit exactly one 'needs-you'
141
- * push per conversation for its NEW (not-yet-notified) asks, coalesced. An
142
- * ask no longer present (resolved/missing) is simply dropped, never
143
- * notified. */
144
- async runInboxPass() {
145
- const asks = await this.readPendingAsks();
146
- const prev = this.lastSeen.snapshot();
147
- const nextAsks = {};
148
- const newByConversation = new Map();
149
- for (const ask of asks) {
150
- if (prev.asks[ask.id]?.present === true) {
151
- // Already known + already notified at some point — keep tracked, never
152
- // re-notify the same unresolved ask.
153
- nextAsks[ask.id] = { present: true };
154
- continue;
155
- }
156
- const list = newByConversation.get(ask.conversationId) ?? [];
157
- list.push(ask);
158
- newByConversation.set(ask.conversationId, list);
159
- }
160
- for (const [conversationId, list] of newByConversation) {
161
- const first = list[0];
162
- const extra = list.length - 1;
163
- const sent = await this.emit(conversationId, {
164
- conversationId,
165
- kind: 'needs-you',
166
- askId: first.jobId,
167
- title: first.conversationTitle,
168
- snippet: extra > 0 ? `${first.title} (+${extra} more)` : first.title,
77
+ snippet: `This conversation is now ${node.status}.`,
169
78
  });
170
- if (sent) {
171
- for (const ask of list)
172
- nextAsks[ask.id] = { present: true };
173
- }
174
- // Rate-capped: leave these ask ids OUT of nextAsks so the next 'inbox'
175
- // invalidation still sees them as new and retries once the window clears.
79
+ roots[node.node_id] = sent ? { status: node.status, attention_count: node.attention_count } : before;
176
80
  }
177
- this.lastSeen.replace({ schemaVersion: prev.schemaVersion, updatedAt: this.now(), roots: prev.roots, asks: nextAsks });
81
+ this.lastSeen.replace({ schemaVersion: previous.schemaVersion, updatedAt: this.now(), roots });
178
82
  }
179
- /** Send one push per ELIGIBLE subscription — one whose authScope is on the
180
- * watched boundary (`isTargetScope`) AND that opted in for this payload kind.
181
- * Respects the per-conversation rate cap; prunes any subscription the push
182
- * service reports gone (404/410) or whose endpoint fails the push-service
183
- * allowlist re-check. Tracks per-subscription delivery for this notification
184
- * (`deliveredForKey`) so a retry after a transient failure on one
185
- * subscription never re-sends to a subscription that already got `'sent'`.
186
- * Returns true iff last-seen may advance: false when suppressed by the rate
187
- * cap OR when a transient send error means the item must be retried next
188
- * pass. A no-eligible pass returns true (nothing to retry). */
189
83
  async emit(conversationId, payload) {
190
- // Eligible = in the watched auth scope AND opted-in for this payload kind.
191
- const eligible = this.registry.snapshot().filter((r) => {
192
- if (!this.isTargetScope(r.authScope))
193
- return false;
194
- if (payload.kind === 'done' && !r.prefs.doneNotifications)
195
- return false;
196
- return true;
197
- });
198
- // Keyed by conversation + kind: a later, distinct event reusing this key
199
- // (once cleared below) must start with a fresh delivered set.
84
+ const eligible = this.registry.snapshot().filter((record) => this.isTargetScope(record.authScope) && record.prefs.doneNotifications);
200
85
  const key = `${conversationId}:${payload.kind}`;
201
- // No eligible subscriber -> the event is fully handled (nothing to retry);
202
- // advance last-seen. Checked BEFORE the rate cap so a no-eligible pass never
203
- // stalls the state on a phantom retry.
204
86
  if (eligible.length === 0) {
205
87
  this.deliveredForKey.delete(key);
206
88
  return true;
@@ -208,22 +90,14 @@ export class PushDiffEngine {
208
90
  const now = this.now();
209
91
  const last = this.lastPushAt.get(conversationId) ?? 0;
210
92
  if (now - last < this.rateWindowMs)
211
- return false; // rate-capped -> retry next pass
93
+ return false;
212
94
  this.lastPushAt.set(conversationId, now);
213
95
  const delivered = this.deliveredForKey.get(key) ?? new Set();
214
96
  let transientFailure = false;
215
97
  for (const record of eligible) {
216
- // Already delivered to this subscription for this event on an earlier
217
- // pass — never re-send it (this is the fix for duplicate pushes on
218
- // transient-failure retry: only the subscriptions that actually failed
219
- // are retried).
220
98
  if (delivered.has(record.id))
221
99
  continue;
222
100
  if (!isAllowedPushEndpoint(record.endpoint)) {
223
- // Defense in depth: re-check the push-service allowlist immediately
224
- // before every outbound connect (no DNS/host TOCTOU), even though
225
- // normalizeEndpoint already enforced it at subscribe time. A record
226
- // that fails this can never be sent to safely — prune it.
227
101
  this.registry.deleteById(record.id);
228
102
  continue;
229
103
  }
@@ -241,11 +115,6 @@ export class PushDiffEngine {
241
115
  else
242
116
  transientFailure = true;
243
117
  }
244
- // A transient send failure must NOT advance last-seen — retry next pass
245
- // (design: "update last-seen only after a successful diff pass"), and the
246
- // subscriptions already delivered above must stay remembered so that retry
247
- // only reaches the ones that failed. A pruned 'gone'/disallowed record is
248
- // not a failure: nothing left to retry for it.
249
118
  if (transientFailure) {
250
119
  this.deliveredForKey.set(key, delivered);
251
120
  return false;
@@ -22,14 +22,10 @@ export interface PushLastSeenRootState {
22
22
  status: NodeLifeStatus;
23
23
  attention_count: number;
24
24
  }
25
- export interface PushLastSeenAskState {
26
- present: boolean;
27
- }
28
25
  export interface PushLastSeenFile {
29
26
  schemaVersion: number;
30
27
  updatedAt: number;
31
28
  roots: Record<string, PushLastSeenRootState>;
32
- asks: Record<string, PushLastSeenAskState>;
33
29
  }
34
30
  /** A locally generated VAPID keypair, persisted so the same identity signs
35
31
  * every outbound push across restarts. The private key never leaves this
@@ -222,16 +222,12 @@ function isValidRegistryFile(value) {
222
222
  function isValidLastSeenFile(value) {
223
223
  if (!isRecord(value) || value.schemaVersion !== SCHEMA_VERSION || !isNumber(value.updatedAt))
224
224
  return false;
225
- if (!isRecord(value.roots) || !isRecord(value.asks))
225
+ if (!isRecord(value.roots))
226
226
  return false;
227
227
  for (const record of Object.values(value.roots)) {
228
228
  if (!isRecord(record) || !isString(record.status) || !isNumber(record.attention_count))
229
229
  return false;
230
230
  }
231
- for (const record of Object.values(value.asks)) {
232
- if (!isRecord(record) || typeof record.present !== 'boolean')
233
- return false;
234
- }
235
231
  return true;
236
232
  }
237
233
  function loadRegistryFile(path) {
@@ -245,7 +241,7 @@ function loadRegistryFile(path) {
245
241
  }
246
242
  function loadLastSeenFile(path) {
247
243
  if (!existsSync(path)) {
248
- return { schemaVersion: SCHEMA_VERSION, updatedAt: 0, roots: {}, asks: {} };
244
+ return { schemaVersion: SCHEMA_VERSION, updatedAt: 0, roots: {} };
249
245
  }
250
246
  const parsed = readJsonFile(path);
251
247
  if (!isValidLastSeenFile(parsed)) {
@@ -362,7 +358,6 @@ export class PushLastSeenStore {
362
358
  schemaVersion: this.state.schemaVersion,
363
359
  updatedAt: this.state.updatedAt,
364
360
  roots: { ...this.state.roots },
365
- asks: { ...this.state.asks },
366
361
  };
367
362
  }
368
363
  replace(next) {
@@ -42,7 +42,6 @@ import { apiSocketPath, isSafeNodeId } from '../../core/canvas/paths.js';
42
42
  import { emitEvent } from '../../core/events/emit.js';
43
43
  import { bindWebEventSource } from '../../core/events/source.js';
44
44
  import { canvasRosterLeaf } from '../../commands/canvas-roster.js';
45
- import { humanList } from '../../commands/human/queue.js';
46
45
  import { startEventHub } from './events.js';
47
46
  import { createDevServer } from './dev-server.js';
48
47
  import { PushLastSeenStore, PushRegistryStore, PushRequestError, loadOrCreateVapidKeypair, parsePushDeleteBody, parsePushSubscriptionBody, pushBodyMaxBytes, } from './push-registry.js';
@@ -399,41 +398,13 @@ export async function startWebServer(opts) {
399
398
  targetScopes.add('local');
400
399
  // §push — the server-side web-push registry + diff engine (design D8). One
401
400
  // persisted, auth-scoped subscription registry; one locally-generated VAPID
402
- // identity signing every send; one diff engine that re-reads canvas+decks on
403
- // the SAME SSE invalidations the browser clients get (via eventHub.subscribe,
404
- // no HTTP self-loop) and pushes 'done'/'needs-you' notifications.
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.
405
404
  const pushRegistry = new PushRegistryStore();
406
405
  const pushLastSeen = new PushLastSeenStore();
407
406
  const vapid = loadOrCreateVapidKeypair();
408
407
  webpush.setVapidDetails(vapid.subject, vapid.publicKey, vapid.privateKey);
409
- // Page through every pending human ask, keeping only entries with the deck
410
- // provenance (job + conversation) the payload/dedupe logic needs.
411
- const collectPendingAsks = async () => {
412
- const out = [];
413
- let cursor;
414
- for (let page = 0; page < 50; page++) {
415
- const result = (await humanList.run({
416
- limit: 100,
417
- ...(cursor !== undefined ? { cursor } : {}),
418
- }));
419
- for (const item of result.items) {
420
- if (item.job_id === undefined || item.conversation_id === undefined)
421
- continue;
422
- out.push({
423
- id: item.id,
424
- jobId: item.job_id,
425
- title: item.title ?? item.job_id,
426
- conversationId: item.conversation_id,
427
- conversationTitle: item.conversation_title ?? item.conversation_id,
428
- blockedSince: item.blocked_since,
429
- });
430
- }
431
- if (result.next_cursor === null)
432
- break;
433
- cursor = result.next_cursor;
434
- }
435
- return out;
436
- };
437
408
  const pushEngine = new PushDiffEngine({
438
409
  registry: pushRegistry,
439
410
  lastSeen: pushLastSeen,
@@ -445,7 +416,6 @@ export async function startWebServer(opts) {
445
416
  const snap = (await canvasRosterLeaf.run({}));
446
417
  return snap.nodes;
447
418
  },
448
- readPendingAsks: collectPendingAsks,
449
419
  isTargetScope: (s) => targetScopes.has(s),
450
420
  sendPush: async (record, payload) => {
451
421
  try {
@@ -463,8 +433,6 @@ export async function startWebServer(opts) {
463
433
  const unsubscribePush = eventHub.subscribe((kind) => {
464
434
  if (kind === 'nodes')
465
435
  void pushEngine.onNodesInvalidation();
466
- else if (kind === 'inbox')
467
- void pushEngine.onInboxInvalidation();
468
436
  });
469
437
  // Assigned before listen() when --dev; the request handler closes over it.
470
438
  let vite;
@@ -191,84 +191,6 @@ export interface MessageRequest {
191
191
  export interface ReviveRequest {
192
192
  fresh?: boolean;
193
193
  }
194
- /**
195
- * The five resolution flows (design §5.2). humanloop's `InteractionKind` also
196
- * has `review`; the deck loader normalizes it (and any unknown/absent kind)
197
- * onto one of these five so a deck always renders through a known flow.
198
- */
199
- export type DeckKind = 'notify' | 'validation' | 'decision' | 'context' | 'error';
200
- /** One option of a decision/validation interaction (humanloop InteractionOption). */
201
- export interface DeckOption {
202
- id: string;
203
- label: string;
204
- /** The option's consequence/explanation (humanloop `description`). */
205
- description?: string;
206
- }
207
- /** One interaction within a deck (humanloop Interaction, normalized for the web). */
208
- export interface DeckInteraction {
209
- id: string;
210
- title: string;
211
- subtitle: string;
212
- /** Markdown body (bodyPath already inlined by `crtr human deck`). */
213
- body?: string;
214
- kind: DeckKind;
215
- options: DeckOption[];
216
- multiSelect: boolean;
217
- allowFreetext: boolean;
218
- freetextLabel?: string;
219
- }
220
- /**
221
- * A pending ask, ranked in the inbox list (design §5.2). Provenance carries
222
- * private node routing and an optional authored source label for presentation.
223
- */
224
- export interface DeckSummary {
225
- /** Opaque, stable inbox-entry id (base64url of the interaction dir). */
226
- id: string;
227
- /** The interaction job id (basename of the interaction dir). */
228
- job_id: string;
229
- /** The first interaction's kind — the glyph + flow for the row. */
230
- kind: DeckKind;
231
- title: string;
232
- subtitle: string;
233
- /** ISO-8601 — when the ask started blocking (drives the wait duration + rank). */
234
- blocked_since: string;
235
- /** Humanloop's current claim owner, when a person/session is handling it. */
236
- claim_owner?: string;
237
- /** Authored display label: source sessionName, then askedBy. */
238
- source_label?: string;
239
- /** The conversation (spine root) this ask belongs to. */
240
- conversation_id: string;
241
- conversation_title: string;
242
- /** The node that raised the ask. */
243
- asking_node_id: string;
244
- asking_node_name: string;
245
- /** The asking node's cwd — sub-DAG scoping. */
246
- cwd: string;
247
- /** How many interactions the deck holds (a multi-question deck). */
248
- interaction_count: number;
249
- }
250
- /** The full deck for a resolution flow (`crtr human deck <id> --json`). */
251
- export interface DeckDetail extends DeckSummary {
252
- interactions: DeckInteraction[];
253
- }
254
- /** One interaction's answer (humanloop InteractionResponse). */
255
- export interface DeckAnswer {
256
- id: string;
257
- selectedOptionId?: string;
258
- selectedOptionIds?: string[];
259
- freetext?: string;
260
- optionComments?: Record<string, string>;
261
- }
262
- /** `crtr human resolve <id> --json` body. */
263
- export interface ResolveDeckRequest {
264
- responses: DeckAnswer[];
265
- }
266
- /** `crtr human resolve <id> --json` success. */
267
- export interface ResolveDeckResponse {
268
- resolved: true;
269
- job_id: string;
270
- delivered: boolean;
271
- }
272
194
  /**
273
195
  * Engine state carried in `snapshot.state` — pi's OWN `get_state` payload, not a
274
196
  * mirror of it. `BrokerSnapshot['state']` is this same type, so the welcome frame
@@ -290,33 +212,3 @@ export type DialogResponseValue = {
290
212
  } | {
291
213
  cancelled: true;
292
214
  };
293
- /**
294
- * A typed content block within a view tab. Discriminated union of three
295
- * block kinds: inline/sourced markdown, a KPI grid, and a bar-list chart.
296
- */
297
- export type ViewBlock = {
298
- kind: 'markdown';
299
- source: {
300
- node_id: string;
301
- path: string;
302
- } | {
303
- inline: string;
304
- };
305
- } | {
306
- kind: 'kpis';
307
- items: {
308
- label: string;
309
- value: string;
310
- unit?: string;
311
- sub?: string;
312
- }[];
313
- } | {
314
- kind: 'barlist';
315
- title: string;
316
- rows: {
317
- label: string;
318
- value: number;
319
- max?: number;
320
- note?: string;
321
- }[];
322
- };
@@ -81,7 +81,7 @@ const webServeLeaf = defineLeaf({
81
81
  type: 'bool',
82
82
  required: false,
83
83
  default: false,
84
- constraint: 'Serve shell assets via a Vite dev server (middleware mode, HMR) instead of the prebuilt dist/web-client/ bundle. For contributors iterating on the shell or a builtin view. The bridge, SSE lane, and WS relay are identical in both modes.',
84
+ constraint: 'Serve shell assets via a Vite dev server (middleware mode, HMR) instead of the prebuilt dist/web-client/ bundle. The REST proxy, SSE lane, and WS relay are identical in both modes.',
85
85
  },
86
86
  ],
87
87
  output: [],
@@ -100,7 +100,7 @@ const webServeLeaf = defineLeaf({
100
100
  const open = input['open'] ?? false;
101
101
  const dev = input['dev'] ?? false;
102
102
  const server = await startWebServer({ port, host, token, dev });
103
- const nodeUrlShape = `${server.url}/node/<id>`;
103
+ const nodeUrlShape = `${server.url}/nodes/<id>`;
104
104
  const browserUrl = token !== undefined ? `${server.url}?token=${encodeURIComponent(token)}` : server.url;
105
105
  process.stdout.write(`crtr surface web serving on ${server.url}${dev ? ' (--dev: Vite middleware)' : ''}\n` +
106
106
  ` open a node: ${nodeUrlShape}\n` +
@@ -10,9 +10,11 @@ import { tmpdir } from 'node:os';
10
10
  import { join } from 'node:path';
11
11
  import { randomBytes } from 'node:crypto';
12
12
  import { Readable } from 'node:stream';
13
- import { parseArgv } from '../../core/command.js';
13
+ import { parseArgv, unknownPathError } from '../../core/command.js';
14
14
  import { renderLeafArgv } from '../../core/help.js';
15
15
  import { humanAsk, sourceStamp } from '../human/prompts.js';
16
+ import { humanReviewBranch } from '../human/review.js';
17
+ import { registerHuman } from '../human.js';
16
18
  import { coerceSingleSelectAgainst } from '../human/queue.js';
17
19
  // ---------------------------------------------------------------------------
18
20
  // Helper: write a temp JSON file and return its path.
@@ -37,32 +39,42 @@ async function withPipedStdin(body, fn) {
37
39
  }
38
40
  }
39
41
  // ---------------------------------------------------------------------------
40
- // human review — positional file (path) + required --subtitle + optional --output
42
+ // human review new — positional file (path) + required --subtitle + optional --output
41
43
  // ---------------------------------------------------------------------------
42
- describe('human review: params', () => {
43
- const params = [
44
- { kind: 'positional', name: 'file', type: 'path', required: true, constraint: 'Existing .md file.' },
45
- { kind: 'flag', name: 'subtitle', type: 'string', required: true, constraint: 'Review request.' },
46
- { kind: 'flag', name: 'output', type: 'path', required: false, constraint: 'Where to write feedback.' },
47
- ];
48
- test('parses file + required subtitle', async () => {
49
- const result = await parseArgv(params, ['/tmp/plan.md', '--subtitle', 'Review this plan so implementation can begin safely.']);
44
+ describe('human review command branch', () => {
45
+ const review = registerHuman().children.find((child) => child.name === 'review');
46
+ const newLeaf = humanReviewBranch.children.find((child) => child.name === 'new' && child.kind === 'leaf');
47
+ test('registers the canonical review branch', () => {
48
+ assert.equal(review, humanReviewBranch);
49
+ assert.deepEqual(humanReviewBranch.children.map((child) => child.name), ['new', 'comment']);
50
+ });
51
+ test('bare review names valid children rather than accepting the legacy file positional', () => {
52
+ const error = unknownPathError(humanReviewBranch, ['human', 'review'], '/tmp/plan.md');
53
+ assert.equal(error.code, 'unknown_path');
54
+ assert.match(error.message, /unknown subcommand: \/tmp\/plan\.md/);
55
+ assert.match(String(error.details?.next), /Valid children: new, comment/);
56
+ });
57
+ test('new parses file + required subtitle', async () => {
58
+ assert.ok(newLeaf);
59
+ const result = await parseArgv(newLeaf.help.params ?? [], ['/tmp/plan.md', '--subtitle', 'Review this plan so implementation can begin safely.']);
50
60
  assert.equal(result['file'], '/tmp/plan.md');
51
61
  assert.equal(result['subtitle'], 'Review this plan so implementation can begin safely.');
52
62
  });
53
- test('parses file + subtitle + --output', async () => {
54
- const result = await parseArgv(params, ['/tmp/plan.md', '--subtitle', 'Review this plan so implementation can begin safely.', '--output', '/tmp/fb.json']);
63
+ test('new parses file + subtitle + --output', async () => {
64
+ assert.ok(newLeaf);
65
+ const result = await parseArgv(newLeaf.help.params ?? [], ['/tmp/plan.md', '--subtitle', 'Review this plan so implementation can begin safely.', '--output', '/tmp/fb.json']);
55
66
  assert.equal(result['file'], '/tmp/plan.md');
56
67
  assert.equal(result['output'], '/tmp/fb.json');
57
68
  });
58
69
  // Validation is complete, never first-failure: one invocation yields ONE
59
70
  // error naming every missing required parameter, and its Next: mandates the
60
71
  // schema read rather than patching the first field.
61
- test('missing file AND missing subtitle throw ONE missing_parameter naming both', async () => {
62
- await assert.rejects(() => parseArgv(params, [], { leafPath: ['human', 'review'] }), (err) => {
72
+ test('new missing file AND subtitle throws ONE missing_parameter naming both', async () => {
73
+ assert.ok(newLeaf);
74
+ await assert.rejects(() => parseArgv(newLeaf.help.params ?? [], [], { leafPath: ['human', 'review', 'new'] }), (err) => {
63
75
  assert.match(err.message, /required parameters are missing: positional FILE, --subtitle/);
64
76
  assert.equal(err.details?.field, 'file, subtitle');
65
- assert.match(err.details?.next ?? '', /Run `crtr human review -h` and read the full schema before re-issuing/);
77
+ assert.match(err.details?.next ?? '', /Run `crtr human review new -h` and read the full schema before re-issuing/);
66
78
  return true;
67
79
  });
68
80
  });
@@ -20,7 +20,7 @@ import { CrtrClient, ApiError } from '../api/index.js';
20
20
  import { apiErrorToCliError } from '../core/io.js';
21
21
  import { ensureDaemon, DAEMON_VERIFY_WINDOW_MS } from '../daemon/manage.js';
22
22
  import { readState } from '../core/config.js';
23
- import { resolveRemoteCanvasTarget } from '../core/view/remote-canvas-target.js';
23
+ import { resolveRemoteCanvasTarget } from '../core/remote-canvas-target.js';
24
24
  import { RemoteCanvasSource } from '../core/canvas/remote-canvas-source.js';
25
25
  import { crtrHome } from '../core/canvas/paths.js';
26
26
  // ---------------------------------------------------------------------------
@@ -186,8 +186,8 @@ function summaryToRow(s) {
186
186
  }
187
187
  /** `NodeDetailDTO` → `NodeMeta`. Populates the durable-identity ∪ runtime fields
188
188
  * the DTO projects; the durable LAUNCH-RECIPE facts a projection cannot carry
189
- * (`launch`/`env`, `persona_ack`, `human_work_target`, `private_fork_*`,
190
- * `model_override`, `passive_default`, `fork_from`, `pi_session_file`,
189
+ * (`launch`/`env`, `persona_ack`, `model_override`, `passive_default`,
190
+ * `fork_from`, `pi_session_file`,
191
191
  * `cycle_pending`) are left undefined — read-only viewer/inspect consumers
192
192
  * (Stage B-7/B-9) never read them; the daemon owns the full meta for revive. */
193
193
  function detailToMeta(d) {
@@ -8,7 +8,7 @@
8
8
  import { defineLeaf } from '../core/command.js';
9
9
  import { runBrowse } from '../core/canvas/browse/app.js';
10
10
  import { cliClient, cliCanvasSource } from './api-client.js';
11
- import { resolveRemoteCanvasTarget } from '../core/view/remote-canvas-target.js';
11
+ import { resolveRemoteCanvasTarget } from '../core/remote-canvas-target.js';
12
12
  import { RemoteEventStream } from '../core/canvas/remote-event-stream.js';
13
13
  import { readState } from '../core/config.js';
14
14
  import { getDefaultProfileId } from '../core/profiles/default-binding.js';
@@ -1,6 +1,6 @@
1
1
  // `crtr canvas issue new` — capture a quick todo/idea/bug into a GitHub issue.
2
2
  //
3
- // Bound to the alt+c → i → (idea|bug) prefix chord: the menu opens a tmux
3
+ // Bound to the alt+c → c → (idea|bug) prefix chord: the menu opens a tmux
4
4
  // display-popup that runs this leaf in the originating pane's cwd (the popup is
5
5
  // started with `-d #{pane_current_path}`). The leaf:
6
6
  // 1. reads a free-text note from the popup's TTY (type, Ctrl-D to submit),
@@ -5,7 +5,7 @@
5
5
  import { defineLeaf } from '../core/command.js';
6
6
  import { InputError } from '../core/io.js';
7
7
  import { updateState } from '../core/config.js';
8
- import { getRemoteCanvasTarget } from '../core/view/remote-canvas-target.js';
8
+ import { getRemoteCanvasTarget } from '../core/remote-canvas-target.js';
9
9
  const SCOPE = 'user';
10
10
  export const canvasUseLeaf = defineLeaf({
11
11
  name: 'use',