@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
@@ -1,11 +1,13 @@
1
1
  import { before, after, test } from "node:test";
2
2
  import assert from "node:assert/strict";
3
3
  import { spawn } from "node:child_process";
4
- import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
4
+ import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
5
5
  import { LockedJsonFile } from "../../../../../core/locked-file.ts";
6
+ import { initializeFreshScopedStore } from "../../../../../core/scoped-state/migrate.ts";
7
+ import { writeRawConfig } from "../../../../../core/config.ts";
6
8
  import { expandModelCandidates } from "../../../../../core/model-routes.ts";
7
9
  import type { SubscriptionCredential } from "../../../lib/subscription-state.ts";
8
- import { dirname, join } from "node:path";
10
+ import { join } from "node:path";
9
11
  import { tmpdir } from "node:os";
10
12
 
11
13
  // Child processes reach crouter's locked-file primitive by absolute URL: they run under
@@ -24,44 +26,32 @@ const previousModelIntent = process.env.CRTR_MODEL_INTENT;
24
26
  const previousNodeCwd = process.env.CRTR_NODE_CWD;
25
27
 
26
28
  function writeLadderConfig() {
27
- const configPath = join(nodeCwd, ".crouter", "config.json");
28
- mkdirSync(dirname(configPath), { recursive: true });
29
- writeFileSync(
30
- configPath,
31
- `${JSON.stringify(
32
- {
33
- modelLadders: {
34
- anthropic: {
35
- ultra: "anthropic/claude-fable-5:high",
36
- strong: "anthropic/claude-opus-4-8:high",
37
- medium: "anthropic/claude-sonnet-4-6:high",
38
- light: "anthropic/custom-light-x",
39
- },
40
- openai: {
41
- ultra: "openai-codex/gpt-5.6-sol:max",
42
- strong: "openai-codex/gpt-5.6-sol:high",
43
- medium: "openai-codex/gpt-5.6-terra:medium",
44
- light: "openai-codex/gpt-5.6-luna:low",
45
- },
46
- },
29
+ writeRawConfig("user", {
30
+ modelLadders: {
31
+ anthropic: {
32
+ ultra: "anthropic/claude-fable-5:high",
33
+ strong: "anthropic/claude-opus-4-8:high",
34
+ medium: "anthropic/claude-sonnet-4-6:high",
35
+ light: "anthropic/custom-light-x",
47
36
  },
48
- null,
49
- 2,
50
- )}\n`,
51
- "utf8",
52
- );
37
+ openai: {
38
+ ultra: "openai-codex/gpt-5.6-sol:max",
39
+ strong: "openai-codex/gpt-5.6-sol:high",
40
+ medium: "openai-codex/gpt-5.6-terra:medium",
41
+ light: "openai-codex/gpt-5.6-luna:low",
42
+ },
43
+ },
44
+ });
53
45
  }
54
46
 
55
47
  function writeSameModelRouteConfig() {
56
- const configPath = join(nodeCwd, ".crouter", "config.json");
57
- mkdirSync(dirname(configPath), { recursive: true });
58
- writeFileSync(configPath, `${JSON.stringify({
48
+ writeRawConfig("user", {
59
49
  modelRoutes: {
60
- primary: { family: "openai", credentialSource: "primary", providerId: "openai-codex", models: { strong: "openai-codex/gpt-5.6-sol:high" } },
61
- alternate: { family: "openai", credentialSource: "alternate", providerId: "anthropic", models: { strong: "anthropic/gpt-5.6-sol:high" } },
50
+ primary: { family: "openai", credentialSource: "primary", providerId: "openai-codex", models: { ultra: "openai-codex/gpt-5.6-sol:high", strong: "openai-codex/gpt-5.6-sol:high", medium: "openai-codex/gpt-5.6-sol:high", light: "openai-codex/gpt-5.6-sol:high" } },
51
+ alternate: { family: "openai", credentialSource: "alternate", providerId: "anthropic", models: { ultra: "anthropic/gpt-5.6-sol:high", strong: "anthropic/gpt-5.6-sol:high", medium: "anthropic/gpt-5.6-sol:high", light: "anthropic/gpt-5.6-sol:high" } },
62
52
  },
63
53
  modelRouting: { credentialSourceOrder: ["primary", "alternate"], familyOrder: ["openai"] },
64
- }, null, 2)}\n`, "utf8");
54
+ });
65
55
  }
66
56
 
67
57
  function credential(label: string, overrides: Partial<SubscriptionCredential> = {}): SubscriptionCredential {
@@ -121,6 +111,8 @@ before(async () => {
121
111
  process.env.HOME = home;
122
112
  process.env.PI_CODING_AGENT_DIR = join(home, ".pi", "agent");
123
113
  process.env.CRTR_NODE_CWD = nodeCwd;
114
+ initializeFreshScopedStore({ kind: "user", root: join(home, ".crouter") });
115
+ initializeFreshScopedStore({ kind: "provider", root: process.env.PI_CODING_AGENT_DIR });
124
116
  helpers = await import("../../../lib/subscription-state.ts");
125
117
  providerManagement = await import("../../../../../core/provider-management.ts");
126
118
  rotationModule = await import("../../provider-rotation.ts");
@@ -363,7 +355,7 @@ test("the synthesized ladder registry preserves family preference before configu
363
355
  family: "anthropic",
364
356
  strength: "strong",
365
357
  spec: "anthropic/claude-opus-4-8:high",
366
- }, home, null);
358
+ }, nodeCwd, null);
367
359
 
368
360
  assert.deepEqual(candidates.map((candidate) => `${candidate.family}/${candidate.strength}`), [
369
361
  "anthropic/strong", "openai/strong", "anthropic/medium", "openai/medium",
@@ -473,7 +465,7 @@ test("a stale success cannot reopen a slot cooled down by a newer 429", async ()
473
465
  test("pool mutations take the cross-process pool-file lock", async () => {
474
466
  await resetRotationState();
475
467
  await helpers.writeSubscriptionPool("openai-codex", [credential("work")]);
476
- const poolFile = join(home, ".pi", "agent", "openai-codex-subscriptions.json");
468
+ const poolFile = join(home, ".pi", "agent", "openai-codex-credentials.json");
477
469
 
478
470
  const lockHolder = spawn(
479
471
  process.execPath,
@@ -531,14 +523,8 @@ await backend.withLockAsync(async () => {
531
523
  readyTimer = setTimeout(() => reject(new Error("lock-holder did not signal readiness within 60s")), 60_000);
532
524
  }),
533
525
  ]);
534
- const mutation = helpers.markSubscriptionAttempt("openai-codex", "work", 123);
535
- // Let the async acquirer observe the held cross-process lock before releasing it. The
536
- // single asynchronous lock path waits without blocking the event loop, then commits once
537
- // the holder releases.
538
- await new Promise((resolve) => setTimeout(resolve, 300));
539
- lockHolder.stdin!.write("release\n");
540
- lockHolder.stdin!.end();
541
- const pool = await mutation;
526
+ // Health is SQL-only, so the credential-file lock cannot delay it.
527
+ const pool = await within(helpers.markSubscriptionAttempt("openai-codex", "work", 123), 1_000, "health write waited on the credential-file lock");
542
528
  assert.equal(pool[0].lastAttemptAt, 123);
543
529
  } finally {
544
530
  if (readyTimer) clearTimeout(readyTimer);
@@ -806,6 +792,7 @@ function makeRotationCtx(modelIntent?: string) {
806
792
  const ctx = {
807
793
  model: { provider: "openai-codex", id: "gpt-5.6-sol", api: "openai-codex-responses" },
808
794
  thinkingLevel: "high",
795
+ cwd: nodeCwd,
809
796
  ui: { setStatus() {} },
810
797
  modelRegistry: {
811
798
  find(provider: string, id: string) {
@@ -1376,7 +1363,7 @@ test("self-terminates after consecutive transport-only exhausted passes; an HTTP
1376
1363
  const terminateCalls: string[] = [];
1377
1364
  let resolveTerminated: (tried: string) => void;
1378
1365
  const terminated = new Promise<string>((resolve) => { resolveTerminated = resolve; });
1379
- rotationModule.__setTerminatePoisonedProcessForTest((tried) => {
1366
+ rotationModule.__setTerminatePoisonedProcessForTest(async (tried) => {
1380
1367
  terminateCalls.push(tried);
1381
1368
  resolveTerminated(tried);
1382
1369
  return true;
@@ -1837,13 +1824,14 @@ test("emits an actionable 'not authenticated' error without switching models whe
1837
1824
  assert.match(emitted[0].error.errorMessage, /All provider routes exhausted \(tried openai\)/);
1838
1825
  });
1839
1826
 
1840
- // The builtin ladder is available even with no ~/.crouter/config.json, so a config-less
1841
- // user can still resolve cross-provider fallbacks.
1827
+ // The builtin ladder is available with no user configuration, so a config-less user can still
1828
+ // resolve cross-provider fallbacks.
1842
1829
  test("degrades gracefully via the builtin ladder when a config-less user has no cross-provider credentials", async () => {
1843
1830
  await resetRotationState();
1844
- rmSync(join(nodeCwd, ".crouter", "config.json"), { force: true });
1831
+ writeRawConfig("user", {});
1845
1832
 
1846
1833
  const ctx = {
1834
+ cwd: nodeCwd,
1847
1835
  model: { provider: "anthropic", id: "claude-opus-4-8", api: "anthropic-messages" },
1848
1836
  ui: { setStatus() {} },
1849
1837
  modelRegistry: {
@@ -21,7 +21,7 @@ declare function defaultSleep(ms: number): Promise<void>;
21
21
  /** Test-only seam: override the sleep implementation used for in-place/wait-out retries. Pass undefined to restore the default. */
22
22
  export declare function __setSleepForTest(fn: typeof defaultSleep | undefined): void;
23
23
  export declare const POISONED_TRANSPORT_PASS_LIMIT = 2;
24
- declare function defaultTerminatePoisonedProcess(tried: string): boolean;
24
+ declare function defaultTerminatePoisonedProcess(tried: string): Promise<boolean>;
25
25
  /** Test-only seam: override poisoned-process self-termination. Pass undefined to restore the default. */
26
26
  export declare function __setTerminatePoisonedProcessForTest(fn: typeof defaultTerminatePoisonedProcess | undefined): void;
27
27
  /** Test-only seam for the bounded, non-fatal subscription bookkeeping path. */
@@ -6,7 +6,7 @@ import { readMergedLaunchConfig } from '../../../core/config.js';
6
6
  import { expandModelCandidates, modelRequestFromConfig, probeRouteAvailability } from '../../../core/model-routes.js';
7
7
  import { envModelExact, envNodeId } from '../../../shared/env.js';
8
8
  import { ManagedProviderCoolingError } from '../../../core/runtime/managed-provider-cooling.js';
9
- import { recordTransportPoisonVerdict } from '../../../core/runtime/busy.js';
9
+ import { recordBrokerTurn } from '../../../core/runtime/broker/daemon-ops.js';
10
10
  import { recognizeProviderError } from '../../../core/provider-error-recognition.js';
11
11
  import { normalizeProviderFailure, providerFailureDiagnostic } from '../../../core/provider-failure.js';
12
12
  // A response without Retry-After proves only that THIS attempt was throttled; it
@@ -110,7 +110,7 @@ export function __setSleepForTest(fn) {
110
110
  // offline box parks the node until the network returns instead of spending its
111
111
  // respawn budget (daemon/fleet.ts, `deferRespawnWhileOffline`).
112
112
  export const POISONED_TRANSPORT_PASS_LIMIT = 2;
113
- function defaultTerminatePoisonedProcess(tried) {
113
+ async function defaultTerminatePoisonedProcess(tried) {
114
114
  // Only the broker process itself may self-terminate: runBroker stamps
115
115
  // CRTR_BROKER_PID with its own pid at boot. Any other host (tests, tooling)
116
116
  // keeps the ordinary terminal-error path.
@@ -118,9 +118,16 @@ function defaultTerminatePoisonedProcess(tried) {
118
118
  return false;
119
119
  const routes = tried.split(', ').filter((route) => route !== '');
120
120
  const nodeId = envNodeId();
121
- if (nodeId !== undefined && routes.length > 0) {
122
- recordTransportPoisonVerdict(nodeId, { consecutivePasses: POISONED_TRANSPORT_PASS_LIMIT, routes });
121
+ if (nodeId === undefined || routes.length === 0) {
122
+ throw new Error('poisoned broker is missing CRTR_NODE_ID or attempted routes');
123
123
  }
124
+ await recordBrokerTurn(nodeId, {
125
+ event: 'exit-diagnostic',
126
+ exit_diagnostic: {
127
+ schema: 'crtr.execution-exit-diagnostic/v1',
128
+ transport_poison: { consecutive_passes: POISONED_TRANSPORT_PASS_LIMIT, routes },
129
+ },
130
+ });
124
131
  logRotation(`process transport poisoned: ${POISONED_TRANSPORT_PASS_LIMIT} consecutive route-queue passes failed with no HTTP response (tried ${tried}); exiting so the daemon respawns this broker fresh`);
125
132
  process.kill(process.pid, "SIGTERM");
126
133
  return true;
@@ -705,7 +712,7 @@ async function runManagedProvider(state, model, context, options, stream) {
705
712
  const tried = [...attemptedRoutes].join(', ');
706
713
  if (lastTransientFailure !== undefined) {
707
714
  state.transportOnlyExhaustedPasses = sawHttpEvidence ? 0 : state.transportOnlyExhaustedPasses + 1;
708
- if (state.transportOnlyExhaustedPasses >= POISONED_TRANSPORT_PASS_LIMIT && activeTerminatePoisonedProcess(tried)) {
715
+ if (state.transportOnlyExhaustedPasses >= POISONED_TRANSPORT_PASS_LIMIT && await activeTerminatePoisonedProcess(tried)) {
709
716
  // The stream is deliberately left OPEN: the SIGTERM handler sees a live
710
717
  // turn, so it either certifies a clean abort (→ the daemon respawns and
711
718
  // resumes with a continuation prompt) or marks the turn dirty (→ the
@@ -42,7 +42,7 @@ import type { ProviderOptionsConfig } from '../../../types.js';
42
42
  import { expandModelCandidates, modelRequestFromConfig, probeRouteAvailability } from '../../../core/model-routes.js';
43
43
  import { envModelExact, envNodeId } from '../../../shared/env.js';
44
44
  import { ManagedProviderCoolingError } from '../../../core/runtime/managed-provider-cooling.js';
45
- import { recordTransportPoisonVerdict } from '../../../core/runtime/busy.js';
45
+ import { recordBrokerTurn } from '../../../core/runtime/broker/daemon-ops.js';
46
46
  import { recognizeProviderError, type ProviderErrorSignal } from '../../../core/provider-error-recognition.js';
47
47
  import { normalizeProviderFailure, providerFailureDiagnostic, type NormalizedProviderFailure } from '../../../core/provider-failure.js';
48
48
 
@@ -213,16 +213,23 @@ export function __setSleepForTest(fn: typeof defaultSleep | undefined): void {
213
213
  // respawn budget (daemon/fleet.ts, `deferRespawnWhileOffline`).
214
214
  export const POISONED_TRANSPORT_PASS_LIMIT = 2;
215
215
 
216
- function defaultTerminatePoisonedProcess(tried: string): boolean {
216
+ async function defaultTerminatePoisonedProcess(tried: string): Promise<boolean> {
217
217
  // Only the broker process itself may self-terminate: runBroker stamps
218
218
  // CRTR_BROKER_PID with its own pid at boot. Any other host (tests, tooling)
219
219
  // keeps the ordinary terminal-error path.
220
220
  if (process.env["CRTR_BROKER_PID"] !== String(process.pid)) return false;
221
221
  const routes = tried.split(', ').filter((route) => route !== '');
222
222
  const nodeId = envNodeId();
223
- if (nodeId !== undefined && routes.length > 0) {
224
- recordTransportPoisonVerdict(nodeId, { consecutivePasses: POISONED_TRANSPORT_PASS_LIMIT, routes });
223
+ if (nodeId === undefined || routes.length === 0) {
224
+ throw new Error('poisoned broker is missing CRTR_NODE_ID or attempted routes');
225
225
  }
226
+ await recordBrokerTurn(nodeId, {
227
+ event: 'exit-diagnostic',
228
+ exit_diagnostic: {
229
+ schema: 'crtr.execution-exit-diagnostic/v1',
230
+ transport_poison: { consecutive_passes: POISONED_TRANSPORT_PASS_LIMIT, routes },
231
+ },
232
+ });
226
233
  logRotation(
227
234
  `process transport poisoned: ${POISONED_TRANSPORT_PASS_LIMIT} consecutive route-queue passes failed with no HTTP response (tried ${tried}); exiting so the daemon respawns this broker fresh`,
228
235
  );
@@ -892,7 +899,7 @@ async function runManagedProvider(
892
899
  const tried = [...attemptedRoutes].join(', ');
893
900
  if (lastTransientFailure !== undefined) {
894
901
  state.transportOnlyExhaustedPasses = sawHttpEvidence ? 0 : state.transportOnlyExhaustedPasses + 1;
895
- if (state.transportOnlyExhaustedPasses >= POISONED_TRANSPORT_PASS_LIMIT && activeTerminatePoisonedProcess(tried)) {
902
+ if (state.transportOnlyExhaustedPasses >= POISONED_TRANSPORT_PASS_LIMIT && await activeTerminatePoisonedProcess(tried)) {
896
903
  // The stream is deliberately left OPEN: the SIGTERM handler sees a live
897
904
  // turn, so it either certifies a clean abort (→ the daemon respawns and
898
905
  // resumes with a continuation prompt) or marks the turn dirty (→ the
package/dist/cli.js CHANGED
@@ -3,12 +3,13 @@ import './suppress-experimental-warnings.js';
3
3
  import { openSync } from 'node:fs';
4
4
  import { enableCompileCache } from 'node:module';
5
5
  import { fileURLToPath } from 'node:url';
6
- import { resolveRoot } from './build-root.js';
6
+ import { isDaemonControlInvocation, resolveDaemonControlRoot, resolveRoot } from './build-root.js';
7
7
  import { maybeBootRoot } from './core/runtime/front-door.js';
8
8
  import { maybeAutoUpdate } from './core/auto-update.js';
9
9
  import { ensureProjectScope } from './core/bootstrap.js';
10
10
  import { provisionExports, pruneLegacyExports } from './core/host-exports/export.js';
11
11
  import { revalidateBundlePlugins } from './core/command-plugins/revalidate.js';
12
+ import { runCli } from './core/command.js';
12
13
  import { dispatchWithStaleRecovery } from './core/manifest-recovery.js';
13
14
  import { installStdoutErrorPolicy } from './core/stdout-errors.js';
14
15
  import { handle } from './core/io.js';
@@ -47,6 +48,14 @@ async function main() {
47
48
  // bootRoot exec'd pi inline and exited; unreachable.
48
49
  }
49
50
  mark('cli.front_door_passed');
51
+ // Daemon control must remain callable immediately after an upgrade: its
52
+ // selected successor performs the user/provider store conversion, so this
53
+ // dispatch cannot first read scoped settings, installed plugins, or hooks.
54
+ // The compact tree reuses the daemon definitions and the normal dispatcher.
55
+ if (isDaemonControlInvocation(process.argv)) {
56
+ await runCli(await resolveDaemonControlRoot(), process.argv);
57
+ return;
58
+ }
50
59
  // Bring installed bundle plugins back in step with their endpoints before the
51
60
  // tree is built, so a package this pass replaces is the one this invocation
52
61
  // dispatches against. TTL-gated and non-fatal — see revalidate.ts.
@@ -0,0 +1,11 @@
1
+ export interface HumanDaemon {
2
+ /** The isolated canvas home, and the value of both `CRTR_HOME` and `HOME`. */
3
+ home: string;
4
+ /** A scratch directory for the page sources a fixture authors. */
5
+ sources: string;
6
+ dispose(): Promise<void>;
7
+ }
8
+ /** Bind the human routes on an isolated home's socket. Every environment
9
+ * change is undone by `dispose`, so a fixture can run beside the developer's
10
+ * own canvas without touching it. */
11
+ export declare function startHumanDaemon(prefix: string): Promise<HumanDaemon>;
@@ -0,0 +1,60 @@
1
+ // A crtrd the human client surfaces can actually talk to.
2
+ //
3
+ // The inbox and the attach viewer now read every page and request over the
4
+ // daemon's human routes, so a fixture that exercises them needs a daemon on the
5
+ // socket `cliClient()` resolves. It gets the REAL route tables rather than a
6
+ // re-implementation: the projections under test are the daemon's, and a second
7
+ // copy of them in a fixture would pass while the shipped ones drifted.
8
+ //
9
+ // The routes read an on-disk canvas, so the helper also stands up an isolated
10
+ // home with the canvas schema and the scope store crtrd installs at startup —
11
+ // opening a page resolves its components from scope settings rooted at HOME.
12
+ import { createServer } from 'node:http';
13
+ import { mkdtempSync, realpathSync, rmSync } from 'node:fs';
14
+ import { tmpdir } from 'node:os';
15
+ import { join } from 'node:path';
16
+ import { migrate, openDb } from '#core/canvas/db';
17
+ import { resetScopeCache } from '#core/scope';
18
+ import { initializeFreshScopedStore } from '#core/scoped-state/migrate';
19
+ import { Router } from '#daemon/api/router';
20
+ import { humanRequestRoutes } from '#daemon/api/handlers/human-requests';
21
+ import { inboxRoutes } from '#daemon/api/handlers/inbox';
22
+ /** Bind the human routes on an isolated home's socket. Every environment
23
+ * change is undone by `dispose`, so a fixture can run beside the developer's
24
+ * own canvas without touching it. */
25
+ export async function startHumanDaemon(prefix) {
26
+ // Canonical, because a request row stores its directory as given while every
27
+ // read path resolves one first: a home behind a symlink (every macOS tmpdir)
28
+ // would make the two disagree.
29
+ const home = realpathSync(mkdtempSync(join(tmpdir(), `${prefix}-`)));
30
+ const sources = mkdtempSync(join(tmpdir(), `${prefix}-src-`));
31
+ const previousHome = process.env['HOME'];
32
+ const previousCrtrHome = process.env['CRTR_HOME'];
33
+ process.env['HOME'] = home;
34
+ process.env['CRTR_HOME'] = home;
35
+ resetScopeCache();
36
+ initializeFreshScopedStore({ kind: 'user', root: join(home, '.crouter') });
37
+ migrate(openDb());
38
+ const router = new Router().registerAll(inboxRoutes).registerAll(humanRequestRoutes);
39
+ const server = createServer((req, res) => { void router.handle(req, res); });
40
+ await new Promise((resolve) => server.listen(join(home, 'crtrd.sock'), resolve));
41
+ return {
42
+ home,
43
+ sources,
44
+ async dispose() {
45
+ server.closeAllConnections();
46
+ await new Promise((resolve) => server.close(() => resolve()));
47
+ rmSync(home, { recursive: true, force: true });
48
+ rmSync(sources, { recursive: true, force: true });
49
+ if (previousCrtrHome === undefined)
50
+ delete process.env['CRTR_HOME'];
51
+ else
52
+ process.env['CRTR_HOME'] = previousCrtrHome;
53
+ if (previousHome === undefined)
54
+ delete process.env['HOME'];
55
+ else
56
+ process.env['HOME'] = previousHome;
57
+ resetScopeCache();
58
+ },
59
+ };
60
+ }
@@ -151,7 +151,7 @@ export async function buildCanvasPanelLines(nodeId, asks, palette, source, crons
151
151
  const kind = faint(nameCell(n?.kind ?? '', KIND_W));
152
152
  const tokens = muted(padStartVisible(tokensCell(id, remote), TOK_W));
153
153
  const badges = `${cycleBadge(n)}${await childBadgeFor(n)}${liveBelowBadgeFor(n)}${askBadge(id, asks)}${activityCell(id, n, remote)}`;
154
- const line = ` ${direction} ${nodeGlyph(n, remote)} ${name} ${kind} ${tokens}${badges}`;
154
+ const line = ` ${direction} ${nodeGlyph(n)} ${name} ${kind} ${tokens}${badges}`;
155
155
  return truncate(line);
156
156
  };
157
157
  const reportIds = [...(mgr !== undefined ? [mgr] : []), ...live];
@@ -1,5 +1,5 @@
1
1
  import { Container } from '@earendil-works/pi-tui';
2
- import type { TicketSummary } from '../../../core/human/types.js';
2
+ import { type InboxRow } from '../../inbox/dto-adapt.js';
3
3
  import type { AttachSession } from '../session/context.js';
4
4
  export type StripSession = Pick<AttachSession, 'nodeId' | 'remote' | 'canvasSource' | 'tui' | 'pal'>;
5
5
  export interface InboxStripHooks {
@@ -8,7 +8,7 @@ export interface InboxStripHooks {
8
8
  /** Drop the below-editor roster's highlight — the two lists are mutually exclusive. */
9
9
  exitRoster: () => void;
10
10
  /** Open this ticket — the inline ticket panel, or its fallbacks. */
11
- openTicket: (ticket: TicketSummary) => void;
11
+ openTicket: (ticket: InboxRow) => void;
12
12
  /** True while the ticket panel is open — it IS the expanded notification,
13
13
  * so the strip's own rows hide rather than duplicate the flag. */
14
14
  suppressed: () => boolean;
@@ -26,6 +26,6 @@ export interface InboxStrip {
26
26
  /** True while the strip holds the highlight. */
27
27
  active(): boolean;
28
28
  /** The cached pending tickets, for the inbox surface's scan merge. */
29
- pendingTickets(): TicketSummary[];
29
+ pendingTickets(): InboxRow[];
30
30
  }
31
31
  export declare function createInboxStrip(s: StripSession, hooks: InboxStripHooks): InboxStrip;
@@ -13,7 +13,8 @@
13
13
  // child ticket is present in the surface it seats.
14
14
  import { Container, Text, decodeKittyPrintable, matchesKey } from '@earendil-works/pi-tui';
15
15
  import { DynamicBorder } from '@earendil-works/pi-coding-agent';
16
- import { scanInbox, scanPageHistory } from '../../../core/human/scan.js';
16
+ import { byNewestFirst, inboxRowFromDTO } from '../../inbox/dto-adapt.js';
17
+ import { cliClient } from '../../../commands/api-client.js';
17
18
  import { fillBar, fillWidth, navLabel, stripSgr, truncate, REVERSE, YELLOW, RESET } from '../../../core/canvas/nav-render.js';
18
19
  /** Ticket rows shown at once; the window follows the selection. */
19
20
  const MAX_ROWS = 3;
@@ -91,14 +92,21 @@ export function createInboxStrip(s, hooks) {
91
92
  // Same pending merge the inbox surface does — inbox-projected tickets plus
92
93
  // reply-bearing no-inbox pages — but for every subtree node, then scoped to
93
94
  // tickets whose origin is in the subtree.
94
- // ONE page-history walk for the whole subtree, filtered by origin here.
95
- // Calling `scanPageHistory(id)` per node re-walked every ticket directory
96
- // once per subtree node — the same O(all tickets) scan repeated N times for
97
- // a result that is just the union over subtree origins.
95
+ // ONE home-wide page-history read for the whole subtree, filtered by origin
96
+ // here. Asking the daemon per node would repeat the same O(all tickets)
97
+ // projection N times for a result that is just the union over subtree
98
+ // origins.
99
+ const client = cliClient();
100
+ const [inbox, history] = await Promise.all([client.listHumanInbox(), client.getInboxHistory()]);
98
101
  const merged = new Map();
99
- for (const item of scanInbox())
100
- merged.set(item.dir, item);
101
- for (const page of scanPageHistory()) {
102
+ for (const item of inbox.tickets) {
103
+ const row = inboxRowFromDTO(item);
104
+ merged.set(row.dir, row);
105
+ }
106
+ for (const item of history.tickets) {
107
+ const page = inboxRowFromDTO(item);
108
+ if (page.kind !== 'page')
109
+ continue;
102
110
  if (page.source.nodeId === undefined || !nodes.has(page.source.nodeId))
103
111
  continue;
104
112
  if (page.state !== 'pending' || !page.awaitsResponse || page.inbox)
@@ -108,7 +116,7 @@ export function createInboxStrip(s, hooks) {
108
116
  }
109
117
  tickets = [...merged.values()]
110
118
  .filter((t) => t.source.nodeId !== undefined && nodes.has(t.source.nodeId))
111
- .sort((a, b) => ticketTime(b).localeCompare(ticketTime(a)) || a.id.localeCompare(b.id));
119
+ .sort(byNewestFirst);
112
120
  // The selected row may have vanished (answered, canceled) — drop back to
113
121
  // the editor so no ghost highlight lingers.
114
122
  if (selDir !== undefined && !tickets.some((t) => t.dir === selDir))
@@ -1,5 +1,5 @@
1
1
  import type { Component } from '@earendil-works/pi-tui';
2
- import type { TicketSummary } from '../../../core/human/types.js';
2
+ import type { InboxRow } from '../../inbox/dto-adapt.js';
3
3
  import type { AttachSession } from '../session/context.js';
4
4
  export type PanelSession = Pick<AttachSession, 'tui' | 'pal'>;
5
5
  export interface TicketPanelHooks {
@@ -17,7 +17,7 @@ export interface TicketPanel {
17
17
  /** Mounted once into the frame's `ticketPanel` slot; empty while closed. */
18
18
  readonly component: Component;
19
19
  /** Open a ticket's page inline; review/unreadable tickets fall back. */
20
- open(ticket: TicketSummary): void;
20
+ open(ticket: InboxRow): Promise<void>;
21
21
  /** Panel key routing — consumes EVERY chunk while open. */
22
22
  handleKey(data: string): boolean;
23
23
  close(): void;