@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,26 +1,7 @@
1
+ import type { MailEntryDTO } from '../../../api/dto/mail.js';
1
2
  import type { BrokerReportNodeDTO } from '../../../api/dto/broker-ops.js';
2
- import type { OperationId } from '../../events/types.js';
3
- export type BrokerInboxEntryId = string & {
4
- readonly __brokerInboxEntryId: unique symbol;
5
- };
6
- export interface BrokerInboxEntry {
7
- entry_id: BrokerInboxEntryId;
8
- operation_id: OperationId;
9
- ts: string;
10
- from: string | null;
11
- from_name?: string;
12
- tier: 'critical' | 'urgent' | 'normal' | 'deferred';
13
- kind: 'update' | 'urgent' | 'final' | 'message' | 'completed';
14
- ref?: string;
15
- label: string;
16
- data?: Record<string, unknown>;
17
- /** Set only by the human-ticket settlement paths; absent means an ordinary report. */
18
- disposition?: 'human-answer' | 'human-canceled';
19
- }
20
- export declare function readBrokerCursor(nodeId: string): BrokerInboxEntryId | undefined;
21
- export declare function readBrokerInboxSince(nodeId: string, cursor?: string): BrokerInboxEntry[];
22
- export declare function readBrokerInboxRange(nodeId: string, after: string | undefined, through: string): BrokerInboxEntry[];
23
- export declare function readBrokerCanceledEntryIds(nodeId: string): Set<BrokerInboxEntryId>;
3
+ export type BrokerInboxEntryId = string;
4
+ export type BrokerInboxEntry = MailEntryDTO;
24
5
  /** The node id a canonical report ref points at, or undefined when the ref is
25
6
  * absent, absolute, or not a report path. Callers use it to tell whether the
26
7
  * report-node projection they hold can still resolve the ref. */
@@ -41,14 +22,5 @@ export interface InboxDelivery {
41
22
  cards: readonly string[];
42
23
  entries: readonly BrokerInboxEntry[];
43
24
  }
44
- /** Split unread entries into ordered deliveries: each human entry verbatim, and
45
- * each CONTIGUOUS run of node/system entries as one card in the physical slot
46
- * that run occupies. A deferred-only card is folded into the person's delivery
47
- * waiting immediately behind it rather than being deliverable on its own.
48
- *
49
- * The runs are what keep the cursor honest. Exactly one delivery goes out per
50
- * cycle and the rest requeue, while a sent delivery commits the cursor across
51
- * its own entries — so a delivery that spanned a person's message would commit
52
- * past words this cycle never sent. A run can never span one, and node mail
53
- * that arrived after a person's message now waits behind it. */
25
+ /** Keep each person's words separate and in order; fold preceding deferred context into that same input. */
54
26
  export declare function coalesceBrokerInbox(entries: readonly BrokerInboxEntry[], reportNodes: ReadonlyMap<string, BrokerReportNodeDTO>): readonly InboxDelivery[];
@@ -1,90 +1,11 @@
1
- // Broker-local inbox access and rendering. The daemon owns feed delivery; a
2
- // broker only reads its own files and uses daemon-projected report senders.
3
- import { existsSync, readFileSync } from 'node:fs';
4
- import { inboxPath, nodeDir } from '../../canvas/paths.js';
1
+ // Broker inbox rendering uses daemon-projected mail and file-backed report bodies.
2
+ import { readFileSync } from 'node:fs';
3
+ import { nodeDir } from '../../canvas/paths.js';
5
4
  import { formatInboxCard, formatInboxRefInstruction } from '../../../shared/generated-context.js';
6
5
  import { renderBirthAnnouncementBody } from '../../../shared/birth-announcement.js';
7
- const ENTRY_ID = /^(?!0{32}$)[0-9a-f]{32}$/;
8
6
  const BODY_MAX_LINES = 12;
9
7
  const BODY_MAX_CHARS = 1000;
10
8
  const INLINE_REPORT_MAX_CHARS = 1000;
11
- function entryId(value) {
12
- if (typeof value !== 'string' || !ENTRY_ID.test(value))
13
- throw new TypeError('entry_id must be 32 lowercase non-zero hexadecimal characters');
14
- return value;
15
- }
16
- function readPhysicalInbox(nodeId) {
17
- const path = inboxPath(nodeId);
18
- if (!existsSync(path))
19
- return [];
20
- const raw = readFileSync(path, 'utf8');
21
- if (raw === '')
22
- return [];
23
- const lines = raw.split('\n');
24
- if (lines.at(-1) === '')
25
- lines.pop();
26
- if (lines.some((line) => line.trim() === ''))
27
- throw new Error('inbox contains a blank physical line');
28
- const entries = lines.map((line) => {
29
- const parsed = JSON.parse(line);
30
- parsed.entry_id = entryId(parsed.entry_id);
31
- return parsed;
32
- });
33
- const seen = new Set();
34
- for (const entry of entries) {
35
- if (seen.has(entry.entry_id))
36
- throw new Error(`duplicate inbox entry_id: ${entry.entry_id}`);
37
- seen.add(entry.entry_id);
38
- }
39
- return entries;
40
- }
41
- function cursorPath(nodeId) {
42
- return `${inboxPath(nodeId)}.cursor`;
43
- }
44
- export function readBrokerCursor(nodeId) {
45
- const path = cursorPath(nodeId);
46
- if (!existsSync(path))
47
- return undefined;
48
- const raw = readFileSync(path, 'utf8').trim();
49
- return raw === '' ? undefined : entryId(raw);
50
- }
51
- export function readBrokerInboxSince(nodeId, cursor) {
52
- const entries = readPhysicalInbox(nodeId);
53
- if (cursor === undefined)
54
- return entries;
55
- const index = entries.findIndex((entry) => entry.entry_id === entryId(cursor));
56
- if (index < 0)
57
- throw new Error(`inbox cursor entry_id not found: ${entryId(cursor)}`);
58
- return entries.slice(index + 1);
59
- }
60
- export function readBrokerInboxRange(nodeId, after, through) {
61
- const entries = readPhysicalInbox(nodeId);
62
- const throughId = entryId(through);
63
- const throughIndex = entries.findIndex((entry) => entry.entry_id === throughId);
64
- if (throughIndex < 0)
65
- throw new Error(`inbox range through entry_id not found: ${throughId}`);
66
- if (after === undefined)
67
- return entries.slice(0, throughIndex + 1);
68
- const afterId = entryId(after);
69
- const afterIndex = entries.findIndex((entry) => entry.entry_id === afterId);
70
- if (afterIndex < 0)
71
- throw new Error(`inbox range after entry_id not found: ${afterId}`);
72
- if (afterIndex >= throughIndex)
73
- throw new Error(`inbox range is reversed: ${afterId} through ${throughId}`);
74
- return entries.slice(afterIndex + 1, throughIndex + 1);
75
- }
76
- export function readBrokerCanceledEntryIds(nodeId) {
77
- const path = `${inboxPath(nodeId)}.canceled`;
78
- if (!existsSync(path))
79
- return new Set();
80
- const out = new Set();
81
- for (const line of readFileSync(path, 'utf8').split('\n')) {
82
- const value = line.trim();
83
- if (value !== '')
84
- out.add(entryId(value));
85
- }
86
- return out;
87
- }
88
9
  function inlineBody(entry) {
89
10
  const body = typeof entry.data?.['body'] === 'string' ? String(entry.data['body']).trim() : '';
90
11
  return body === '' || body === entry.label ? '' : body;
@@ -174,16 +95,7 @@ export function entryCards(entry) {
174
95
  return [];
175
96
  return cards.filter((card) => typeof card === 'string');
176
97
  }
177
- /** Split unread entries into ordered deliveries: each human entry verbatim, and
178
- * each CONTIGUOUS run of node/system entries as one card in the physical slot
179
- * that run occupies. A deferred-only card is folded into the person's delivery
180
- * waiting immediately behind it rather than being deliverable on its own.
181
- *
182
- * The runs are what keep the cursor honest. Exactly one delivery goes out per
183
- * cycle and the rest requeue, while a sent delivery commits the cursor across
184
- * its own entries — so a delivery that spanned a person's message would commit
185
- * past words this cycle never sent. A run can never span one, and node mail
186
- * that arrived after a person's message now waits behind it. */
98
+ /** Keep each person's words separate and in order; fold preceding deferred context into that same input. */
187
99
  export function coalesceBrokerInbox(entries, reportNodes) {
188
100
  const deliveries = [];
189
101
  let run = [];
@@ -70,6 +70,7 @@ export declare class RebindDriver {
70
70
  private removeInstalledSubscription;
71
71
  private captureSystemPrompt;
72
72
  private executeSubscriptionCallback;
73
+ private publishAndScheduleProviderRecovery;
73
74
  private ackTo;
74
75
  }
75
76
  export {};
@@ -5,7 +5,7 @@ import { emitEvent } from '../../events/emit.js';
5
5
  import { operationIdContext } from '../../events/operation-id.js';
6
6
  import { installPersonaTransitionGate } from '../broker-persona-guidance.js';
7
7
  import { abortSessionFromExtension } from './extension-abort.js';
8
- import { clearFault, invalidateProviderRetryEpisode, readFault } from '../fault.js';
8
+ import { brokerRecovery, mutateBrokerFault, mutateBrokerProviderRetry } from './daemon-ops.js';
9
9
  const MAX_ADMITTED_REPLACEMENTS = 2;
10
10
  const REPLACEMENT_DEADLINE_MS = 30_000;
11
11
  const REPLACEMENT_DEADLINE_EXCEEDED = Symbol('replacement-deadline-exceeded');
@@ -101,15 +101,15 @@ export class RebindDriver {
101
101
  // every later rebind explicitly marks the old session's episode invalid.
102
102
  if (this.installed !== undefined) {
103
103
  if (typeof this.sessionValue.sessionFile === 'string' && this.sessionValue.sessionFile !== '') {
104
- invalidateProviderRetryEpisode(this.deps.nodeId, this.sessionValue.sessionFile);
104
+ await mutateBrokerProviderRetry(this.deps.nodeId, { op: 'invalidate', session_id: this.sessionValue.sessionManager.getSessionId() });
105
105
  }
106
106
  // A daemon-owned auto marker belongs to the outgoing session whether
107
107
  // that session has a durable path or not. Retaining it lets the
108
108
  // replacement inherit an old anchor, attempts, and backoff; fatal and
109
109
  // manual markers stay visible.
110
- const fault = readFault(this.deps.nodeId);
110
+ const fault = (await brokerRecovery(this.deps.nodeId)).fault;
111
111
  if (fault?.link === 'pi→provider' && fault.retry.disposition === 'auto' && fault.retry.by === 'daemon') {
112
- clearFault(this.deps.nodeId, { link: 'pi→provider', preserveProviderRetryEpisode: true });
112
+ await mutateBrokerFault(this.deps.nodeId, { op: 'clear', link: 'pi→provider', preserve_episode: true });
113
113
  }
114
114
  }
115
115
  this.installed?.executingTools.clear();
@@ -149,7 +149,7 @@ export class RebindDriver {
149
149
  installPersonaTransitionGate(this.deps.nodeId, {
150
150
  agent,
151
151
  sessionManager: candidateSession.sessionManager,
152
- });
152
+ }, () => this.deps.faultRetry().notePersonaGateFailure());
153
153
  agent.steeringMode = 'all';
154
154
  agent.followUpMode = 'all';
155
155
  installTrailingThinkingGuard(agent);
@@ -288,21 +288,30 @@ export class RebindDriver {
288
288
  generation.stagedOverflowFailure = { errorMessage: event.errorMessage };
289
289
  if (event.type === 'agent_settled') {
290
290
  this.agentRunActiveValue = false;
291
- this.deps.faultRetry().publishSettledProviderFault(generation);
292
- if (this.shutdownRequested) {
293
- this.deps.disposeAndExit('shutdown-after-settle');
294
- return;
295
- }
291
+ void this.publishAndScheduleProviderRecovery(generation);
296
292
  }
297
293
  this.deps.toolGroups.observeToolGroupEvent(event);
298
294
  this.deps.projection().relayEvent(event, generation);
299
- if (event.type === 'agent_settled')
300
- this.deps.faultRetry().schedule();
301
295
  }
302
296
  catch (err) {
303
297
  emitEvent({ level: 'debug', event: 'broker.runtime.diagnostic', fields: { message: `event relay threw: ${String(err)}` } });
304
298
  }
305
299
  }
300
+ async publishAndScheduleProviderRecovery(generation) {
301
+ try {
302
+ await this.deps.faultRetry().publishSettledProviderFault(generation);
303
+ if (this.shutdownRequested) {
304
+ this.deps.disposeAndExit('shutdown-after-settle');
305
+ return;
306
+ }
307
+ await this.deps.faultRetry().schedule();
308
+ }
309
+ catch (error) {
310
+ emitEvent({ level: 'error', event: 'broker.daemon.operation.failed', node_id: this.deps.nodeId, error, fields: { operation: 'provider_fault_settlement' } });
311
+ if (this.shutdownRequested)
312
+ this.deps.disposeAndExit('shutdown-after-settle');
313
+ }
314
+ }
306
315
  ackTo(client, op, ok = true, detail, id) {
307
316
  this.deps.registry.sendFrame(client, { type: 'ack', for: op, ok, ...(detail !== undefined ? { detail } : {}), ...(id !== undefined ? { id } : {}) });
308
317
  }
@@ -23,5 +23,5 @@ interface PersonaTransitionSession {
23
23
  };
24
24
  }
25
25
  /** Gate each provider request on durable delivery of the current persona delta. */
26
- export declare function installPersonaTransitionGate(nodeId: string, session: PersonaTransitionSession): void;
26
+ export declare function installPersonaTransitionGate(nodeId: string, session: PersonaTransitionSession, noteFailure?: () => void): void;
27
27
  export {};
@@ -1,7 +1,5 @@
1
1
  import { contextDir } from '../canvas/paths.js';
2
- import { isDaemonTransportApiError } from '../../api/errors.js';
3
2
  import { emitEvent } from '../events/emit.js';
4
- import { clearFault, recordFault } from './fault.js';
5
3
  import { brokerExtensionState, commitBrokerPersonaAck } from './broker/daemon-ops.js';
6
4
  import { readRoadmap, roadmapPath } from './roadmap.js';
7
5
  import { buildSubPersonaMenu, renderConfigChangeDelta } from '../substrate/render.js';
@@ -115,7 +113,7 @@ export async function deliverPendingPersonaTransition(initialState, deliver) {
115
113
  }
116
114
  }
117
115
  /** Gate each provider request on durable delivery of the current persona delta. */
118
- export function installPersonaTransitionGate(nodeId, session) {
116
+ export function installPersonaTransitionGate(nodeId, session, noteFailure = () => { }) {
119
117
  const { agent } = session;
120
118
  const previousTransform = agent.transformContext;
121
119
  agent.transformContext = async (messages, signal) => {
@@ -139,19 +137,10 @@ export function installPersonaTransitionGate(nodeId, session) {
139
137
  for (const context of new Set([active, messages, transformed]))
140
138
  context.push(message);
141
139
  });
142
- clearFault(nodeId, { link: 'broker↔crtrd' });
143
140
  return transformed;
144
141
  }
145
142
  catch (error) {
146
- if (isDaemonTransportApiError(error)) {
147
- recordFault(nodeId, {
148
- link: 'broker↔crtrd',
149
- op: 'persona transition',
150
- kind: 'connection',
151
- retry: { disposition: 'manual' },
152
- message: error.message,
153
- });
154
- }
143
+ noteFailure();
155
144
  emitEvent({
156
145
  event: 'broker.daemon.operation.failed',
157
146
  level: 'error',
@@ -16,7 +16,7 @@
16
16
  // + model registry are real SDK construction helpers (NOT part of the swappable
17
17
  // engine seam — the fake engine receives the real, extension-loaded loader so
18
18
  // the real canvas-stophook fires session_start).
19
- import { envModelIntent, envNodeCwd, envProfileId } from '../../shared/env.js';
19
+ import { envModelIntent, envNodeCwd, envNodeId, envProfileId } from '../../shared/env.js';
20
20
  import { createServer } from 'node:net';
21
21
  import { existsSync, readFileSync, unlinkSync } from 'node:fs';
22
22
  import { join } from 'node:path';
@@ -34,8 +34,7 @@ import { assertEngineVersion, loadBrokerEngine } from './broker-sdk.js';
34
34
  import { resolveBundledPiPackageDir } from './pi-cli.js';
35
35
  import { captureSessionChatCapabilities } from './command-surface.js';
36
36
  import { PoolCredentialStore } from '../pool-credential-store.js';
37
- import { clearCleanAbort, markBusy, markCleanAbort } from './busy.js';
38
- import { clearFault, recordFaultForCurrentNode } from './fault.js';
37
+ import { mutateBrokerFault, recordBrokerTurn } from './broker/daemon-ops.js';
39
38
  import { modelRequestFromConfig, selectInitialModelRoute, unregisteredConcreteModel } from '../model-routes.js';
40
39
  import { KNOWN_STREAM_WAIT_UI } from './stream-watchdog.js';
41
40
  import { probeOnline as probeOnlineReal } from './connectivity.js';
@@ -121,10 +120,6 @@ export function disposeActiveSession() {
121
120
  }
122
121
  // runBroker — the broker process body (plan T4 steps 1–6)
123
122
  export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), startupTs = new Date().toISOString()) {
124
- // A clean-abort certificate belongs only to the dead broker that wrote it.
125
- // Fleet classification consumes it as proof that the dead broker had a turn
126
- // in flight even though Pi's settled abort already cleared the busy marker.
127
- clearCleanAbort(nodeId);
128
123
  // The canonical broker event source (job/log.jsonl) is bound before any other
129
124
  // work in this function — no path/env/state setup may precede it, and the
130
125
  // binder independently validates nodeId before constructing that path.
@@ -619,7 +614,7 @@ export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), sta
619
614
  emitEvent({ level: 'error', event: 'broker.socket.failed', error: err });
620
615
  disposeAndExit('socket-error', 1);
621
616
  });
622
- server.listen(sockPath, () => {
617
+ server.listen(sockPath, async () => {
623
618
  // Binding view.sock is the exact inverse of a `connect ENOENT view.sock`
624
619
  // fault, so the moment the listener accepts, any socket-absence marker a
625
620
  // viewer/relay recorded during the revive→bind gap is provably stale. The
@@ -627,15 +622,25 @@ export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), sta
627
622
  // waiting for a client to reconnect — a headless node with nobody attached
628
623
  // never gets that reconnect, which is how the stale ⚠ leaked. A genuine
629
624
  // post-bind failure is re-recorded by the next failed client op.
630
- clearFault(nodeId, { link: 'viewer↔broker' });
631
- clearFault(nodeId, { link: 'relay↔broker' });
625
+ void Promise.all([
626
+ mutateBrokerFault(nodeId, { op: 'clear', link: 'viewer↔broker' }),
627
+ mutateBrokerFault(nodeId, { op: 'clear', link: 'relay↔broker' }),
628
+ ]).catch((error) => emitEvent({ level: 'error', event: 'broker.daemon.operation.failed', node_id: nodeId, error, fields: { operation: 'broker_socket_bound_fault_clear' } }));
632
629
  // The listener is also the broker startup boundary: a pending or
633
630
  // surviving-admitted provider episode is re-armed only once this
634
631
  // replacement can accept its normal viewer/daemon traffic. Independent of
635
632
  // the link faults cleared above — those are viewer/relay socket markers,
636
633
  // this is the provider retry episode. An invalidated record is
637
634
  // intentionally inert inside FaultRetry.
638
- const recovery = faultRetry.recoverOnStartup();
635
+ let recovery;
636
+ try {
637
+ recovery = await faultRetry.recoverOnStartup();
638
+ }
639
+ catch (error) {
640
+ emitEvent({ level: 'error', event: 'broker.daemon.operation.failed', node_id: nodeId, error, fields: { operation: 'recovery_startup' } });
641
+ disposeAndExit('recovery-startup-failed', 1);
642
+ return;
643
+ }
639
644
  // A launch prompt delivers only after the listener is accepting, so a
640
645
  // root-spawn readiness proof and prompt admission share one boundary. This
641
646
  // includes the one continuation carried by a clean runtime-abort resume.
@@ -666,13 +671,8 @@ export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), sta
666
671
  // Initialize presence to the truthful zero state at boot — this also
667
672
  // overwrites a stale attach.json a crashed prior incarnation left behind.
668
673
  registry.persistAttachState();
669
- // A daemon fleet bounce gives a busy Pi a short, bounded chance to persist
670
- // its aborted turn before teardown. `session.abort()` resolves only after Pi
671
- // reaches idle (and thus after its message_end persistence); only then may we
672
- // leave the durable clean-abort certificate that preserves the otherwise
673
- // cleared evidence that this broker had a turn in flight. A timeout/rejection
674
- // deliberately leaves no certificate: the surviving busy marker carries the
675
- // same interrupted-turn fact through the fleet's shared SIGKILL deadline.
674
+ // Record teardown-aborted only after Pi persists the aborted turn.
675
+ // Timeout or rejection leaves the SQL interrupted-turn evidence intact.
676
676
  const ABORT_BEFORE_EXIT_MS = 2_500;
677
677
  let signalExitInFlight = false;
678
678
  const abortAndExit = async (reason) => {
@@ -699,7 +699,7 @@ export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), sta
699
699
  new Promise((resolve) => { timer = setTimeout(() => resolve(false), remaining); }),
700
700
  ]);
701
701
  if (settled)
702
- markCleanAbort(nodeId);
702
+ await recordBrokerTurn(nodeId, { event: 'closed', end_reason: 'teardown-aborted' });
703
703
  }
704
704
  finally {
705
705
  if (timer !== undefined)
@@ -711,7 +711,7 @@ export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), sta
711
711
  // The engine never reached an abortable persisted turn in the budget.
712
712
  // Preserve the dirty interrupted-turn witness so recovery resumes the
713
713
  // saved transcript and explicitly re-drives the stopped work.
714
- markBusy(nodeId);
714
+ await recordBrokerTurn(nodeId, { event: 'interrupted' });
715
715
  }
716
716
  }
717
717
  disposeAndExit(reason);
@@ -783,6 +783,12 @@ export function snapshotMessages(session, boundaryReviewId) {
783
783
  // viable at all (tier 3) — this is NOT a fault; the caller decides what to do
784
784
  // with it (construct a model-less session at boot, or leave a running session
785
785
  // alone on a failed re-drive attempt).
786
+ function currentBrokerNodeId() {
787
+ const nodeId = envNodeId();
788
+ if (nodeId === undefined || nodeId === '')
789
+ throw new Error('broker launch is missing CRTR_NODE_ID');
790
+ return nodeId;
791
+ }
786
792
  async function resolveLaunchModel(services, cfg) {
787
793
  const routeRequest = modelRequestFromConfig(cfg.model, envModelIntent(), cfg.modelExact === true);
788
794
  if (routeRequest === undefined)
@@ -794,7 +800,7 @@ async function resolveLaunchModel(services, cfg) {
794
800
  };
795
801
  const unknown = unregisteredConcreteModel(routeRequest, registry, routeOptions);
796
802
  if (unknown !== undefined) {
797
- recordFaultForCurrentNode({ link: 'crtr→pi', op: 'model resolution at launch', kind: 'model-not-found', retry: { disposition: 'fatal' }, message: `model '${unknown.request.spec}' is not registered in the serving model registry` });
803
+ await mutateBrokerFault(currentBrokerNodeId(), { op: 'record', input: { link: 'crtr→pi', op: 'model resolution at launch', kind: 'model-not-found', retry: { disposition: 'fatal' }, message: `model '${unknown.request.spec}' is not registered in the serving model registry` } });
798
804
  throw new Error(`[broker] FATAL: model '${unknown.request.spec}' is not registered in the serving model registry`);
799
805
  }
800
806
  const selection = selectInitialModelRoute(routeRequest, registry, routeOptions);
@@ -807,7 +813,7 @@ async function resolveLaunchModel(services, cfg) {
807
813
  }
808
814
  if (cfg.modelExact === true) {
809
815
  const rejection = selection.rejected.map(({ candidate, reason }) => `'${candidate.providerId}/${candidate.modelId}' ${reason}`).join('; ');
810
- recordFaultForCurrentNode({ link: 'crtr→pi', op: 'model resolution at launch', kind: 'model-not-found', retry: { disposition: 'fatal' }, message: `exact-consult model '${cfg.model}' is unavailable — refusing to substitute (${rejection})` });
816
+ await mutateBrokerFault(currentBrokerNodeId(), { op: 'record', input: { link: 'crtr→pi', op: 'model resolution at launch', kind: 'model-not-found', retry: { disposition: 'fatal' }, message: `exact-consult model '${cfg.model}' is unavailable — refusing to substitute (${rejection})` } });
811
817
  throw new Error(`[broker] FATAL: exact-consult model '${cfg.model}' is unavailable`);
812
818
  }
813
819
  emitEvent({ level: 'warn', event: 'broker.model.none_viable', fields: { rejected_candidates: selection.rejected.slice(0, 16).map(({ candidate, reason }) => ({ provider: candidate.providerId, model: candidate.modelId, reason, route_id: candidate.routeId, credential_source: candidate.credentialSource })), rejected_candidates_omitted: Math.max(0, selection.rejected.length - 16) } });
@@ -1,13 +1,7 @@
1
1
  import { type SubscriptionRef } from '../canvas/index.js';
2
- import { type InboxTier } from '../feed/inbox.js';
3
- /** Fan a lifecycle or birth notice to every given subscriber. Active subscribers
4
- * receive inbox mail; passive subscribers receive passive mail. Shared by
5
- * terminal-outcome paths and externally created children, so callers preserve
6
- * the existing subscription's delivery mode rather than inventing a wake path.
7
- *
8
- * `tier` defaults to a waking `normal`. A caller whose outcome is not worth
9
- * starting a manager's cycle passes `deferred`, which rides the manager's next
10
- * natural cycle instead. */
2
+ import type { InboxTier } from '../feed/inbox.js';
3
+ /** Fan a lifecycle or birth notice to every given subscriber. A passive
4
+ * subscription is a non-waking delivery; active subscriptions wake. */
11
5
  export declare function fanDoctrineWake(fromId: string, subscribers: readonly SubscriptionRef[], label: string, data: Record<string, unknown>, tier?: InboxTier): void;
12
6
  export interface CloseNodeResult {
13
7
  /** The focused node that was closed — the cascade root. */
@@ -32,7 +32,7 @@
32
32
  // inside the closing set. A node still subscribed to by a manager outside the
33
33
  // subtree is left running — "only kill the children if they are only subscribed
34
34
  // to by the agent being closed", generalized to any depth via a fixpoint.
35
- import { cancelCronsOnWake, getNode, subscriptionsOf, subscribersOf, } from '../canvas/index.js';
35
+ import { getNode, subscriptionsOf, subscribersOf, } from '../canvas/index.js';
36
36
  import { transition } from './lifecycle.js';
37
37
  import { requestBrokerTeardown } from './host.js';
38
38
  import { tearDownNode, reapIfEmpty } from './placement.js';
@@ -40,31 +40,20 @@ import { crtrHome, contextDir, jobDir, nodeDir, reportsDir } from '../canvas/pat
40
40
  import { discoverLifecycleHookRegistry } from '../command-hooks/discovery.js';
41
41
  import { invokeLifecycleHooks } from '../command-hooks/transport/exec-lifecycle.js';
42
42
  import { emitEvent } from '../events/emit.js';
43
- import { appendInbox } from '../feed/inbox.js';
44
- import { appendPassive } from '../feed/passive.js';
45
- /** Fan a lifecycle or birth notice to every given subscriber. Active subscribers
46
- * receive inbox mail; passive subscribers receive passive mail. Shared by
47
- * terminal-outcome paths and externally created children, so callers preserve
48
- * the existing subscription's delivery mode rather than inventing a wake path.
49
- *
50
- * `tier` defaults to a waking `normal`. A caller whose outcome is not worth
51
- * starting a manager's cycle passes `deferred`, which rides the manager's next
52
- * natural cycle instead. */
43
+ import { enqueueNodeMail } from '../feed/messages.js';
44
+ /** Fan a lifecycle or birth notice to every given subscriber. A passive
45
+ * subscription is a non-waking delivery; active subscriptions wake. */
53
46
  export function fanDoctrineWake(fromId, subscribers, label, data, tier = 'normal') {
54
47
  for (const sub of subscribers) {
55
48
  try {
56
- const notice = { from: fromId, tier, kind: 'message', label, data };
57
- if (sub.active) {
58
- const entry = appendInbox(sub.node_id, notice);
59
- // A wake-capable notice consumes the subscriber's cancel-on-wake
60
- // deadline: the thing it was waiting for arrived. `deferred` is the
61
- // exception — it never wakes a node, riding the next natural cycle
62
- // instead, so the deadline it was racing must survive.
63
- if (entry.tier !== 'deferred')
64
- cancelCronsOnWake(sub.node_id);
65
- }
66
- else
67
- appendPassive(sub.node_id, notice);
49
+ enqueueNodeMail(sub.node_id, {
50
+ senderNodeId: fromId,
51
+ kind: 'message',
52
+ label,
53
+ bodyJson: data,
54
+ urgency: tier,
55
+ wake: sub.active ? 1 : 0,
56
+ });
68
57
  }
69
58
  catch {
70
59
  /* one unavailable subscriber never blocks the rest */
@@ -246,12 +235,12 @@ export function closeNode(rootId, opts = {}) {
246
235
  // own broker tree before the response can settle.
247
236
  tearDownNode(id);
248
237
  // 3) Leave the resume notice AFTER the watcher is gone, so it survives.
249
- appendInbox(id, {
250
- from: null,
251
- tier: 'normal',
238
+ enqueueNodeMail(id, {
252
239
  kind: 'message',
253
240
  label: cancellationLabel(id === rootId, deadChildren),
254
- data: { reason: 'user-close', cascade_root: rootId, canceled_children: deadChildren },
241
+ bodyJson: { reason: 'user-close', cascade_root: rootId, canceled_children: deadChildren },
242
+ urgency: 'normal',
243
+ wake: 1,
255
244
  });
256
245
  }
257
246
  // 4) Wake any SURVIVING manager subscribed to this node — the doctrine wake.
@@ -1,96 +1,6 @@
1
- import { type Fault, type FaultKind, type FaultLink, type FaultProviderError, type FaultRetry } from '../fault-classifier.js';
2
- export type { Fault, FaultKind, FaultLink, FaultRetry, FaultRetryDisposition, FaultRetryOwner } from '../fault-classifier.js';
1
+ export type { Fault, FaultKind, FaultLink, FaultProviderError, FaultRetry, FaultRetryDisposition, FaultRetryOwner, } from '../fault-classifier.js';
3
2
  export declare const FAULT_QUIET_MS: number;
4
- export interface FaultRecordInput {
5
- link: FaultLink;
6
- op: string;
7
- kind: FaultKind;
8
- retry: FaultRetry;
9
- message: string;
10
- operation_id?: string;
11
- since?: string;
12
- anchorEntryId?: string;
13
- providerError?: FaultProviderError;
14
- }
15
- /** A provider-retry episode outlives its broker-local timer. Its transcript
16
- * path and anchor are explicit coordinates, so replacement invalidation never
17
- * has to guess which conversation a marker belongs to. */
18
- export interface ProviderRetryEpisode {
19
- state: 'pending' | 'admitted' | 'invalidated';
20
- sessionFile: string;
21
- anchorEntryId: string | null;
22
- fault: Fault;
23
- }
24
- export declare function recordFault(nodeId: string, input: FaultRecordInput): void;
25
- /** Atomically establishes the crash-recovery authority before publishing its
26
- * ordinary marker, so a broker death can never leave only a retryable fault. */
27
- export declare function recordPendingProviderRetryFault(nodeId: string, sessionFile: string, input: FaultRecordInput): Fault | null;
28
- export declare function recordFaultForCurrentNode(input: FaultRecordInput): boolean;
29
- export declare function clearFault(nodeId: string, opts?: {
30
- link?: FaultLink;
31
- preserveProviderRetryEpisode?: boolean;
32
- }): boolean;
33
- export declare function clearFaultForCurrentNode(opts?: {
34
- link?: FaultLink;
35
- }): boolean;
36
- export declare function readFault(nodeId: string): Fault | null;
37
- export declare function readProviderRetryEpisode(nodeId: string): ProviderRetryEpisode | null;
38
- /** Persist a newly scheduled provider retry before its broker-local timer is armed. */
39
- export declare function recordPendingProviderRetryEpisode(nodeId: string, episode: Omit<ProviderRetryEpisode, 'state'>): boolean;
40
- /** Admission is irreversible EXCEPT through a proven no-progress rollback: a
41
- * broker startup that finds no assistant content or tool activity past the
42
- * episode's anchor may reopen it via `reopenProviderRetryEpisode` below. Short
43
- * of that proof, an admitted episode is never replayed. */
44
- export declare function admitProviderRetryEpisode(nodeId: string, sessionFile: string, fault: Fault): boolean;
45
- /** Reopens an `admitted` episode to `pending` so a surviving broker startup can
46
- * re-drive it exactly like a never-admitted one. Callable only under the same
47
- * no-progress proof `recoverOnStartup` establishes — the branch segment from
48
- * `anchorEntryId` to the current leaf carries no assistant content and no tool
49
- * activity. Guarded by the same transcript-identity coordinate `admitProviderRetryEpisode`
50
- * uses, so a foreign or already-invalidated episode is never reopened. */
51
- export declare function reopenProviderRetryEpisode(nodeId: string, sessionFile: string): boolean;
52
- /** A replacement explicitly invalidates its old transcript's retry episode. */
53
- export declare function invalidateProviderRetryEpisode(nodeId: string, sessionFile: string): boolean;
54
- export declare function clearProviderRetryEpisode(nodeId: string): void;
55
- export declare function readFaultAsync(nodeId: string): Promise<Fault | null>;
56
- export interface BootFaultAttempt {
57
- /** The recorded fault's operation + message (e.g. an unresolvable `--model`
58
- * spec, or a model that disappeared mid-launch), scoped to THIS attempt, or
59
- * null when none applies. A broker that fatal-crashes before it binds its
60
- * view socket leaves the launching caller with only the opaque "socket
61
- * never bound" symptom; callers append this so the real cause surfaces
62
- * instead. Only a `crtr→pi` fatal launch fault with a non-empty op and
63
- * message qualifies — never a stale marker from an earlier attempt (see
64
- * `beginBootFaultAttempt`) and never an unrelated fault kind (e.g. a
65
- * viewer↔broker connect failure racing the same boot). */
66
- explanation(): string | null;
67
- }
68
- /** Snapshot fault state immediately before a broker launch begins, returning a
69
- * reader that is only trustworthy for a fault recorded by THIS attempt.
70
- *
71
- * `clearFault` can silently fail to remove a prior marker (its own removal
72
- * errors are swallowed, and its result goes unchecked by callers), so rather
73
- * than assume that call succeeded, this independently CONFIRMS no fault is
74
- * present at the moment of launch. Other processes (a viewer, a relay) can
75
- * still write THEIR OWN fault links after this snapshot, but `explanation()`
76
- * only ever accepts a fatal `crtr→pi` launch fault — the one shape only a
77
- * newly launched broker itself writes (`resolveLaunchModel` in `broker.ts`) —
78
- * so no ACCEPTED fault can exist before this snapshot without also surviving
79
- * a failed clear, which the snapshot already catches. When a stale fault
80
- * survives the clear, `explanation()` fails closed (returns null) rather than
81
- * risk surfacing an old, unrelated cause as if it were fresh.
82
- *
83
- * Call this the instant before the launch call it is guarding, so the window
84
- * in which an unrelated write could occur stays as small as possible. */
85
- export declare function beginBootFaultAttempt(nodeId: string): BootFaultAttempt;
86
- /** True when a raw engine error says pi could not resolve a credential for the model's
87
- * provider at all. pi raises `Provider is not configured: <id>` whenever auth resolution
88
- * yields nothing, and `Credential store read/modify failed for <id>` when the store itself
89
- * errored — for crouter's managed providers both mean "the pool did not hand over a usable
90
- * credential just now", which is frequently transient (a refresh in flight, a momentary read
91
- * failure) and never something the agent can fix from inside its own turn. Classified as a
92
- * plain `other` fault it is FATAL, so the node parks and every wake re-fails on the same
93
- * provider; the broker instead substitutes an authenticated provider and re-drives. */
3
+ /** True when Pi could not resolve credentials for a provider. */
94
4
  export declare function isProviderUnconfiguredError(message: string): boolean;
95
- /** True when a raw engine error is the provider 404 "model missing" signal. */
5
+ /** True when a provider reports that a requested model is unavailable. */
96
6
  export declare function isModelNotFoundError(message: string): boolean;