@north-light/crouter 0.3.312 → 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 (495) 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 +13 -1
  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 +16 -3
  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 +51 -8
  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 +2 -1
  140. package/dist/core/__tests__/on-read-dedup-resume.test.js +2 -1
  141. package/dist/core/__tests__/on-read-nested-store.test.js +2 -1
  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 +4 -1
  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 +2 -1
  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 +18 -4
  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/config.d.ts +17 -12
  217. package/dist/core/config.js +106 -155
  218. package/dist/core/feed/__tests__/inbox-migrate.test.js +27 -31
  219. package/dist/core/feed/feed.d.ts +0 -6
  220. package/dist/core/feed/feed.js +68 -56
  221. package/dist/core/feed/inbox.d.ts +7 -81
  222. package/dist/core/feed/inbox.js +46 -378
  223. package/dist/core/feed/messages.d.ts +58 -0
  224. package/dist/core/feed/messages.js +217 -0
  225. package/dist/core/fs-utils.d.ts +4 -0
  226. package/dist/core/fs-utils.js +21 -1
  227. package/dist/core/human/answer.d.ts +1 -1
  228. package/dist/core/human/answer.js +1 -1
  229. package/dist/core/human/claim.d.ts +1 -1
  230. package/dist/core/human/claim.js +2 -4
  231. package/dist/core/human/component-docs.js +1 -1
  232. package/dist/core/human/feedback-companion.js +3 -2
  233. package/dist/core/human/feedback.d.ts +5 -8
  234. package/dist/core/human/feedback.js +57 -85
  235. package/dist/core/human/page-authoring.d.ts +30 -0
  236. package/dist/core/human/page-authoring.js +19 -0
  237. package/dist/core/human/requests.d.ts +136 -0
  238. package/dist/core/human/requests.js +515 -0
  239. package/dist/core/human/root.d.ts +0 -7
  240. package/dist/core/human/root.js +0 -17
  241. package/dist/core/human/scan.d.ts +2 -7
  242. package/dist/core/human/scan.js +48 -132
  243. package/dist/core/human/summary.d.ts +1 -1
  244. package/dist/core/human/summary.js +1 -1
  245. package/dist/core/human/tickets.d.ts +23 -83
  246. package/dist/core/human/tickets.js +92 -243
  247. package/dist/core/human/types.d.ts +5 -1
  248. package/dist/core/installed-plugins.js +8 -3
  249. package/dist/core/keybindings/__tests__/resolve.test.js +19 -17
  250. package/dist/core/locked-file.d.ts +6 -3
  251. package/dist/core/locked-file.js +36 -9
  252. package/dist/core/memory/extensions.js +2 -0
  253. package/dist/core/preview-registry.js +0 -1
  254. package/dist/core/profiles/__tests__/env-store.test.js +2 -0
  255. package/dist/core/profiles/default-binding.d.ts +0 -4
  256. package/dist/core/profiles/default-binding.js +12 -58
  257. package/dist/core/profiles/env-store.js +8 -3
  258. package/dist/core/profiles/manifest.d.ts +2 -37
  259. package/dist/core/profiles/manifest.js +35 -161
  260. package/dist/core/profiles/select.js +3 -0
  261. package/dist/core/review/__tests__/capture-origin.test.js +13 -2
  262. package/dist/core/review/__tests__/comments.test.js +28 -10
  263. package/dist/core/review/__tests__/remap.test.js +28 -10
  264. package/dist/core/review/__tests__/stage-identity.test.js +17 -7
  265. package/dist/core/review/birth.d.ts +1 -1
  266. package/dist/core/review/birth.js +34 -5
  267. package/dist/core/review/comments.js +1 -1
  268. package/dist/core/review/document.js +1 -1
  269. package/dist/core/review/project.d.ts +5 -1
  270. package/dist/core/review/project.js +14 -36
  271. package/dist/core/review/realize.d.ts +3 -6
  272. package/dist/core/review/realize.js +51 -168
  273. package/dist/core/review/remap.js +1 -1
  274. package/dist/core/review/stage.d.ts +3 -2
  275. package/dist/core/review/stage.js +2 -3
  276. package/dist/core/review/store.d.ts +3 -21
  277. package/dist/core/review/store.js +140 -186
  278. package/dist/core/review/types.d.ts +0 -1
  279. package/dist/core/runtime/__tests__/install-id-cache-scoping.test.js +9 -5
  280. package/dist/core/runtime/__tests__/spawn-env.test.js +8 -9
  281. package/dist/core/runtime/broker/auth-reload.js +9 -10
  282. package/dist/core/runtime/broker/daemon-ops.d.ts +25 -8
  283. package/dist/core/runtime/broker/daemon-ops.js +42 -9
  284. package/dist/core/runtime/broker/extension-abort.d.ts +3 -0
  285. package/dist/core/runtime/broker/extension-abort.js +11 -0
  286. package/dist/core/runtime/broker/fault-retry.d.ts +15 -6
  287. package/dist/core/runtime/broker/fault-retry.js +142 -95
  288. package/dist/core/runtime/broker/inbox.d.ts +4 -32
  289. package/dist/core/runtime/broker/inbox.js +4 -92
  290. package/dist/core/runtime/broker/rebind.d.ts +1 -0
  291. package/dist/core/runtime/broker/rebind.js +21 -12
  292. package/dist/core/runtime/broker-persona-guidance.d.ts +1 -1
  293. package/dist/core/runtime/broker-persona-guidance.js +2 -13
  294. package/dist/core/runtime/broker.js +28 -22
  295. package/dist/core/runtime/close.d.ts +3 -9
  296. package/dist/core/runtime/close.js +16 -27
  297. package/dist/core/runtime/fault.d.ts +3 -93
  298. package/dist/core/runtime/fault.js +9 -419
  299. package/dist/core/runtime/kickoff.d.ts +3 -6
  300. package/dist/core/runtime/kickoff.js +12 -18
  301. package/dist/core/runtime/launch.js +1 -1
  302. package/dist/core/runtime/lifecycle.js +40 -7
  303. package/dist/core/runtime/placement.js +2 -2
  304. package/dist/core/runtime/recycle.js +8 -2
  305. package/dist/core/runtime/reset.js +22 -6
  306. package/dist/core/runtime/revive.js +226 -218
  307. package/dist/core/runtime/spawn.js +14 -3
  308. package/dist/core/scoped-state/db.d.ts +7 -0
  309. package/dist/core/scoped-state/db.js +92 -0
  310. package/dist/core/scoped-state/migrate.d.ts +11 -0
  311. package/dist/core/scoped-state/migrate.js +198 -0
  312. package/dist/core/scoped-state/paths.d.ts +9 -0
  313. package/dist/core/scoped-state/paths.js +27 -0
  314. package/dist/core/scoped-state/profiles.d.ts +12 -0
  315. package/dist/core/scoped-state/profiles.js +62 -0
  316. package/dist/core/scoped-state/providers.d.ts +16 -0
  317. package/dist/core/scoped-state/providers.js +8 -0
  318. package/dist/core/scoped-state/schema.d.ts +3 -0
  319. package/dist/core/scoped-state/schema.js +26 -0
  320. package/dist/core/scoped-state/settings.d.ts +28 -0
  321. package/dist/core/scoped-state/settings.js +82 -0
  322. package/dist/core/subscription-state.d.ts +29 -48
  323. package/dist/core/subscription-state.js +176 -712
  324. package/dist/core/worktree-close.js +4 -4
  325. package/dist/core/worktree-mutation-async.js +2 -2
  326. package/dist/core/worktree-sweep.js +11 -16
  327. package/dist/core/worktree.js +6 -12
  328. package/dist/daemon/__tests__/autostart-storm.test.js +1 -39
  329. package/dist/daemon/__tests__/helpers/source-daemon.d.ts +2 -2
  330. package/dist/daemon/__tests__/helpers/source-daemon.js +7 -6
  331. package/dist/daemon/__tests__/integration/migration-startup.test.js +59 -26
  332. package/dist/daemon/__tests__/node-deadline-lane.test.js +2 -1
  333. package/dist/daemon/__tests__/node-outcome-birth-invariants.test.js +39 -15
  334. package/dist/daemon/__tests__/node-outcome-delivery.test.js +39 -10
  335. package/dist/daemon/__tests__/reconciler-signature.test.js +2 -2
  336. package/dist/daemon/__tests__/subtree-filter-freshness.test.js +2 -2
  337. package/dist/daemon/api/__tests__/broker-settle-park.test.js +17 -12
  338. package/dist/daemon/api/__tests__/canvas-snapshot-fields.test.js +27 -5
  339. package/dist/daemon/api/__tests__/model-config.test.js +8 -8
  340. package/dist/daemon/api/__tests__/node-create-description.test.js +22 -5
  341. package/dist/daemon/api/__tests__/node-model-validation.test.js +21 -1
  342. package/dist/daemon/api/__tests__/nodes-activity-query.test.js +10 -12
  343. package/dist/daemon/api/__tests__/profile-launch-gates.test.js +4 -1
  344. package/dist/daemon/api/__tests__/profile-metadata-route.test.js +4 -1
  345. package/dist/daemon/api/__tests__/reopen-delivery.test.js +26 -8
  346. package/dist/daemon/api/__tests__/seam/api-server.test.js +24 -32
  347. package/dist/daemon/api/__tests__/seam/b10-attach-modelauth.test.js +4 -1
  348. package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +5 -4
  349. package/dist/daemon/api/__tests__/seam/profile-delete.test.js +27 -41
  350. package/dist/daemon/api/__tests__/submit-result.test.js +3 -2
  351. package/dist/daemon/api/bridge.js +1 -1
  352. package/dist/daemon/api/handlers/bash-jobs.js +6 -7
  353. package/dist/daemon/api/handlers/broker-ops.js +47 -84
  354. package/dist/daemon/api/handlers/broker-recovery.d.ts +4 -0
  355. package/dist/daemon/api/handlers/broker-recovery.js +251 -0
  356. package/dist/daemon/api/handlers/canvas.js +2 -44
  357. package/dist/daemon/api/handlers/daemon.js +41 -0
  358. package/dist/daemon/api/handlers/feedback-comments.js +2 -2
  359. package/dist/daemon/api/handlers/health.js +10 -5
  360. package/dist/daemon/api/handlers/human-requests.js +168 -188
  361. package/dist/daemon/api/handlers/human.js +3 -151
  362. package/dist/daemon/api/handlers/inbox-page.d.ts +4 -0
  363. package/dist/daemon/api/handlers/inbox-page.js +89 -0
  364. package/dist/daemon/api/handlers/inbox.js +21 -120
  365. package/dist/daemon/api/handlers/messages.d.ts +1 -0
  366. package/dist/daemon/api/handlers/messages.js +73 -15
  367. package/dist/daemon/api/handlers/node-outcomes.js +58 -13
  368. package/dist/daemon/api/handlers/nodes.js +7 -13
  369. package/dist/daemon/api/handlers/reviews.js +4 -29
  370. package/dist/daemon/api/map.d.ts +25 -3
  371. package/dist/daemon/api/map.js +84 -14
  372. package/dist/daemon/api/server.js +68 -9
  373. package/dist/daemon/control.d.ts +18 -0
  374. package/dist/daemon/cron/disposition.d.ts +2 -0
  375. package/dist/daemon/cron/disposition.js +8 -5
  376. package/dist/daemon/cron/settle.js +37 -13
  377. package/dist/daemon/cron/sinks.d.ts +18 -1
  378. package/dist/daemon/cron/sinks.js +47 -93
  379. package/dist/daemon/crtrd-cli.js +4 -19
  380. package/dist/daemon/crtrd.d.ts +2 -0
  381. package/dist/daemon/crtrd.js +206 -81
  382. package/dist/daemon/fleet.js +5 -6
  383. package/dist/daemon/human/finish.d.ts +12 -24
  384. package/dist/daemon/human/finish.js +88 -285
  385. package/dist/daemon/human/settle.d.ts +40 -0
  386. package/dist/daemon/human/settle.js +89 -0
  387. package/dist/daemon/human/sweep.d.ts +20 -5
  388. package/dist/daemon/human/sweep.js +56 -60
  389. package/dist/daemon/manage.d.ts +21 -16
  390. package/dist/daemon/manage.js +85 -51
  391. package/dist/daemon/messaging/node-message.d.ts +1 -1
  392. package/dist/daemon/messaging/node-message.js +9 -12
  393. package/dist/daemon/park-activity.js +3 -3
  394. package/dist/daemon/reconcilers/bash-deadline.js +6 -7
  395. package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
  396. package/dist/daemon/reconcilers/broker-supervision.js +41 -19
  397. package/dist/daemon/reconcilers/controller-death.js +6 -18
  398. package/dist/daemon/reconcilers/delivery-lane.d.ts +9 -0
  399. package/dist/daemon/reconcilers/delivery-lane.js +130 -0
  400. package/dist/daemon/reconcilers/live-obligation.js +3 -3
  401. package/dist/daemon/reconcilers/node-deadline.js +1 -1
  402. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -1
  403. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +10 -12
  404. package/dist/daemon/reconcilers/node-lifecycle/tick.js +5 -5
  405. package/dist/daemon/reconcilers/node-lifecycle/wants-execution.js +1 -1
  406. package/dist/daemon/reconcilers/pending-review-submit.js +3 -3
  407. package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -8
  408. package/dist/daemon/reconcilers/storage-maintenance.js +13 -43
  409. package/dist/daemon/review/companion.js +5 -11
  410. package/dist/daemon/review/deliver.d.ts +1 -5
  411. package/dist/daemon/review/deliver.js +3 -52
  412. package/dist/daemon/review/finish.d.ts +2 -27
  413. package/dist/daemon/review/finish.js +79 -263
  414. package/dist/daemon/review/sweep.d.ts +3 -10
  415. package/dist/daemon/review/sweep.js +13 -131
  416. package/dist/daemon/startup-policy.d.ts +0 -5
  417. package/dist/daemon/startup-policy.js +0 -5
  418. package/dist/index.d.ts +2 -1
  419. package/dist/index.js +1 -1
  420. package/dist/migrations/__tests__/activation-concurrency.test.js +3 -2
  421. package/dist/migrations/__tests__/activation.test.js +9 -6
  422. package/dist/migrations/activation.d.ts +3 -2
  423. package/dist/migrations/activation.js +2 -4
  424. package/dist/migrations/corpus.d.ts +2 -5
  425. package/dist/migrations/corpus.js +9 -20
  426. package/dist/migrations/runner.d.ts +3 -1
  427. package/dist/migrations/runner.js +6 -2
  428. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +21 -89
  429. package/dist/pi-extensions/__tests__/canvas-goal-capture-envelope.test.js +4 -2
  430. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +51 -33
  431. package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.js +16 -2
  432. package/dist/pi-extensions/__tests__/pre-command-gate.test.js +13 -1
  433. package/dist/pi-extensions/canvas-inbox-watcher.js +98 -244
  434. package/dist/pi-extensions/canvas-passive-context.d.ts +4 -8
  435. package/dist/pi-extensions/canvas-passive-context.js +85 -37
  436. package/dist/pi-extensions/canvas-stophook.js +47 -31
  437. package/dist/shared/env.d.ts +1 -0
  438. package/dist/shared/env.js +3 -0
  439. package/package.json +1 -1
  440. package/runtime.lock.json +5 -5
  441. package/dist/clients/attach/__tests__/page-block.test.js +0 -54
  442. package/dist/clients/inbox/review-visibility.d.ts +0 -5
  443. package/dist/clients/inbox/review-visibility.js +0 -19
  444. package/dist/commands/canvas-rebuild-index.d.ts +0 -2
  445. package/dist/commands/canvas-rebuild-index.js +0 -46
  446. package/dist/core/__tests__/human-cancel-guard.test.js +0 -110
  447. package/dist/core/__tests__/human-deliver.test.d.ts +0 -1
  448. package/dist/core/__tests__/human-deliver.test.js +0 -256
  449. package/dist/core/__tests__/human-node-not-supervised.test.d.ts +0 -1
  450. package/dist/core/__tests__/human-node-not-supervised.test.js +0 -89
  451. package/dist/core/__tests__/integration/human-deliver-e2e.test.d.ts +0 -1
  452. package/dist/core/__tests__/integration/human-deliver-e2e.test.js +0 -131
  453. package/dist/core/__tests__/phase4-review-store.test.d.ts +0 -1
  454. package/dist/core/__tests__/phase4-review-store.test.js +0 -144
  455. package/dist/core/__tests__/watchdog-abort-arms-retry.test.d.ts +0 -1
  456. package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +0 -110
  457. package/dist/core/canvas/human-deliveries.d.ts +0 -39
  458. package/dist/core/canvas/human-deliveries.js +0 -75
  459. package/dist/core/canvas/node-outcome-deliveries.d.ts +0 -64
  460. package/dist/core/canvas/node-outcome-deliveries.js +0 -159
  461. package/dist/core/feed/passive.d.ts +0 -3
  462. package/dist/core/feed/passive.js +0 -53
  463. package/dist/core/human/__tests__/inbox-cancel-worker.d.ts +0 -1
  464. package/dist/core/human/__tests__/inbox-cancel-worker.js +0 -7
  465. package/dist/core/human/__tests__/inbox-claim-worker.d.ts +0 -1
  466. package/dist/core/human/__tests__/inbox-claim-worker.js +0 -17
  467. package/dist/core/human/__tests__/inbox-stale-claim-worker.d.ts +0 -1
  468. package/dist/core/human/__tests__/inbox-stale-claim-worker.js +0 -8
  469. package/dist/core/human/__tests__/integration/inbox-core.test.d.ts +0 -1
  470. package/dist/core/human/__tests__/integration/inbox-core.test.js +0 -145
  471. package/dist/core/human/__tests__/page-tickets.test.d.ts +0 -1
  472. package/dist/core/human/__tests__/page-tickets.test.js +0 -161
  473. package/dist/core/review/ticket-filter.d.ts +0 -17
  474. package/dist/core/review/ticket-filter.js +0 -21
  475. package/dist/core/runtime/broker/passive.d.ts +0 -17
  476. package/dist/core/runtime/broker/passive.js +0 -44
  477. package/dist/core/runtime/busy.d.ts +0 -46
  478. package/dist/core/runtime/busy.js +0 -150
  479. package/dist/daemon/__tests__/startup-block-marker.test.d.ts +0 -1
  480. package/dist/daemon/__tests__/startup-block-marker.test.js +0 -86
  481. package/dist/daemon/api/__tests__/review-terminal-conflict.test.d.ts +0 -1
  482. package/dist/daemon/api/__tests__/review-terminal-conflict.test.js +0 -98
  483. package/dist/daemon/human/deliver-action.d.ts +0 -3
  484. package/dist/daemon/human/deliver-action.js +0 -9
  485. package/dist/daemon/node-outcome/deliver-outcome.d.ts +0 -3
  486. package/dist/daemon/node-outcome/deliver-outcome.js +0 -9
  487. package/dist/daemon/reconcilers/human-delivery-lane.d.ts +0 -10
  488. package/dist/daemon/reconcilers/human-delivery-lane.js +0 -41
  489. package/dist/daemon/reconcilers/node-outcome-delivery-lane.d.ts +0 -10
  490. package/dist/daemon/reconcilers/node-outcome-delivery-lane.js +0 -41
  491. package/dist/daemon/startup-block-marker.d.ts +0 -25
  492. package/dist/daemon/startup-block-marker.js +0 -99
  493. /package/dist/{clients/attach/__tests__/page-block.test.d.ts → api/dto/mail.js} +0 -0
  494. /package/dist/{commands/sys/__tests__/migrate.test.d.ts → api/dto/recovery.js} +0 -0
  495. /package/dist/{core/__tests__/human-cancel-guard.test.d.ts → commands/__tests__/integration/migrate.test.d.ts} +0 -0
@@ -0,0 +1,93 @@
1
+ // dto-adapt.ts — the one place daemon human DTOs become the shapes the inbox
2
+ // and the attach viewer render. Pure: no I/O, no canvas state, no second read.
3
+ //
4
+ // The viewer surfaces used to build these shapes by scanning canvas SQL
5
+ // themselves. They now read the daemon's projections, so every field below
6
+ // comes from one already-consistent snapshot rather than from a field-by-field
7
+ // re-derivation each surface had to keep in step.
8
+ import { validatePageManifest } from '../../core/human/page-schema.js';
9
+ /** The wire response map and the renderer's differ in one place: an anchor is a
10
+ * flat optional-field object on the wire and a discriminated union in core.
11
+ * Nothing here re-validates, because the responses a page renders are the ones
12
+ * the daemon already accepted against the same manifest — the read path this
13
+ * replaced did not validate them either, and an in-flight partial autosave is
14
+ * deliberately allowed to be incomplete. */
15
+ function responsesFromDTO(responses) {
16
+ return responses;
17
+ }
18
+ function pageRowFromDTO(dto) {
19
+ return {
20
+ dir: dto.request_dir,
21
+ id: dto.request_id,
22
+ inboxTicketId: dto.ticket_id,
23
+ kind: 'page',
24
+ title: dto.title,
25
+ subtitle: dto.subtitle ?? '',
26
+ dialect: dto.dialect,
27
+ placement: dto.placement,
28
+ inbox: dto.inbox,
29
+ steps: dto.steps,
30
+ slotKinds: dto.slot_kinds,
31
+ awaitsResponse: dto.awaits_response,
32
+ source: dto.source,
33
+ emittedAt: dto.emitted_at,
34
+ recommendedOptions: (dto.recommended_options ?? []).map((option) => ({
35
+ slotId: option.slot_id,
36
+ optionId: option.option_id,
37
+ label: option.label,
38
+ })),
39
+ ...(dto.fast_action === undefined
40
+ ? {}
41
+ : { fastAction: { kind: dto.fast_action.kind, responses: responsesFromDTO(dto.fast_action.responses) } }),
42
+ state: dto.state,
43
+ ...(dto.answer_digest === undefined ? {} : { answerDigest: dto.answer_digest }),
44
+ };
45
+ }
46
+ function reviewRowFromDTO(dto) {
47
+ return {
48
+ dir: dto.request_dir,
49
+ id: dto.request_id,
50
+ inboxTicketId: dto.ticket_id,
51
+ kind: 'review',
52
+ title: dto.title,
53
+ subtitle: dto.subtitle,
54
+ blockedSince: dto.blocked_since,
55
+ source: dto.source,
56
+ };
57
+ }
58
+ export function inboxRowFromDTO(dto) {
59
+ return dto.kind === 'page' ? pageRowFromDTO(dto) : reviewRowFromDTO(dto);
60
+ }
61
+ export function pageViewFromDTO(dto) {
62
+ return {
63
+ // The manifest is parsed, not cast: a page whose manifest no longer
64
+ // validates must fail loudly here rather than reach the renderer.
65
+ manifest: validatePageManifest(dto.page),
66
+ document: dto.source_document,
67
+ progress: dto.progress === null ? null : responsesFromDTO(dto.progress.responses),
68
+ state: dto.state,
69
+ revision: dto.revision,
70
+ };
71
+ }
72
+ /** The stored one-line answer digest, or undefined when the page was not
73
+ * answered. A canceled page carries no digest by construction. */
74
+ export function answerDigestOf(dto) {
75
+ const result = dto.result;
76
+ if (result === null || result.kind !== 'page')
77
+ return undefined;
78
+ return result.summary.replace(/\s+/g, ' ').trim();
79
+ }
80
+ /** What a surface says when a settled request refuses a second settlement. */
81
+ export function settledStatusOf(dto) {
82
+ const result = dto.result;
83
+ if (result !== null && result.kind === 'canceled')
84
+ return 'ticket was already canceled';
85
+ if (result !== null && result.kind === 'page')
86
+ return 'ticket was already resolved: page submitted';
87
+ return 'ticket was already resolved';
88
+ }
89
+ /** The row sort every inbox surface shares: newest first, request id breaking ties. */
90
+ export function byNewestFirst(a, b) {
91
+ const time = (row) => row.kind === 'page' ? row.emittedAt : row.blockedSince;
92
+ return time(b).localeCompare(time(a)) || a.id.localeCompare(b.id);
93
+ }
@@ -1,10 +1,11 @@
1
1
  import type { ProductPageComponents } from '../../types.js';
2
2
  import type { PageResponses } from '../../core/human/page-schema.js';
3
- import type { PageTicket } from '../../core/human/tickets.js';
3
+ import type { InboxPageView } from './dto-adapt.js';
4
4
  import type { Key } from './tui/keys.js';
5
5
  export interface PageAdapterOptions {
6
- dir: string;
7
- ticket: PageTicket;
6
+ /** The opaque inbox ticket id autosave posts against. */
7
+ ticketId: string;
8
+ page: InboxPageView;
8
9
  productKinds: ProductPageComponents;
9
10
  cols: number;
10
11
  rows: number;
@@ -27,6 +28,6 @@ export declare class PageAdapter {
27
28
  setInputBuffer(text: string): void;
28
29
  canAcceptHostKeys(): boolean;
29
30
  handleKey(input: string, key: Key): void;
30
- reload(ticket: PageTicket): void;
31
+ reload(page: InboxPageView): void;
31
32
  close(): void;
32
33
  }
@@ -1,5 +1,5 @@
1
1
  import { pageAwaitsResponse } from '../../core/human/page-schema.js';
2
- import { writePageProgress } from '../../core/human/tickets.js';
2
+ import { cliClient } from '../../commands/api-client.js';
3
3
  import { mountPanel } from './tui/panel.js';
4
4
  /** Embeds the page renderer in a controller-owned rectangle. */
5
5
  export class PageAdapter {
@@ -9,19 +9,19 @@ export class PageAdapter {
9
9
  manifest;
10
10
  constructor(opts) {
11
11
  this.opts = opts;
12
- this.manifest = opts.ticket.manifest;
12
+ this.manifest = opts.page.manifest;
13
13
  this.panel = mountPanel({
14
- manifest: opts.ticket.manifest,
15
- document: opts.ticket.document,
14
+ manifest: opts.page.manifest,
15
+ document: opts.page.document,
16
16
  productKinds: opts.productKinds,
17
- initialResponses: opts.ticket.progress,
17
+ initialResponses: opts.page.progress,
18
18
  cols: opts.cols,
19
19
  rows: opts.rows,
20
20
  onProgress: (responses) => {
21
- try {
22
- writePageProgress(opts.dir, responses);
23
- }
24
- catch { /* partial in-flight input may not validate yet */ }
21
+ // Autosave is advisory: partial in-flight input may not validate yet,
22
+ // and the answer the person actually submits goes through the respond
23
+ // route, which revalidates. A rejected autosave loses nothing.
24
+ void cliClient().postInboxProgress(opts.ticketId, responses).catch(() => { });
25
25
  opts.onProgress?.(responses);
26
26
  },
27
27
  onComplete: opts.onComplete,
@@ -46,9 +46,9 @@ export class PageAdapter {
46
46
  }
47
47
  this.panel.handleKey(input, key);
48
48
  }
49
- reload(ticket) {
50
- this.manifest = ticket.manifest;
51
- this.panel.loadPage(ticket.manifest, { document: ticket.document, initialResponses: ticket.progress, productKinds: this.opts.productKinds });
49
+ reload(page) {
50
+ this.manifest = page.manifest;
51
+ this.panel.loadPage(page.manifest, { document: page.document, initialResponses: page.progress, productKinds: this.opts.productKinds });
52
52
  this.opts.onDirty();
53
53
  }
54
54
  close() { this.panel.unmount(); }
@@ -1,11 +1,16 @@
1
1
  import type { PageResponses } from '../../core/human/page-schema.js';
2
- export declare function ticketIdFor(dir: string): string;
3
- export declare function resolveTicketPage(dir: string, responses: PageResponses): Promise<void>;
4
- export declare function cancelTicketViaDaemon(dir: string, opts: {
2
+ /** Settle a page request with the person's answer. The request id a scan
3
+ * already carries IS the settlement identity — there is no bridge node to
4
+ * derive one from. An omitted actor is what records a person, not a
5
+ * programmatic writer, as the author of the result. */
6
+ export declare function resolveTicketPage(requestId: string, responses: PageResponses): Promise<void>;
7
+ /** Close a page request from the inbox without answering it. The inbox is the
8
+ * recipient surface, so this is always a dismissal, never the requester
9
+ * withdrawing its own request. */
10
+ export declare function dismissTicketViaDaemon(requestId: string, opts: {
5
11
  reason: string;
6
12
  actor: string;
7
- disposition?: 'canceled' | 'dismissed';
8
13
  }): Promise<void>;
9
14
  export declare function daemonErrorMessage(err: unknown): string;
10
- export type ResolveFailure = 'unreachable' | 'already_resolved' | 'delivery_failed' | 'other';
15
+ export type ResolveFailure = 'unreachable' | 'already_settled' | 'other';
11
16
  export declare function resolveFailureKind(err: unknown): ResolveFailure;
@@ -1,14 +1,17 @@
1
- import { basename } from 'node:path';
2
1
  import { ApiError } from '../../api/errors.js';
3
2
  import { cliClient } from '../../commands/api-client.js';
4
- export function ticketIdFor(dir) {
5
- return basename(dir);
3
+ /** Settle a page request with the person's answer. The request id a scan
4
+ * already carries IS the settlement identity — there is no bridge node to
5
+ * derive one from. An omitted actor is what records a person, not a
6
+ * programmatic writer, as the author of the result. */
7
+ export async function resolveTicketPage(requestId, responses) {
8
+ await cliClient().respondHumanRequest(requestId, { responses });
6
9
  }
7
- export async function resolveTicketPage(dir, responses) {
8
- await cliClient().resolveHumanTicket(ticketIdFor(dir), { responses });
9
- }
10
- export async function cancelTicketViaDaemon(dir, opts) {
11
- await cliClient().cancelHumanTicket(ticketIdFor(dir), opts);
10
+ /** Close a page request from the inbox without answering it. The inbox is the
11
+ * recipient surface, so this is always a dismissal, never the requester
12
+ * withdrawing its own request. */
13
+ export async function dismissTicketViaDaemon(requestId, opts) {
14
+ await cliClient().dismissHumanRequest(requestId, opts);
12
15
  }
13
16
  function isUnreachable(err) {
14
17
  if (err instanceof ApiError)
@@ -26,9 +29,7 @@ export function daemonErrorMessage(err) {
26
29
  export function resolveFailureKind(err) {
27
30
  if (isUnreachable(err))
28
31
  return 'unreachable';
29
- if (err instanceof ApiError && err.status === 409 && err.code === 'ticket_already_resolved')
30
- return 'already_resolved';
31
- if (err instanceof ApiError && err.status === 500 && err.code === 'delivery_failed')
32
- return 'delivery_failed';
32
+ if (err instanceof ApiError && err.status === 409 && err.code === 'already_settled')
33
+ return 'already_settled';
33
34
  return 'other';
34
35
  }
@@ -14,7 +14,6 @@ export interface ResolvedReview {
14
14
  }
15
15
  export interface ReviewClient {
16
16
  byId(reviewId: string): Promise<ResolvedReview>;
17
- byBridge(bridgeNodeId: string): Promise<ResolvedReview>;
18
17
  createInline(p: {
19
18
  originNodeId: string;
20
19
  file: string;
@@ -40,10 +40,6 @@ export function createReviewClient(opts = {}) {
40
40
  const review = await request(() => cliClient().getReview(reviewId));
41
41
  return await resolveReview(review, review.companion_node_id, request);
42
42
  },
43
- async byBridge(bridgeNodeId) {
44
- const review = await request(() => cliClient().getReviewByBridge(bridgeNodeId));
45
- return await resolveReview(review, review.companion_node_id, request);
46
- },
47
43
  async createInline(p) {
48
44
  const review = await request(() => cliClient().createReview({
49
45
  origin_kind: 'inline',
@@ -1,7 +1,8 @@
1
1
  import type { SurfaceHost } from '../surfaces/host.js';
2
2
  export interface ReviewAdapterOptions {
3
3
  host: SurfaceHost;
4
- dir: string;
4
+ /** The review request's own id — the same id its inbox row carries. */
5
+ reviewId: string;
5
6
  }
6
7
  /** Resolve a durable review ticket and open it in its own tmux window. */
7
8
  export declare class ReviewAdapter {
@@ -1,4 +1,3 @@
1
- import { basename } from 'node:path';
2
1
  import { openReviewWindow } from './review/launch.js';
3
2
  import { createReviewClient, ReviewTerminalError, terminalRefusalNotice } from './review/review-client.js';
4
3
  /** Resolve a durable review ticket and open it in its own tmux window. */
@@ -25,20 +24,19 @@ export class ReviewAdapter {
25
24
  this.opts.host.notice('The review is unavailable in a remote attach — the file and companion live on the host.');
26
25
  return;
27
26
  }
28
- const bridgeNodeId = basename(this.opts.dir);
29
27
  let review;
30
28
  try {
31
- review = await createReviewClient().byBridge(bridgeNodeId);
29
+ review = await createReviewClient().byId(this.opts.reviewId);
32
30
  }
33
31
  catch (error) {
34
- this.opts.host.notice(noticeForBridgeFailure(error));
32
+ this.opts.host.notice(noticeForLookupFailure(error));
35
33
  return;
36
34
  }
37
35
  if (!this.stopped)
38
36
  openReviewWindow(this.opts.host, review);
39
37
  }
40
38
  }
41
- function noticeForBridgeFailure(error) {
39
+ function noticeForLookupFailure(error) {
42
40
  if (error instanceof ReviewTerminalError)
43
41
  return terminalRefusalNotice(error);
44
42
  return error instanceof Error ? error.message : String(error);
@@ -1,9 +1,9 @@
1
1
  import type { SurfaceHost } from '../surfaces/host.js';
2
- import type { TicketSummary } from '../../core/human/types.js';
2
+ import type { InboxRow } from './dto-adapt.js';
3
3
  export interface InboxSurfaceOptions {
4
4
  host: SurfaceHost;
5
5
  /** Injection seams for tests; production passes none. */
6
- scan?: () => TicketSummary[];
6
+ scan?: () => Promise<InboxRow[]>;
7
7
  }
8
8
  export interface InboxSurfaceOwner {
9
9
  /** Mount when closed and close when open. */
@@ -1,7 +1,6 @@
1
1
  import { InboxController } from './controller.js';
2
- import { scanInbox } from '../../core/human/scan.js';
2
+ import { byNewestFirst, inboxRowFromDTO } from './dto-adapt.js';
3
3
  import { cliClient } from '../../commands/api-client.js';
4
- import { filterVisibleReviewTickets } from './review-visibility.js';
5
4
  import { decodeInboxKey } from './tui/keys.js';
6
5
  import { clipLine, visibleWidth } from './tui/ansi.js';
7
6
  class InboxComponent {
@@ -46,6 +45,14 @@ function padFrame(lines, cols, rows) {
46
45
  return clipped + ' '.repeat(Math.max(0, cols - visibleWidth(clipped)));
47
46
  });
48
47
  }
48
+ /** Reach the row source once before mounting, so a daemon that cannot answer
49
+ * surfaces as a notice instead of an inbox that silently has nothing in it. */
50
+ async function probeRows(opts) {
51
+ if (opts.scan !== undefined)
52
+ return opts.scan();
53
+ const { tickets } = await cliClient().listHumanInbox();
54
+ return tickets.map(inboxRowFromDTO).sort(byNewestFirst);
55
+ }
49
56
  export function createInboxSurface(opts) {
50
57
  let session;
51
58
  const close = () => {
@@ -62,12 +69,11 @@ export function createInboxSurface(opts) {
62
69
  const mount = (current) => {
63
70
  if (current.closed || session !== current)
64
71
  return;
65
- const localScan = opts.scan ?? scanInbox;
66
72
  const nextController = new InboxController({
67
73
  host: opts.host,
68
74
  onDirty: () => current.handle?.invalidate(),
69
75
  onClosed: close,
70
- scan: () => filterVisibleReviewTickets(localScan(), current.visibleIds),
76
+ ...(opts.scan === undefined ? {} : { scan: opts.scan }),
71
77
  onInboxActivity: () => refresh(current),
72
78
  ...(current.preselectDir === undefined ? {} : { initialSelection: current.preselectDir }),
73
79
  });
@@ -89,16 +95,22 @@ export function createInboxSurface(opts) {
89
95
  throw error;
90
96
  }
91
97
  };
98
+ // The first load decides whether the inbox opens at all — an unreachable
99
+ // daemon is a notice, not an empty surface. Afterwards the controller owns
100
+ // its own rows, so activity only has to tell it to re-read.
92
101
  const refresh = (current, initial = false) => {
102
+ if (!initial && current.controller !== undefined) {
103
+ void current.controller.invalidate();
104
+ return;
105
+ }
93
106
  const generation = ++current.refreshGeneration;
94
- void cliClient().listHumanInbox().then(({ tickets }) => {
107
+ void probeRows(opts).then(() => {
95
108
  if (current.closed || session !== current || generation !== current.refreshGeneration)
96
109
  return;
97
- current.visibleIds = new Set(tickets.map((ticket) => ticket.ticket_id));
98
110
  if (current.controller === undefined)
99
111
  mount(current);
100
112
  else
101
- current.controller.invalidate();
113
+ void current.controller.invalidate();
102
114
  }, (error) => {
103
115
  if (!initial || current.closed || session !== current || generation !== current.refreshGeneration)
104
116
  return;
@@ -119,7 +131,6 @@ export function createInboxSurface(opts) {
119
131
  const current = {
120
132
  closed: false,
121
133
  refreshGeneration: 0,
122
- visibleIds: new Set(),
123
134
  ...(preselectDir === undefined ? {} : { preselectDir }),
124
135
  };
125
136
  session = current;
@@ -1,8 +1,8 @@
1
- import type { TicketSummary } from '../../core/human/types.js';
1
+ import type { InboxRow } from './dto-adapt.js';
2
2
  export declare const KIND_ICON: Record<string, string>;
3
3
  export declare const KIND_COLOR: Record<string, string>;
4
4
  export declare function formatTimeAgo(iso: string): string;
5
5
  /** Pure inbox rows; selection and terminal ownership belong to InboxController. */
6
- export declare function buildInboxLines(items: TicketSummary[], width: number, selectedIndex: number, height?: number): string[];
6
+ export declare function buildInboxLines(items: InboxRow[], width: number, selectedIndex: number, height?: number): string[];
7
7
  /** What the agent suggests, for a row that says so without opening the page. */
8
- export declare function recommendedLabel(item: TicketSummary): string | undefined;
8
+ export declare function recommendedLabel(item: InboxRow): string | undefined;
@@ -1,7 +1,7 @@
1
1
  // Run with: node --import tsx/esm --test 'src/commands/__tests__/human.test.ts'
2
2
  import { test, describe } from 'node:test';
3
3
  import assert from 'node:assert/strict';
4
- import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
4
+ import { mkdirSync, mkdtempSync, rmSync } from 'node:fs';
5
5
  import { tmpdir } from 'node:os';
6
6
  import { join } from 'node:path';
7
7
  import { Readable } from 'node:stream';
@@ -13,6 +13,8 @@ import { humanSend as buildHumanSend } from '../human/prompts.js';
13
13
  const humanSend = buildHumanSend();
14
14
  import { registerHuman } from '../human.js';
15
15
  import { pageHelpText } from '../human/shared.js';
16
+ import { writeRawConfig } from '../../core/config.js';
17
+ import { initializeFreshScopedStore } from '../../core/scoped-state/migrate.js';
16
18
  const nlThreadRegistration = {
17
19
  kind: 'nl-thread',
18
20
  description: 'message conversation with participants and metadata',
@@ -37,7 +39,8 @@ function withPageSurface(pageSurface, run) {
37
39
  const originalHome = process.env['HOME'];
38
40
  process.env['HOME'] = home;
39
41
  mkdirSync(join(home, '.crouter'), { recursive: true });
40
- writeFileSync(join(home, '.crouter', 'config.json'), JSON.stringify({ page_surface: pageSurface }));
42
+ initializeFreshScopedStore({ kind: 'user', root: join(home, '.crouter') });
43
+ writeRawConfig('user', { page_surface: pageSurface });
41
44
  try {
42
45
  return run();
43
46
  }
@@ -140,17 +143,30 @@ test('human components catalog and contracts teach product registrations', () =>
140
143
  assert.equal(renderComponentContract('ProductCard', [legacyRegistration]), "`<ProductCard>` — product-registered, wire kind `product-card`\n\nproduct-registered; config is passed through unvalidated (unvalidated: true) — see the product's own docs");
141
144
  });
142
145
  test('human components show resolves every registry name, families included', async () => {
143
- const show = humanComponents.children.find((child) => child.name === 'show');
144
- assert.ok(show !== undefined && show.kind === 'leaf');
145
- const question = await show.run({ component: 'UserQuestion' });
146
- assert.ok(question !== undefined);
147
- assert.equal(question['contract'], componentDoc('UserQuestion')?.contract);
148
- assert.match(String(question['contract']), /wire kind `options`/);
149
- // A shadcn family member resolves to the family contract that documents it.
150
- const cardHeader = await show.run({ component: 'CardHeader' });
151
- assert.equal(cardHeader?.['contract'], componentDoc('Card')?.contract);
152
- await assert.rejects(() => show.run({ component: 'crtr-options' }), (err) => {
153
- assert.equal(err.code, 'unknown_component');
154
- return true;
155
- });
146
+ const home = mkdtempSync(join(tmpdir(), 'crtr-human-components-'));
147
+ const originalHome = process.env['HOME'];
148
+ process.env['HOME'] = home;
149
+ initializeFreshScopedStore({ kind: 'user', root: join(home, '.crouter') });
150
+ try {
151
+ const show = humanComponents.children.find((child) => child.name === 'show');
152
+ assert.ok(show !== undefined && show.kind === 'leaf');
153
+ const question = await show.run({ component: 'UserQuestion' });
154
+ assert.ok(question !== undefined);
155
+ assert.equal(question['contract'], componentDoc('UserQuestion')?.contract);
156
+ assert.match(String(question['contract']), /wire kind `options`/);
157
+ // A shadcn family member resolves to the family contract that documents it.
158
+ const cardHeader = await show.run({ component: 'CardHeader' });
159
+ assert.equal(cardHeader?.['contract'], componentDoc('Card')?.contract);
160
+ await assert.rejects(() => show.run({ component: 'crtr-options' }), (err) => {
161
+ assert.equal(err.code, 'unknown_component');
162
+ return true;
163
+ });
164
+ }
165
+ finally {
166
+ if (originalHome === undefined)
167
+ delete process.env['HOME'];
168
+ else
169
+ process.env['HOME'] = originalHome;
170
+ rmSync(home, { recursive: true, force: true });
171
+ }
156
172
  });
@@ -1,13 +1,17 @@
1
1
  import assert from 'node:assert/strict';
2
- import { existsSync, mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { existsSync, mkdtempSync, mkdirSync, rmSync } from 'node:fs';
3
3
  import { spawn } from 'node:child_process';
4
4
  import { createServer } from 'node:http';
5
5
  import { tmpdir } from 'node:os';
6
6
  import { join } from 'node:path';
7
7
  import test from 'node:test';
8
8
  import { createNode, subscribe } from '../../../core/canvas/canvas.js';
9
- import { closeDb } from '../../../core/canvas/db.js';
9
+ import { closeDb, migrate, openDb } from '../../../core/canvas/db.js';
10
10
  import { apiSocketPath } from '../../../core/canvas/paths.js';
11
+ import { updateConfig, updateState } from '../../../core/config.js';
12
+ import { closeScopedStores } from '../../../core/scoped-state/db.js';
13
+ import { initializeFreshScopedStore } from '../../../core/scoped-state/migrate.js';
14
+ import { setRelayToken } from '../../../core/secrets.js';
11
15
  import { Router } from '../../../daemon/api/router.js';
12
16
  import { createApiServer } from '../../../daemon/api/server.js';
13
17
  function node(id, parent) {
@@ -86,13 +90,19 @@ function startMockRemoteCanvas(route) {
86
90
  test('canvas dashboard renders scoped and full cycles from one node snapshot without per-node API reads', async (t) => {
87
91
  const root = mkdtempSync(join(tmpdir(), 'crtr-dashboard-'));
88
92
  const home = join(root, 'canvas');
93
+ const userHome = join(root, 'user');
89
94
  mkdirSync(home, { recursive: true });
90
- const previousHome = process.env['CRTR_HOME'];
95
+ const previousCanvasHome = process.env['CRTR_HOME'];
96
+ const previousUserHome = process.env['HOME'];
91
97
  const originalHandle = Router.prototype.handle;
92
98
  const requests = [];
93
99
  try {
94
100
  process.env['CRTR_HOME'] = home;
101
+ process.env['HOME'] = userHome;
102
+ mkdirSync(join(userHome, '.crouter'), { recursive: true });
95
103
  closeDb();
104
+ migrate(openDb());
105
+ initializeFreshScopedStore({ kind: 'user', root: join(userHome, '.crouter') });
96
106
  createNode(node('root', null));
97
107
  createNode(node('left', 'root'));
98
108
  createNode(node('right', 'root'));
@@ -162,10 +172,15 @@ test('canvas dashboard renders scoped and full cycles from one node snapshot wit
162
172
  finally {
163
173
  Router.prototype.handle = originalHandle;
164
174
  closeDb();
165
- if (previousHome === undefined)
175
+ closeScopedStores();
176
+ if (previousCanvasHome === undefined)
166
177
  delete process.env['CRTR_HOME'];
167
178
  else
168
- process.env['CRTR_HOME'] = previousHome;
179
+ process.env['CRTR_HOME'] = previousCanvasHome;
180
+ if (previousUserHome === undefined)
181
+ delete process.env['HOME'];
182
+ else
183
+ process.env['HOME'] = previousUserHome;
169
184
  rmSync(root, { recursive: true, force: true });
170
185
  }
171
186
  });
@@ -173,6 +188,7 @@ test('canvas dashboard reads full-forest ticket counts from the selected remote
173
188
  const root = mkdtempSync(join(tmpdir(), 'crtr-dashboard-remote-'));
174
189
  const home = join(root, 'canvas');
175
190
  const userHome = join(root, 'user');
191
+ const previousUserHome = process.env['HOME'];
176
192
  const remote = await startMockRemoteCanvas((args) => {
177
193
  if (args[1] === 'node' && args[2] === 'inspect' && args[3] === 'list') {
178
194
  return { nodes: [node('root', null), node('child', 'root')] };
@@ -187,13 +203,17 @@ test('canvas dashboard reads full-forest ticket counts from the selected remote
187
203
  });
188
204
  t.after(() => remote.close());
189
205
  try {
206
+ process.env['HOME'] = userHome;
190
207
  mkdirSync(join(userHome, '.crouter'), { recursive: true });
191
- writeFileSync(join(userHome, '.crouter', 'config.json'), JSON.stringify({
192
- remoteCanvas: { targets: { remote: { previewEndpoint: remote.url, relayTokenRef: 'remote' } } },
193
- }));
194
- writeFileSync(join(userHome, '.crouter', 'state.json'), JSON.stringify({ activeCanvas: 'remote' }));
195
- writeFileSync(join(userHome, '.crouter', 'secrets.json'), JSON.stringify({ relayTokens: { remote: 'test-token' } }));
196
- const result = await runDashboard(home, undefined, { HOME: userHome });
208
+ initializeFreshScopedStore({ kind: 'user', root: join(userHome, '.crouter') });
209
+ updateConfig('user', (config) => {
210
+ config.remoteCanvas.targets['remote'] = { previewEndpoint: remote.url, relayTokenRef: 'remote' };
211
+ });
212
+ updateState('user', (state) => {
213
+ state.activeCanvas = 'remote';
214
+ });
215
+ setRelayToken('remote', 'test-token', 'user');
216
+ const result = await runDashboard(home);
197
217
  assert.equal(result.code, 0, result.stderr);
198
218
  const output = JSON.parse(result.stdout);
199
219
  assert.deepEqual(output.rows.map((row) => ({ node_id: row.node_id, asks: row.asks })), [
@@ -207,6 +227,11 @@ test('canvas dashboard reads full-forest ticket counts from the selected remote
207
227
  assert.equal(remote.requests.length, 3, `remote issued ${remote.requests.length} commands: ${remote.requests.map((args) => args.join(' ')).join(' | ')}`);
208
228
  }
209
229
  finally {
230
+ closeScopedStores();
231
+ if (previousUserHome === undefined)
232
+ delete process.env['HOME'];
233
+ else
234
+ process.env['HOME'] = previousUserHome;
210
235
  rmSync(root, { recursive: true, force: true });
211
236
  }
212
237
  });