@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
@@ -7,8 +7,11 @@ import { after, before, test } from 'node:test';
7
7
  import assert from 'node:assert/strict';
8
8
  import { readFileSync } from 'node:fs';
9
9
  import { subscribe } from '../../canvas/index.js';
10
+ import { claimNodeMail } from '../../canvas/deliveries.js';
11
+ import { beginExecution } from '../../canvas/executions.js';
10
12
  import { resolveRef } from '../../canvas/history.js';
11
- import { appendInbox, coalesce, readInboxSince } from '../../feed/inbox.js';
13
+ import { coalesce, nodeMailEntry } from '../../feed/inbox.js';
14
+ import { enqueueNodeMail } from '../../feed/messages.js';
12
15
  import { pushUpdate } from '../../feed/feed.js';
13
16
  import { contextDirNote } from '../../runtime/bearings-render.js';
14
17
  import { coalesceBrokerInbox } from '../../runtime/broker/inbox.js';
@@ -16,15 +19,24 @@ import { createHeadlessHarness } from '../helpers/harness.js';
16
19
  let h;
17
20
  let root;
18
21
  let recipient;
22
+ let recipientExecution;
19
23
  before(async () => {
20
24
  h = await createHeadlessHarness({ sessionPrefix: 'crtr-inbox-reference-guidance' });
21
25
  root = h.spawnRoot('inbox reference guidance seam root');
22
26
  recipient = h.fabricateBrokerNode({ id: 'inbox-reference-recipient', parent: root, status: 'idle' });
27
+ recipientExecution = beginExecution(recipient, { daemonEpoch: h.fleet.epoch() });
23
28
  });
24
29
  after(async () => {
25
30
  if (h !== undefined)
26
31
  await h.dispose();
27
32
  });
33
+ function latestEntry() {
34
+ const claim = claimNodeMail(recipient, recipientExecution, 'wake');
35
+ assert.equal(claim.action, 'claimed');
36
+ const delivery = claim.deliveries.at(-1);
37
+ assert.ok(delivery, 'the newly enqueued delivery is handed to the recipient execution');
38
+ return nodeMailEntry(delivery);
39
+ }
28
40
  function onlyCard(entries) {
29
41
  const deliveries = coalesce(entries);
30
42
  assert.equal(deliveries.length, 1, 'one non-human inbox entry produces one card');
@@ -36,7 +48,7 @@ test('delivered report and message refs name the exact way to read their bodies'
36
48
  subscribe(recipient, publisher, true);
37
49
  const reportBody = 'published report body';
38
50
  await pushUpdate(publisher, reportBody);
39
- const reportEntry = readInboxSince(recipient).at(-1);
51
+ const reportEntry = latestEntry();
40
52
  assert.equal(reportEntry.ref?.startsWith(`${publisher}:reports/`), true, 'delivery carries the canonical report handle');
41
53
  const reportRef = reportEntry.ref;
42
54
  const reportCard = onlyCard([reportEntry]);
@@ -49,13 +61,15 @@ test('delivered report and message refs name the exact way to read their bodies'
49
61
  'a'.repeat(1001),
50
62
  Array.from({ length: 13 }, (_, i) => `line ${i + 1}`).join('\n'),
51
63
  ]) {
52
- const message = appendInbox(recipient, {
53
- from: publisher,
54
- tier: 'normal',
64
+ enqueueNodeMail(recipient, {
65
+ senderNodeId: publisher,
66
+ urgency: 'normal',
67
+ wake: 1,
55
68
  kind: 'message',
56
69
  label: 'long message',
57
- data: { body },
70
+ bodyJson: { body },
58
71
  });
72
+ const message = latestEntry();
59
73
  assert.ok(message.ref?.startsWith('/'), 'a clipped message stores its full body at an absolute recipient path');
60
74
  const messageCard = onlyCard([message]);
61
75
  const brokerMessageCard = coalesceBrokerInbox([message], new Map())[0].text;
@@ -8,11 +8,35 @@ import assert from 'node:assert/strict';
8
8
  import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
9
9
  import { join } from 'node:path';
10
10
  import { closeDb } from '../../canvas/db.js';
11
- import { readOutcomeDelivery } from '../../canvas/node-outcome-deliveries.js';
11
+ import { messageBodyForDelivery, readExternalActionDelivery } from '../../canvas/deliveries.js';
12
12
  import { createHeadlessHarness } from '../helpers/harness.js';
13
13
  let h;
14
14
  let root;
15
15
  let project;
16
+ function outcomeDelivery(nodeId) {
17
+ const row = readExternalActionDelivery(`node-outcome:${nodeId}`);
18
+ if (row === null)
19
+ return null;
20
+ const adapter = row.adapter;
21
+ if (adapter?.adapter !== 'subprocess' || !Array.isArray(adapter.argv) || !adapter.argv.every((entry) => typeof entry === 'string') || typeof adapter.cwd !== 'string')
22
+ throw new Error(`outcome delivery ${row.deliveryId} has an invalid subprocess adapter`);
23
+ if (row.state !== 'armed' && row.state !== 'pending' && row.state !== 'handed_off' && row.state !== 'acknowledged' && row.state !== 'permanent_failed')
24
+ throw new Error(`outcome delivery ${row.deliveryId} has an invalid state`);
25
+ return {
26
+ state: row.state === 'handed_off' ? 'running' : row.state === 'acknowledged' ? 'accepted' : row.state,
27
+ actionName: row.destinationId,
28
+ argv: adapter.argv,
29
+ cwd: adapter.cwd,
30
+ configOrigin: typeof adapter.config_origin === 'string' ? adapter.config_origin : '',
31
+ payload: adapter.payload ?? null,
32
+ document: row.messageId === null ? null : messageBodyForDelivery(row.deliveryId),
33
+ attempt: row.attempts,
34
+ nextAttemptAt: row.nextAttemptAt ?? 0,
35
+ acceptedAt: row.acknowledgedAt,
36
+ permanentFailedAt: row.failedAt,
37
+ lastFailure: row.lastFailure,
38
+ };
39
+ }
16
40
  function assertKeys(value, expected, label) {
17
41
  assert.deepEqual(Object.keys(value).sort(), [...expected].sort(), `${label} has the pinned document fields`);
18
42
  }
@@ -54,7 +78,7 @@ function assertResultDocument(document, nodeId, action, payloadJson, attempt) {
54
78
  function deliveryWhen(nodeId, predicate, label) {
55
79
  return h.waitFor(() => {
56
80
  closeDb();
57
- const delivery = readOutcomeDelivery(nodeId);
81
+ const delivery = outcomeDelivery(nodeId);
58
82
  return delivery !== null && predicate(delivery) ? delivery : null;
59
83
  }, { label, timeoutMs: 20_000 });
60
84
  }
@@ -71,7 +95,7 @@ async function createAndFinalize(action, payload) {
71
95
  const nodeId = createdBody.node_id;
72
96
  await h.awaitBoot(nodeId);
73
97
  closeDb();
74
- const armed = readOutcomeDelivery(nodeId);
98
+ const armed = outcomeDelivery(nodeId);
75
99
  assert.notEqual(armed, null, `node birth arms ${action} delivery`);
76
100
  assert.equal(armed.state, 'armed');
77
101
  assert.equal(armed.actionName, action);
@@ -14,7 +14,7 @@ import { tmpdir } from 'node:os';
14
14
  import { join } from 'node:path';
15
15
  import { gitSync } from '../git.js';
16
16
  import { getNode } from '../canvas/canvas.js';
17
- import { closeDb } from '../canvas/db.js';
17
+ import { closeDb, migrate, openDb } from '../canvas/db.js';
18
18
  import { spawnNode } from '../runtime/nodes.js';
19
19
  import { spawnChild } from '../runtime/spawn.js';
20
20
  import { managedWorktreePath } from '../worktree.js';
@@ -41,6 +41,7 @@ beforeEach(() => {
41
41
  closeDb();
42
42
  rmSync(home, { recursive: true, force: true });
43
43
  process.env['CRTR_HOME'] = home;
44
+ migrate(openDb());
44
45
  });
45
46
  after(async () => {
46
47
  closeDb();
@@ -10,7 +10,7 @@ import { tmpdir } from 'node:os';
10
10
  import { join } from 'node:path';
11
11
  import { createNode, deliverAndSettleMessageWait, getNode, subscribe, setMessageWait, setStatus } from '../canvas/canvas.js';
12
12
  import { armCron, cancelCron, setCronState } from '../canvas/crons.js';
13
- import { closeDb, openDb } from '../canvas/db.js';
13
+ import { closeDb, openDb, migrate } from '../canvas/db.js';
14
14
  import { hasLiveObligation } from '../../daemon/reconcilers/live-obligation.js';
15
15
  import { contextDir } from '../canvas/paths.js';
16
16
  import { bashJobPaths } from '../bash-jobs.js';
@@ -61,6 +61,7 @@ before(() => {
61
61
  beforeEach(() => {
62
62
  closeDb();
63
63
  rmSync(home, { recursive: true, force: true });
64
+ migrate(openDb());
64
65
  });
65
66
  after(() => {
66
67
  closeDb();
@@ -6,18 +6,19 @@
6
6
  // an async writer whose provider returned an incomplete token set.
7
7
  import { before, test } from 'node:test';
8
8
  import assert from 'node:assert/strict';
9
- import { mkdtempSync, readFileSync } from 'node:fs';
9
+ import { mkdtempSync } from 'node:fs';
10
10
  import { tmpdir } from 'node:os';
11
11
  import { join } from 'node:path';
12
+ import { initializeFreshScopedStore } from '../scoped-state/migrate.js';
12
13
  const agentDir = mkdtempSync(join(tmpdir(), 'crtr-pool-guard-'));
13
14
  process.env['PI_CODING_AGENT_DIR'] = agentDir;
14
15
  // Imported dynamically so `PI_CODING_AGENT_DIR` is already set: the pool path is resolved per
15
16
  // access, but the import must not race the env write in any future refactor.
16
17
  let state;
17
18
  before(async () => {
19
+ initializeFreshScopedStore({ kind: 'provider', root: agentDir });
18
20
  state = await import('../subscription-state.js');
19
21
  });
20
- const POOL = join(agentDir, 'openai-codex-subscriptions.json');
21
22
  async function seed() {
22
23
  await state.writeSubscriptionPool('openai-codex', [
23
24
  {
@@ -33,7 +34,7 @@ async function seed() {
33
34
  ]);
34
35
  }
35
36
  function stored() {
36
- const pool = JSON.parse(readFileSync(POOL, 'utf8'));
37
+ const pool = state.readSubscriptionPool('openai-codex');
37
38
  assert.equal(pool.length, 1, 'the row itself must survive every refused write');
38
39
  return pool[0];
39
40
  }
@@ -10,27 +10,41 @@
10
10
  // Run: node --import tsx/esm --test src/core/__tests__/warm-claim-preference-snapshot.test.ts
11
11
  import { test, before, beforeEach, after } from 'node:test';
12
12
  import assert from 'node:assert/strict';
13
- import { mkdtempSync, mkdirSync, rmSync } from 'node:fs';
13
+ import { mkdtempSync, rmSync } from 'node:fs';
14
14
  import { tmpdir } from 'node:os';
15
15
  import { join } from 'node:path';
16
- import { closeDb } from '../canvas/db.js';
16
+ import { closeDb, migrate, openDb } from '../canvas/db.js';
17
+ import { resetScopeCache } from '../scope.js';
18
+ import { closeScopedStores } from '../scoped-state/db.js';
19
+ import { initializeFreshScopedStore } from '../scoped-state/migrate.js';
17
20
  import { spawnNode } from '../runtime/nodes.js';
18
21
  import { deliverBearingsLive } from '../runtime/deliver-live.js';
19
22
  import { loadContextExposureState } from '../substrate/injected-store.js';
20
23
  let home;
24
+ const previousHome = process.env['HOME'];
21
25
  before(() => {
22
26
  home = mkdtempSync(join(tmpdir(), 'crtr-warm-snapshot-'));
23
- process.env['CRTR_HOME'] = home;
27
+ process.env['HOME'] = home;
28
+ process.env['CRTR_HOME'] = join(home, 'canvas');
24
29
  });
25
30
  beforeEach(() => {
26
31
  closeDb();
32
+ closeScopedStores();
27
33
  rmSync(home, { recursive: true, force: true });
28
- mkdirSync(home, { recursive: true });
34
+ resetScopeCache();
35
+ initializeFreshScopedStore({ kind: 'user', root: join(home, '.crouter') });
36
+ migrate(openDb());
29
37
  });
30
38
  after(() => {
31
39
  closeDb();
40
+ closeScopedStores();
32
41
  rmSync(home, { recursive: true, force: true });
33
42
  delete process.env['CRTR_HOME'];
43
+ if (previousHome === undefined)
44
+ delete process.env['HOME'];
45
+ else
46
+ process.env['HOME'] = previousHome;
47
+ resetScopeCache();
34
48
  });
35
49
  test('the claim path persists a frozen preference snapshot', async () => {
36
50
  const meta = await spawnNode({ kind: 'general', cwd: '/tmp/work', parent: null });
@@ -13,7 +13,7 @@ import { mkdtempSync, rmSync } from 'node:fs';
13
13
  import { tmpdir } from 'node:os';
14
14
  import { join } from 'node:path';
15
15
  import { createNode, getNode } from '../canvas/canvas.js';
16
- import { closeDb } from '../canvas/db.js';
16
+ import { closeDb, migrate, openDb } from '../canvas/db.js';
17
17
  import { requestYield } from '../runtime/promote.js';
18
18
  let home;
19
19
  function mkOrchestrator(id) {
@@ -36,6 +36,7 @@ before(() => {
36
36
  beforeEach(() => {
37
37
  closeDb();
38
38
  rmSync(home, { recursive: true, force: true });
39
+ migrate(openDb());
39
40
  });
40
41
  after(() => {
41
42
  closeDb();
@@ -2,6 +2,7 @@ import { homedir } from 'node:os';
2
2
  import { join } from 'node:path';
3
3
  import { findProjectScopeRoot, resetScopeCache, userScopeRoot } from './scope.js';
4
4
  import { ensureScopeInitialized } from './config.js';
5
+ import { initializeFreshScopedStore } from './scoped-state/migrate.js';
5
6
  import { CRTR_DIR_NAME } from '../types.js';
6
7
  import { envDebug } from '../shared/env.js';
7
8
  const SKIP_SUBCOMMANDS = new Set([
@@ -29,6 +30,7 @@ export function ensureProjectScope(argv) {
29
30
  return;
30
31
  if (shouldSkipForArgv(argv))
31
32
  return;
33
+ initializeFreshScopedStore({ kind: 'user', root: userScopeRoot() });
32
34
  // Already inside a project scope (here or in an ancestor) — nothing to do.
33
35
  if (findProjectScopeRoot() !== null)
34
36
  return;
@@ -1,24 +1,69 @@
1
1
  import assert from 'node:assert/strict';
2
- import { mkdirSync, mkdtempSync, rmSync } from 'node:fs';
2
+ import { existsSync, mkdtempSync, rmSync } from 'node:fs';
3
3
  import test from 'node:test';
4
- import { nodeDir } from '../../canvas/paths.js';
5
- import { readFault } from '../../runtime/fault.js';
4
+ import { CrtrClient } from '../../../api/client.js';
5
+ import { createNode } from '../../canvas/canvas.js';
6
+ import { closeDb, migrate, openDb } from '../../canvas/db.js';
7
+ import { apiSocketPath } from '../../canvas/paths.js';
8
+ import { readFault } from '../../canvas/recovery.js';
9
+ import { createApiServer } from '../../../daemon/api/server.js';
6
10
  import { SocketTransport } from '../transport-socket.js';
11
+ async function waitFor(check, label) {
12
+ for (let i = 0; i < 200; i++) {
13
+ if (check())
14
+ return;
15
+ await new Promise((resolve) => setTimeout(resolve, 5));
16
+ }
17
+ throw new Error(`timed out waiting for ${label}`);
18
+ }
19
+ async function waitForSocket() {
20
+ const client = CrtrClient.forLocalSocket({ autostart: false });
21
+ await waitFor(() => existsSync(apiSocketPath()), 'the API socket path');
22
+ for (let i = 0; i < 200; i++) {
23
+ try {
24
+ await client.healthz();
25
+ return;
26
+ }
27
+ catch {
28
+ await new Promise((resolve) => setTimeout(resolve, 5));
29
+ }
30
+ }
31
+ throw new Error('timed out waiting for the API socket');
32
+ }
33
+ function node(nodeId) {
34
+ return {
35
+ node_id: nodeId,
36
+ name: nodeId,
37
+ created: new Date().toISOString(),
38
+ cwd: '/tmp/work',
39
+ kind: 'general',
40
+ mode: 'base',
41
+ lifecycle: 'terminal',
42
+ status: 'active',
43
+ };
44
+ }
7
45
  test('a missing dormant broker does not leave a viewer↔broker fault', async () => {
8
46
  const previousHome = process.env['CRTR_HOME'];
9
47
  const home = mkdtempSync('/tmp/crtr-transport-socket-');
48
+ let server;
10
49
  process.env['CRTR_HOME'] = home;
50
+ closeDb();
51
+ migrate(openDb());
11
52
  try {
53
+ server = createApiServer();
54
+ await waitForSocket();
12
55
  const nodeId = 'dormant-node';
13
- mkdirSync(nodeDir(nodeId), { recursive: true });
56
+ createNode(node(nodeId));
14
57
  const transport = new SocketTransport(nodeId);
15
58
  await assert.rejects(transport.redial());
16
- assert.equal(readFault(nodeId)?.link, 'viewer↔broker', 'an ordinary failed redial records the outage');
59
+ await waitFor(() => readFault(nodeId)?.link === 'viewer↔broker', 'the failed redial fault');
17
60
  await assert.rejects(transport.redial({ brokerUnavailableIsExpected: true }));
18
- assert.equal(readFault(nodeId), null, 'a dormant node with no broker is normal, not a fault');
61
+ await waitFor(() => readFault(nodeId) === null, 'the expected-unavailable fault clear');
19
62
  transport.destroy();
20
63
  }
21
64
  finally {
65
+ await server?.close();
66
+ closeDb();
22
67
  if (previousHome === undefined)
23
68
  delete process.env['CRTR_HOME'];
24
69
  else
@@ -20,6 +20,7 @@ export declare class SocketTransport extends EventEmitter implements Transport {
20
20
  redial(options?: RedialOptions): Promise<void>;
21
21
  send(frame: ClientToBroker): void;
22
22
  destroy(): void;
23
+ private clearSocketFault;
23
24
  private onData;
24
25
  private onError;
25
26
  private onClose;
@@ -11,7 +11,8 @@ import { EventEmitter } from 'node:events';
11
11
  import { createConnection } from 'node:net';
12
12
  import { viewSocketPath } from '../canvas/paths.js';
13
13
  import { classify } from '../fault-classifier.js';
14
- import { clearFault, recordFault } from '../runtime/fault.js';
14
+ import { clearNodeFault, recordNodeFault } from '../runtime/broker/daemon-ops.js';
15
+ import { emitEvent } from '../events/emit.js';
15
16
  import { CLIENT_READ_CAPS, encodeFrame, FrameDecoder, FrameOverflowError, } from '../runtime/broker-protocol.js';
16
17
  import { BrokerUnavailableError } from './transport.js';
17
18
  export class SocketTransport extends EventEmitter {
@@ -37,7 +38,7 @@ export class SocketTransport extends EventEmitter {
37
38
  this.redialFaultRecorded = true;
38
39
  }
39
40
  const classified = classify('viewer↔broker', err);
40
- recordFault(this.nodeId, {
41
+ void recordNodeFault(this.nodeId, {
41
42
  link: 'viewer↔broker',
42
43
  op,
43
44
  kind: classified.kind,
@@ -45,6 +46,8 @@ export class SocketTransport extends EventEmitter {
45
46
  ? { disposition: 'auto', by: 'client' }
46
47
  : { disposition: 'manual' },
47
48
  message: err instanceof Error ? err.message : String(err),
49
+ }).catch((error) => {
50
+ emitEvent({ event: 'broker.daemon.operation.failed', level: 'error', node_id: this.nodeId, error, fields: { operation: 'viewer_fault_record' } });
48
51
  });
49
52
  }
50
53
  connect() {
@@ -52,7 +55,7 @@ export class SocketTransport extends EventEmitter {
52
55
  this.socket = socket;
53
56
  socket.on('connect', () => {
54
57
  this.redialFaultRecorded = false;
55
- clearFault(this.nodeId, { link: 'viewer↔broker' });
58
+ this.clearSocketFault();
56
59
  this.emit('connect');
57
60
  });
58
61
  socket.on('data', (chunk) => this.onData(chunk));
@@ -68,7 +71,7 @@ export class SocketTransport extends EventEmitter {
68
71
  this.closeEmitted = false;
69
72
  if (options.brokerUnavailableIsExpected) {
70
73
  this.redialFaultRecorded = false;
71
- clearFault(this.nodeId, { link: 'viewer↔broker' });
74
+ this.clearSocketFault();
72
75
  }
73
76
  return new Promise((resolve, reject) => {
74
77
  const socket = createConnection(this.socketPath);
@@ -79,7 +82,7 @@ export class SocketTransport extends EventEmitter {
79
82
  return;
80
83
  settled = true;
81
84
  this.redialFaultRecorded = false;
82
- clearFault(this.nodeId, { link: 'viewer↔broker' });
85
+ this.clearSocketFault();
83
86
  this.emit('connect');
84
87
  resolve();
85
88
  });
@@ -127,6 +130,11 @@ export class SocketTransport extends EventEmitter {
127
130
  }
128
131
  }
129
132
  }
133
+ clearSocketFault() {
134
+ void clearNodeFault(this.nodeId, { link: 'viewer↔broker' }).catch((error) => {
135
+ emitEvent({ event: 'broker.daemon.operation.failed', level: 'error', node_id: this.nodeId, error, fields: { operation: 'viewer_fault_clear' } });
136
+ });
137
+ }
130
138
  onData(chunk) {
131
139
  let frames;
132
140
  try {
@@ -1,14 +1,14 @@
1
- // attention.test.ts — tickets are keyed by their human bridge node directory.
1
+ // attention.test.ts — pending requests are attributed by requester identity.
2
2
  import { test, before, beforeEach, after } from 'node:test';
3
3
  import assert from 'node:assert/strict';
4
- import { mkdtempSync, rmSync, mkdirSync } from 'node:fs';
4
+ import { mkdtempSync, rmSync } from 'node:fs';
5
5
  import { tmpdir } from 'node:os';
6
6
  import { join } from 'node:path';
7
- import { atomicWriteJson, bindTicketReplyRoute, pageManifestPath } from '../../human/convention.js';
7
+ import { createPageRequest } from '../../human/requests.js';
8
8
  import { createNode } from '../canvas.js';
9
9
  import { closeDb } from '../db.js';
10
- import { nodeDir } from '../paths.js';
11
10
  import { ticketCountsForNodes, pendingTicketsForView, invalidateTicketCounts } from '../attention.js';
11
+ import { migrate, openDb } from '../db.js';
12
12
  function meta(id, cwd, extra) {
13
13
  return {
14
14
  node_id: id,
@@ -22,26 +22,25 @@ function meta(id, cwd, extra) {
22
22
  ...extra,
23
23
  };
24
24
  }
25
- // A ticket only counts as attention when it routes a reply back, so the fixture binds
26
- // the reply route the same way `human send` does before writing the page manifest.
27
- function seedPage(bridgeId) {
28
- const dir = nodeDir(bridgeId);
29
- mkdirSync(dir, { recursive: true });
30
- bindTicketReplyRoute(dir, bridgeId);
31
- atomicWriteJson(pageManifestPath(dir), {
32
- schema: 'crtr.page/v2',
33
- dialect: 'jsx',
34
- title: bridgeId,
35
- subtitle: 'Acknowledge this ticket so the request can proceed.',
36
- delivery: { placement: 'inline', inbox: true, reply: true },
37
- document: 'page.tsx',
38
- steps: 1,
39
- slots: [],
25
+ function seedPage(requestId, requesterNodeId) {
26
+ createPageRequest({
27
+ request_id: requestId,
28
+ requester_node_id: requesterNodeId,
29
+ prepared: {
30
+ document: '<html><head><title>Request</title></head><body>Request</body></html>',
31
+ manifest: {
32
+ schema: 'crtr.page/v2',
33
+ dialect: 'html',
34
+ title: requestId,
35
+ subtitle: 'Acknowledge this ticket so the request can proceed.',
36
+ delivery: { placement: 'inline', inbox: true, reply: true },
37
+ document: 'page.html',
38
+ steps: 1,
39
+ slots: [],
40
+ },
41
+ },
40
42
  });
41
43
  }
42
- function bridge(id, parent, cwd) {
43
- createNode(meta(id, cwd, { kind: 'human', parent }));
44
- }
45
44
  let home;
46
45
  let sharedCwd;
47
46
  let soloCwd;
@@ -55,6 +54,7 @@ beforeEach(() => {
55
54
  closeDb();
56
55
  invalidateTicketCounts();
57
56
  rmSync(home, { recursive: true, force: true });
57
+ migrate(openDb());
58
58
  });
59
59
  after(() => {
60
60
  closeDb();
@@ -62,27 +62,21 @@ after(() => {
62
62
  rmSync(d, { recursive: true, force: true });
63
63
  delete process.env['CRTR_HOME'];
64
64
  });
65
- test('ticketCountsForNodes follows bridge parents even when asking nodes share a cwd', () => {
65
+ test('ticketCountsForNodes follows requester identity even when asking nodes share a cwd', () => {
66
66
  createNode(meta('a', sharedCwd));
67
67
  createNode(meta('b', sharedCwd));
68
68
  createNode(meta('c', soloCwd));
69
- bridge('ha1', 'a', sharedCwd);
70
- bridge('ha2', 'a', sharedCwd);
71
- bridge('hb', 'b', sharedCwd);
72
- bridge('hc', 'c', soloCwd);
73
- seedPage('ha1');
74
- seedPage('ha2');
75
- seedPage('hb');
76
- seedPage('hc');
69
+ seedPage('request-a1', 'a');
70
+ seedPage('request-a2', 'a');
71
+ seedPage('request-b', 'b');
72
+ seedPage('request-c', 'c');
77
73
  assert.deepEqual(ticketCountsForNodes(['a', 'b', 'c']), { a: 2, b: 1, c: 1 });
78
74
  });
79
75
  test('pendingTicketsForView returns the asking node rather than a cwd bucket', () => {
80
76
  createNode(meta('a', sharedCwd));
81
77
  createNode(meta('b', sharedCwd));
82
- bridge('ha', 'a', sharedCwd);
83
- bridge('hb', 'b', sharedCwd);
84
- seedPage('ha');
85
- seedPage('hb');
78
+ seedPage('request-a', 'a');
79
+ seedPage('request-b', 'b');
86
80
  assert.deepEqual(pendingTicketsForView('a').map(({ node_id, count }) => ({ node_id, count })), [
87
81
  { node_id: 'a', count: 1 },
88
82
  ]);
@@ -8,12 +8,12 @@
8
8
  // regression rather than a reader bug, so it is worth pinning.
9
9
  import { test, before, beforeEach, after } from 'node:test';
10
10
  import assert from 'node:assert/strict';
11
- import { mkdtempSync, rmSync, mkdirSync, writeFileSync } from 'node:fs';
11
+ import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
12
12
  import { tmpdir } from 'node:os';
13
13
  import { join } from 'node:path';
14
14
  import { createNode } from '../canvas.js';
15
- import { closeDb } from '../db.js';
16
- import { nodeDir, sessionPtrPath } from '../paths.js';
15
+ import { closeDb, migrate, openDb } from '../db.js';
16
+ import { resetSession } from '../sessions.js';
17
17
  import { nodeArtifacts, groupCorpus } from '../history.js';
18
18
  const NODE = 'test-transcript-node';
19
19
  function meta(id, cwd) {
@@ -45,8 +45,6 @@ function stampEntry(msgTs, origin) {
45
45
  /** A session file in the real on-disk shape: stamps precede their messages,
46
46
  * one inbound turn is unstamped, and an assistant turn sits between them. */
47
47
  function seedSession(home) {
48
- const dir = nodeDir(NODE);
49
- mkdirSync(dir, { recursive: true });
50
48
  const file = join(home, 'session.jsonl');
51
49
  writeFileSync(file, [
52
50
  JSON.stringify({ type: 'custom', customType: 'crtr-stamp', data: { v: 1, kind: 'session', payload: { node: NODE, crtr: '0.0.0' } } }),
@@ -57,7 +55,7 @@ function seedSession(home) {
57
55
  messageEntry('user', 'a delivery', 2000),
58
56
  messageEntry('user', 'no stamp for this one', 3000),
59
57
  ].join('\n'), 'utf8');
60
- writeFileSync(sessionPtrPath(NODE), file, 'utf8');
58
+ resetSession(NODE, { sessionId: 'history-transcript-session', transcriptPath: file });
61
59
  }
62
60
  let home;
63
61
  let cwd;
@@ -68,6 +66,8 @@ before(() => {
68
66
  });
69
67
  beforeEach(() => {
70
68
  closeDb();
69
+ rmSync(home, { recursive: true, force: true });
70
+ migrate(openDb());
71
71
  });
72
72
  after(() => {
73
73
  closeDb();
@@ -1,9 +1,12 @@
1
1
  // render-remote.test.ts — the safe-defaults contract for `render.ts`'s
2
2
  // `*FromSource` functions when given a `RemoteCanvasSource`: every field that
3
- // would require a local disk/SQLite read (hanging, streaming, viewed, ctx
4
- // tokens, asks, goal, prompts, lastAssistant) must come back suppressed to
5
- // its safe default instead of touching this process's local state. Reuses
6
- // the mock-server harness shape from `remote-canvas-source.test.ts`.
3
+ // would require a local disk/SQLite read (viewed, ctx tokens, asks, goal,
4
+ // prompts, lastAssistant) must come back suppressed to its safe default
5
+ // instead of touching this process's local state. `hanging`/`streaming` are
6
+ // not suppressed — they are projected by the REMOTE daemon and arrive on the
7
+ // row, so the contract for them is that the row carries the remote fault and
8
+ // never the local one. Reuses the mock-server harness shape from
9
+ // `remote-canvas-source.test.ts`.
7
10
  //
8
11
  // This is adversarial, not merely a clean-machine assertion: BEFORE calling
9
12
  // the render functions, the test seeds real, CONFLICTING local state for the
@@ -23,10 +26,10 @@ import { atomicWriteJson, pageManifestPath } from '#core/human/convention';
23
26
  import { RemoteCanvasSource } from '../remote-canvas-source.js';
24
27
  import { dashboardRowsAllFromSource, enrichRowsFromSource, loadPreviewFromSource, renderForestFromSource } from '../render-source.js';
25
28
  import { createNode } from '../canvas.js';
26
- import { closeDb } from '../db.js';
29
+ import { closeDb, migrate, openDb } from '../db.js';
27
30
  import { openFocusRow } from '../focuses.js';
28
31
  import { jobDir, contextDir, nodeDir } from '../paths.js';
29
- import { recordFault } from '../../runtime/fault.js';
32
+ import { recordFault } from '../recovery.js';
30
33
  function startMockCrtrServer(route) {
31
34
  return new Promise((resolve) => {
32
35
  const server = createServer((req, res) => {
@@ -63,8 +66,9 @@ function meta(id, extra) {
63
66
  ...extra,
64
67
  };
65
68
  }
66
- function row(id) {
69
+ function row(id, fault) {
67
70
  return {
71
+ ...(fault === undefined ? {} : { fault }),
68
72
  node_id: id,
69
73
  name: id,
70
74
  kind: 'general',
@@ -97,6 +101,7 @@ beforeEach(() => {
97
101
  closeDb();
98
102
  rmSync(home, { recursive: true, force: true });
99
103
  rmSync(nodeDir('poison-ask'), { recursive: true, force: true });
104
+ migrate(openDb());
100
105
  });
101
106
  after(() => {
102
107
  closeDb();
@@ -146,11 +151,22 @@ function seedPoisonedLocalState() {
146
151
  ].join('\n'));
147
152
  return sf;
148
153
  }
154
+ /** What the remote daemon projected onto its own row — the only fault a remote
155
+ * row may ever show. */
156
+ const remoteFault = {
157
+ link: 'daemon→node',
158
+ op: 'remote turn',
159
+ kind: 'wedged',
160
+ retry: { disposition: 'manual' },
161
+ message: 'remote daemon fault',
162
+ since: new Date().toISOString(),
163
+ operation_id: '44444444444444444444444444444444',
164
+ };
149
165
  test('dashboardRowsAllFromSource / enrichRowsFromSource / loadPreviewFromSource suppress every local-read field to its safe default for a RemoteCanvasSource, even with conflicting local state for the same node id', async (t) => {
150
166
  sessionFile = seedPoisonedLocalState();
151
167
  const server = await startMockCrtrServer((args) => {
152
168
  if (args[1] === 'node' && args[2] === 'inspect' && args[3] === 'list') {
153
- return { body: { nodes: [row('a')] } };
169
+ return { body: { nodes: [row('a', remoteFault)] } };
154
170
  }
155
171
  if (args[1] === 'node' && args[2] === 'inspect' && args[3] === 'show') {
156
172
  return {
@@ -177,7 +193,7 @@ test('dashboardRowsAllFromSource / enrichRowsFromSource / loadPreviewFromSource
177
193
  const rows = await dashboardRowsAllFromSource(source);
178
194
  assert.equal(rows.length, 1);
179
195
  const r = rows[0];
180
- assert.equal(r.hanging, null, 'local active fault must not leak into a remote row');
196
+ assert.equal(r.hanging?.message, 'remote daemon fault', 'the remote row must carry the fault its own daemon projected');
181
197
  assert.equal(r.streaming, false);
182
198
  assert.equal(r.viewed, false, 'local focus must not leak into a remote row');
183
199
  await enrichRowsFromSource(source, rows);