@north-light/crouter 0.3.311 → 0.3.313

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (520) hide show
  1. package/dist/api/client.d.ts +27 -30
  2. package/dist/api/client.js +80 -67
  3. package/dist/api/dto/broker-ops.d.ts +10 -20
  4. package/dist/api/dto/canvas.d.ts +1 -10
  5. package/dist/api/dto/health.d.ts +113 -0
  6. package/dist/api/dto/human-requests.d.ts +14 -3
  7. package/dist/api/dto/human.d.ts +2 -48
  8. package/dist/api/dto/human.js +3 -2
  9. package/dist/api/dto/inbox.d.ts +14 -0
  10. package/dist/api/dto/mail.d.ts +43 -0
  11. package/dist/api/dto/nodes.d.ts +11 -8
  12. package/dist/api/dto/recovery.d.ts +96 -0
  13. package/dist/api/dto/reviews.d.ts +2 -2
  14. package/dist/api/routes.d.ts +9 -6
  15. package/dist/api/routes.js +11 -11
  16. package/dist/build-root.d.ts +4 -0
  17. package/dist/build-root.js +11 -1
  18. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/integration/provider-rotation.test.ts +35 -47
  19. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +1 -1
  20. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +12 -5
  21. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +12 -5
  22. package/dist/cli.js +10 -1
  23. package/dist/clients/__tests__/helpers/human-daemon.d.ts +11 -0
  24. package/dist/clients/__tests__/helpers/human-daemon.js +60 -0
  25. package/dist/clients/attach/chrome/canvas-panels.js +1 -1
  26. package/dist/clients/attach/chrome/inbox-strip.d.ts +3 -3
  27. package/dist/clients/attach/chrome/inbox-strip.js +17 -9
  28. package/dist/clients/attach/chrome/ticket-panel.d.ts +2 -2
  29. package/dist/clients/attach/chrome/ticket-panel.js +77 -46
  30. package/dist/clients/attach/overlays/graph.js +6 -9
  31. package/dist/clients/attach/render/chat-view.d.ts +5 -4
  32. package/dist/clients/attach/render/chat-view.js +22 -13
  33. package/dist/clients/attach/render/page-block.d.ts +11 -7
  34. package/dist/clients/attach/render/page-block.js +64 -55
  35. package/dist/clients/attach/viewer.js +746 -735
  36. package/dist/clients/inbox/__tests__/integration/inbox-controller.test.js +56 -56
  37. package/dist/clients/inbox/__tests__/integration/stale-row-activation.test.js +45 -32
  38. package/dist/clients/inbox/controller.d.ts +42 -14
  39. package/dist/clients/inbox/controller.js +240 -124
  40. package/dist/clients/inbox/dto-adapt.d.ts +28 -0
  41. package/dist/clients/inbox/dto-adapt.js +93 -0
  42. package/dist/clients/inbox/page-adapter.d.ts +5 -4
  43. package/dist/clients/inbox/page-adapter.js +12 -12
  44. package/dist/clients/inbox/resolve.d.ts +10 -5
  45. package/dist/clients/inbox/resolve.js +13 -12
  46. package/dist/clients/inbox/review/review-client.d.ts +0 -1
  47. package/dist/clients/inbox/review/review-client.js +0 -4
  48. package/dist/clients/inbox/review-adapter.d.ts +2 -1
  49. package/dist/clients/inbox/review-adapter.js +3 -5
  50. package/dist/clients/inbox/surface.d.ts +2 -2
  51. package/dist/clients/inbox/surface.js +19 -8
  52. package/dist/clients/inbox/tui.d.ts +3 -3
  53. package/dist/commands/__tests__/human.test.js +31 -15
  54. package/dist/commands/__tests__/integration/dashboard-snapshot.test.js +36 -11
  55. package/dist/commands/{sys/__tests__ → __tests__/integration}/migrate.test.js +142 -36
  56. package/dist/commands/__tests__/revive-now-gate.test.js +2 -0
  57. package/dist/commands/api-client.d.ts +5 -4
  58. package/dist/commands/api-client.js +13 -7
  59. package/dist/commands/canvas-history/shared.js +1 -1
  60. package/dist/commands/canvas-history.js +1 -1
  61. package/dist/commands/canvas-roster.js +1 -1
  62. package/dist/commands/canvas.js +1 -2
  63. package/dist/commands/human/feedback.js +20 -17
  64. package/dist/commands/human/prompts.js +45 -36
  65. package/dist/commands/human/queue.js +73 -123
  66. package/dist/commands/human/review.js +6 -16
  67. package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +2 -0
  68. package/dist/commands/memory/__tests__/memory-list-and-lint-ignore.test.js +2 -0
  69. package/dist/commands/memory/__tests__/repository-root-lint.test.js +2 -0
  70. package/dist/commands/node-inspect-artifacts.js +1 -1
  71. package/dist/commands/node-lifecycle-revive.d.ts +2 -2
  72. package/dist/commands/node-lifecycle-revive.js +9 -19
  73. package/dist/commands/pkg/plugin-manage.js +0 -1
  74. package/dist/commands/profile/show.js +4 -12
  75. package/dist/commands/surface-tmux-spread.js +1 -5
  76. package/dist/commands/sys/__tests__/config-model-ladders.test.js +23 -30
  77. package/dist/commands/sys/__tests__/sync-project-guidance.test.js +37 -11
  78. package/dist/commands/sys/branch.d.ts +2 -0
  79. package/dist/commands/sys/branch.js +19 -0
  80. package/dist/commands/sys/config.js +106 -33
  81. package/dist/commands/sys/daemon.d.ts +2 -0
  82. package/dist/commands/sys/daemon.js +130 -7
  83. package/dist/commands/sys/doctor.js +5 -15
  84. package/dist/commands/sys/migrate.js +21 -92
  85. package/dist/commands/sys/setup-settings-runner.js +4 -2
  86. package/dist/commands/sys.js +2 -15
  87. package/dist/core/__tests__/boot-fault-attempt.test.js +23 -1
  88. package/dist/core/__tests__/boot.test.js +32 -25
  89. package/dist/core/__tests__/broker-launch-candidates.test.js +49 -0
  90. package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +149 -176
  91. package/dist/core/__tests__/canvas-inbox-watcher-naming.test.js +59 -10
  92. package/dist/core/__tests__/canvas-inbox-watcher.test.js +76 -20
  93. package/dist/core/__tests__/canvas.test.js +18 -47
  94. package/dist/core/__tests__/child-death-wake.test.js +29 -7
  95. package/dist/core/__tests__/cli-help-contract.test.js +2 -0
  96. package/dist/core/__tests__/close.test.js +29 -10
  97. package/dist/core/__tests__/collectible.test.js +2 -1
  98. package/dist/core/__tests__/config-change-delta.test.js +2 -0
  99. package/dist/core/__tests__/context-intro.test.js +17 -5
  100. package/dist/core/__tests__/cron-armed-context-failure.test.js +17 -12
  101. package/dist/core/__tests__/cron-held-settlement.test.js +21 -3
  102. package/dist/core/__tests__/cron-node-sink-parked-root.test.js +29 -10
  103. package/dist/core/__tests__/cron-self-cancel-delivery.test.js +14 -2
  104. package/dist/core/__tests__/cron-timeout-descendants.test.js +13 -1
  105. package/dist/core/__tests__/daemon-boot.test.js +51 -14
  106. package/dist/core/__tests__/fixtures/fake-engine.d.ts +1 -1
  107. package/dist/core/__tests__/fixtures/fake-engine.js +8 -3
  108. package/dist/core/__tests__/focuses.test.js +10 -5
  109. package/dist/core/__tests__/helpers/harness.js +50 -18
  110. package/dist/core/__tests__/history-inbox.test.js +12 -16
  111. package/dist/core/__tests__/human-action-delivery.test.js +48 -28
  112. package/dist/core/__tests__/human-actions.test.js +7 -3
  113. package/dist/core/__tests__/inline-memory-refs.test.js +7 -2
  114. package/dist/core/__tests__/integration/broker-fork-seam.test.js +37 -10
  115. package/dist/core/__tests__/integration/broker-sdk-wiring.test.js +42 -0
  116. package/dist/core/__tests__/integration/broker-snapshot-history.test.js +42 -29
  117. package/dist/core/__tests__/integration/broker-wedge-supervision.test.js +36 -35
  118. package/dist/core/__tests__/integration/command-plugins.test.js +15 -6
  119. package/dist/core/__tests__/integration/deferred-no-wake.test.js +113 -92
  120. package/dist/core/__tests__/integration/host-teardown-process-group.test.js +9 -5
  121. package/dist/core/__tests__/integration/lifecycle-hooks.test.js +312 -1
  122. package/dist/core/__tests__/integration/plugin-revalidate.test.js +4 -0
  123. package/dist/core/__tests__/integration/profile-pause.test.js +4 -4
  124. package/dist/core/__tests__/integration/refresh-stall-recycle.test.js +9 -12
  125. package/dist/core/__tests__/integration/revive.test.js +67 -21
  126. package/dist/core/__tests__/integration/spawn-root.test.js +62 -19
  127. package/dist/core/__tests__/integration/subscription-delivery.test.js +33 -21
  128. package/dist/core/__tests__/integration/worktree-land.test.js +5 -2
  129. package/dist/core/__tests__/integration/worktree-reap.test.js +15 -1
  130. package/dist/core/__tests__/kickoff.test.js +36 -39
  131. package/dist/core/__tests__/lifecycle-terminal-reasons.test.js +2 -1
  132. package/dist/core/__tests__/lifecycle.test.js +2 -1
  133. package/dist/core/__tests__/live-lifecycle-prompt.test.js +13 -1
  134. package/dist/core/__tests__/memory-resolver-precedence.test.js +2 -0
  135. package/dist/core/__tests__/migration.test.js +145 -31
  136. package/dist/core/__tests__/model-pin-durability.test.js +4 -1
  137. package/dist/core/__tests__/model-routes-config.test.js +13 -5
  138. package/dist/core/__tests__/node-outcome.test.js +93 -26
  139. package/dist/core/__tests__/on-read-crouter-home-fence.test.js +4 -3
  140. package/dist/core/__tests__/on-read-dedup-resume.test.js +8 -7
  141. package/dist/core/__tests__/on-read-nested-store.test.js +8 -7
  142. package/dist/core/__tests__/passive-subscription.test.js +50 -157
  143. package/dist/core/__tests__/plugin-kinds.test.js +6 -4
  144. package/dist/core/__tests__/plugin-link-symlinked-scope-root.test.js +6 -1
  145. package/dist/core/__tests__/plugin-page-components.test.js +6 -4
  146. package/dist/core/__tests__/preview-registry-sync.test.js +2 -0
  147. package/dist/core/__tests__/profile-project-memory-delivery.test.js +35 -32
  148. package/dist/core/__tests__/prune.test.js +11 -5
  149. package/dist/core/__tests__/push-final-guard.test.js +14 -7
  150. package/dist/core/__tests__/relaunch-root.test.js +30 -2
  151. package/dist/core/__tests__/remote-canvas-target.test.js +7 -1
  152. package/dist/core/__tests__/repository-root-identity.test.js +4 -0
  153. package/dist/core/__tests__/review-model-floor.test.js +6 -3
  154. package/dist/core/__tests__/revive-all.test.js +13 -3
  155. package/dist/core/__tests__/revive-capacity.test.js +26 -4
  156. package/dist/core/__tests__/revive-parked-fresh.test.js +31 -8
  157. package/dist/core/__tests__/seam/broker-attach-stream.test.js +1 -1
  158. package/dist/core/__tests__/seam/broker-cap-freeze.test.js +4 -3
  159. package/dist/core/__tests__/seam/broker-crash-teardown.test.js +11 -14
  160. package/dist/core/__tests__/seam/broker-provider-retry.test.js +85 -71
  161. package/dist/core/__tests__/seam/dormancy-release.test.js +33 -19
  162. package/dist/core/__tests__/seam/held-deferred-human-prompt.test.js +7 -5
  163. package/dist/core/__tests__/seam/inbox-reference-guidance.test.js +20 -6
  164. package/dist/core/__tests__/seam/node-outcome-delivery.test.js +27 -3
  165. package/dist/core/__tests__/spawn-worktree-id-conflict.test.js +5 -4
  166. package/dist/core/__tests__/stop-guard.test.js +2 -1
  167. package/dist/core/__tests__/subscription-pool-credential-guard.test.js +4 -3
  168. package/dist/core/__tests__/warm-claim-preference-snapshot.test.js +19 -5
  169. package/dist/core/__tests__/yield-ensures-daemon.test.js +2 -1
  170. package/dist/core/bootstrap.js +2 -0
  171. package/dist/core/broker-client/__tests__/transport-socket.test.js +51 -6
  172. package/dist/core/broker-client/transport-socket.d.ts +1 -0
  173. package/dist/core/broker-client/transport-socket.js +13 -5
  174. package/dist/core/canvas/__tests__/attention.test.js +29 -35
  175. package/dist/core/canvas/__tests__/history-transcript.test.js +6 -6
  176. package/dist/core/canvas/__tests__/render-remote.test.js +25 -9
  177. package/dist/core/canvas/attention.d.ts +2 -5
  178. package/dist/core/canvas/attention.js +15 -64
  179. package/dist/core/canvas/boot.d.ts +6 -7
  180. package/dist/core/canvas/boot.js +5 -9
  181. package/dist/core/canvas/canvas.d.ts +13 -109
  182. package/dist/core/canvas/canvas.js +140 -401
  183. package/dist/core/canvas/crons.d.ts +2 -0
  184. package/dist/core/canvas/crons.js +16 -15
  185. package/dist/core/canvas/daemon-owner.js +10 -0
  186. package/dist/core/canvas/db.d.ts +2 -2
  187. package/dist/core/canvas/db.js +2 -18
  188. package/dist/core/canvas/deliveries.d.ts +104 -0
  189. package/dist/core/canvas/deliveries.js +354 -0
  190. package/dist/core/canvas/executions.d.ts +29 -0
  191. package/dist/core/canvas/executions.js +68 -0
  192. package/dist/core/canvas/history.js +35 -35
  193. package/dist/core/canvas/index.d.ts +3 -1
  194. package/dist/core/canvas/index.js +3 -1
  195. package/dist/core/canvas/migrations.js +20 -12
  196. package/dist/core/canvas/nav-model.js +1 -3
  197. package/dist/core/canvas/nav-render.d.ts +4 -4
  198. package/dist/core/canvas/nav-render.js +11 -21
  199. package/dist/core/canvas/node-sql-migration.d.ts +3 -0
  200. package/dist/core/canvas/node-sql-migration.js +261 -0
  201. package/dist/core/canvas/paths.d.ts +2 -16
  202. package/dist/core/canvas/paths.js +2 -31
  203. package/dist/core/canvas/recovery.d.ts +76 -0
  204. package/dist/core/canvas/recovery.js +588 -0
  205. package/dist/core/canvas/remote-canvas-source.js +4 -0
  206. package/dist/core/canvas/render-source.d.ts +16 -27
  207. package/dist/core/canvas/render-source.js +16 -45
  208. package/dist/core/canvas/sessions.d.ts +33 -0
  209. package/dist/core/canvas/sessions.js +78 -0
  210. package/dist/core/canvas/types.d.ts +33 -33
  211. package/dist/core/canvas/types.js +2 -5
  212. package/dist/core/canvas/waits.d.ts +18 -0
  213. package/dist/core/canvas/waits.js +70 -0
  214. package/dist/core/canvas/worktrees.d.ts +40 -0
  215. package/dist/core/canvas/worktrees.js +93 -0
  216. package/dist/core/command-hooks/artifact.d.ts +6 -0
  217. package/dist/core/command-hooks/artifact.js +22 -6
  218. package/dist/core/command-hooks/discovery.d.ts +2 -0
  219. package/dist/core/command-hooks/discovery.js +2 -0
  220. package/dist/core/command-hooks/lifecycle-catalog.d.ts +20 -2
  221. package/dist/core/command-hooks/lifecycle-catalog.js +7 -2
  222. package/dist/core/command-hooks/lifecycle-create.d.ts +4 -0
  223. package/dist/core/command-hooks/lifecycle-create.js +51 -0
  224. package/dist/core/command-hooks/schema.d.ts +2 -2
  225. package/dist/core/command-hooks/schema.js +5 -4
  226. package/dist/core/command-hooks/transport/exec-invoke.js +3 -1
  227. package/dist/core/command-hooks/transport/exec-lifecycle.d.ts +18 -8
  228. package/dist/core/command-hooks/transport/exec-lifecycle.js +89 -30
  229. package/dist/core/config.d.ts +17 -12
  230. package/dist/core/config.js +106 -155
  231. package/dist/core/errors.d.ts +1 -0
  232. package/dist/core/errors.js +4 -0
  233. package/dist/core/feed/__tests__/inbox-migrate.test.js +27 -31
  234. package/dist/core/feed/feed.d.ts +0 -6
  235. package/dist/core/feed/feed.js +68 -56
  236. package/dist/core/feed/inbox.d.ts +7 -81
  237. package/dist/core/feed/inbox.js +46 -378
  238. package/dist/core/feed/messages.d.ts +58 -0
  239. package/dist/core/feed/messages.js +217 -0
  240. package/dist/core/fs-utils.d.ts +4 -0
  241. package/dist/core/fs-utils.js +21 -1
  242. package/dist/core/human/answer.d.ts +1 -1
  243. package/dist/core/human/answer.js +1 -1
  244. package/dist/core/human/claim.d.ts +1 -1
  245. package/dist/core/human/claim.js +2 -4
  246. package/dist/core/human/component-docs.js +1 -1
  247. package/dist/core/human/feedback-companion.js +4 -3
  248. package/dist/core/human/feedback.d.ts +5 -8
  249. package/dist/core/human/feedback.js +57 -85
  250. package/dist/core/human/page-authoring.d.ts +30 -0
  251. package/dist/core/human/page-authoring.js +19 -0
  252. package/dist/core/human/requests.d.ts +136 -0
  253. package/dist/core/human/requests.js +515 -0
  254. package/dist/core/human/root.d.ts +0 -7
  255. package/dist/core/human/root.js +0 -17
  256. package/dist/core/human/scan.d.ts +2 -7
  257. package/dist/core/human/scan.js +48 -132
  258. package/dist/core/human/summary.d.ts +1 -1
  259. package/dist/core/human/summary.js +1 -1
  260. package/dist/core/human/tickets.d.ts +23 -83
  261. package/dist/core/human/tickets.js +92 -243
  262. package/dist/core/human/types.d.ts +5 -1
  263. package/dist/core/installed-plugins.js +8 -3
  264. package/dist/core/keybindings/__tests__/resolve.test.js +19 -17
  265. package/dist/core/locked-file.d.ts +6 -3
  266. package/dist/core/locked-file.js +36 -9
  267. package/dist/core/memory/extensions.js +2 -0
  268. package/dist/core/preview-registry.js +0 -1
  269. package/dist/core/profiles/__tests__/env-store.test.js +2 -0
  270. package/dist/core/profiles/default-binding.d.ts +0 -4
  271. package/dist/core/profiles/default-binding.js +12 -58
  272. package/dist/core/profiles/env-store.js +8 -3
  273. package/dist/core/profiles/manifest.d.ts +2 -37
  274. package/dist/core/profiles/manifest.js +35 -161
  275. package/dist/core/profiles/select.js +3 -0
  276. package/dist/core/review/__tests__/capture-origin.test.js +13 -2
  277. package/dist/core/review/__tests__/comments.test.js +28 -10
  278. package/dist/core/review/__tests__/remap.test.js +28 -10
  279. package/dist/core/review/__tests__/stage-identity.test.js +17 -7
  280. package/dist/core/review/birth.d.ts +1 -1
  281. package/dist/core/review/birth.js +34 -5
  282. package/dist/core/review/comments.js +1 -1
  283. package/dist/core/review/companion.d.ts +1 -1
  284. package/dist/core/review/companion.js +2 -2
  285. package/dist/core/review/document.js +1 -1
  286. package/dist/core/review/project.d.ts +5 -1
  287. package/dist/core/review/project.js +14 -36
  288. package/dist/core/review/realize.d.ts +3 -6
  289. package/dist/core/review/realize.js +51 -168
  290. package/dist/core/review/remap.js +1 -1
  291. package/dist/core/review/stage.d.ts +3 -2
  292. package/dist/core/review/stage.js +2 -3
  293. package/dist/core/review/store.d.ts +3 -21
  294. package/dist/core/review/store.js +140 -186
  295. package/dist/core/review/types.d.ts +0 -1
  296. package/dist/core/runtime/__tests__/install-id-cache-scoping.test.js +9 -5
  297. package/dist/core/runtime/__tests__/spawn-env.test.js +8 -9
  298. package/dist/core/runtime/broker/auth-reload.js +9 -10
  299. package/dist/core/runtime/broker/daemon-ops.d.ts +25 -8
  300. package/dist/core/runtime/broker/daemon-ops.js +42 -9
  301. package/dist/core/runtime/broker/extension-abort.d.ts +3 -0
  302. package/dist/core/runtime/broker/extension-abort.js +11 -0
  303. package/dist/core/runtime/broker/fault-retry.d.ts +15 -6
  304. package/dist/core/runtime/broker/fault-retry.js +142 -95
  305. package/dist/core/runtime/broker/inbox.d.ts +4 -32
  306. package/dist/core/runtime/broker/inbox.js +4 -92
  307. package/dist/core/runtime/broker/rebind.d.ts +1 -0
  308. package/dist/core/runtime/broker/rebind.js +21 -12
  309. package/dist/core/runtime/broker-persona-guidance.d.ts +1 -1
  310. package/dist/core/runtime/broker-persona-guidance.js +2 -13
  311. package/dist/core/runtime/broker.js +28 -22
  312. package/dist/core/runtime/close.d.ts +3 -9
  313. package/dist/core/runtime/close.js +16 -27
  314. package/dist/core/runtime/fault.d.ts +3 -93
  315. package/dist/core/runtime/fault.js +9 -419
  316. package/dist/core/runtime/kickoff.d.ts +3 -6
  317. package/dist/core/runtime/kickoff.js +12 -18
  318. package/dist/core/runtime/launch.js +1 -1
  319. package/dist/core/runtime/lifecycle.js +40 -7
  320. package/dist/core/runtime/nodes.d.ts +5 -1
  321. package/dist/core/runtime/nodes.js +26 -11
  322. package/dist/core/runtime/placement.js +2 -2
  323. package/dist/core/runtime/recycle.js +24 -14
  324. package/dist/core/runtime/reset.js +26 -7
  325. package/dist/core/runtime/revive.js +226 -217
  326. package/dist/core/runtime/spawn.d.ts +4 -1
  327. package/dist/core/runtime/spawn.js +43 -5
  328. package/dist/core/runtime/warm-pool.d.ts +2 -2
  329. package/dist/core/runtime/warm-pool.js +23 -3
  330. package/dist/core/scoped-state/db.d.ts +7 -0
  331. package/dist/core/scoped-state/db.js +92 -0
  332. package/dist/core/scoped-state/migrate.d.ts +11 -0
  333. package/dist/core/scoped-state/migrate.js +198 -0
  334. package/dist/core/scoped-state/paths.d.ts +9 -0
  335. package/dist/core/scoped-state/paths.js +27 -0
  336. package/dist/core/scoped-state/profiles.d.ts +12 -0
  337. package/dist/core/scoped-state/profiles.js +62 -0
  338. package/dist/core/scoped-state/providers.d.ts +16 -0
  339. package/dist/core/scoped-state/providers.js +8 -0
  340. package/dist/core/scoped-state/schema.d.ts +3 -0
  341. package/dist/core/scoped-state/schema.js +26 -0
  342. package/dist/core/scoped-state/settings.d.ts +28 -0
  343. package/dist/core/scoped-state/settings.js +82 -0
  344. package/dist/core/subscription-state.d.ts +29 -48
  345. package/dist/core/subscription-state.js +176 -712
  346. package/dist/core/worktree-close.js +4 -4
  347. package/dist/core/worktree-mutation-async.js +2 -2
  348. package/dist/core/worktree-sweep.js +11 -16
  349. package/dist/core/worktree.js +6 -12
  350. package/dist/daemon/__tests__/autostart-storm.test.js +1 -39
  351. package/dist/daemon/__tests__/helpers/source-daemon.d.ts +2 -2
  352. package/dist/daemon/__tests__/helpers/source-daemon.js +7 -6
  353. package/dist/daemon/__tests__/integration/migration-startup.test.js +59 -26
  354. package/dist/daemon/__tests__/node-deadline-lane.test.js +2 -1
  355. package/dist/daemon/__tests__/node-outcome-birth-invariants.test.js +41 -17
  356. package/dist/daemon/__tests__/node-outcome-delivery.test.js +39 -10
  357. package/dist/daemon/__tests__/reconciler-signature.test.js +2 -2
  358. package/dist/daemon/__tests__/subtree-filter-freshness.test.js +2 -2
  359. package/dist/daemon/api/__tests__/broker-settle-park.test.js +17 -12
  360. package/dist/daemon/api/__tests__/canvas-snapshot-fields.test.js +27 -5
  361. package/dist/daemon/api/__tests__/model-config.test.js +8 -8
  362. package/dist/daemon/api/__tests__/node-create-description.test.js +22 -5
  363. package/dist/daemon/api/__tests__/node-model-validation.test.js +21 -1
  364. package/dist/daemon/api/__tests__/nodes-activity-query.test.js +10 -12
  365. package/dist/daemon/api/__tests__/profile-launch-gates.test.js +6 -3
  366. package/dist/daemon/api/__tests__/profile-metadata-route.test.js +4 -1
  367. package/dist/daemon/api/__tests__/reopen-delivery.test.js +26 -8
  368. package/dist/daemon/api/__tests__/seam/api-server.test.js +24 -32
  369. package/dist/daemon/api/__tests__/seam/b10-attach-modelauth.test.js +4 -1
  370. package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +5 -4
  371. package/dist/daemon/api/__tests__/seam/profile-delete.test.js +29 -43
  372. package/dist/daemon/api/__tests__/submit-result.test.js +3 -2
  373. package/dist/daemon/api/bridge.js +1 -1
  374. package/dist/daemon/api/handlers/bash-jobs.js +6 -7
  375. package/dist/daemon/api/handlers/broker-ops.js +47 -84
  376. package/dist/daemon/api/handlers/broker-recovery.d.ts +4 -0
  377. package/dist/daemon/api/handlers/broker-recovery.js +251 -0
  378. package/dist/daemon/api/handlers/canvas.js +2 -44
  379. package/dist/daemon/api/handlers/daemon.js +41 -0
  380. package/dist/daemon/api/handlers/feedback-comments.js +2 -2
  381. package/dist/daemon/api/handlers/health.js +10 -5
  382. package/dist/daemon/api/handlers/human-requests.js +168 -188
  383. package/dist/daemon/api/handlers/human.js +3 -148
  384. package/dist/daemon/api/handlers/inbox-page.d.ts +4 -0
  385. package/dist/daemon/api/handlers/inbox-page.js +89 -0
  386. package/dist/daemon/api/handlers/inbox.js +21 -120
  387. package/dist/daemon/api/handlers/messages.d.ts +1 -0
  388. package/dist/daemon/api/handlers/messages.js +73 -15
  389. package/dist/daemon/api/handlers/node-outcomes.js +58 -13
  390. package/dist/daemon/api/handlers/nodes.d.ts +1 -0
  391. package/dist/daemon/api/handlers/nodes.js +41 -42
  392. package/dist/daemon/api/handlers/reviews.js +4 -29
  393. package/dist/daemon/api/map.d.ts +25 -3
  394. package/dist/daemon/api/map.js +84 -14
  395. package/dist/daemon/api/server.js +68 -9
  396. package/dist/daemon/control.d.ts +18 -0
  397. package/dist/daemon/cron/disposition.d.ts +2 -0
  398. package/dist/daemon/cron/disposition.js +8 -5
  399. package/dist/daemon/cron/settle.js +37 -13
  400. package/dist/daemon/cron/sinks.d.ts +18 -1
  401. package/dist/daemon/cron/sinks.js +47 -93
  402. package/dist/daemon/crtrd-cli.js +4 -19
  403. package/dist/daemon/crtrd.d.ts +2 -0
  404. package/dist/daemon/crtrd.js +206 -81
  405. package/dist/daemon/fleet.js +5 -6
  406. package/dist/daemon/human/finish.d.ts +12 -24
  407. package/dist/daemon/human/finish.js +88 -285
  408. package/dist/daemon/human/settle.d.ts +40 -0
  409. package/dist/daemon/human/settle.js +89 -0
  410. package/dist/daemon/human/sweep.d.ts +20 -5
  411. package/dist/daemon/human/sweep.js +56 -60
  412. package/dist/daemon/manage.d.ts +21 -16
  413. package/dist/daemon/manage.js +85 -51
  414. package/dist/daemon/messaging/node-message.d.ts +1 -1
  415. package/dist/daemon/messaging/node-message.js +9 -12
  416. package/dist/daemon/park-activity.js +3 -3
  417. package/dist/daemon/reconcilers/bash-deadline.js +6 -7
  418. package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
  419. package/dist/daemon/reconcilers/broker-supervision.js +41 -19
  420. package/dist/daemon/reconcilers/controller-death.js +6 -18
  421. package/dist/daemon/reconcilers/delivery-lane.d.ts +9 -0
  422. package/dist/daemon/reconcilers/delivery-lane.js +130 -0
  423. package/dist/daemon/reconcilers/live-obligation.js +3 -3
  424. package/dist/daemon/reconcilers/node-deadline.js +1 -1
  425. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -1
  426. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +10 -12
  427. package/dist/daemon/reconcilers/node-lifecycle/tick.js +5 -5
  428. package/dist/daemon/reconcilers/node-lifecycle/wants-execution.js +1 -1
  429. package/dist/daemon/reconcilers/pending-review-submit.js +3 -3
  430. package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -8
  431. package/dist/daemon/reconcilers/storage-maintenance.js +13 -43
  432. package/dist/daemon/review/companion.js +5 -11
  433. package/dist/daemon/review/deliver.d.ts +1 -5
  434. package/dist/daemon/review/deliver.js +3 -52
  435. package/dist/daemon/review/finish.d.ts +2 -27
  436. package/dist/daemon/review/finish.js +79 -263
  437. package/dist/daemon/review/sweep.d.ts +3 -10
  438. package/dist/daemon/review/sweep.js +13 -131
  439. package/dist/daemon/startup-policy.d.ts +0 -5
  440. package/dist/daemon/startup-policy.js +0 -5
  441. package/dist/hook-authoring.d.ts +28 -2
  442. package/dist/hook-authoring.js +53 -1
  443. package/dist/index.d.ts +3 -2
  444. package/dist/index.js +1 -1
  445. package/dist/migrations/__tests__/activation-concurrency.test.js +3 -2
  446. package/dist/migrations/__tests__/activation.test.js +9 -6
  447. package/dist/migrations/activation.d.ts +3 -2
  448. package/dist/migrations/activation.js +2 -4
  449. package/dist/migrations/corpus.d.ts +2 -5
  450. package/dist/migrations/corpus.js +9 -20
  451. package/dist/migrations/runner.d.ts +3 -1
  452. package/dist/migrations/runner.js +6 -2
  453. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +21 -89
  454. package/dist/pi-extensions/__tests__/canvas-goal-capture-envelope.test.js +4 -2
  455. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +51 -33
  456. package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.js +16 -2
  457. package/dist/pi-extensions/__tests__/pre-command-gate.test.js +13 -1
  458. package/dist/pi-extensions/canvas-inbox-watcher.js +98 -244
  459. package/dist/pi-extensions/canvas-passive-context.d.ts +4 -8
  460. package/dist/pi-extensions/canvas-passive-context.js +85 -37
  461. package/dist/pi-extensions/canvas-stophook.js +47 -31
  462. package/dist/shared/env.d.ts +1 -0
  463. package/dist/shared/env.js +3 -0
  464. package/package.json +1 -1
  465. package/runtime.lock.json +5 -5
  466. package/dist/clients/attach/__tests__/page-block.test.js +0 -54
  467. package/dist/clients/inbox/review-visibility.d.ts +0 -5
  468. package/dist/clients/inbox/review-visibility.js +0 -19
  469. package/dist/commands/canvas-rebuild-index.d.ts +0 -2
  470. package/dist/commands/canvas-rebuild-index.js +0 -46
  471. package/dist/core/__tests__/human-cancel-guard.test.js +0 -110
  472. package/dist/core/__tests__/human-deliver.test.d.ts +0 -1
  473. package/dist/core/__tests__/human-deliver.test.js +0 -256
  474. package/dist/core/__tests__/human-node-not-supervised.test.d.ts +0 -1
  475. package/dist/core/__tests__/human-node-not-supervised.test.js +0 -89
  476. package/dist/core/__tests__/integration/human-deliver-e2e.test.d.ts +0 -1
  477. package/dist/core/__tests__/integration/human-deliver-e2e.test.js +0 -131
  478. package/dist/core/__tests__/phase4-review-store.test.d.ts +0 -1
  479. package/dist/core/__tests__/phase4-review-store.test.js +0 -144
  480. package/dist/core/__tests__/watchdog-abort-arms-retry.test.d.ts +0 -1
  481. package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +0 -110
  482. package/dist/core/canvas/human-deliveries.d.ts +0 -39
  483. package/dist/core/canvas/human-deliveries.js +0 -75
  484. package/dist/core/canvas/node-outcome-deliveries.d.ts +0 -64
  485. package/dist/core/canvas/node-outcome-deliveries.js +0 -159
  486. package/dist/core/feed/passive.d.ts +0 -3
  487. package/dist/core/feed/passive.js +0 -53
  488. package/dist/core/human/__tests__/inbox-cancel-worker.d.ts +0 -1
  489. package/dist/core/human/__tests__/inbox-cancel-worker.js +0 -7
  490. package/dist/core/human/__tests__/inbox-claim-worker.d.ts +0 -1
  491. package/dist/core/human/__tests__/inbox-claim-worker.js +0 -17
  492. package/dist/core/human/__tests__/inbox-stale-claim-worker.d.ts +0 -1
  493. package/dist/core/human/__tests__/inbox-stale-claim-worker.js +0 -8
  494. package/dist/core/human/__tests__/integration/inbox-core.test.d.ts +0 -1
  495. package/dist/core/human/__tests__/integration/inbox-core.test.js +0 -145
  496. package/dist/core/human/__tests__/page-tickets.test.d.ts +0 -1
  497. package/dist/core/human/__tests__/page-tickets.test.js +0 -161
  498. package/dist/core/review/ticket-filter.d.ts +0 -17
  499. package/dist/core/review/ticket-filter.js +0 -21
  500. package/dist/core/runtime/broker/passive.d.ts +0 -17
  501. package/dist/core/runtime/broker/passive.js +0 -44
  502. package/dist/core/runtime/busy.d.ts +0 -46
  503. package/dist/core/runtime/busy.js +0 -150
  504. package/dist/daemon/__tests__/startup-block-marker.test.d.ts +0 -1
  505. package/dist/daemon/__tests__/startup-block-marker.test.js +0 -86
  506. package/dist/daemon/api/__tests__/review-terminal-conflict.test.d.ts +0 -1
  507. package/dist/daemon/api/__tests__/review-terminal-conflict.test.js +0 -98
  508. package/dist/daemon/human/deliver-action.d.ts +0 -3
  509. package/dist/daemon/human/deliver-action.js +0 -9
  510. package/dist/daemon/node-outcome/deliver-outcome.d.ts +0 -3
  511. package/dist/daemon/node-outcome/deliver-outcome.js +0 -9
  512. package/dist/daemon/reconcilers/human-delivery-lane.d.ts +0 -10
  513. package/dist/daemon/reconcilers/human-delivery-lane.js +0 -41
  514. package/dist/daemon/reconcilers/node-outcome-delivery-lane.d.ts +0 -10
  515. package/dist/daemon/reconcilers/node-outcome-delivery-lane.js +0 -41
  516. package/dist/daemon/startup-block-marker.d.ts +0 -25
  517. package/dist/daemon/startup-block-marker.js +0 -99
  518. /package/dist/{clients/attach/__tests__/page-block.test.d.ts → api/dto/mail.js} +0 -0
  519. /package/dist/{commands/sys/__tests__/migrate.test.d.ts → api/dto/recovery.js} +0 -0
  520. /package/dist/{core/__tests__/human-cancel-guard.test.d.ts → commands/__tests__/integration/migrate.test.d.ts} +0 -0
@@ -3,12 +3,22 @@ import assert from 'node:assert/strict';
3
3
  import { mkdtempSync, rmSync, mkdirSync, writeFileSync, existsSync, readdirSync } from 'node:fs';
4
4
  import { tmpdir } from 'node:os';
5
5
  import { join } from 'node:path';
6
- import { createNode, getNode, subscribe, subscriptionsOf } from '../canvas/canvas.js';
6
+ import { createNode as createRawNode, getNode, subscribe, subscriptionsOf } from '../canvas/canvas.js';
7
7
  import { nodeDir } from '../canvas/paths.js';
8
- import { closeDb } from '../canvas/db.js';
8
+ import { closeDb, openDb, migrate } from '../canvas/db.js';
9
+ import { beginExecution } from '../canvas/executions.js';
10
+ import { bindSession } from '../canvas/sessions.js';
9
11
  import { closeNode } from '../runtime/close.js';
10
12
  import { reapEmptyNodes } from '../runtime/placement.js';
11
- import { readInboxSince } from '../feed/inbox.js';
13
+ function nodeMail(nodeId) {
14
+ return openDb().prepare(`SELECT m.sender_node_id AS "from", m.kind, m.label, m.body_ref AS ref, m.body_json AS data
15
+ FROM deliveries d JOIN messages m ON m.message_id = d.message_id
16
+ WHERE d.destination_kind = 'node_inbox' AND d.destination_id = ?
17
+ ORDER BY m.seq`).all(nodeId).map((row) => ({
18
+ ...row,
19
+ data: row.data === null ? null : JSON.parse(row.data),
20
+ }));
21
+ }
12
22
  import { FinalizationError, pushFinal } from '../feed/feed.js';
13
23
  let home;
14
24
  /** Write a minimal pi session containing one assistant message, so the node
@@ -22,6 +32,14 @@ function withSession(id) {
22
32
  writeFileSync(f, JSON.stringify({ type: 'message', message: { role: 'assistant', content: [{ type: 'text', text: 'hi' }] } }) + '\n');
23
33
  return f;
24
34
  }
35
+ function createNode(meta) {
36
+ const created = createRawNode(meta);
37
+ if (meta.pi_session_file !== null && meta.pi_session_file !== undefined) {
38
+ const executionId = beginExecution(meta.node_id, { daemonEpoch: 'test' });
39
+ assert.equal(bindSession(meta.node_id, { executionId, sessionId: meta.pi_session_id ?? meta.node_id, transcriptPath: meta.pi_session_file }), 'bound');
40
+ }
41
+ return created;
42
+ }
25
43
  function node(id, over = {}) {
26
44
  return {
27
45
  node_id: id,
@@ -48,6 +66,7 @@ before(() => {
48
66
  beforeEach(() => {
49
67
  closeDb();
50
68
  rmSync(home, { recursive: true, force: true });
69
+ migrate(openDb());
51
70
  });
52
71
  after(() => {
53
72
  closeDb();
@@ -105,18 +124,18 @@ test('appends a resume notice naming the dead children to each closed node', ()
105
124
  spawnEdge('N', 'A');
106
125
  spawnEdge('A', 'C');
107
126
  closeNode('N');
108
- const nNotice = readInboxSince('N').at(-1);
127
+ const nNotice = nodeMail('N').at(-1);
109
128
  assert.equal(nNotice.from, null);
110
129
  assert.equal(nNotice.kind, 'message');
111
130
  assert.match(nNotice.label, /CLOSED by the user/);
112
131
  assert.match(nNotice.label, /A \(A\)/); // dead child named
113
132
  assert.deepEqual(nNotice.data?.['canceled_children'], ['A']);
114
133
  assert.equal(nNotice.data?.['cascade_root'], 'N');
115
- const aNotice = readInboxSince('A').at(-1);
134
+ const aNotice = nodeMail('A').at(-1);
116
135
  assert.match(aNotice.label, /CANCELED/);
117
136
  assert.match(aNotice.label, /C \(C\)/);
118
137
  // A leaf has no dead children — gets the short "session preserved" notice.
119
- const cNotice = readInboxSince('C').at(-1);
138
+ const cNotice = nodeMail('C').at(-1);
120
139
  assert.match(cNotice.label, /session is preserved/);
121
140
  assert.deepEqual(cNotice.data?.['canceled_children'], []);
122
141
  });
@@ -169,7 +188,7 @@ test('close first suppresses a later final publication and its subscriber pointe
169
188
  await assert.rejects(() => pushFinal('child', 'too late'), (error) => error instanceof FinalizationError && error.code === 'finalization_forbidden');
170
189
  assert.equal(getNode('child')?.final_report, null, 'close owns the terminal outcome');
171
190
  assert.deepEqual(readdirSync(join(nodeDir('child'), 'reports')).filter((name) => name.endsWith('-final.md')), [], 'a rejected final leaves no canonical report');
172
- assert.equal(readInboxSince('manager').filter((entry) => entry.kind === 'final').length, 0, 'a rejected final never wakes a subscriber with a final pointer');
191
+ assert.equal(nodeMail('manager').filter((entry) => entry.kind === 'final').length, 0, 'a rejected final never wakes a subscriber with a final pointer');
173
192
  });
174
193
  test('final publication first remains the one canonical final after close', async () => {
175
194
  createNode(node('child'));
@@ -184,7 +203,7 @@ test('final publication first remains the one canonical final after close', asyn
184
203
  assert.equal(child.intent, 'done');
185
204
  assert.equal(child.final_report, canonical, 'close preserves the original canonical marker');
186
205
  assert.ok(existsSync(publication.reportPath), 'the canonical report remains on disk');
187
- const finalPointers = readInboxSince('manager').filter((entry) => entry.kind === 'final');
206
+ const finalPointers = nodeMail('manager').filter((entry) => entry.kind === 'final');
188
207
  assert.equal(finalPointers.length, 1, 'the manager receives exactly one final pointer');
189
208
  assert.equal(finalPointers[0]?.ref, `child:reports/${canonical}`);
190
209
  });
@@ -239,7 +258,7 @@ test('closing an EMPTY node with an open managed worktree cancels it without rea
239
258
  assert.equal(meta?.managed_worktree?.state, 'open', 'node retains worktree ownership');
240
259
  assert.ok(existsSync(dir), 'node dir remains');
241
260
  assert.ok(existsSync(worktreePath), 'managed checkout remains reachable through its node');
242
- assert.match(readInboxSince(id).at(-1)?.label ?? '', /session is preserved/);
261
+ assert.match(nodeMail(id).at(-1)?.label ?? '', /session is preserved/);
243
262
  assert.deepEqual(reapEmptyNodes(), [], 'bulk empty reap also preserves the open managed worktree node');
244
263
  assert.equal(getNode(id)?.managed_worktree?.state, 'open', 'bulk reap retains worktree ownership');
245
264
  });
@@ -251,7 +270,7 @@ test('reaping an empty child still notifies a surviving external manager', () =>
251
270
  spawnEdge('mgr', 'child');
252
271
  closeNode('child');
253
272
  assert.equal(getNode('child'), null, 'empty child reaped');
254
- const note = readInboxSince('mgr').at(-1);
273
+ const note = nodeMail('mgr').at(-1);
255
274
  assert.match(note.label, /Child closed/);
256
275
  assert.equal(note.data?.['child'], 'child');
257
276
  });
@@ -4,7 +4,7 @@ import { mkdtempSync, rmSync } from 'node:fs';
4
4
  import { tmpdir } from 'node:os';
5
5
  import { join } from 'node:path';
6
6
  import { createNode, getRow, isCollectible, setFrozen, transitionStatusIntent, } from '../canvas/canvas.js';
7
- import { closeDb } from '../canvas/db.js';
7
+ import { closeDb, migrate, openDb } from '../canvas/db.js';
8
8
  let home;
9
9
  function node(id, over = {}) {
10
10
  return {
@@ -31,6 +31,7 @@ before(() => {
31
31
  beforeEach(() => {
32
32
  closeDb();
33
33
  rmSync(home, { recursive: true, force: true });
34
+ migrate(openDb());
34
35
  });
35
36
  after(() => {
36
37
  closeDb();
@@ -11,6 +11,7 @@ import assert from 'node:assert/strict';
11
11
  import { mkdtempSync, mkdirSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
12
12
  import { tmpdir } from 'node:os';
13
13
  import { join } from 'node:path';
14
+ import { ensureScopeInitialized } from '../config.js';
14
15
  import { resetScopeCache } from '../scope.js';
15
16
  import { clearSessionCache } from '../substrate/session-cache.js';
16
17
  import { renderConfigChangeDelta, renderKnowledgeForSubject, renderPreferencesForSubject, } from '../substrate/render.js';
@@ -60,6 +61,7 @@ before(() => {
60
61
  writeFileSync(join(user, 'delta-dev-knowledge.md'), ['---', 'kind: knowledge', `when-and-why-to-read: "${DEV_KNOWLEDGE_WHEN}"`, 'gate: {kind: developer}', 'surfaces:', ' - {on: boot, at: preview}', '---', '', 'ignored body', ''].join('\n'));
61
62
  process.chdir(work);
62
63
  resetScopeCache();
64
+ ensureScopeInitialized('user', join(home, '.crouter'));
63
65
  clearSessionCache();
64
66
  });
65
67
  after(() => {
@@ -11,7 +11,9 @@ import assert from 'node:assert/strict';
11
11
  import { existsSync, mkdtempSync, mkdirSync, rmSync } from 'node:fs';
12
12
  import { tmpdir } from 'node:os';
13
13
  import { join } from 'node:path';
14
- import { closeDb } from '../canvas/db.js';
14
+ import { closeDb, migrate, openDb } from '../canvas/db.js';
15
+ import { ensureScopeInitialized } from '../config.js';
16
+ import { closeScopedStores } from '../scoped-state/db.js';
15
17
  import { apiSocketPath } from '../canvas/paths.js';
16
18
  import { spawnNode } from '../runtime/nodes.js';
17
19
  import { appendSituationalContext, formatSituationalProse, situationalContextEnvelope, } from '../runtime/situational-context.js';
@@ -19,6 +21,7 @@ import registerCanvasContextIntro, { CONTEXT_INTRO_CUSTOM_TYPE, } from '../../pi
19
21
  import { buildContextBearings as buildContextIntro } from '../runtime/bearings.js';
20
22
  import { createApiServer } from '../../daemon/api/server.js';
21
23
  let home;
24
+ let priorUserHome;
22
25
  let server;
23
26
  async function waitForSocket(path) {
24
27
  for (let i = 0; i < 200; i++) {
@@ -30,26 +33,35 @@ async function waitForSocket(path) {
30
33
  }
31
34
  before(() => {
32
35
  home = mkdtempSync(join(tmpdir(), 'crtr-ctxintro-'));
36
+ priorUserHome = process.env['HOME'];
37
+ process.env['HOME'] = home;
33
38
  process.env['CRTR_HOME'] = home;
34
39
  });
35
40
  beforeEach(async () => {
36
41
  closeDb();
37
42
  rmSync(home, { recursive: true, force: true });
38
43
  mkdirSync(home, { recursive: true });
44
+ ensureScopeInitialized('user', join(home, '.crouter'));
45
+ migrate(openDb());
39
46
  server = createApiServer();
40
47
  await waitForSocket(apiSocketPath());
41
48
  });
42
49
  afterEach(async () => {
43
50
  await server.close();
51
+ closeScopedStores();
44
52
  });
45
53
  after(() => {
46
54
  closeDb();
47
55
  rmSync(home, { recursive: true, force: true });
48
56
  delete process.env['CRTR_HOME'];
49
57
  delete process.env['CRTR_NODE_ID'];
58
+ if (priorUserHome === undefined)
59
+ delete process.env['HOME'];
60
+ else
61
+ process.env['HOME'] = priorUserHome;
50
62
  });
51
- test('the stored situational card rides the bearings body; absent when unset', () => {
52
- const meta = spawnNode({ kind: 'general', cwd: '/tmp/work', parent: null });
63
+ test('the stored situational card rides the bearings body; absent when unset', async () => {
64
+ const meta = await spawnNode({ kind: 'general', cwd: '/tmp/work', parent: null });
53
65
  assert.equal(situationalContextEnvelope(meta.node_id), null, 'no card until something is set');
54
66
  assert.doesNotMatch(buildContextIntro(meta.node_id), /kind="situational"/, 'bearings carry no card when unset');
55
67
  appendSituationalContext(meta.node_id, formatSituationalProse('user is looking at the billing applet'));
@@ -73,7 +85,7 @@ function fakeCtx(pi) {
73
85
  return { sessionManager: { getBranch: () => pi.entries } };
74
86
  }
75
87
  test('session_start injects the block as the first message of an empty session', async () => {
76
- const meta = spawnNode({ kind: 'general', cwd: '/tmp/work', parent: null });
88
+ const meta = await spawnNode({ kind: 'general', cwd: '/tmp/work', parent: null });
77
89
  process.env['CRTR_NODE_ID'] = meta.node_id;
78
90
  const pi = makeFakePi();
79
91
  registerCanvasContextIntro(pi);
@@ -87,7 +99,7 @@ test('session_start injects the block as the first message of an empty session',
87
99
  assert.match(pi.sent[0].content, /<crtr-bearings>/);
88
100
  });
89
101
  test('session_start is idempotent across resume (skips if already in history)', async () => {
90
- const meta = spawnNode({ kind: 'general', cwd: '/tmp/work', parent: null });
102
+ const meta = await spawnNode({ kind: 'general', cwd: '/tmp/work', parent: null });
91
103
  process.env['CRTR_NODE_ID'] = meta.node_id;
92
104
  // Restored session already carries OUR block (which names this node id) → no
93
105
  // duplicate injection. The content matters: the guard is fork-aware and only
@@ -12,8 +12,10 @@ import { tmpdir } from 'node:os';
12
12
  import { join } from 'node:path';
13
13
  import { listNodes } from '../canvas/canvas.js';
14
14
  import { armCron, getCron, listCronRuns } from '../canvas/crons.js';
15
- import { closeDb } from '../canvas/db.js';
16
- import { createProfile, profileManifestPath, profileRoot } from '../profiles/manifest.js';
15
+ import { closeDb, migrate, openDb } from '../canvas/db.js';
16
+ import { ensureScopeInitialized } from '../config.js';
17
+ import { closeScopedStores } from '../scoped-state/db.js';
18
+ import { createProfile, deleteProfile, profileManifestPath } from '../profiles/manifest.js';
17
19
  import { resetScopeCache } from '../scope.js';
18
20
  import { headlessBrokerHost } from '../runtime/host.js';
19
21
  import { resetFleetForTests } from '../runtime/fleet.js';
@@ -78,10 +80,13 @@ beforeEach(() => {
78
80
  fleet.fleet.register(nodeId, handle);
79
81
  return handle;
80
82
  });
83
+ ensureScopeInitialized('user', join(userHome, '.crouter'));
84
+ migrate(openDb());
81
85
  });
82
86
  afterEach(() => {
83
87
  headlessBrokerHost.launch = originalLaunch;
84
88
  closeDb();
89
+ closeScopedStores();
85
90
  resetFleetForTests();
86
91
  });
87
92
  after(() => {
@@ -126,17 +131,17 @@ test('a corrupt armed env snapshot fails the run instead of silently dropping th
126
131
  assertSettledAsArmingFailure(id, record, /run could not be armed: the armed env snapshot/, nodesBefore);
127
132
  }
128
133
  });
129
- test('an unreadable profile manifest fails the run, while a deleted profile still runs as root', async () => {
130
- const unreadable = createProfile('cron-unreadable').profileId;
134
+ test('a profile artifact is ignored while a deleted SQL profile runs as root', async () => {
135
+ const existing = createProfile('cron-existing').profileId;
131
136
  const deleted = createProfile('cron-deleted').profileId;
132
- // Corrupt one manifest in place and delete the other profile outright: the
133
- // two states the old resolver could not tell apart.
134
- writeFileSync(profileManifestPath(unreadable), '{ not json', 'utf8');
135
- rmSync(profileRoot(deleted), { recursive: true, force: true });
136
- arm({ cron_id: 'profile-unreadable', profile: unreadable });
137
- const nodesBefore = listNodes().length;
138
- const failed = await executeCron(getCron('profile-unreadable'), { outOfBand: false });
139
- assertSettledAsArmingFailure('profile-unreadable', failed, /run could not be armed: the armed profile .* manifest could not be read/, nodesBefore);
137
+ // Profile identity is SQL-authoritative. The legacy artifact cannot change
138
+ // the context an already-armed run uses.
139
+ writeFileSync(profileManifestPath(existing), '{ not json', 'utf8');
140
+ arm({ cron_id: 'profile-existing', profile: existing });
141
+ const ranExisting = await executeCron(getCron('profile-existing'), { outOfBand: false });
142
+ assert.equal(ranExisting?.exit_code, 0, 'a corrupt profile artifact does not alter the SQL profile context');
143
+ assert.equal(readFileSync(marker('profile-existing'), 'utf8'), existing, 'the run retains the SQL-backed profile identity');
144
+ deleteProfile(deleted);
140
145
  arm({ cron_id: 'profile-deleted', profile: deleted });
141
146
  const ran = await executeCron(getCron('profile-deleted'), { outOfBand: false });
142
147
  assert.equal(ran?.exit_code, 0, 'a deleted profile is the spec root fallback — the run proceeds');
@@ -7,19 +7,22 @@
7
7
  // consumption — and a poke (`pokeHeldCrons`) re-dues every held active row
8
8
  // now. These pin the branch's truth table: the exact class of scheduling
9
9
  // defect that otherwise fails silently weeks later.
10
- import { after, afterEach, before, test } from 'node:test';
10
+ import { after, afterEach, before, beforeEach, test } from 'node:test';
11
11
  import assert from 'node:assert/strict';
12
- import { mkdtempSync, rmSync } from 'node:fs';
12
+ import { mkdtempSync, mkdirSync, rmSync } from 'node:fs';
13
13
  import { tmpdir } from 'node:os';
14
14
  import { join } from 'node:path';
15
15
  import { setTimeout as delay } from 'node:timers/promises';
16
- import { closeDb, openDb } from '../canvas/db.js';
16
+ import { closeDb, migrate, openDb } from '../canvas/db.js';
17
+ import { ensureScopeInitialized } from '../config.js';
18
+ import { closeScopedStores } from '../scoped-state/db.js';
17
19
  import { armCron, cancelCron, getCron, listCronRuns, pokeHeldCrons, setCronState, } from '../canvas/crons.js';
18
20
  import { executeCron, runDueCrons } from '../../daemon/cron-run.js';
19
21
  const HELD_DELIVERED = 'deferred (exit 75) — held for poke';
20
22
  const HELD_FAR_FUTURE = '9999-12-31T23:59:59.999Z';
21
23
  let home;
22
24
  let realHome;
25
+ let realUserHome;
23
26
  function arm(overrides) {
24
27
  armCron({
25
28
  name: overrides.cron_id,
@@ -45,10 +48,21 @@ function arm(overrides) {
45
48
  before(() => {
46
49
  home = mkdtempSync(join(tmpdir(), 'crtr-cron-held-'));
47
50
  realHome = process.env['CRTR_HOME'];
51
+ realUserHome = process.env['HOME'];
52
+ process.env['HOME'] = home;
48
53
  process.env['CRTR_HOME'] = home;
49
54
  });
55
+ beforeEach(() => {
56
+ closeDb();
57
+ closeScopedStores();
58
+ rmSync(home, { recursive: true, force: true });
59
+ mkdirSync(home, { recursive: true });
60
+ ensureScopeInitialized('user', join(home, '.crouter'));
61
+ migrate(openDb());
62
+ });
50
63
  afterEach(() => {
51
64
  closeDb();
65
+ closeScopedStores();
52
66
  });
53
67
  after(() => {
54
68
  closeDb();
@@ -57,6 +71,10 @@ after(() => {
57
71
  delete process.env['CRTR_HOME'];
58
72
  else
59
73
  process.env['CRTR_HOME'] = realHome;
74
+ if (realUserHome === undefined)
75
+ delete process.env['HOME'];
76
+ else
77
+ process.env['HOME'] = realUserHome;
60
78
  });
61
79
  test('a recurring exit-75 run parks: held, backstop untouched, no disposition', async () => {
62
80
  // on-change makes the skipped disposition observable: were the branch to
@@ -10,9 +10,10 @@ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
10
10
  import { tmpdir } from 'node:os';
11
11
  import { join } from 'node:path';
12
12
  import { createNode, getNode, listNodes } from '../canvas/canvas.js';
13
+ import { ensureScopeInitialized } from '../config.js';
14
+ import { closeScopedStores } from '../scoped-state/db.js';
13
15
  import { armCron, getCron } from '../canvas/crons.js';
14
- import { closeDb } from '../canvas/db.js';
15
- import { readInboxSince } from '../feed/inbox.js';
16
+ import { closeDb, migrate, openDb } from '../canvas/db.js';
16
17
  import { headlessBrokerHost } from '../runtime/host.js';
17
18
  import { resetFleetForTests } from '../runtime/fleet.js';
18
19
  import { applyParkEvent, parkEvent } from '../../daemon/reconcilers/live-obligation.js';
@@ -20,6 +21,7 @@ import { executeCron } from '../../daemon/cron-run.js';
20
21
  import { bindTestFleet } from './helpers/fleet.js';
21
22
  let home;
22
23
  let priorHome;
24
+ let priorUserHome;
23
25
  let fleet;
24
26
  let launches;
25
27
  let originalLaunch;
@@ -36,6 +38,14 @@ function node(id, over = {}) {
36
38
  ...over,
37
39
  };
38
40
  }
41
+ function nodeMail(nodeId) {
42
+ return openDb().prepare(`SELECT m.body_json, d.urgency FROM deliveries d JOIN messages m ON m.message_id = d.message_id
43
+ WHERE d.destination_kind = 'node_inbox' AND d.destination_id = ? ORDER BY m.seq`).all(nodeId).map((row) => {
44
+ const data = row;
45
+ const value = data.body_json === null ? null : JSON.parse(data.body_json);
46
+ return { body: typeof value?.body === 'string' ? value.body : null, urgency: data.urgency };
47
+ });
48
+ }
39
49
  function arm({ cron_id, ...overrides }) {
40
50
  armCron({
41
51
  cron_id,
@@ -79,12 +89,16 @@ function parkResidentRoot(id) {
79
89
  before(() => {
80
90
  home = mkdtempSync(join(tmpdir(), 'crtr-cron-node-sink-parked-root-'));
81
91
  priorHome = process.env['CRTR_HOME'];
92
+ priorUserHome = process.env['HOME'];
82
93
  process.env['CRTR_HOME'] = home;
94
+ process.env['HOME'] = home;
83
95
  });
84
96
  beforeEach(() => {
85
97
  closeDb();
86
98
  rmSync(home, { recursive: true, force: true });
87
99
  mkdirSync(home, { recursive: true });
100
+ ensureScopeInitialized('user', join(home, '.crouter'));
101
+ migrate(openDb());
88
102
  resetFleetForTests();
89
103
  fleet = bindTestFleet();
90
104
  launches = [];
@@ -99,6 +113,7 @@ beforeEach(() => {
99
113
  afterEach(() => {
100
114
  headlessBrokerHost.launch = originalLaunch;
101
115
  closeDb();
116
+ closeScopedStores();
102
117
  resetFleetForTests();
103
118
  });
104
119
  after(() => {
@@ -107,16 +122,20 @@ after(() => {
107
122
  delete process.env['CRTR_HOME'];
108
123
  else
109
124
  process.env['CRTR_HOME'] = priorHome;
125
+ if (priorUserHome === undefined)
126
+ delete process.env['HOME'];
127
+ else
128
+ process.env['HOME'] = priorUserHome;
110
129
  });
111
- test('cron node sink delivers to a parked resident root and resumes its existing session without escalation', async () => {
130
+ test('cron node sink creates a durable delivery for a parked resident root without escalation', async () => {
112
131
  parkResidentRoot('parked-root');
113
132
  arm({ cron_id: 'parked-root-cron', sink: JSON.stringify({ node: 'parked-root' }), anchor_node: 'parked-root' });
114
133
  const record = await executeCron(getCron('parked-root-cron'), { outOfBand: false });
115
- assert.equal(record?.delivered, 'delivered: node parked-root');
134
+ assert.match(record?.delivered ?? '', /^delivered: /);
116
135
  assert.equal(getCron('parked-root-cron').state, 'active', 'delivery does not pause the cron');
117
- assert.deepEqual(readInboxSince('parked-root', undefined).map((entry) => entry.data?.['body']), ['cron output']);
118
- assert.deepEqual(launches, [{ nodeId: 'parked-root', resuming: true }], 'the parked session is resumed exactly once');
119
- assert.equal(getNode('parked-root').status, 'active', 'revive restores the parked root to its active cycle');
136
+ assert.deepEqual(nodeMail('parked-root').map((entry) => entry.body), ['cron output']);
137
+ assert.deepEqual(launches, [], 'the delivery lane wakes the destination after it claims mail');
138
+ assert.equal(getNode('parked-root').status, 'done', 'the parked root remains parked until delivery claims the row');
120
139
  assert.deepEqual(listNodes().map((entry) => entry.node_id), ['parked-root'], 'no escalation node was created');
121
140
  });
122
141
  test('finalized and canceled node-sink targets still pause and escalate without delivery', async () => {
@@ -131,7 +150,7 @@ test('finalized and canceled node-sink targets still pause and escalate without
131
150
  const record = await executeCron(getCron(`${id}-cron`), { outOfBand: false });
132
151
  assert.match(record?.delivered ?? '', /^failure: cron paused, escalation node /, `${id}: failure is escalated`);
133
152
  assert.equal(getCron(`${id}-cron`).state, 'paused', `${id}: cron is paused`);
134
- assert.equal(readInboxSince(id, undefined).length, 0, `${id}: no message was appended`);
153
+ assert.equal(nodeMail(id).length, 0, `${id}: no message was appended`);
135
154
  assert.equal(listNodes().length, before + 1, `${id}: exactly one escalation node was created`);
136
155
  }
137
156
  });
@@ -139,9 +158,9 @@ test('a deferred node-sink entry reaches the parked root durably but never reviv
139
158
  parkResidentRoot('deferred-root');
140
159
  arm({ cron_id: 'deferred-root-cron', sink: JSON.stringify({ node: 'deferred-root' }), tier: 'deferred' });
141
160
  const record = await executeCron(getCron('deferred-root-cron'), { outOfBand: false });
142
- assert.equal(record?.delivered, 'delivered: node deferred-root');
161
+ assert.match(record?.delivered ?? '', /^delivered: /);
143
162
  assert.equal(getCron('deferred-root-cron').state, 'active');
144
- assert.deepEqual(readInboxSince('deferred-root', undefined).map((entry) => entry.tier), ['deferred']);
163
+ assert.deepEqual(nodeMail('deferred-root').map((entry) => entry.urgency), ['deferred']);
145
164
  assert.deepEqual(launches, [], 'deferred delivery never launches a dormant target');
146
165
  assert.equal(getNode('deferred-root').status, 'done', 'the parked target remains parked');
147
166
  });
@@ -9,11 +9,14 @@ import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
9
9
  import { tmpdir } from 'node:os';
10
10
  import { join } from 'node:path';
11
11
  import { setTimeout as delay } from 'node:timers/promises';
12
- import { closeDb } from '../canvas/db.js';
12
+ import { closeDb, migrate, openDb } from '../canvas/db.js';
13
+ import { ensureScopeInitialized } from '../config.js';
14
+ import { closeScopedStores } from '../scoped-state/db.js';
13
15
  import { armCron, cancelCron, getCron } from '../canvas/crons.js';
14
16
  import { executeCron, markSelfCanceledCronRun } from '../../daemon/cron-run.js';
15
17
  let home;
16
18
  let realHome;
19
+ let realUserHome;
17
20
  function arm(overrides) {
18
21
  armCron({
19
22
  name: overrides.cron_id,
@@ -39,10 +42,15 @@ function arm(overrides) {
39
42
  before(() => {
40
43
  home = mkdtempSync(join(tmpdir(), 'crtr-cron-broker-capacity-'));
41
44
  realHome = process.env['CRTR_HOME'];
45
+ realUserHome = process.env['HOME'];
46
+ process.env['HOME'] = home;
42
47
  process.env['CRTR_HOME'] = home;
48
+ ensureScopeInitialized('user', join(home, '.crouter'));
49
+ migrate(openDb());
43
50
  });
44
51
  afterEach(() => {
45
52
  closeDb();
53
+ closeScopedStores();
46
54
  });
47
55
  after(() => {
48
56
  closeDb();
@@ -51,6 +59,10 @@ after(() => {
51
59
  delete process.env['CRTR_HOME'];
52
60
  else
53
61
  process.env['CRTR_HOME'] = realHome;
62
+ if (realUserHome === undefined)
63
+ delete process.env['HOME'];
64
+ else
65
+ process.env['HOME'] = realUserHome;
54
66
  });
55
67
  test('an on-change cron that cancels itself still delivers its final output', async () => {
56
68
  const runIdPath = join(home, 'self-cancel-run-id');
@@ -68,5 +80,5 @@ test('an on-change cron that cancels itself still delivers its final output', as
68
80
  assert.equal(markSelfCanceledCronRun('self-cancel-delivery', readFileSync(runIdPath, 'utf8')), true);
69
81
  assert.equal(cancelCron('self-cancel-delivery', { preserveRunningProcess: true }), true);
70
82
  const record = await run;
71
- assert.equal(record?.delivered, 'delivered: human send --inbox');
83
+ assert.match(record?.delivered ?? '', /^delivered: [0-9a-f]{32}$/, 'the durable human delivery was created after self-cancel');
72
84
  });
@@ -15,7 +15,9 @@ import assert from 'node:assert/strict';
15
15
  import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
16
16
  import { tmpdir } from 'node:os';
17
17
  import { join } from 'node:path';
18
- import { closeDb } from '../canvas/db.js';
18
+ import { closeDb, migrate, openDb } from '../canvas/db.js';
19
+ import { ensureScopeInitialized } from '../config.js';
20
+ import { closeScopedStores } from '../scoped-state/db.js';
19
21
  import { armCron, getCron } from '../canvas/crons.js';
20
22
  import { isPidAlive } from '../canvas/pid.js';
21
23
  import { executeCron } from '../../daemon/cron-run.js';
@@ -34,6 +36,7 @@ setInterval(() => {}, 1000);
34
36
  `;
35
37
  let home;
36
38
  let realHome;
39
+ let realUserHome;
37
40
  let marker;
38
41
  let command;
39
42
  function arm(overrides) {
@@ -61,7 +64,11 @@ function arm(overrides) {
61
64
  before(() => {
62
65
  home = mkdtempSync(join(tmpdir(), 'crtr-cron-timeout-descendants-'));
63
66
  realHome = process.env['CRTR_HOME'];
67
+ realUserHome = process.env['HOME'];
68
+ process.env['HOME'] = home;
64
69
  process.env['CRTR_HOME'] = home;
70
+ ensureScopeInitialized('user', join(home, '.crouter'));
71
+ migrate(openDb());
65
72
  marker = join(home, 'descendant.pid');
66
73
  const intermediate = join(home, 'intermediate.cjs');
67
74
  const descendant = join(home, 'descendant.cjs');
@@ -84,11 +91,16 @@ after(() => {
84
91
  }
85
92
  }
86
93
  closeDb();
94
+ closeScopedStores();
87
95
  rmSync(home, { recursive: true, force: true });
88
96
  if (realHome === undefined)
89
97
  delete process.env['CRTR_HOME'];
90
98
  else
91
99
  process.env['CRTR_HOME'] = realHome;
100
+ if (realUserHome === undefined)
101
+ delete process.env['HOME'];
102
+ else
103
+ process.env['HOME'] = realUserHome;
92
104
  });
93
105
  test('a TERM-ignoring descendant outside the shell process group is reaped before the timeout is recorded', async () => {
94
106
  arm({ cron_id: 'timeout-descendants', command });