@north-light/crouter 0.3.311 → 0.3.313

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 (520) hide show
  1. package/dist/api/client.d.ts +27 -30
  2. package/dist/api/client.js +80 -67
  3. package/dist/api/dto/broker-ops.d.ts +10 -20
  4. package/dist/api/dto/canvas.d.ts +1 -10
  5. package/dist/api/dto/health.d.ts +113 -0
  6. package/dist/api/dto/human-requests.d.ts +14 -3
  7. package/dist/api/dto/human.d.ts +2 -48
  8. package/dist/api/dto/human.js +3 -2
  9. package/dist/api/dto/inbox.d.ts +14 -0
  10. package/dist/api/dto/mail.d.ts +43 -0
  11. package/dist/api/dto/nodes.d.ts +11 -8
  12. package/dist/api/dto/recovery.d.ts +96 -0
  13. package/dist/api/dto/reviews.d.ts +2 -2
  14. package/dist/api/routes.d.ts +9 -6
  15. package/dist/api/routes.js +11 -11
  16. package/dist/build-root.d.ts +4 -0
  17. package/dist/build-root.js +11 -1
  18. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/integration/provider-rotation.test.ts +35 -47
  19. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +1 -1
  20. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +12 -5
  21. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +12 -5
  22. package/dist/cli.js +10 -1
  23. package/dist/clients/__tests__/helpers/human-daemon.d.ts +11 -0
  24. package/dist/clients/__tests__/helpers/human-daemon.js +60 -0
  25. package/dist/clients/attach/chrome/canvas-panels.js +1 -1
  26. package/dist/clients/attach/chrome/inbox-strip.d.ts +3 -3
  27. package/dist/clients/attach/chrome/inbox-strip.js +17 -9
  28. package/dist/clients/attach/chrome/ticket-panel.d.ts +2 -2
  29. package/dist/clients/attach/chrome/ticket-panel.js +77 -46
  30. package/dist/clients/attach/overlays/graph.js +6 -9
  31. package/dist/clients/attach/render/chat-view.d.ts +5 -4
  32. package/dist/clients/attach/render/chat-view.js +22 -13
  33. package/dist/clients/attach/render/page-block.d.ts +11 -7
  34. package/dist/clients/attach/render/page-block.js +64 -55
  35. package/dist/clients/attach/viewer.js +746 -735
  36. package/dist/clients/inbox/__tests__/integration/inbox-controller.test.js +56 -56
  37. package/dist/clients/inbox/__tests__/integration/stale-row-activation.test.js +45 -32
  38. package/dist/clients/inbox/controller.d.ts +42 -14
  39. package/dist/clients/inbox/controller.js +240 -124
  40. package/dist/clients/inbox/dto-adapt.d.ts +28 -0
  41. package/dist/clients/inbox/dto-adapt.js +93 -0
  42. package/dist/clients/inbox/page-adapter.d.ts +5 -4
  43. package/dist/clients/inbox/page-adapter.js +12 -12
  44. package/dist/clients/inbox/resolve.d.ts +10 -5
  45. package/dist/clients/inbox/resolve.js +13 -12
  46. package/dist/clients/inbox/review/review-client.d.ts +0 -1
  47. package/dist/clients/inbox/review/review-client.js +0 -4
  48. package/dist/clients/inbox/review-adapter.d.ts +2 -1
  49. package/dist/clients/inbox/review-adapter.js +3 -5
  50. package/dist/clients/inbox/surface.d.ts +2 -2
  51. package/dist/clients/inbox/surface.js +19 -8
  52. package/dist/clients/inbox/tui.d.ts +3 -3
  53. package/dist/commands/__tests__/human.test.js +31 -15
  54. package/dist/commands/__tests__/integration/dashboard-snapshot.test.js +36 -11
  55. package/dist/commands/{sys/__tests__ → __tests__/integration}/migrate.test.js +142 -36
  56. package/dist/commands/__tests__/revive-now-gate.test.js +2 -0
  57. package/dist/commands/api-client.d.ts +5 -4
  58. package/dist/commands/api-client.js +13 -7
  59. package/dist/commands/canvas-history/shared.js +1 -1
  60. package/dist/commands/canvas-history.js +1 -1
  61. package/dist/commands/canvas-roster.js +1 -1
  62. package/dist/commands/canvas.js +1 -2
  63. package/dist/commands/human/feedback.js +20 -17
  64. package/dist/commands/human/prompts.js +45 -36
  65. package/dist/commands/human/queue.js +73 -123
  66. package/dist/commands/human/review.js +6 -16
  67. package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +2 -0
  68. package/dist/commands/memory/__tests__/memory-list-and-lint-ignore.test.js +2 -0
  69. package/dist/commands/memory/__tests__/repository-root-lint.test.js +2 -0
  70. package/dist/commands/node-inspect-artifacts.js +1 -1
  71. package/dist/commands/node-lifecycle-revive.d.ts +2 -2
  72. package/dist/commands/node-lifecycle-revive.js +9 -19
  73. package/dist/commands/pkg/plugin-manage.js +0 -1
  74. package/dist/commands/profile/show.js +4 -12
  75. package/dist/commands/surface-tmux-spread.js +1 -5
  76. package/dist/commands/sys/__tests__/config-model-ladders.test.js +23 -30
  77. package/dist/commands/sys/__tests__/sync-project-guidance.test.js +37 -11
  78. package/dist/commands/sys/branch.d.ts +2 -0
  79. package/dist/commands/sys/branch.js +19 -0
  80. package/dist/commands/sys/config.js +106 -33
  81. package/dist/commands/sys/daemon.d.ts +2 -0
  82. package/dist/commands/sys/daemon.js +130 -7
  83. package/dist/commands/sys/doctor.js +5 -15
  84. package/dist/commands/sys/migrate.js +21 -92
  85. package/dist/commands/sys/setup-settings-runner.js +4 -2
  86. package/dist/commands/sys.js +2 -15
  87. package/dist/core/__tests__/boot-fault-attempt.test.js +23 -1
  88. package/dist/core/__tests__/boot.test.js +32 -25
  89. package/dist/core/__tests__/broker-launch-candidates.test.js +49 -0
  90. package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +149 -176
  91. package/dist/core/__tests__/canvas-inbox-watcher-naming.test.js +59 -10
  92. package/dist/core/__tests__/canvas-inbox-watcher.test.js +76 -20
  93. package/dist/core/__tests__/canvas.test.js +18 -47
  94. package/dist/core/__tests__/child-death-wake.test.js +29 -7
  95. package/dist/core/__tests__/cli-help-contract.test.js +2 -0
  96. package/dist/core/__tests__/close.test.js +29 -10
  97. package/dist/core/__tests__/collectible.test.js +2 -1
  98. package/dist/core/__tests__/config-change-delta.test.js +2 -0
  99. package/dist/core/__tests__/context-intro.test.js +17 -5
  100. package/dist/core/__tests__/cron-armed-context-failure.test.js +17 -12
  101. package/dist/core/__tests__/cron-held-settlement.test.js +21 -3
  102. package/dist/core/__tests__/cron-node-sink-parked-root.test.js +29 -10
  103. package/dist/core/__tests__/cron-self-cancel-delivery.test.js +14 -2
  104. package/dist/core/__tests__/cron-timeout-descendants.test.js +13 -1
  105. package/dist/core/__tests__/daemon-boot.test.js +51 -14
  106. package/dist/core/__tests__/fixtures/fake-engine.d.ts +1 -1
  107. package/dist/core/__tests__/fixtures/fake-engine.js +8 -3
  108. package/dist/core/__tests__/focuses.test.js +10 -5
  109. package/dist/core/__tests__/helpers/harness.js +50 -18
  110. package/dist/core/__tests__/history-inbox.test.js +12 -16
  111. package/dist/core/__tests__/human-action-delivery.test.js +48 -28
  112. package/dist/core/__tests__/human-actions.test.js +7 -3
  113. package/dist/core/__tests__/inline-memory-refs.test.js +7 -2
  114. package/dist/core/__tests__/integration/broker-fork-seam.test.js +37 -10
  115. package/dist/core/__tests__/integration/broker-sdk-wiring.test.js +42 -0
  116. package/dist/core/__tests__/integration/broker-snapshot-history.test.js +42 -29
  117. package/dist/core/__tests__/integration/broker-wedge-supervision.test.js +36 -35
  118. package/dist/core/__tests__/integration/command-plugins.test.js +15 -6
  119. package/dist/core/__tests__/integration/deferred-no-wake.test.js +113 -92
  120. package/dist/core/__tests__/integration/host-teardown-process-group.test.js +9 -5
  121. package/dist/core/__tests__/integration/lifecycle-hooks.test.js +312 -1
  122. package/dist/core/__tests__/integration/plugin-revalidate.test.js +4 -0
  123. package/dist/core/__tests__/integration/profile-pause.test.js +4 -4
  124. package/dist/core/__tests__/integration/refresh-stall-recycle.test.js +9 -12
  125. package/dist/core/__tests__/integration/revive.test.js +67 -21
  126. package/dist/core/__tests__/integration/spawn-root.test.js +62 -19
  127. package/dist/core/__tests__/integration/subscription-delivery.test.js +33 -21
  128. package/dist/core/__tests__/integration/worktree-land.test.js +5 -2
  129. package/dist/core/__tests__/integration/worktree-reap.test.js +15 -1
  130. package/dist/core/__tests__/kickoff.test.js +36 -39
  131. package/dist/core/__tests__/lifecycle-terminal-reasons.test.js +2 -1
  132. package/dist/core/__tests__/lifecycle.test.js +2 -1
  133. package/dist/core/__tests__/live-lifecycle-prompt.test.js +13 -1
  134. package/dist/core/__tests__/memory-resolver-precedence.test.js +2 -0
  135. package/dist/core/__tests__/migration.test.js +145 -31
  136. package/dist/core/__tests__/model-pin-durability.test.js +4 -1
  137. package/dist/core/__tests__/model-routes-config.test.js +13 -5
  138. package/dist/core/__tests__/node-outcome.test.js +93 -26
  139. package/dist/core/__tests__/on-read-crouter-home-fence.test.js +4 -3
  140. package/dist/core/__tests__/on-read-dedup-resume.test.js +8 -7
  141. package/dist/core/__tests__/on-read-nested-store.test.js +8 -7
  142. package/dist/core/__tests__/passive-subscription.test.js +50 -157
  143. package/dist/core/__tests__/plugin-kinds.test.js +6 -4
  144. package/dist/core/__tests__/plugin-link-symlinked-scope-root.test.js +6 -1
  145. package/dist/core/__tests__/plugin-page-components.test.js +6 -4
  146. package/dist/core/__tests__/preview-registry-sync.test.js +2 -0
  147. package/dist/core/__tests__/profile-project-memory-delivery.test.js +35 -32
  148. package/dist/core/__tests__/prune.test.js +11 -5
  149. package/dist/core/__tests__/push-final-guard.test.js +14 -7
  150. package/dist/core/__tests__/relaunch-root.test.js +30 -2
  151. package/dist/core/__tests__/remote-canvas-target.test.js +7 -1
  152. package/dist/core/__tests__/repository-root-identity.test.js +4 -0
  153. package/dist/core/__tests__/review-model-floor.test.js +6 -3
  154. package/dist/core/__tests__/revive-all.test.js +13 -3
  155. package/dist/core/__tests__/revive-capacity.test.js +26 -4
  156. package/dist/core/__tests__/revive-parked-fresh.test.js +31 -8
  157. package/dist/core/__tests__/seam/broker-attach-stream.test.js +1 -1
  158. package/dist/core/__tests__/seam/broker-cap-freeze.test.js +4 -3
  159. package/dist/core/__tests__/seam/broker-crash-teardown.test.js +11 -14
  160. package/dist/core/__tests__/seam/broker-provider-retry.test.js +85 -71
  161. package/dist/core/__tests__/seam/dormancy-release.test.js +33 -19
  162. package/dist/core/__tests__/seam/held-deferred-human-prompt.test.js +7 -5
  163. package/dist/core/__tests__/seam/inbox-reference-guidance.test.js +20 -6
  164. package/dist/core/__tests__/seam/node-outcome-delivery.test.js +27 -3
  165. package/dist/core/__tests__/spawn-worktree-id-conflict.test.js +5 -4
  166. package/dist/core/__tests__/stop-guard.test.js +2 -1
  167. package/dist/core/__tests__/subscription-pool-credential-guard.test.js +4 -3
  168. package/dist/core/__tests__/warm-claim-preference-snapshot.test.js +19 -5
  169. package/dist/core/__tests__/yield-ensures-daemon.test.js +2 -1
  170. package/dist/core/bootstrap.js +2 -0
  171. package/dist/core/broker-client/__tests__/transport-socket.test.js +51 -6
  172. package/dist/core/broker-client/transport-socket.d.ts +1 -0
  173. package/dist/core/broker-client/transport-socket.js +13 -5
  174. package/dist/core/canvas/__tests__/attention.test.js +29 -35
  175. package/dist/core/canvas/__tests__/history-transcript.test.js +6 -6
  176. package/dist/core/canvas/__tests__/render-remote.test.js +25 -9
  177. package/dist/core/canvas/attention.d.ts +2 -5
  178. package/dist/core/canvas/attention.js +15 -64
  179. package/dist/core/canvas/boot.d.ts +6 -7
  180. package/dist/core/canvas/boot.js +5 -9
  181. package/dist/core/canvas/canvas.d.ts +13 -109
  182. package/dist/core/canvas/canvas.js +140 -401
  183. package/dist/core/canvas/crons.d.ts +2 -0
  184. package/dist/core/canvas/crons.js +16 -15
  185. package/dist/core/canvas/daemon-owner.js +10 -0
  186. package/dist/core/canvas/db.d.ts +2 -2
  187. package/dist/core/canvas/db.js +2 -18
  188. package/dist/core/canvas/deliveries.d.ts +104 -0
  189. package/dist/core/canvas/deliveries.js +354 -0
  190. package/dist/core/canvas/executions.d.ts +29 -0
  191. package/dist/core/canvas/executions.js +68 -0
  192. package/dist/core/canvas/history.js +35 -35
  193. package/dist/core/canvas/index.d.ts +3 -1
  194. package/dist/core/canvas/index.js +3 -1
  195. package/dist/core/canvas/migrations.js +20 -12
  196. package/dist/core/canvas/nav-model.js +1 -3
  197. package/dist/core/canvas/nav-render.d.ts +4 -4
  198. package/dist/core/canvas/nav-render.js +11 -21
  199. package/dist/core/canvas/node-sql-migration.d.ts +3 -0
  200. package/dist/core/canvas/node-sql-migration.js +261 -0
  201. package/dist/core/canvas/paths.d.ts +2 -16
  202. package/dist/core/canvas/paths.js +2 -31
  203. package/dist/core/canvas/recovery.d.ts +76 -0
  204. package/dist/core/canvas/recovery.js +588 -0
  205. package/dist/core/canvas/remote-canvas-source.js +4 -0
  206. package/dist/core/canvas/render-source.d.ts +16 -27
  207. package/dist/core/canvas/render-source.js +16 -45
  208. package/dist/core/canvas/sessions.d.ts +33 -0
  209. package/dist/core/canvas/sessions.js +78 -0
  210. package/dist/core/canvas/types.d.ts +33 -33
  211. package/dist/core/canvas/types.js +2 -5
  212. package/dist/core/canvas/waits.d.ts +18 -0
  213. package/dist/core/canvas/waits.js +70 -0
  214. package/dist/core/canvas/worktrees.d.ts +40 -0
  215. package/dist/core/canvas/worktrees.js +93 -0
  216. package/dist/core/command-hooks/artifact.d.ts +6 -0
  217. package/dist/core/command-hooks/artifact.js +22 -6
  218. package/dist/core/command-hooks/discovery.d.ts +2 -0
  219. package/dist/core/command-hooks/discovery.js +2 -0
  220. package/dist/core/command-hooks/lifecycle-catalog.d.ts +20 -2
  221. package/dist/core/command-hooks/lifecycle-catalog.js +7 -2
  222. package/dist/core/command-hooks/lifecycle-create.d.ts +4 -0
  223. package/dist/core/command-hooks/lifecycle-create.js +51 -0
  224. package/dist/core/command-hooks/schema.d.ts +2 -2
  225. package/dist/core/command-hooks/schema.js +5 -4
  226. package/dist/core/command-hooks/transport/exec-invoke.js +3 -1
  227. package/dist/core/command-hooks/transport/exec-lifecycle.d.ts +18 -8
  228. package/dist/core/command-hooks/transport/exec-lifecycle.js +89 -30
  229. package/dist/core/config.d.ts +17 -12
  230. package/dist/core/config.js +106 -155
  231. package/dist/core/errors.d.ts +1 -0
  232. package/dist/core/errors.js +4 -0
  233. package/dist/core/feed/__tests__/inbox-migrate.test.js +27 -31
  234. package/dist/core/feed/feed.d.ts +0 -6
  235. package/dist/core/feed/feed.js +68 -56
  236. package/dist/core/feed/inbox.d.ts +7 -81
  237. package/dist/core/feed/inbox.js +46 -378
  238. package/dist/core/feed/messages.d.ts +58 -0
  239. package/dist/core/feed/messages.js +217 -0
  240. package/dist/core/fs-utils.d.ts +4 -0
  241. package/dist/core/fs-utils.js +21 -1
  242. package/dist/core/human/answer.d.ts +1 -1
  243. package/dist/core/human/answer.js +1 -1
  244. package/dist/core/human/claim.d.ts +1 -1
  245. package/dist/core/human/claim.js +2 -4
  246. package/dist/core/human/component-docs.js +1 -1
  247. package/dist/core/human/feedback-companion.js +4 -3
  248. package/dist/core/human/feedback.d.ts +5 -8
  249. package/dist/core/human/feedback.js +57 -85
  250. package/dist/core/human/page-authoring.d.ts +30 -0
  251. package/dist/core/human/page-authoring.js +19 -0
  252. package/dist/core/human/requests.d.ts +136 -0
  253. package/dist/core/human/requests.js +515 -0
  254. package/dist/core/human/root.d.ts +0 -7
  255. package/dist/core/human/root.js +0 -17
  256. package/dist/core/human/scan.d.ts +2 -7
  257. package/dist/core/human/scan.js +48 -132
  258. package/dist/core/human/summary.d.ts +1 -1
  259. package/dist/core/human/summary.js +1 -1
  260. package/dist/core/human/tickets.d.ts +23 -83
  261. package/dist/core/human/tickets.js +92 -243
  262. package/dist/core/human/types.d.ts +5 -1
  263. package/dist/core/installed-plugins.js +8 -3
  264. package/dist/core/keybindings/__tests__/resolve.test.js +19 -17
  265. package/dist/core/locked-file.d.ts +6 -3
  266. package/dist/core/locked-file.js +36 -9
  267. package/dist/core/memory/extensions.js +2 -0
  268. package/dist/core/preview-registry.js +0 -1
  269. package/dist/core/profiles/__tests__/env-store.test.js +2 -0
  270. package/dist/core/profiles/default-binding.d.ts +0 -4
  271. package/dist/core/profiles/default-binding.js +12 -58
  272. package/dist/core/profiles/env-store.js +8 -3
  273. package/dist/core/profiles/manifest.d.ts +2 -37
  274. package/dist/core/profiles/manifest.js +35 -161
  275. package/dist/core/profiles/select.js +3 -0
  276. package/dist/core/review/__tests__/capture-origin.test.js +13 -2
  277. package/dist/core/review/__tests__/comments.test.js +28 -10
  278. package/dist/core/review/__tests__/remap.test.js +28 -10
  279. package/dist/core/review/__tests__/stage-identity.test.js +17 -7
  280. package/dist/core/review/birth.d.ts +1 -1
  281. package/dist/core/review/birth.js +34 -5
  282. package/dist/core/review/comments.js +1 -1
  283. package/dist/core/review/companion.d.ts +1 -1
  284. package/dist/core/review/companion.js +2 -2
  285. package/dist/core/review/document.js +1 -1
  286. package/dist/core/review/project.d.ts +5 -1
  287. package/dist/core/review/project.js +14 -36
  288. package/dist/core/review/realize.d.ts +3 -6
  289. package/dist/core/review/realize.js +51 -168
  290. package/dist/core/review/remap.js +1 -1
  291. package/dist/core/review/stage.d.ts +3 -2
  292. package/dist/core/review/stage.js +2 -3
  293. package/dist/core/review/store.d.ts +3 -21
  294. package/dist/core/review/store.js +140 -186
  295. package/dist/core/review/types.d.ts +0 -1
  296. package/dist/core/runtime/__tests__/install-id-cache-scoping.test.js +9 -5
  297. package/dist/core/runtime/__tests__/spawn-env.test.js +8 -9
  298. package/dist/core/runtime/broker/auth-reload.js +9 -10
  299. package/dist/core/runtime/broker/daemon-ops.d.ts +25 -8
  300. package/dist/core/runtime/broker/daemon-ops.js +42 -9
  301. package/dist/core/runtime/broker/extension-abort.d.ts +3 -0
  302. package/dist/core/runtime/broker/extension-abort.js +11 -0
  303. package/dist/core/runtime/broker/fault-retry.d.ts +15 -6
  304. package/dist/core/runtime/broker/fault-retry.js +142 -95
  305. package/dist/core/runtime/broker/inbox.d.ts +4 -32
  306. package/dist/core/runtime/broker/inbox.js +4 -92
  307. package/dist/core/runtime/broker/rebind.d.ts +1 -0
  308. package/dist/core/runtime/broker/rebind.js +21 -12
  309. package/dist/core/runtime/broker-persona-guidance.d.ts +1 -1
  310. package/dist/core/runtime/broker-persona-guidance.js +2 -13
  311. package/dist/core/runtime/broker.js +28 -22
  312. package/dist/core/runtime/close.d.ts +3 -9
  313. package/dist/core/runtime/close.js +16 -27
  314. package/dist/core/runtime/fault.d.ts +3 -93
  315. package/dist/core/runtime/fault.js +9 -419
  316. package/dist/core/runtime/kickoff.d.ts +3 -6
  317. package/dist/core/runtime/kickoff.js +12 -18
  318. package/dist/core/runtime/launch.js +1 -1
  319. package/dist/core/runtime/lifecycle.js +40 -7
  320. package/dist/core/runtime/nodes.d.ts +5 -1
  321. package/dist/core/runtime/nodes.js +26 -11
  322. package/dist/core/runtime/placement.js +2 -2
  323. package/dist/core/runtime/recycle.js +24 -14
  324. package/dist/core/runtime/reset.js +26 -7
  325. package/dist/core/runtime/revive.js +226 -217
  326. package/dist/core/runtime/spawn.d.ts +4 -1
  327. package/dist/core/runtime/spawn.js +43 -5
  328. package/dist/core/runtime/warm-pool.d.ts +2 -2
  329. package/dist/core/runtime/warm-pool.js +23 -3
  330. package/dist/core/scoped-state/db.d.ts +7 -0
  331. package/dist/core/scoped-state/db.js +92 -0
  332. package/dist/core/scoped-state/migrate.d.ts +11 -0
  333. package/dist/core/scoped-state/migrate.js +198 -0
  334. package/dist/core/scoped-state/paths.d.ts +9 -0
  335. package/dist/core/scoped-state/paths.js +27 -0
  336. package/dist/core/scoped-state/profiles.d.ts +12 -0
  337. package/dist/core/scoped-state/profiles.js +62 -0
  338. package/dist/core/scoped-state/providers.d.ts +16 -0
  339. package/dist/core/scoped-state/providers.js +8 -0
  340. package/dist/core/scoped-state/schema.d.ts +3 -0
  341. package/dist/core/scoped-state/schema.js +26 -0
  342. package/dist/core/scoped-state/settings.d.ts +28 -0
  343. package/dist/core/scoped-state/settings.js +82 -0
  344. package/dist/core/subscription-state.d.ts +29 -48
  345. package/dist/core/subscription-state.js +176 -712
  346. package/dist/core/worktree-close.js +4 -4
  347. package/dist/core/worktree-mutation-async.js +2 -2
  348. package/dist/core/worktree-sweep.js +11 -16
  349. package/dist/core/worktree.js +6 -12
  350. package/dist/daemon/__tests__/autostart-storm.test.js +1 -39
  351. package/dist/daemon/__tests__/helpers/source-daemon.d.ts +2 -2
  352. package/dist/daemon/__tests__/helpers/source-daemon.js +7 -6
  353. package/dist/daemon/__tests__/integration/migration-startup.test.js +59 -26
  354. package/dist/daemon/__tests__/node-deadline-lane.test.js +2 -1
  355. package/dist/daemon/__tests__/node-outcome-birth-invariants.test.js +41 -17
  356. package/dist/daemon/__tests__/node-outcome-delivery.test.js +39 -10
  357. package/dist/daemon/__tests__/reconciler-signature.test.js +2 -2
  358. package/dist/daemon/__tests__/subtree-filter-freshness.test.js +2 -2
  359. package/dist/daemon/api/__tests__/broker-settle-park.test.js +17 -12
  360. package/dist/daemon/api/__tests__/canvas-snapshot-fields.test.js +27 -5
  361. package/dist/daemon/api/__tests__/model-config.test.js +8 -8
  362. package/dist/daemon/api/__tests__/node-create-description.test.js +22 -5
  363. package/dist/daemon/api/__tests__/node-model-validation.test.js +21 -1
  364. package/dist/daemon/api/__tests__/nodes-activity-query.test.js +10 -12
  365. package/dist/daemon/api/__tests__/profile-launch-gates.test.js +6 -3
  366. package/dist/daemon/api/__tests__/profile-metadata-route.test.js +4 -1
  367. package/dist/daemon/api/__tests__/reopen-delivery.test.js +26 -8
  368. package/dist/daemon/api/__tests__/seam/api-server.test.js +24 -32
  369. package/dist/daemon/api/__tests__/seam/b10-attach-modelauth.test.js +4 -1
  370. package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +5 -4
  371. package/dist/daemon/api/__tests__/seam/profile-delete.test.js +29 -43
  372. package/dist/daemon/api/__tests__/submit-result.test.js +3 -2
  373. package/dist/daemon/api/bridge.js +1 -1
  374. package/dist/daemon/api/handlers/bash-jobs.js +6 -7
  375. package/dist/daemon/api/handlers/broker-ops.js +47 -84
  376. package/dist/daemon/api/handlers/broker-recovery.d.ts +4 -0
  377. package/dist/daemon/api/handlers/broker-recovery.js +251 -0
  378. package/dist/daemon/api/handlers/canvas.js +2 -44
  379. package/dist/daemon/api/handlers/daemon.js +41 -0
  380. package/dist/daemon/api/handlers/feedback-comments.js +2 -2
  381. package/dist/daemon/api/handlers/health.js +10 -5
  382. package/dist/daemon/api/handlers/human-requests.js +168 -188
  383. package/dist/daemon/api/handlers/human.js +3 -148
  384. package/dist/daemon/api/handlers/inbox-page.d.ts +4 -0
  385. package/dist/daemon/api/handlers/inbox-page.js +89 -0
  386. package/dist/daemon/api/handlers/inbox.js +21 -120
  387. package/dist/daemon/api/handlers/messages.d.ts +1 -0
  388. package/dist/daemon/api/handlers/messages.js +73 -15
  389. package/dist/daemon/api/handlers/node-outcomes.js +58 -13
  390. package/dist/daemon/api/handlers/nodes.d.ts +1 -0
  391. package/dist/daemon/api/handlers/nodes.js +41 -42
  392. package/dist/daemon/api/handlers/reviews.js +4 -29
  393. package/dist/daemon/api/map.d.ts +25 -3
  394. package/dist/daemon/api/map.js +84 -14
  395. package/dist/daemon/api/server.js +68 -9
  396. package/dist/daemon/control.d.ts +18 -0
  397. package/dist/daemon/cron/disposition.d.ts +2 -0
  398. package/dist/daemon/cron/disposition.js +8 -5
  399. package/dist/daemon/cron/settle.js +37 -13
  400. package/dist/daemon/cron/sinks.d.ts +18 -1
  401. package/dist/daemon/cron/sinks.js +47 -93
  402. package/dist/daemon/crtrd-cli.js +4 -19
  403. package/dist/daemon/crtrd.d.ts +2 -0
  404. package/dist/daemon/crtrd.js +206 -81
  405. package/dist/daemon/fleet.js +5 -6
  406. package/dist/daemon/human/finish.d.ts +12 -24
  407. package/dist/daemon/human/finish.js +88 -285
  408. package/dist/daemon/human/settle.d.ts +40 -0
  409. package/dist/daemon/human/settle.js +89 -0
  410. package/dist/daemon/human/sweep.d.ts +20 -5
  411. package/dist/daemon/human/sweep.js +56 -60
  412. package/dist/daemon/manage.d.ts +21 -16
  413. package/dist/daemon/manage.js +85 -51
  414. package/dist/daemon/messaging/node-message.d.ts +1 -1
  415. package/dist/daemon/messaging/node-message.js +9 -12
  416. package/dist/daemon/park-activity.js +3 -3
  417. package/dist/daemon/reconcilers/bash-deadline.js +6 -7
  418. package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
  419. package/dist/daemon/reconcilers/broker-supervision.js +41 -19
  420. package/dist/daemon/reconcilers/controller-death.js +6 -18
  421. package/dist/daemon/reconcilers/delivery-lane.d.ts +9 -0
  422. package/dist/daemon/reconcilers/delivery-lane.js +130 -0
  423. package/dist/daemon/reconcilers/live-obligation.js +3 -3
  424. package/dist/daemon/reconcilers/node-deadline.js +1 -1
  425. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -1
  426. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +10 -12
  427. package/dist/daemon/reconcilers/node-lifecycle/tick.js +5 -5
  428. package/dist/daemon/reconcilers/node-lifecycle/wants-execution.js +1 -1
  429. package/dist/daemon/reconcilers/pending-review-submit.js +3 -3
  430. package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -8
  431. package/dist/daemon/reconcilers/storage-maintenance.js +13 -43
  432. package/dist/daemon/review/companion.js +5 -11
  433. package/dist/daemon/review/deliver.d.ts +1 -5
  434. package/dist/daemon/review/deliver.js +3 -52
  435. package/dist/daemon/review/finish.d.ts +2 -27
  436. package/dist/daemon/review/finish.js +79 -263
  437. package/dist/daemon/review/sweep.d.ts +3 -10
  438. package/dist/daemon/review/sweep.js +13 -131
  439. package/dist/daemon/startup-policy.d.ts +0 -5
  440. package/dist/daemon/startup-policy.js +0 -5
  441. package/dist/hook-authoring.d.ts +28 -2
  442. package/dist/hook-authoring.js +53 -1
  443. package/dist/index.d.ts +3 -2
  444. package/dist/index.js +1 -1
  445. package/dist/migrations/__tests__/activation-concurrency.test.js +3 -2
  446. package/dist/migrations/__tests__/activation.test.js +9 -6
  447. package/dist/migrations/activation.d.ts +3 -2
  448. package/dist/migrations/activation.js +2 -4
  449. package/dist/migrations/corpus.d.ts +2 -5
  450. package/dist/migrations/corpus.js +9 -20
  451. package/dist/migrations/runner.d.ts +3 -1
  452. package/dist/migrations/runner.js +6 -2
  453. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +21 -89
  454. package/dist/pi-extensions/__tests__/canvas-goal-capture-envelope.test.js +4 -2
  455. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +51 -33
  456. package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.js +16 -2
  457. package/dist/pi-extensions/__tests__/pre-command-gate.test.js +13 -1
  458. package/dist/pi-extensions/canvas-inbox-watcher.js +98 -244
  459. package/dist/pi-extensions/canvas-passive-context.d.ts +4 -8
  460. package/dist/pi-extensions/canvas-passive-context.js +85 -37
  461. package/dist/pi-extensions/canvas-stophook.js +47 -31
  462. package/dist/shared/env.d.ts +1 -0
  463. package/dist/shared/env.js +3 -0
  464. package/package.json +1 -1
  465. package/runtime.lock.json +5 -5
  466. package/dist/clients/attach/__tests__/page-block.test.js +0 -54
  467. package/dist/clients/inbox/review-visibility.d.ts +0 -5
  468. package/dist/clients/inbox/review-visibility.js +0 -19
  469. package/dist/commands/canvas-rebuild-index.d.ts +0 -2
  470. package/dist/commands/canvas-rebuild-index.js +0 -46
  471. package/dist/core/__tests__/human-cancel-guard.test.js +0 -110
  472. package/dist/core/__tests__/human-deliver.test.d.ts +0 -1
  473. package/dist/core/__tests__/human-deliver.test.js +0 -256
  474. package/dist/core/__tests__/human-node-not-supervised.test.d.ts +0 -1
  475. package/dist/core/__tests__/human-node-not-supervised.test.js +0 -89
  476. package/dist/core/__tests__/integration/human-deliver-e2e.test.d.ts +0 -1
  477. package/dist/core/__tests__/integration/human-deliver-e2e.test.js +0 -131
  478. package/dist/core/__tests__/phase4-review-store.test.d.ts +0 -1
  479. package/dist/core/__tests__/phase4-review-store.test.js +0 -144
  480. package/dist/core/__tests__/watchdog-abort-arms-retry.test.d.ts +0 -1
  481. package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +0 -110
  482. package/dist/core/canvas/human-deliveries.d.ts +0 -39
  483. package/dist/core/canvas/human-deliveries.js +0 -75
  484. package/dist/core/canvas/node-outcome-deliveries.d.ts +0 -64
  485. package/dist/core/canvas/node-outcome-deliveries.js +0 -159
  486. package/dist/core/feed/passive.d.ts +0 -3
  487. package/dist/core/feed/passive.js +0 -53
  488. package/dist/core/human/__tests__/inbox-cancel-worker.d.ts +0 -1
  489. package/dist/core/human/__tests__/inbox-cancel-worker.js +0 -7
  490. package/dist/core/human/__tests__/inbox-claim-worker.d.ts +0 -1
  491. package/dist/core/human/__tests__/inbox-claim-worker.js +0 -17
  492. package/dist/core/human/__tests__/inbox-stale-claim-worker.d.ts +0 -1
  493. package/dist/core/human/__tests__/inbox-stale-claim-worker.js +0 -8
  494. package/dist/core/human/__tests__/integration/inbox-core.test.d.ts +0 -1
  495. package/dist/core/human/__tests__/integration/inbox-core.test.js +0 -145
  496. package/dist/core/human/__tests__/page-tickets.test.d.ts +0 -1
  497. package/dist/core/human/__tests__/page-tickets.test.js +0 -161
  498. package/dist/core/review/ticket-filter.d.ts +0 -17
  499. package/dist/core/review/ticket-filter.js +0 -21
  500. package/dist/core/runtime/broker/passive.d.ts +0 -17
  501. package/dist/core/runtime/broker/passive.js +0 -44
  502. package/dist/core/runtime/busy.d.ts +0 -46
  503. package/dist/core/runtime/busy.js +0 -150
  504. package/dist/daemon/__tests__/startup-block-marker.test.d.ts +0 -1
  505. package/dist/daemon/__tests__/startup-block-marker.test.js +0 -86
  506. package/dist/daemon/api/__tests__/review-terminal-conflict.test.d.ts +0 -1
  507. package/dist/daemon/api/__tests__/review-terminal-conflict.test.js +0 -98
  508. package/dist/daemon/human/deliver-action.d.ts +0 -3
  509. package/dist/daemon/human/deliver-action.js +0 -9
  510. package/dist/daemon/node-outcome/deliver-outcome.d.ts +0 -3
  511. package/dist/daemon/node-outcome/deliver-outcome.js +0 -9
  512. package/dist/daemon/reconcilers/human-delivery-lane.d.ts +0 -10
  513. package/dist/daemon/reconcilers/human-delivery-lane.js +0 -41
  514. package/dist/daemon/reconcilers/node-outcome-delivery-lane.d.ts +0 -10
  515. package/dist/daemon/reconcilers/node-outcome-delivery-lane.js +0 -41
  516. package/dist/daemon/startup-block-marker.d.ts +0 -25
  517. package/dist/daemon/startup-block-marker.js +0 -99
  518. /package/dist/{clients/attach/__tests__/page-block.test.d.ts → api/dto/mail.js} +0 -0
  519. /package/dist/{commands/sys/__tests__/migrate.test.d.ts → api/dto/recovery.js} +0 -0
  520. /package/dist/{core/__tests__/human-cancel-guard.test.d.ts → commands/__tests__/integration/migrate.test.d.ts} +0 -0
@@ -1,148 +1,3 @@
1
- // Human bridge and ticket-work routes owned by crtrd. Ticket directories are
2
- // derived from bridge node ids; callers never supply a filesystem path, root,
3
- // handler, or claim binding.
4
- import { existsSync } from 'node:fs';
5
- import { ApiError } from '../../../api/index.js';
6
- import { isSafeNodeId } from '../../../core/canvas/paths.js';
7
- import { pageManifestPath, readTicketReplyRoute, reviewPath } from '../../../core/human/convention.js';
8
- import { ticketDir } from '../../../core/human/root.js';
9
- import { readTicketResult, validatePageTicketResponses } from '../../../core/human/tickets.js';
10
- import { getReviewByBridge } from '../../../core/review/store.js';
11
- import { ReviewOperationError } from '../../../core/review/types.js';
12
- import { spawnNode } from '../../../core/runtime/nodes.js';
13
- import { cancelHumanTicket, resolvePageTicket } from '../../human/finish.js';
14
- import { cancelReview } from '../../review/finish.js';
15
- function requireInteractionTicketId(ctx) {
16
- const ticketId = ctx.params['ticket_id'];
17
- if (ticketId === undefined || !isSafeNodeId(ticketId)) {
18
- throw new ApiError(400, 'invalid_request', 'invalid interaction ticket id');
19
- }
20
- return ticketId;
21
- }
22
- // POST /v1/human/bridge — create a terminal bridge without a broker
23
- function handleCreateBridge(ctx) {
24
- const req = ctx.body;
25
- if (req === undefined || typeof req !== 'object') {
26
- throw new ApiError(400, 'invalid_request', 'bridge body is required');
27
- }
28
- const { kind, cwd, name } = req;
29
- if (kind !== 'human')
30
- throw new ApiError(400, 'invalid_request', 'bridge kind must be "human"');
31
- if (typeof cwd !== 'string' || cwd === '')
32
- throw new ApiError(400, 'invalid_request', 'bridge body requires `cwd`');
33
- if (typeof name !== 'string' || name === '')
34
- throw new ApiError(400, 'invalid_request', 'bridge body requires `name`');
35
- const parent = req.parent ?? null;
36
- if (parent !== null && (typeof parent !== 'string' || parent === '')) {
37
- throw new ApiError(400, 'invalid_request', 'bridge `parent` must be a node id or null');
38
- }
39
- try {
40
- const node = spawnNode({ kind: 'human', parent, creator: parent, cwd, name, lifecycle: 'terminal' });
41
- return { status: 200, body: { node_id: node.node_id, name: node.name } };
42
- }
43
- catch (error) {
44
- throw new ApiError(400, 'invalid_request', String(error));
45
- }
46
- }
47
- // POST /v1/human/tickets/:ticket_id/resolve and /cancel
48
- function reviewSubmitGuidance() {
49
- return new ApiError(400, 'invalid_request', 'review approvals use POST /v1/human/reviews/:review_id/submit');
50
- }
51
- /** The ticket resolve route accepts only a page response body. */
52
- function requireResolveRequest(ctx) {
53
- const request = ctx.body;
54
- if (request === undefined || request === null || typeof request !== 'object' || Array.isArray(request)) {
55
- throw new ApiError(400, 'invalid_request', 'ticket resolve body is required');
56
- }
57
- const body = request;
58
- const fields = Object.keys(body);
59
- if (fields.length === 1 && fields[0] === 'responses')
60
- return { responses: body['responses'] };
61
- if ('feedback' in body)
62
- throw reviewSubmitGuidance();
63
- throw new ApiError(400, 'invalid_request', 'ticket resolve body requires exactly `responses`');
64
- }
65
- function requirePageTicket(dir) {
66
- const page = existsSync(pageManifestPath(dir));
67
- const review = existsSync(reviewPath(dir));
68
- if (review && !page)
69
- throw reviewSubmitGuidance();
70
- if (!page || review) {
71
- throw new ApiError(400, 'invalid_request', 'ticket has no unambiguous page kind');
72
- }
73
- }
74
- function invalidResolveRequest(error) {
75
- const detail = error instanceof Error ? error.message : String(error);
76
- if (detail === 'page_has_no_response_lifecycle')
77
- return new ApiError(409, 'page_has_no_response_lifecycle', 'this page has no response lifecycle');
78
- return new ApiError(400, 'invalid_request', `invalid ticket resolve body: ${detail}`);
79
- }
80
- function preflightResolve(validate) {
81
- try {
82
- return validate();
83
- }
84
- catch (error) {
85
- throw invalidResolveRequest(error);
86
- }
87
- }
88
- async function handleResolve(ctx) {
89
- const ticketId = requireInteractionTicketId(ctx);
90
- const request = requireResolveRequest(ctx);
91
- const dir = ticketDir(ticketId);
92
- requirePageTicket(dir);
93
- const responses = preflightResolve(() => validatePageTicketResponses(dir, request.responses));
94
- const replyExpected = readTicketReplyRoute(dir) !== null;
95
- await resolvePageTicket(ticketId, responses);
96
- return { status: 200, body: { completed: true, reply_delivered: replyExpected, kind: 'page' } };
97
- }
98
- function hasPublishedTicket(dir) {
99
- return existsSync(pageManifestPath(dir)) || readTicketResult(dir) !== null;
100
- }
101
- async function handleCancel(ctx) {
102
- const ticketId = requireInteractionTicketId(ctx);
103
- const request = ctx.body;
104
- if (request !== undefined && (typeof request !== 'object' || request === null)) {
105
- throw new ApiError(400, 'invalid_request', 'ticket cancel body must be an object');
106
- }
107
- if (request?.disposition !== undefined && request.disposition !== 'canceled' && request.disposition !== 'dismissed') {
108
- throw new ApiError(400, 'invalid_request', '`disposition` must be "canceled" or "dismissed"');
109
- }
110
- const dir = ticketDir(ticketId);
111
- const review = getReviewByBridge(ticketId);
112
- try {
113
- if (review !== null) {
114
- if (review.state === 'approved') {
115
- throw new ApiError(409, 'ticket_already_resolved', 'ticket already resolved');
116
- }
117
- const finished = await cancelReview(review.review_id, request ?? {});
118
- if (finished.outcome === 'already_settled') {
119
- throw new ApiError(409, 'ticket_already_resolved', 'ticket already resolved');
120
- }
121
- return { status: 200, body: { canceled: true } };
122
- }
123
- // A binding row has no published ticket. It is intentionally
124
- // indistinguishable from an unknown node id on this ticket surface.
125
- if (!hasPublishedTicket(dir)) {
126
- throw new ApiError(404, 'ticket_not_found', 'no matching ticket');
127
- }
128
- await cancelHumanTicket(ticketId, request ?? {});
129
- return { status: 200, body: { canceled: true } };
130
- }
131
- catch (error) {
132
- if (error instanceof ApiError)
133
- throw error;
134
- if (error instanceof Error && error.message === 'page_has_no_response_lifecycle') {
135
- throw new ApiError(409, 'page_has_no_response_lifecycle', 'this page has no response lifecycle');
136
- }
137
- // Review errors are not part of the retained ticket route's vocabulary.
138
- if (error instanceof ReviewOperationError) {
139
- throw new ApiError(409, 'ticket_already_resolved', 'ticket already resolved');
140
- }
141
- throw new ApiError(500, 'internal', 'the ticket could not be canceled');
142
- }
143
- }
144
- export const humanRoutes = [
145
- { method: 'POST', pattern: '/v1/human/bridge', handler: handleCreateBridge },
146
- { method: 'POST', pattern: '/v1/human/tickets/:ticket_id/resolve', handler: handleResolve },
147
- { method: 'POST', pattern: '/v1/human/tickets/:ticket_id/cancel', handler: handleCancel },
148
- ];
1
+ // Human page and review lifecycle routes live on request identity. The former
2
+ // bridge-creation and ticket resolve/cancel routes are intentionally absent.
3
+ export const humanRoutes = [];
@@ -0,0 +1,4 @@
1
+ import type { InboxPageDTO } from '../../../api/index.js';
2
+ import { type HumanRequestRecord } from '../../../core/human/requests.js';
3
+ /** Project the one SQL-selected page revision for every page reader. */
4
+ export declare function inboxPageProjection(request: HumanRequestRecord): InboxPageDTO;
@@ -0,0 +1,89 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { readPageFeedback } from '../../../core/human/feedback.js';
3
+ import { pageModulePath, pagePath } from '../../../core/human/convention.js';
4
+ import { parsePage } from '../../../core/human/page.js';
5
+ import { presentationDir } from '../../../core/human/requests.js';
6
+ import { readPageProgress, readTicketResult } from '../../../core/human/tickets.js';
7
+ import { toPageFeedbackDTO } from '../map.js';
8
+ function pageSlotToDTO(slot) {
9
+ const dto = {
10
+ kind: slot.kind,
11
+ step: slot.step,
12
+ config: slot.config,
13
+ };
14
+ if (slot.id !== undefined)
15
+ dto.id = slot.id;
16
+ if (slot.unvalidated === true)
17
+ dto.unvalidated = true;
18
+ if (slot.display === true)
19
+ dto.display = true;
20
+ return dto;
21
+ }
22
+ function pageManifestToDTO(manifest) {
23
+ const dto = {
24
+ schema: 'crtr.page/v2',
25
+ dialect: manifest.dialect,
26
+ title: manifest.title,
27
+ delivery: manifest.delivery,
28
+ document: manifest.document,
29
+ steps: manifest.steps,
30
+ slots: manifest.slots.map(pageSlotToDTO),
31
+ };
32
+ if (manifest.subtitle !== undefined)
33
+ dto.subtitle = manifest.subtitle;
34
+ if (manifest.source !== undefined) {
35
+ const source = {};
36
+ if (manifest.source.sessionName !== undefined)
37
+ source.sessionName = manifest.source.sessionName;
38
+ if (manifest.source.askedBy !== undefined)
39
+ source.askedBy = manifest.source.askedBy;
40
+ if (manifest.source.emittedAt !== undefined)
41
+ source.emittedAt = manifest.source.emittedAt;
42
+ if (manifest.source.profileName !== undefined)
43
+ source.profileName = manifest.source.profileName;
44
+ if (manifest.source.nodeId !== undefined)
45
+ source.nodeId = manifest.source.nodeId;
46
+ if (Object.keys(source).length > 0)
47
+ dto.source = source;
48
+ }
49
+ return dto;
50
+ }
51
+ function state(request) {
52
+ if (!request.settleable)
53
+ return 'passive';
54
+ if (request.state !== 'settled')
55
+ return 'pending';
56
+ return request.outcome === 'canceled' || request.outcome === 'dismissed' ? 'canceled' : 'resolved';
57
+ }
58
+ function result(request) {
59
+ const terminal = readTicketResult(request.request_dir);
60
+ if (terminal === null)
61
+ return null;
62
+ if (terminal.kind === 'page' || terminal.kind === 'canceled') {
63
+ return terminal;
64
+ }
65
+ throw new Error(`page request has an invalid terminal result: ${request.request_id}`);
66
+ }
67
+ /** Project the one SQL-selected page revision for every page reader. */
68
+ export function inboxPageProjection(request) {
69
+ if (request.kind !== 'page')
70
+ throw new Error(`request is not a page: ${request.request_id}`);
71
+ const revision = presentationDir(request);
72
+ const manifest = parsePage(revision);
73
+ const sourceDocument = readFileSync(pagePath(revision, manifest.dialect), 'utf8');
74
+ const document = manifest.dialect === 'jsx' ? readFileSync(pageModulePath(revision), 'utf8') : sourceDocument;
75
+ const progress = request.settleable ? readPageProgress(request.request_dir) : null;
76
+ return {
77
+ ticket_id: request.inbox_ticket_id,
78
+ kind: 'page',
79
+ state: state(request),
80
+ revision,
81
+ page: pageManifestToDTO(manifest),
82
+ document,
83
+ source_document: sourceDocument,
84
+ document_media_type: manifest.dialect === 'jsx' ? 'text/jsx' : 'text/html',
85
+ progress: progress === null ? null : { responses: progress },
86
+ result: result(request),
87
+ feedback: toPageFeedbackDTO(readPageFeedback(request.request_dir)),
88
+ };
89
+ }
@@ -1,65 +1,22 @@
1
1
  // Ticket inbox handlers — crtrd `/v1/human/inbox` (Northlight crouter-inbox
2
2
  // v1, inbox-contract.md §A). This public ticket-serving resource enumerates,
3
3
  // reads, responds to, and cancels tickets while preserving its product DTOs.
4
- import { createHash } from 'node:crypto';
5
- import { existsSync, readdirSync, realpathSync, statSync } from 'node:fs';
6
- import { basename, resolve } from 'node:path';
7
4
  import { ApiError } from '../../../api/index.js';
8
- import { readPageFeedback } from '../../../core/human/feedback.js';
9
- import { toPageFeedbackDTO } from '../map.js';
10
- import { pageManifestPath, reviewPath } from '../../../core/human/convention.js';
5
+ import { inboxPageProjection } from './inbox-page.js';
6
+ import { getRequestByInboxTicket } from '../../../core/human/requests.js';
11
7
  import { parsePage } from '../../../core/human/page.js';
12
- import { ticketsRoot } from '../../../core/human/root.js';
13
8
  import { scanInbox, scanPageHistory } from '../../../core/human/scan.js';
14
- import { readPageTicket, readTicketResult, validatePageTicketResponses, writePageProgress, } from '../../../core/human/tickets.js';
9
+ import { readPageTicket, readTicketResult, selectedPageDir, validatePageTicketResponses, writePageProgress, } from '../../../core/human/tickets.js';
15
10
  import { describePageAnswer } from '../../../core/human/answer.js';
16
11
  import { cancelHumanTicket, resolvePageTicket } from '../../human/finish.js';
17
- import { filterTerminalReviewTickets } from '../../../core/review/ticket-filter.js';
18
12
  const DEFAULT_CANCEL_REASON = 'Canceled from the inbox.';
19
13
  const CANCEL_REASON_MAX = 1000;
20
14
  const TICKET_ID_PATTERN = /^[a-f0-9]{64}$/;
21
- // Opaque ticket id resolution
22
- function ticketHash(canonicalRoot, ticketBasename) {
23
- return createHash('sha256').update(`${canonicalRoot}\0${ticketBasename}`, 'utf8').digest('hex');
24
- }
25
15
  /** Resolve one opaque inbox ticket id to its canonical directory. Shared with
26
16
  * the feedback-comment routes, which address tickets by the same ids. */
27
17
  export function resolveTicket(ticketId) {
28
- let canonicalRoot;
29
- try {
30
- canonicalRoot = realpathSync(ticketsRoot());
31
- }
32
- catch {
33
- return null;
34
- }
35
- let entries;
36
- try {
37
- entries = readdirSync(canonicalRoot);
38
- }
39
- catch {
40
- return null;
41
- }
42
- for (const entry of entries) {
43
- if (ticketHash(canonicalRoot, entry) !== ticketId)
44
- continue;
45
- const candidate = resolve(canonicalRoot, entry);
46
- let canonicalDir;
47
- try {
48
- if (!statSync(candidate).isDirectory())
49
- continue;
50
- canonicalDir = realpathSync(candidate);
51
- }
52
- catch {
53
- continue;
54
- }
55
- if (resolve(canonicalDir, '..') !== canonicalRoot || basename(canonicalDir) !== entry)
56
- continue;
57
- if (existsSync(pageManifestPath(canonicalDir)))
58
- return { ticketId: entry, dir: canonicalDir, kind: 'page' };
59
- if (existsSync(reviewPath(canonicalDir)))
60
- return { ticketId: entry, dir: canonicalDir, kind: 'review' };
61
- }
62
- return null;
18
+ const request = getRequestByInboxTicket(ticketId);
19
+ return request === null ? null : { ticketId: request.request_id, dir: request.request_dir, kind: request.kind };
63
20
  }
64
21
  export function requireTicketId(params) {
65
22
  const ticketId = params['ticket_id'];
@@ -69,49 +26,6 @@ export function requireTicketId(params) {
69
26
  return ticketId;
70
27
  }
71
28
  // Projections — humanloop canonical shapes → wire DTOs
72
- function pageSlotToDTO(slot) {
73
- const dto = {
74
- kind: slot.kind,
75
- step: slot.step,
76
- config: slot.config,
77
- };
78
- if (slot.id !== undefined)
79
- dto.id = slot.id;
80
- if (slot.unvalidated === true)
81
- dto.unvalidated = true;
82
- if (slot.display === true)
83
- dto.display = true;
84
- return dto;
85
- }
86
- function pageManifestToDTO(manifest) {
87
- const dto = {
88
- schema: 'crtr.page/v2',
89
- dialect: manifest.dialect,
90
- title: manifest.title,
91
- delivery: manifest.delivery,
92
- document: manifest.document,
93
- steps: manifest.steps,
94
- slots: manifest.slots.map(pageSlotToDTO),
95
- };
96
- if (manifest.subtitle !== undefined)
97
- dto.subtitle = manifest.subtitle;
98
- if (manifest.source !== undefined) {
99
- const source = {};
100
- if (manifest.source.sessionName !== undefined)
101
- source.sessionName = manifest.source.sessionName;
102
- if (manifest.source.askedBy !== undefined)
103
- source.askedBy = manifest.source.askedBy;
104
- if (manifest.source.emittedAt !== undefined)
105
- source.emittedAt = manifest.source.emittedAt;
106
- if (manifest.source.profileName !== undefined)
107
- source.profileName = manifest.source.profileName;
108
- if (manifest.source.nodeId !== undefined)
109
- source.nodeId = manifest.source.nodeId;
110
- if (Object.keys(source).length > 0)
111
- dto.source = source;
112
- }
113
- return dto;
114
- }
115
29
  function isPlainObject(value) {
116
30
  return typeof value === 'object' && value !== null && !Array.isArray(value);
117
31
  }
@@ -164,9 +78,11 @@ function isSlotValidationError(err) {
164
78
  }
165
79
  // GET /v1/human/inbox — enumerate
166
80
  /** The one page-summary projection: the pending list and the per-node history differ only in which tickets they walk. */
167
- function pageSummaryToDTO(item, canonicalRoot) {
81
+ function pageSummaryToDTO(item) {
168
82
  const dto = {
169
- ticket_id: createHash('sha256').update(`${canonicalRoot}\0${item.id}`, 'utf8').digest('hex'),
83
+ request_id: item.id,
84
+ request_dir: item.dir,
85
+ ticket_id: item.inboxTicketId,
170
86
  kind: 'page',
171
87
  title: item.title,
172
88
  placement: item.placement,
@@ -191,16 +107,15 @@ function pageSummaryToDTO(item, canonicalRoot) {
191
107
  return dto;
192
108
  }
193
109
  function handleList() {
194
- const allItems = scanInbox();
195
- const filtered = filterTerminalReviewTickets(allItems);
196
- const canonicalRoot = realpathSync(ticketsRoot());
197
- const tickets = filtered.map((item) => {
110
+ const tickets = scanInbox().map((item) => {
198
111
  if (item.kind === 'page') {
199
- return pageSummaryToDTO(item, canonicalRoot);
112
+ return pageSummaryToDTO(item);
200
113
  }
201
114
  else if (item.kind === 'review') {
202
115
  return {
203
- ticket_id: createHash('sha256').update(`${canonicalRoot}\0${item.id}`, 'utf8').digest('hex'),
116
+ request_id: item.id,
117
+ request_dir: item.dir,
118
+ ticket_id: item.inboxTicketId,
204
119
  kind: 'review',
205
120
  title: item.title,
206
121
  subtitle: item.subtitle,
@@ -224,8 +139,7 @@ function handleHistory(ctx) {
224
139
  throw new ApiError(400, 'invalid_request', 'node_id must be nonempty when present');
225
140
  }
226
141
  const history = scanPageHistory(nodeId ?? undefined);
227
- const canonicalRoot = realpathSync(ticketsRoot());
228
- const tickets = history.map((item) => pageSummaryToDTO(item, canonicalRoot));
142
+ const tickets = history.map(pageSummaryToDTO);
229
143
  return { status: 200, body: { tickets } };
230
144
  }
231
145
  // GET /v1/human/inbox/:ticket_id — read a page ticket
@@ -237,28 +151,15 @@ function handleGetPage(ctx) {
237
151
  if (resolved.kind === 'review') {
238
152
  throw new ApiError(409, 'ticket_kind_unsupported', 'review tickets have no page read operation');
239
153
  }
240
- let ticket;
154
+ const request = getRequestByInboxTicket(ticketId);
155
+ if (request === null || request.kind !== 'page')
156
+ throw new ApiError(404, 'ticket_not_found', 'no matching ticket');
241
157
  try {
242
- ticket = readPageTicket(resolved.dir);
158
+ return { status: 200, body: inboxPageProjection(request) };
243
159
  }
244
- catch (err) {
160
+ catch {
245
161
  throw new ApiError(500, 'internal', 'the ticket could not be read');
246
162
  }
247
- const progress = ticket.progress;
248
- const progressDTO = progress === null ? null : { responses: progress };
249
- return {
250
- status: 200,
251
- body: {
252
- ticket_id: ticketId,
253
- kind: 'page',
254
- state: ticket.state,
255
- page: pageManifestToDTO(ticket.manifest),
256
- document: ticket.manifest.dialect === 'jsx' ? ticket.module : ticket.document,
257
- document_media_type: ticket.manifest.dialect === 'jsx' ? 'text/jsx' : 'text/html',
258
- progress: progressDTO,
259
- feedback: toPageFeedbackDTO(readPageFeedback(resolved.dir)),
260
- },
261
- };
262
163
  }
263
164
  // POST /v1/human/inbox/:ticket_id/respond — submit
264
165
  async function handleRespond(ctx) {
@@ -382,7 +283,7 @@ function handleGetResponse(ctx) {
382
283
  throw new ApiError(409, 'ticket_kind_mismatch', 'unexpected result kind');
383
284
  }
384
285
  try {
385
- const manifest = parsePage(resolved.dir);
286
+ const manifest = parsePage(selectedPageDir(resolved.dir));
386
287
  return { status: 200, body: { ...result, answer: describePageAnswer(manifest, result.responses, { completedAt: result.completedAt }) } };
387
288
  }
388
289
  catch {
@@ -1,2 +1,3 @@
1
1
  import type { RouteTable } from '../router.js';
2
+ export declare const brokerMailRoutes: RouteTable;
2
3
  export declare const messageRoutes: RouteTable;
@@ -2,7 +2,9 @@
2
2
  // inbox message now (201) or fresh-revives with no inbox entry. `{id}` is the
3
3
  // target node.
4
4
  import { join } from 'node:path';
5
- import { appendInbox, cancelPendingHumanMessages } from '../../../core/feed/inbox.js';
5
+ import { claimNodeMail, acknowledgeNodeMail } from '../../../core/canvas/deliveries.js';
6
+ import { nodeMailEntry } from '../../../core/feed/inbox.js';
7
+ import { enqueueNodeMail, cancelPendingNodeMail } from '../../../core/feed/messages.js';
6
8
  import { reviveNode } from '../../../core/runtime/revive.js';
7
9
  import { BrokerUnreachableError } from '../../../core/runtime/broker-request.js';
8
10
  import { isBrokerLive } from '../../../core/runtime/model-swap.js';
@@ -319,23 +321,25 @@ async function handleMessage(ctx) {
319
321
  const messageBody = hasBody
320
322
  ? req.body
321
323
  : 'A one-off structured-output request has been granted. Submit a result matching the requested schema with `crtr push result` before you stop; after it is accepted, continue normally.';
322
- return appendInbox(id, {
323
- from,
324
- tier,
324
+ return enqueueNodeMail(id, {
325
+ senderNodeId: from,
326
+ urgency: tier,
327
+ wake: 1,
325
328
  kind: 'message',
326
329
  label: label(messageBody),
327
- data: { body: messageBody, ...(hasSidecar ? { situational: true } : {}), ...cardData },
330
+ bodyJson: { body: messageBody, ...(hasSidecar ? { situational: true } : {}), ...cardData },
328
331
  });
329
332
  }
330
333
  // Context-only: a hidden wake marker excluded from the visible digest. Its
331
334
  // one-shot cards have no visible delivery to ride, so the watcher's context
332
335
  // channel carries them.
333
- return appendInbox(id, {
334
- from,
335
- tier,
336
+ return enqueueNodeMail(id, {
337
+ senderNodeId: from,
338
+ urgency: tier,
339
+ wake: 1,
336
340
  kind: 'message',
337
341
  label: hasSidecar ? '(ambient context updated)' : '(context delivered)',
338
- data: { ...(hasSidecar ? { situational: true } : {}), situationalOnly: true, ...cardData },
342
+ bodyJson: { ...(hasSidecar ? { situational: true } : {}), situationalOnly: true, ...cardData },
339
343
  });
340
344
  };
341
345
  // Deferred guard: a done/canceled/finalized target has no natural
@@ -364,14 +368,14 @@ async function handleMessage(ctx) {
364
368
  // Wake-capable durable mail wins the same park-completion boundary as a live
365
369
  // broker input. A completion that won before this append is handled by the
366
370
  // fresh row read below, which revives the now-parked node.
367
- if (entry.tier !== 'deferred')
371
+ if (entry.urgency !== 'deferred')
368
372
  withCanvasWrite(() => recordPendingParkActivity(id));
369
373
  const current = getNode(id);
370
374
  if (current === null)
371
375
  throw notFound(`unknown node: ${id}`, { received: id });
372
376
  // Deferred mail normally waits for a natural cycle, but a frozen row already
373
377
  // owes a thaw; consume its deadline when that durable future wake arrives.
374
- if (entry.tier !== 'deferred' || meta.frozen_at !== null)
378
+ if (meta.frozen_at !== null)
375
379
  cancelCronsOnWake(id);
376
380
  // A wake-capable entry for an active or idle target is admitted by the
377
381
  // lifecycle tick. Reopen delivery preserves this handler's synchronous wake
@@ -380,7 +384,7 @@ async function handleMessage(ctx) {
380
384
  let revived = false;
381
385
  let frozen = false;
382
386
  const needsSynchronousWake = req.reopen || current.lifecycle === 'terminal' || !wantsExecution(current);
383
- if (needsSynchronousWake && entry.tier !== 'deferred' && !paused && !isBrokerLive(current)) {
387
+ if (needsSynchronousWake && entry.urgency !== 'deferred' && !paused && !isBrokerLive(current)) {
384
388
  try {
385
389
  // The entry is already durable, so a wake denied for capacity is only
386
390
  // delayed: the row freezes and the tick relaunches it — at which point
@@ -398,8 +402,8 @@ async function handleMessage(ctx) {
398
402
  delivered: true,
399
403
  revived,
400
404
  ...(frozen ? { not_revived_reason: 'capacity_frozen' } : {}),
401
- delivered_at: entry.ts,
402
- ...(entry.tier === tier ? {} : { delivered_tier: entry.tier }),
405
+ delivered_at: entry.createdAt,
406
+ ...(entry.urgency === tier ? {} : { delivered_tier: entry.urgency }),
403
407
  ...(req.delivery === 'interactive' ? { delivered_via: 'inbox' } : {}),
404
408
  };
405
409
  return { status: 201, body };
@@ -417,7 +421,7 @@ async function handleInterrupt(ctx) {
417
421
  // 1. Boot-window close: mark undelivered human-send inbox entries canceled so
418
422
  // a send riding the durable path (dormant target / mid-revive fallback) is
419
423
  // never injected after the Esc — the watcher skips canceled entries.
420
- const canceled = cancelPendingHumanMessages(id);
424
+ const canceled = cancelPendingNodeMail(id, { senderNodeId: 'human', kind: 'message' });
421
425
  // 2. Abort whatever is live. The broker acks once processed; on its single
422
426
  // frame loop that ack also implies every earlier-accepted deliver was
423
427
  // already routed, so a just-started turn is caught, not missed.
@@ -442,6 +446,60 @@ async function handleInterrupt(ctx) {
442
446
  };
443
447
  return { status: 200, body };
444
448
  }
449
+ function mailBody(ctx) {
450
+ if (typeof ctx.body !== 'object' || ctx.body === null || Array.isArray(ctx.body))
451
+ throw usage('mail requires an object body');
452
+ const body = ctx.body;
453
+ if (typeof body['execution_id'] !== 'string' || body['execution_id'].trim() === '')
454
+ throw usage('execution_id is required');
455
+ return body;
456
+ }
457
+ function handleMailClaim(ctx) {
458
+ const body = mailBody(ctx);
459
+ const channel = body['channel'];
460
+ if (channel !== 'wake' && channel !== 'passive')
461
+ throw usage('channel must be wake or passive');
462
+ const result = claimNodeMail(ctx.params['id'], body['execution_id'], channel);
463
+ const projected = {
464
+ action: result.action,
465
+ deliveries: result.deliveries.map((delivery) => ({
466
+ delivery_id: delivery.deliveryId,
467
+ attempts: delivery.attempts,
468
+ handoff: delivery.handoff,
469
+ entry: nodeMailEntry(delivery),
470
+ })),
471
+ };
472
+ return { status: 200, body: projected };
473
+ }
474
+ function handleMailAcknowledge(ctx) {
475
+ const body = mailBody(ctx);
476
+ if (!Array.isArray(body['deliveries']))
477
+ throw usage('deliveries must be an array');
478
+ const receipts = body['deliveries'].map((value) => {
479
+ if (typeof value !== 'object' || value === null || Array.isArray(value))
480
+ throw usage('each delivery must be an object');
481
+ const receipt = value;
482
+ if (typeof receipt['delivery_id'] !== 'string' || receipt['delivery_id'] === '')
483
+ throw usage('delivery_id is required');
484
+ if (!Number.isSafeInteger(receipt['attempts']) || receipt['attempts'] < 1)
485
+ throw usage('attempts must be a positive integer');
486
+ if (receipt['disposition'] !== 'acknowledged' && receipt['disposition'] !== 'released')
487
+ throw usage('disposition must be acknowledged or released');
488
+ return { delivery_id: receipt['delivery_id'], attempts: receipt['attempts'], disposition: receipt['disposition'] };
489
+ });
490
+ const result = acknowledgeNodeMail(ctx.params['id'], body['execution_id'], receipts.map((receipt) => ({
491
+ deliveryId: receipt.delivery_id, attempts: receipt.attempts, disposition: receipt.disposition,
492
+ })));
493
+ const projected = {
494
+ action: result.action,
495
+ results: result.results.map((result) => ({ delivery_id: result.deliveryId, outcome: result.outcome })),
496
+ };
497
+ return { status: 200, body: projected };
498
+ }
499
+ export const brokerMailRoutes = [
500
+ { method: 'POST', pattern: '/v1/nodes/:id/mail/claim', handler: handleMailClaim },
501
+ { method: 'POST', pattern: '/v1/nodes/:id/mail/acknowledge', handler: handleMailAcknowledge },
502
+ ];
445
503
  export const messageRoutes = [
446
504
  { method: 'POST', pattern: '/v1/nodes/:id/messages', handler: handleMessage },
447
505
  { method: 'POST', pattern: '/v1/nodes/:id/interrupt', handler: handleInterrupt },