@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,27 +1,20 @@
1
- // Durable programmatic human requests — crtrd `/v1/human/requests`. A request
2
- // is an ordinary page ticket with an optional frozen completion action, so it
3
- // is the same record the inbox lists, answers, and dismisses. Creation is the
4
- // only surface that writes the action binding; every settlement path funnels
5
- // through the shared first-writer-wins store.
6
- import { randomBytes } from 'node:crypto';
7
1
  import { statSync } from 'node:fs';
8
- import { basename, isAbsolute } from 'node:path';
2
+ import { isAbsolute } from 'node:path';
9
3
  import { ApiError } from '../../../api/index.js';
10
- import { readActionDelivery } from '../../../core/canvas/human-deliveries.js';
4
+ import { readExternalActionDelivery } from '../../../core/canvas/deliveries.js';
5
+ import { isSafeNodeId } from '../../../core/canvas/paths.js';
11
6
  import { resolvePageComponents } from '../../../core/config.js';
12
7
  import { resolveHumanAction } from '../../../core/human-actions.js';
13
- import { HUMAN_ACTION_NAME_PATTERN, publishTicketActionBinding, readTicketActionBinding, } from '../../../core/human/action-binding.js';
14
- import { completionEventFor } from '../../../core/human/completion.js';
15
- import { parsePage } from '../../../core/human/page.js';
16
- import { opaqueInboxTicketId, ticketDir } from '../../../core/human/root.js';
17
- import { preparePageSource, publishPage, readPageTicket, readTicketResult, validatePageTicketResponses, } from '../../../core/human/tickets.js';
8
+ import { HUMAN_ACTION_NAME_PATTERN } from '../../../core/human/action-binding.js';
9
+ import { createPageRequest, getRequest } from '../../../core/human/requests.js';
10
+ import { preparePageSource } from '../../../core/human/page-authoring.js';
11
+ import { publishPage, validatePageTicketResponses } from '../../../core/human/tickets.js';
18
12
  import { cancelHumanTicket, resolvePageTicket } from '../../human/finish.js';
19
- import { resolveTicket, requireTicketId } from './inbox.js';
13
+ import { inboxPageProjection } from './inbox-page.js';
20
14
  const REASON_MAX = 1000;
21
15
  const ACTOR_MAX = 200;
22
16
  const DEFAULT_DELIVERY = { placement: 'inline', inbox: true, reply: false };
23
17
  const SOURCE_FIELDS = ['sessionName', 'askedBy', 'emittedAt', 'profileName', 'nodeId'];
24
- // Body validation
25
18
  function isPlainObject(value) {
26
19
  return typeof value === 'object' && value !== null && !Array.isArray(value);
27
20
  }
@@ -31,39 +24,39 @@ function requireNoExtraKeys(obj, allowed, where) {
31
24
  throw new ApiError(400, 'invalid_request', `unexpected field in ${where}: ${key}`);
32
25
  }
33
26
  }
34
- function invalid(message) {
35
- return new ApiError(400, 'invalid_request', message);
36
- }
27
+ function invalid(message) { return new ApiError(400, 'invalid_request', message); }
37
28
  function validatePage(raw) {
38
29
  if (!isPlainObject(raw))
39
30
  throw invalid('`page` must be an object');
40
31
  requireNoExtraKeys(raw, ['dialect', 'source'], '`page`');
41
- const dialect = raw['dialect'];
42
- if (dialect !== 'jsx' && dialect !== 'html')
32
+ if (raw['dialect'] !== 'jsx' && raw['dialect'] !== 'html')
43
33
  throw invalid('`page.dialect` must be "jsx" or "html"');
44
- const source = raw['source'];
45
- if (typeof source !== 'string' || source.trim() === '')
34
+ if (typeof raw['source'] !== 'string' || raw['source'].trim() === '')
46
35
  throw invalid('`page.source` must be the authored page text');
47
- return { dialect, source };
36
+ return { dialect: raw['dialect'], source: raw['source'] };
37
+ }
38
+ function validatePlacement(raw, fallback) {
39
+ const placement = raw ?? fallback;
40
+ if (placement !== 'inline' && placement !== 'panel')
41
+ throw invalid('`delivery.placement` must be "inline" or "panel"');
42
+ return placement;
48
43
  }
49
- /** Creation pins a programmatic request to the inbox with no bridge to reply to. */
50
- function validateCreateDelivery(raw) {
44
+ function validateCreateDelivery(raw, requesterNodeId) {
51
45
  if (raw === undefined)
52
46
  return DEFAULT_DELIVERY;
53
47
  if (!isPlainObject(raw))
54
48
  throw invalid('`delivery` must be an object');
55
49
  requireNoExtraKeys(raw, ['placement', 'inbox', 'reply'], '`delivery`');
56
- const placement = validatePlacement(raw['placement'], DEFAULT_DELIVERY.placement);
57
- const inbox = raw['inbox'] ?? true;
58
- const reply = raw['reply'] ?? false;
59
- if (inbox !== true)
60
- throw invalid('`delivery.inbox` must be true: a programmatic request must stay answerable');
61
- if (reply !== false)
62
- throw invalid('`delivery.reply` must be false: a programmatic request has no agent bridge to reply to');
63
- return { placement, inbox: true, reply: false };
50
+ const inbox = raw['inbox'] ?? DEFAULT_DELIVERY.inbox;
51
+ const reply = raw['reply'] ?? DEFAULT_DELIVERY.reply;
52
+ if (typeof inbox !== 'boolean')
53
+ throw invalid('`delivery.inbox` must be boolean');
54
+ if (typeof reply !== 'boolean')
55
+ throw invalid('`delivery.reply` must be boolean');
56
+ if (reply && requesterNodeId === null)
57
+ throw invalid('`delivery.reply` requires `requester_node_id`');
58
+ return { placement: validatePlacement(raw['placement'], DEFAULT_DELIVERY.placement), inbox, reply };
64
59
  }
65
- /** Replace re-presents a pending page; where the ticket is routed is fixed at
66
- * creation, so only placement is replaceable. */
67
60
  function validateReplaceDelivery(raw, prior) {
68
61
  if (raw === undefined)
69
62
  return prior;
@@ -72,12 +65,6 @@ function validateReplaceDelivery(raw, prior) {
72
65
  requireNoExtraKeys(raw, ['placement'], '`delivery`');
73
66
  return { ...prior, placement: validatePlacement(raw['placement'], prior.placement) };
74
67
  }
75
- function validatePlacement(raw, fallback) {
76
- const placement = raw ?? fallback;
77
- if (placement !== 'inline' && placement !== 'panel')
78
- throw invalid('`delivery.placement` must be "inline" or "panel"');
79
- return placement;
80
- }
81
68
  function validateSource(raw) {
82
69
  if (raw === undefined)
83
70
  return undefined;
@@ -117,40 +104,43 @@ function validateActionSelection(raw) {
117
104
  if (!isPlainObject(raw))
118
105
  throw invalid('`action` must be an object');
119
106
  requireNoExtraKeys(raw, ['name', 'payload'], '`action`');
120
- const name = raw['name'];
121
- if (typeof name !== 'string' || !HUMAN_ACTION_NAME_PATTERN.test(name)) {
107
+ if (typeof raw['name'] !== 'string' || !HUMAN_ACTION_NAME_PATTERN.test(raw['name']))
122
108
  throw invalid('`action.name` must be a declared action name');
123
- }
124
- // The completion document always carries `action.payload`, so an omitted one
125
- // is normalized here rather than serialized away downstream.
126
- return { name, payload: raw['payload'] ?? null };
109
+ return { name: raw['name'], payload: raw['payload'] ?? null };
110
+ }
111
+ function validateRequesterNodeId(raw) {
112
+ if (raw === undefined || raw === null)
113
+ return null;
114
+ if (typeof raw !== 'string' || !isSafeNodeId(raw))
115
+ throw invalid('`requester_node_id` must be a safe node id or null');
116
+ return raw;
127
117
  }
128
118
  function validateCreateRequest(raw) {
129
119
  if (!isPlainObject(raw))
130
120
  throw invalid('request body is required');
131
- requireNoExtraKeys(raw, ['page', 'delivery', 'source', 'creator_cwd', 'action'], 'the request body');
121
+ requireNoExtraKeys(raw, ['page', 'delivery', 'source', 'requester_node_id', 'creator_cwd', 'action'], 'the request body');
132
122
  const source = validateSource(raw['source']);
123
+ const requesterNodeId = validateRequesterNodeId(raw['requester_node_id']);
133
124
  const action = validateActionSelection(raw['action']);
134
125
  return {
135
126
  page: validatePage(raw['page']),
136
- delivery: validateCreateDelivery(raw['delivery']),
127
+ delivery: validateCreateDelivery(raw['delivery'], requesterNodeId),
137
128
  ...(source === undefined ? {} : { source }),
129
+ requesterNodeId,
138
130
  creatorCwd: validateCreatorCwd(raw['creator_cwd']),
139
131
  ...(action === undefined ? {} : { action }),
140
132
  };
141
133
  }
142
- function validateReplaceRequest(raw, priorDelivery) {
134
+ function validateReplaceRequest(raw, prior) {
143
135
  if (!isPlainObject(raw))
144
136
  throw invalid('request body is required');
145
137
  requireNoExtraKeys(raw, ['page', 'delivery'], 'the request body');
146
- return { page: validatePage(raw['page']), delivery: validateReplaceDelivery(raw['delivery'], priorDelivery) };
138
+ return { page: validatePage(raw['page']), delivery: validateReplaceDelivery(raw['delivery'], prior) };
147
139
  }
148
140
  function optionalBoundedString(raw, field, max) {
149
141
  if (raw === undefined)
150
142
  return undefined;
151
- if (typeof raw !== 'string')
152
- throw invalid(`\`${field}\` must be a string`);
153
- if (raw.trim() === '' || raw.length > max)
143
+ if (typeof raw !== 'string' || raw.trim() === '' || raw.length > max)
154
144
  throw invalid(`\`${field}\` must be nonempty after trim and at most ${max} characters`);
155
145
  return raw;
156
146
  }
@@ -173,92 +163,111 @@ function validateSettleRequest(raw) {
173
163
  const actor = optionalBoundedString(raw['actor'], 'actor', ACTOR_MAX);
174
164
  return { ...(reason === undefined ? {} : { reason }), ...(actor === undefined ? {} : { actor }) };
175
165
  }
176
- function resolveRequest(ctx) {
177
- const requestId = requireTicketId({ ticket_id: ctx.params['request_id'] ?? '' });
178
- const resolved = resolveTicket(requestId);
179
- if (resolved === null || resolved.kind !== 'page')
166
+ function requestId(ctx) {
167
+ const id = ctx.params['request_id'];
168
+ if (typeof id !== 'string' || id === '')
169
+ throw invalid('request id is required');
170
+ return id;
171
+ }
172
+ function requirePageRequest(id) {
173
+ const request = getRequest(id);
174
+ if (request === null || request.kind !== 'page')
180
175
  throw new ApiError(404, 'not_found', 'no request with that id');
181
- let manifest;
176
+ return request;
177
+ }
178
+ function manifest(request) {
182
179
  try {
183
- manifest = parsePage(resolved.dir);
180
+ const value = JSON.parse(request.specification_json);
181
+ if (!isPlainObject(value))
182
+ throw new Error('not an object');
183
+ return value;
184
184
  }
185
185
  catch {
186
- throw new ApiError(500, 'internal', 'the request could not be read');
186
+ throw new ApiError(500, 'internal', 'the request specification could not be read');
187
187
  }
188
- return {
189
- requestId,
190
- ticketId: resolved.ticketId,
191
- dir: resolved.dir,
192
- manifest,
193
- result: readTicketResult(resolved.dir),
194
- binding: readTicketActionBinding(resolved.dir),
195
- };
196
188
  }
197
- function requestState(result) {
198
- if (result === null)
189
+ function terminalResult(request) {
190
+ if (request.result_json === null)
191
+ return null;
192
+ try {
193
+ return JSON.parse(request.result_json);
194
+ }
195
+ catch {
196
+ throw new ApiError(500, 'internal', 'the request result could not be read');
197
+ }
198
+ }
199
+ function frozenAction(request) {
200
+ if (request.action_json === null)
201
+ return null;
202
+ try {
203
+ const action = JSON.parse(request.action_json);
204
+ if (action.schema !== 'crtr.human-action-binding/v1' || typeof action.name !== 'string')
205
+ throw new Error('invalid action');
206
+ return action;
207
+ }
208
+ catch {
209
+ throw new ApiError(500, 'internal', 'the request action could not be read');
210
+ }
211
+ }
212
+ function requestState(request) {
213
+ if (request.state !== 'settled')
199
214
  return 'pending';
200
- if (result.kind === 'canceled')
201
- return completionEventFor(result);
202
- return 'answered';
215
+ return request.outcome === 'answered' ? 'answered' : request.outcome === 'dismissed' ? 'dismissed' : 'canceled';
203
216
  }
204
- function deliveryDetail(row) {
205
- if (row === null)
217
+ function deliveryDetail(request) {
218
+ if (request.action_delivery_id === null)
206
219
  return { state: 'none', attempt: 0 };
207
- const detail = { state: row.state, attempt: row.attempt };
208
- // A next attempt is only meaningful for a pending retry; the enqueue instant
209
- // of an untried delivery says nothing a client can act on.
210
- if (row.state === 'pending' && row.lastFailure !== null)
211
- detail.next_attempt_at = new Date(row.nextAttemptAt).toISOString();
212
- if (row.acceptedAt !== null)
213
- detail.accepted_at = new Date(row.acceptedAt).toISOString();
214
- if (row.permanentFailedAt !== null)
215
- detail.permanent_failed_at = new Date(row.permanentFailedAt).toISOString();
216
- if (row.lastFailure !== null) {
217
- const failure = row.lastFailure;
218
- detail.last_failure = {
219
- kind: failure.kind,
220
- ...(failure.exitCode === undefined ? {} : { exit_code: failure.exitCode }),
221
- ...(failure.signal === undefined ? {} : { signal: failure.signal }),
222
- ...(failure.message === undefined ? {} : { message: failure.message }),
223
- ...(failure.stderr === undefined ? {} : { stderr: failure.stderr }),
224
- };
225
- }
220
+ const delivery = readExternalActionDelivery(`human-action:${request.inbox_ticket_id}`);
221
+ if (delivery === null)
222
+ return { state: 'none', attempt: 0 };
223
+ const state = delivery.state === 'acknowledged' ? 'accepted' : delivery.state === 'permanent_failed' ? 'permanent_failed' : delivery.state === 'handed_off' ? 'running' : 'pending';
224
+ const detail = { state, attempt: delivery.attempts };
225
+ if (state === 'pending' && delivery.nextAttemptAt !== null)
226
+ detail.next_attempt_at = new Date(delivery.nextAttemptAt).toISOString();
227
+ if (delivery.acknowledgedAt !== null)
228
+ detail.accepted_at = new Date(delivery.acknowledgedAt).toISOString();
229
+ if (delivery.failedAt !== null)
230
+ detail.permanent_failed_at = new Date(delivery.failedAt).toISOString();
231
+ if (delivery.lastFailure !== null)
232
+ detail.last_failure = delivery.lastFailure;
226
233
  return detail;
227
234
  }
228
235
  function requestToDTO(request) {
229
- const { manifest, result, binding } = request;
230
- const emittedAt = manifest.source?.emittedAt;
231
- if (emittedAt === undefined)
232
- throw new ApiError(500, 'internal', 'the request carries no emitted time');
233
- const state = requestState(result);
236
+ const page = manifest(request);
237
+ const result = terminalResult(request);
238
+ const state = requestState(request);
234
239
  const dto = {
235
- request_id: request.requestId,
240
+ request_id: request.request_id,
241
+ inbox_ticket_id: request.inbox_ticket_id,
242
+ request_dir: request.request_dir,
243
+ kind: request.kind,
236
244
  state,
237
- title: manifest.title,
238
- source: manifest.source ?? {},
239
- emitted_at: emittedAt,
245
+ title: request.title,
246
+ source: page.source ?? {},
247
+ emitted_at: page.source?.emittedAt ?? request.created_at,
240
248
  };
241
- if (manifest.subtitle !== undefined)
242
- dto.subtitle = manifest.subtitle;
249
+ if (request.subtitle !== null)
250
+ dto.subtitle = request.subtitle;
251
+ if (request.kind === 'page')
252
+ dto.page = inboxPageProjection(request);
243
253
  if (result !== null) {
244
- dto.settled_at = result.kind === 'canceled' ? result.canceledAt : result.completedAt;
245
- // Never fabricated for a dismissal or a withdrawal: only an answer has responses.
246
- if (state === 'answered' && result.kind === 'page')
254
+ dto.settled_at = request.settled_at ?? request.updated_at;
255
+ if (result.kind === 'page' && state === 'answered')
247
256
  dto.responses = result.responses;
248
257
  if (result.kind === 'canceled' && result.reason !== undefined)
249
258
  dto.reason = result.reason;
250
- const actor = result.kind === 'review' ? undefined : result.actor;
251
- if (actor !== undefined)
252
- dto.actor = actor;
259
+ if (result.kind === 'page' && result.actor !== undefined)
260
+ dto.actor = result.actor;
261
+ if (result.kind === 'canceled' && result.actor !== undefined)
262
+ dto.actor = result.actor;
253
263
  }
254
- if (binding !== null) {
255
- dto.action = { name: binding.name, payload: binding.payload };
256
- dto.delivery = deliveryDetail(readActionDelivery(request.requestId));
264
+ const action = frozenAction(request);
265
+ if (action !== null) {
266
+ dto.action = { name: action.name, payload: action.payload };
267
+ dto.delivery = deliveryDetail(request);
257
268
  }
258
269
  return dto;
259
270
  }
260
- // POST /v1/human/requests — create
261
- /** Authoring failure is the caller's malformed page, never a server fault. */
262
271
  function prepareOrReject(dialect, document, source, delivery) {
263
272
  try {
264
273
  return preparePageSource({ dialect, document, source, delivery, productKinds: resolvePageComponents() });
@@ -269,9 +278,7 @@ function prepareOrReject(dialect, document, source, delivery) {
269
278
  }
270
279
  function handleCreate(ctx) {
271
280
  const request = validateCreateRequest(ctx.body);
272
- // Action resolution precedes every write: a rejected action must leave no
273
- // inbox row for a human to answer.
274
- let resolvedAction;
281
+ let actionJson;
275
282
  if (request.action !== undefined) {
276
283
  const resolution = resolveHumanAction(request.action.name, request.creatorCwd);
277
284
  if ('kind' in resolution) {
@@ -280,120 +287,93 @@ function handleCreate(ctx) {
280
287
  : `${resolution.name} is declared in ${resolution.configOrigin} but unusable: ${resolution.reason}`;
281
288
  throw new ApiError(400, resolution.kind, detail);
282
289
  }
283
- resolvedAction = resolution;
284
- }
285
- const prepared = prepareOrReject(request.page.dialect, request.page.source, request.source, request.delivery);
286
- const dir = ticketDir(`page-${randomBytes(8).toString('hex')}`);
287
- // The binding is written before the page exists, so a visible request is
288
- // never momentarily unbound and `replace` can never reach the approved effect.
289
- if (request.action !== undefined && resolvedAction !== undefined) {
290
- publishTicketActionBinding(dir, {
291
- schema: 'crtr.human-action-binding/v1',
292
- name: request.action.name,
293
- payload: request.action.payload,
294
- creatorCwd: request.creatorCwd,
295
- configOrigin: resolvedAction.configOrigin,
296
- argv: resolvedAction.argv,
297
- cwd: resolvedAction.cwd,
290
+ actionJson = JSON.stringify({
291
+ schema: 'crtr.human-action-binding/v1', name: request.action.name, payload: request.action.payload,
292
+ creatorCwd: request.creatorCwd, configOrigin: resolution.configOrigin, argv: resolution.argv, cwd: resolution.cwd,
298
293
  });
299
294
  }
300
- const published = publishPage(dir, prepared);
295
+ const prepared = prepareOrReject(request.page.dialect, request.page.source, request.source, request.delivery);
296
+ const created = createPageRequest({
297
+ prepared,
298
+ requester_node_id: request.requesterNodeId,
299
+ ...(actionJson === undefined ? {} : { action_json: actionJson }),
300
+ });
301
301
  return {
302
302
  status: 201,
303
- body: {
304
- request_id: opaqueInboxTicketId(basename(published.dir)),
305
- state: 'pending',
306
- ...(request.action === undefined ? {} : { action: { name: request.action.name } }),
307
- delivery_state: 'none',
308
- },
303
+ body: { request_id: created.request_id, request_dir: created.request_dir, state: 'pending', ...(request.action === undefined ? {} : { action: { name: request.action.name } }), delivery_state: 'none' },
309
304
  };
310
305
  }
311
- // GET /v1/human/requests/:request_id — read
312
306
  function handleGet(ctx) {
313
- return { status: 200, body: requestToDTO(resolveRequest(ctx)) };
307
+ return { status: 200, body: requestToDTO(requirePageRequest(requestId(ctx))) };
314
308
  }
315
- // POST /v1/human/requests/:request_id/replace — revise the pending page
316
309
  function handleReplace(ctx) {
317
- const request = resolveRequest(ctx);
318
- if (request.result !== null)
310
+ const request = requirePageRequest(requestId(ctx));
311
+ if (request.state === 'settled')
319
312
  throw new ApiError(409, 'already_settled', 'the request already has a terminal result');
320
- const body = validateReplaceRequest(ctx.body, request.manifest.delivery);
321
- // Identity and provenance are the creation's, verbatim — a revision changes
322
- // only what is on screen, never who asked or when.
323
- const prepared = prepareOrReject(body.page.dialect, body.page.source, request.manifest.source, body.delivery);
324
- publishPage(request.dir, prepared);
325
- return { status: 200, body: requestToDTO({ ...request, manifest: prepared.manifest }) };
313
+ const page = manifest(request);
314
+ const body = validateReplaceRequest(ctx.body, page.delivery);
315
+ const prepared = prepareOrReject(body.page.dialect, body.page.source, page.source, body.delivery);
316
+ try {
317
+ publishPage(request.request_dir, prepared);
318
+ }
319
+ catch (error) {
320
+ if (error instanceof Error && error.message === `page request is not open: ${request.request_id}`) {
321
+ throw new ApiError(409, 'already_settled', 'the request already has a terminal result');
322
+ }
323
+ throw error;
324
+ }
325
+ return { status: 200, body: requestToDTO(requirePageRequest(request.request_id)) };
326
326
  }
327
- // Settlement — respond, dismiss, cancel
328
- /** The settlement funnels speak the inbox's error vocabulary; requests speak
329
- * the wire contract's. This is the one translation. */
330
327
  function settlementError(error) {
331
- if (error instanceof ApiError) {
332
- if (error.code === 'ticket_already_resolved')
333
- return new ApiError(409, 'already_settled', 'the request already has a terminal result');
334
- if (error.code === 'page_has_no_response_lifecycle')
335
- return new ApiError(409, 'not_settleable', 'this request carries no response lifecycle');
328
+ if (error instanceof ApiError)
336
329
  return error;
337
- }
338
- if (error instanceof Error && error.message === 'page_has_no_response_lifecycle') {
330
+ if (error instanceof Error && error.message.includes('unknown page request'))
331
+ return new ApiError(404, 'not_found', 'no request with that id');
332
+ if (error instanceof Error && error.message === 'page_has_no_response_lifecycle')
339
333
  return new ApiError(409, 'not_settleable', 'this request carries no response lifecycle');
340
- }
341
334
  return new ApiError(500, 'internal', 'the request could not be settled');
342
335
  }
343
336
  function requireSettleable(request) {
344
- if (request.result !== null)
337
+ if (request.state === 'settled')
345
338
  throw new ApiError(409, 'already_settled', 'the request already has a terminal result');
346
- if (readPageTicket(request.dir).state === 'passive') {
339
+ if (!request.settleable)
347
340
  throw new ApiError(409, 'not_settleable', 'this request carries no response lifecycle');
348
- }
349
341
  }
350
342
  async function handleRespond(ctx) {
351
- const request = resolveRequest(ctx);
343
+ const request = requirePageRequest(requestId(ctx));
352
344
  const body = validateRespondRequest(ctx.body);
353
345
  requireSettleable(request);
354
346
  try {
355
- validatePageTicketResponses(request.dir, body.responses);
347
+ validatePageTicketResponses(request.request_dir, body.responses);
356
348
  }
357
349
  catch (error) {
358
- // `requireSettleable` already refused a page with no response lifecycle, so
359
- // anything left here is the caller's response map.
360
350
  throw invalid(error instanceof Error ? error.message : 'the response map is invalid');
361
351
  }
362
- let result;
363
352
  try {
364
- result = await resolvePageTicket(request.ticketId, body.responses, body.actor === undefined ? {} : { actor: body.actor });
353
+ await resolvePageTicket(request.request_id, body.responses, body.actor === undefined ? {} : { actor: body.actor });
365
354
  }
366
355
  catch (error) {
367
356
  throw settlementError(error);
368
357
  }
369
- return { status: 200, body: requestToDTO({ ...request, result, binding: request.binding }) };
358
+ return { status: 200, body: requestToDTO(requirePageRequest(request.request_id)) };
370
359
  }
371
360
  async function settle(ctx, disposition) {
372
- const request = resolveRequest(ctx);
361
+ const request = requirePageRequest(requestId(ctx));
373
362
  const body = validateSettleRequest(ctx.body);
374
363
  requireSettleable(request);
375
- let result;
376
364
  try {
377
- result = await cancelHumanTicket(request.ticketId, { ...body, disposition });
365
+ await cancelHumanTicket(request.request_id, { ...body, disposition });
378
366
  }
379
367
  catch (error) {
380
368
  throw settlementError(error);
381
369
  }
382
- return { status: 200, body: requestToDTO({ ...request, result }) };
383
- }
384
- /** The recipient surface deliberately closing the request without answering. */
385
- function handleDismiss(ctx) {
386
- return settle(ctx, 'dismissed');
387
- }
388
- /** The requester withdrawing its own request. */
389
- function handleCancel(ctx) {
390
- return settle(ctx, 'canceled');
370
+ return { status: 200, body: requestToDTO(requirePageRequest(request.request_id)) };
391
371
  }
392
372
  export const humanRequestRoutes = [
393
373
  { method: 'POST', pattern: '/v1/human/requests', handler: handleCreate },
394
374
  { method: 'GET', pattern: '/v1/human/requests/:request_id', handler: handleGet },
395
375
  { method: 'POST', pattern: '/v1/human/requests/:request_id/replace', handler: handleReplace },
396
376
  { method: 'POST', pattern: '/v1/human/requests/:request_id/respond', handler: handleRespond },
397
- { method: 'POST', pattern: '/v1/human/requests/:request_id/dismiss', handler: handleDismiss },
398
- { method: 'POST', pattern: '/v1/human/requests/:request_id/cancel', handler: handleCancel },
377
+ { method: 'POST', pattern: '/v1/human/requests/:request_id/dismiss', handler: (ctx) => settle(ctx, 'dismissed') },
378
+ { method: 'POST', pattern: '/v1/human/requests/:request_id/cancel', handler: (ctx) => settle(ctx, 'canceled') },
399
379
  ];