@north-light/crouter 0.3.232 → 0.3.234

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 (392) hide show
  1. package/dist/api/client.js +16 -15
  2. package/dist/builtin-memory/internal/memory-loading.md +4 -3
  3. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/integration/provider-rotation.test.ts +1 -1
  4. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/claude-plugin-commands.ts +14 -17
  5. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/crtr-commands/index.ts +7 -11
  6. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/frontmatter-rules/index.ts +8 -8
  7. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +10 -11
  8. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/pi-shell-runner.ts +2 -2
  9. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +3 -3
  10. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +7 -7
  11. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +8 -8
  12. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/statusline.ts +6 -6
  13. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/sysprompt-window.ts +3 -3
  14. package/dist/builtin-pi-packages/pi-crtr-extensions/lib/subscription-state.ts +1 -1
  15. package/dist/clients/attach/chrome/ticket-panel.js +15 -2
  16. package/dist/clients/attach/overlays/graph.js +0 -3
  17. package/dist/clients/attach/overlays/mcp.js +1 -2
  18. package/dist/clients/attach/render/chat-view.js +0 -12
  19. package/dist/clients/attach/render/crtr-output.js +0 -2
  20. package/dist/clients/attach/render/tool-calls.js +0 -6
  21. package/dist/clients/attach/slash/dispatch.js +8 -11
  22. package/dist/clients/attach/viewer.js +532 -534
  23. package/dist/clients/conversation/projection.js +0 -2
  24. package/dist/clients/inbox/controller.js +22 -3
  25. package/dist/clients/inbox/review/companion-pane.js +0 -4
  26. package/dist/clients/inbox/review-adapter.js +0 -7
  27. package/dist/clients/inbox/tui/slots.d.ts +3 -3
  28. package/dist/clients/inbox/tui/types.d.ts +2 -2
  29. package/dist/commands/api-client.js +0 -8
  30. package/dist/commands/attention.js +0 -8
  31. package/dist/commands/canvas-browse.js +2 -1
  32. package/dist/commands/canvas-config.js +0 -10
  33. package/dist/commands/canvas-history.js +2 -1
  34. package/dist/commands/cron.js +5 -18
  35. package/dist/commands/dashboard.js +0 -2
  36. package/dist/commands/human/feedback.js +2 -1
  37. package/dist/commands/human/prompts.js +2 -5
  38. package/dist/commands/human/queue.js +2 -7
  39. package/dist/commands/human/request.js +0 -14
  40. package/dist/commands/human/review.js +2 -1
  41. package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +4 -4
  42. package/dist/commands/memory/find.js +2 -2
  43. package/dist/commands/memory/lint.js +2 -1
  44. package/dist/commands/memory/read.d.ts +2 -7
  45. package/dist/commands/memory/read.js +5 -16
  46. package/dist/commands/memory/shared.d.ts +1 -1
  47. package/dist/commands/memory/shared.js +7 -10
  48. package/dist/commands/memory/write.js +4 -3
  49. package/dist/commands/node/bash.js +2 -1
  50. package/dist/commands/node/create.js +2 -1
  51. package/dist/commands/node/inspect.js +0 -6
  52. package/dist/commands/node/lifecycle.js +4 -13
  53. package/dist/commands/node/message.js +3 -2
  54. package/dist/commands/node/subscription.js +2 -1
  55. package/dist/commands/node/wait.js +4 -3
  56. package/dist/commands/node-context.js +2 -1
  57. package/dist/commands/node-lifecycle-revive.js +0 -2
  58. package/dist/commands/node-worktree.js +2 -1
  59. package/dist/commands/pkg/browse/actions.d.ts +1 -1
  60. package/dist/commands/pkg/browse/actions.js +4 -4
  61. package/dist/commands/pkg/browse/catalog.d.ts +1 -1
  62. package/dist/commands/pkg/browse/catalog.js +15 -15
  63. package/dist/commands/pkg/browse/command-view.d.ts +1 -1
  64. package/dist/commands/pkg/browse/command-view.js +3 -3
  65. package/dist/commands/pkg/browse/detail-panel.d.ts +1 -1
  66. package/dist/commands/pkg/browse/detail-panel.js +8 -8
  67. package/dist/commands/pkg/browse/doc-view.d.ts +1 -1
  68. package/dist/commands/pkg/browse/doc-view.js +3 -3
  69. package/dist/commands/pkg/browse/list-panel.d.ts +1 -1
  70. package/dist/commands/pkg/browse/list-panel.js +3 -3
  71. package/dist/commands/pkg/browse/model.d.ts +3 -3
  72. package/dist/commands/pkg/browse/shell.d.ts +2 -2
  73. package/dist/commands/pkg/browse/shell.js +13 -13
  74. package/dist/commands/pkg/plugin-manage.js +2 -1
  75. package/dist/commands/pkg/shared.js +0 -2
  76. package/dist/commands/profile/delete.js +2 -1
  77. package/dist/commands/push.js +2 -3
  78. package/dist/commands/revive.js +0 -2
  79. package/dist/commands/surface/node/placement.js +2 -1
  80. package/dist/commands/surface-edit.js +2 -1
  81. package/dist/commands/sys/config.js +0 -4
  82. package/dist/commands/sys/daemon.js +0 -10
  83. package/dist/commands/sys/doctor.js +3 -2
  84. package/dist/commands/sys/panels/broker-limits-panel.d.ts +2 -2
  85. package/dist/commands/sys/panels/broker-limits-panel.js +4 -4
  86. package/dist/commands/sys/panels/dependencies-panel.d.ts +2 -2
  87. package/dist/commands/sys/panels/dependencies-panel.js +2 -2
  88. package/dist/commands/sys/panels/keybindings-panel.d.ts +1 -1
  89. package/dist/commands/sys/panels/keybindings-panel.js +5 -5
  90. package/dist/commands/sys/panels/models-panel.d.ts +4 -4
  91. package/dist/commands/sys/panels/models-panel.js +11 -10
  92. package/dist/commands/sys/panels/plugins-panel.d.ts +2 -2
  93. package/dist/commands/sys/panels/plugins-panel.js +2 -2
  94. package/dist/commands/sys/panels/prefs-panel.d.ts +2 -2
  95. package/dist/commands/sys/panels/prefs-panel.js +4 -4
  96. package/dist/commands/sys/panels/profiles-panel.d.ts +1 -1
  97. package/dist/commands/sys/panels/profiles-panel.js +14 -13
  98. package/dist/commands/sys/panels/provider-panel.d.ts +3 -3
  99. package/dist/commands/sys/panels/provider-panel.js +8 -8
  100. package/dist/commands/sys/settings-shell.d.ts +3 -3
  101. package/dist/commands/sys/settings-shell.js +15 -15
  102. package/dist/commands/sys/setup-settings-runner.d.ts +3 -3
  103. package/dist/commands/sys/setup-settings-runner.js +5 -5
  104. package/dist/commands/sys/setup-wizard.d.ts +4 -4
  105. package/dist/commands/sys/setup-wizard.js +8 -8
  106. package/dist/commands/sys/support/prepare.js +4 -4
  107. package/dist/commands/sys/support/submit.js +2 -2
  108. package/dist/commands/sys/sync-deps.js +0 -2
  109. package/dist/commands/sys/sync-project-guidance.js +2 -1
  110. package/dist/commands/sys/sysprompt.js +2 -1
  111. package/dist/core/__tests__/boot.test.js +0 -8
  112. package/dist/core/__tests__/broker-extension-canvas-db-boundary.test.js +23 -1
  113. package/dist/core/__tests__/canvas-db-boundary.test.d.ts +1 -0
  114. package/dist/core/__tests__/canvas-db-boundary.test.js +46 -0
  115. package/dist/core/__tests__/canvas.test.js +1 -1
  116. package/dist/core/__tests__/child-death-wake.test.js +0 -2
  117. package/dist/core/__tests__/cron-armed-context-failure.test.d.ts +1 -0
  118. package/dist/core/__tests__/cron-armed-context-failure.test.js +145 -0
  119. package/dist/core/__tests__/daemon-wedge.test.js +0 -4
  120. package/dist/core/__tests__/dead-node-policy-table.test.js +0 -4
  121. package/dist/core/__tests__/fixtures/fake-engine.js +4 -14
  122. package/dist/core/__tests__/fixtures/fake-pi-host.js +5 -5
  123. package/dist/core/__tests__/focuses.test.js +0 -6
  124. package/dist/core/__tests__/fs-utils.test.d.ts +1 -0
  125. package/dist/core/__tests__/fs-utils.test.js +50 -0
  126. package/dist/core/__tests__/helpers/harness.js +1 -1
  127. package/dist/core/__tests__/inline-memory-refs.test.js +0 -2
  128. package/dist/core/__tests__/integration/broker-fork-seam.test.js +0 -2
  129. package/dist/core/__tests__/integration/broker-sdk-wiring.test.js +3 -16
  130. package/dist/core/__tests__/integration/command-plugins.test.js +0 -24
  131. package/dist/core/__tests__/integration/deferred-no-wake.test.js +0 -6
  132. package/dist/core/__tests__/integration/flagship-lifecycle.test.js +0 -26
  133. package/dist/core/__tests__/integration/live-mutation-verbs.test.js +0 -4
  134. package/dist/core/__tests__/integration/live-mutation.test.js +1 -5
  135. package/dist/core/__tests__/integration/refresh-stall-recycle.test.js +1 -5
  136. package/dist/core/__tests__/integration/revive.test.js +0 -12
  137. package/dist/core/__tests__/integration/subscription-delivery.test.js +0 -6
  138. package/dist/core/__tests__/integration/tmux-surface.test.js +24 -8
  139. package/dist/core/__tests__/integration/worktree-reap.test.js +0 -6
  140. package/dist/core/__tests__/lifecycle.test.js +0 -18
  141. package/dist/core/__tests__/memory-resolver-precedence.test.js +1 -1
  142. package/dist/core/__tests__/migration.test.js +2 -2
  143. package/dist/core/__tests__/on-read-dedup-resume.test.js +3 -3
  144. package/dist/core/__tests__/pid-identity-match.test.js +1 -1
  145. package/dist/core/__tests__/plugin-kinds.test.js +1 -1
  146. package/dist/core/__tests__/plugin-page-components.test.js +1 -1
  147. package/dist/core/__tests__/preview-registry-sync.test.js +42 -1
  148. package/dist/core/__tests__/respawn-throttle.test.js +0 -4
  149. package/dist/core/__tests__/revive-all.test.js +5 -5
  150. package/dist/core/__tests__/revive-parked-fresh.test.js +62 -11
  151. package/dist/core/__tests__/seam/broker-attach-multiclient.test.js +0 -8
  152. package/dist/core/__tests__/seam/broker-attach-stream.test.js +0 -8
  153. package/dist/core/__tests__/seam/broker-crash-teardown.test.js +0 -2
  154. package/dist/core/__tests__/tmux-driver-boundary.test.d.ts +1 -0
  155. package/dist/core/__tests__/tmux-driver-boundary.test.js +50 -0
  156. package/dist/core/activity-signal.d.ts +7 -0
  157. package/dist/core/activity-signal.js +38 -0
  158. package/dist/core/auto-update.js +2 -1
  159. package/dist/core/bootstrap.js +2 -1
  160. package/dist/core/canvas/__tests__/remote-canvas-source.test.js +1 -1
  161. package/dist/core/canvas/__tests__/remote-transport.test.js +1 -1
  162. package/dist/core/canvas/__tests__/render-remote.test.js +1 -1
  163. package/dist/core/canvas/browse/app.js +3 -2
  164. package/dist/core/canvas/browse/model.d.ts +1 -1
  165. package/dist/core/canvas/browse/model.js +0 -4
  166. package/dist/core/canvas/canvas.d.ts +22 -0
  167. package/dist/core/canvas/canvas.js +50 -18
  168. package/dist/core/canvas/crons.js +0 -6
  169. package/dist/core/canvas/db.d.ts +14 -20
  170. package/dist/core/canvas/db.js +30 -1332
  171. package/dist/core/canvas/focuses.js +0 -4
  172. package/dist/core/canvas/history.js +2 -1
  173. package/dist/core/canvas/migrations.d.ts +20 -0
  174. package/dist/core/canvas/migrations.js +1339 -0
  175. package/dist/core/canvas/nav-model.js +1 -11
  176. package/dist/core/canvas/nav-render.js +0 -8
  177. package/dist/core/canvas/remote-canvas-source.js +0 -2
  178. package/dist/core/canvas/render-source.js +31 -13
  179. package/dist/core/command-manifests/manifest.js +0 -10
  180. package/dist/core/command-manifests/schema.js +0 -4
  181. package/dist/core/command-plugins/transport/http-invoke.js +0 -14
  182. package/dist/core/command.js +0 -4
  183. package/dist/core/config.js +2 -1
  184. package/dist/core/feed/inbox.d.ts +10 -0
  185. package/dist/core/feed/inbox.js +18 -12
  186. package/dist/core/fs-utils.d.ts +9 -2
  187. package/dist/core/fs-utils.js +7 -15
  188. package/dist/core/help.js +0 -8
  189. package/dist/core/host-exports/export.d.ts +2 -2
  190. package/dist/core/host-exports/export.js +9 -12
  191. package/dist/core/human/answer.d.ts +2 -2
  192. package/dist/core/human/convention.d.ts +2 -5
  193. package/dist/core/human/convention.js +3 -13
  194. package/dist/core/human/page-schema.d.ts +2 -2
  195. package/dist/core/human/page-schema.js +2 -2
  196. package/dist/core/human/root.js +6 -23
  197. package/dist/core/human/scan.js +24 -7
  198. package/dist/core/human/tickets.d.ts +4 -1
  199. package/dist/core/human/tickets.js +20 -6
  200. package/dist/core/io.js +0 -12
  201. package/dist/core/memory/identity.js +0 -4
  202. package/dist/core/memory/inline-ref-inventory.js +3 -2
  203. package/dist/core/memory/lint.js +3 -6
  204. package/dist/core/memory-resolver.d.ts +5 -0
  205. package/dist/core/memory-resolver.js +14 -12
  206. package/dist/core/pagination.js +0 -2
  207. package/dist/core/preview-registry.d.ts +14 -0
  208. package/dist/core/preview-registry.js +2 -4
  209. package/dist/core/preview-result-path.js +2 -1
  210. package/dist/core/profiles/manifest.d.ts +37 -5
  211. package/dist/core/profiles/manifest.js +44 -24
  212. package/dist/core/profiles/select.js +0 -4
  213. package/dist/core/review/signal.js +4 -23
  214. package/dist/core/review/ticket-filter.d.ts +3 -3
  215. package/dist/core/review/ticket-filter.js +4 -9
  216. package/dist/core/runtime/__tests__/engine-route.test.js +1 -1
  217. package/dist/core/runtime/__tests__/spawn-env.test.js +0 -8
  218. package/dist/core/runtime/bearings-render.d.ts +56 -0
  219. package/dist/core/runtime/bearings-render.js +241 -0
  220. package/dist/core/runtime/bearings.d.ts +2 -17
  221. package/dist/core/runtime/bearings.js +12 -198
  222. package/dist/core/runtime/broker/auth-reload.d.ts +39 -0
  223. package/dist/core/runtime/broker/auth-reload.js +149 -0
  224. package/dist/core/runtime/broker/engine-drive.d.ts +26 -0
  225. package/dist/core/runtime/broker/engine-drive.js +257 -0
  226. package/dist/core/runtime/broker/engine-routing.d.ts +143 -0
  227. package/dist/core/runtime/broker/engine-routing.js +211 -0
  228. package/dist/core/runtime/broker/event-projection.js +3 -2
  229. package/dist/core/runtime/broker/fault-retry.js +5 -4
  230. package/dist/core/runtime/broker/frame-client.d.ts +38 -0
  231. package/dist/core/runtime/broker/frame-client.js +129 -0
  232. package/dist/core/runtime/broker/frame-dispatch.d.ts +12 -189
  233. package/dist/core/runtime/broker/frame-dispatch.js +89 -1476
  234. package/dist/core/runtime/broker/frame-engine-control.d.ts +20 -0
  235. package/dist/core/runtime/broker/frame-engine-control.js +231 -0
  236. package/dist/core/runtime/broker/frame-memory-refs.d.ts +19 -0
  237. package/dist/core/runtime/broker/frame-memory-refs.js +41 -0
  238. package/dist/core/runtime/broker/frame-model-query.d.ts +13 -0
  239. package/dist/core/runtime/broker/frame-model-query.js +69 -0
  240. package/dist/core/runtime/broker/frame-read.d.ts +19 -0
  241. package/dist/core/runtime/broker/frame-read.js +116 -0
  242. package/dist/core/runtime/broker/frame-replies.d.ts +24 -0
  243. package/dist/core/runtime/broker/frame-replies.js +64 -0
  244. package/dist/core/runtime/broker/frame-session.d.ts +34 -0
  245. package/dist/core/runtime/broker/frame-session.js +203 -0
  246. package/dist/core/runtime/broker/turn-ignition.d.ts +42 -0
  247. package/dist/core/runtime/broker/turn-ignition.js +74 -0
  248. package/dist/core/runtime/broker-extension-render.js +9 -85
  249. package/dist/core/runtime/broker-protocol.js +0 -4
  250. package/dist/core/runtime/broker-sdk.js +2 -1
  251. package/dist/core/runtime/broker.d.ts +1 -1
  252. package/dist/core/runtime/broker.js +5 -23
  253. package/dist/core/runtime/fault.js +3 -2
  254. package/dist/core/runtime/headless-pi.js +3 -2
  255. package/dist/core/runtime/host.js +2 -3
  256. package/dist/core/runtime/kickoff.js +0 -4
  257. package/dist/core/runtime/launch-target.js +2 -1
  258. package/dist/core/runtime/launch.js +3 -6
  259. package/dist/core/runtime/lifecycle.js +17 -26
  260. package/dist/core/runtime/managed-provider-cooling.d.ts +1 -1
  261. package/dist/core/runtime/naming.js +0 -2
  262. package/dist/core/runtime/nodes.js +2 -1
  263. package/dist/core/runtime/persona.js +0 -6
  264. package/dist/core/runtime/placement-tmux.js +2 -5
  265. package/dist/core/runtime/placement.js +4 -11
  266. package/dist/core/runtime/recap.js +4 -3
  267. package/dist/core/runtime/reopen.js +4 -7
  268. package/dist/core/runtime/reset.js +0 -4
  269. package/dist/core/runtime/resume-root.js +0 -2
  270. package/dist/core/runtime/revive.js +17 -13
  271. package/dist/core/runtime/session-list-cache.js +2 -2
  272. package/dist/core/runtime/shell-expansion.js +0 -2
  273. package/dist/core/runtime/spawn.js +0 -2
  274. package/dist/core/runtime/stream-watchdog.d.ts +0 -1
  275. package/dist/core/runtime/stream-watchdog.js +13 -18
  276. package/dist/core/runtime/tmux-bindings.js +0 -2
  277. package/dist/core/runtime/tmux-driver.d.ts +12 -0
  278. package/dist/core/runtime/tmux-driver.js +18 -13
  279. package/dist/core/runtime/warm-pool.js +0 -4
  280. package/dist/core/scope.js +4 -3
  281. package/dist/core/spawn.js +2 -3
  282. package/dist/core/subscription-state.js +10 -17
  283. package/dist/core/substrate/__tests__/surface-match-pre-command.test.d.ts +1 -0
  284. package/dist/core/substrate/__tests__/surface-match-pre-command.test.js +92 -0
  285. package/dist/core/substrate/frontmatter-validation.js +1 -1
  286. package/dist/core/substrate/injected-store.d.ts +6 -0
  287. package/dist/core/substrate/injected-store.js +24 -0
  288. package/dist/core/substrate/on-read.d.ts +17 -1
  289. package/dist/core/substrate/on-read.js +36 -2
  290. package/dist/core/substrate/render.js +0 -12
  291. package/dist/core/substrate/schema.d.ts +3 -3
  292. package/dist/core/substrate/schema.js +4 -16
  293. package/dist/core/substrate/surface-match.d.ts +19 -0
  294. package/dist/core/substrate/surface-match.js +60 -2
  295. package/dist/core/termrender/display.js +2 -1
  296. package/dist/core/tui/page-host.d.ts +3 -3
  297. package/dist/core/tui/page-host.js +4 -4
  298. package/dist/core/tui/panel.js +3 -3
  299. package/dist/core/wake.js +0 -12
  300. package/dist/core/worktree.js +0 -2
  301. package/dist/daemon/__tests__/reconciler-signature.test.d.ts +1 -0
  302. package/dist/daemon/__tests__/reconciler-signature.test.js +36 -0
  303. package/dist/daemon/api/__tests__/seam/api-server.test.js +2 -16
  304. package/dist/daemon/api/__tests__/seam/b10-attach-modelauth.test.js +3 -11
  305. package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +0 -6
  306. package/dist/daemon/api/handlers/attach.js +2 -1
  307. package/dist/daemon/api/handlers/broker-ops.js +3 -6
  308. package/dist/daemon/api/handlers/canvas.js +12 -18
  309. package/dist/daemon/api/handlers/feedback-comments.js +0 -8
  310. package/dist/daemon/api/handlers/health.js +3 -2
  311. package/dist/daemon/api/handlers/human-requests.js +0 -10
  312. package/dist/daemon/api/handlers/human.js +1 -5
  313. package/dist/daemon/api/handlers/inbox.js +0 -18
  314. package/dist/daemon/api/handlers/memory.js +1 -1
  315. package/dist/daemon/api/handlers/messages.js +4 -8
  316. package/dist/daemon/api/handlers/nodes.js +10 -21
  317. package/dist/daemon/api/handlers/reports.js +1 -1
  318. package/dist/daemon/api/handlers/reviews.js +1 -6
  319. package/dist/daemon/api/map.js +0 -6
  320. package/dist/daemon/api/router.js +0 -4
  321. package/dist/daemon/api/server.js +2 -5
  322. package/dist/daemon/boot-migrations.d.ts +14 -0
  323. package/dist/daemon/boot-migrations.js +31 -0
  324. package/dist/daemon/cron/armed-context.d.ts +21 -0
  325. package/dist/daemon/cron/armed-context.js +100 -0
  326. package/dist/daemon/cron/capture.d.ts +20 -0
  327. package/dist/daemon/cron/capture.js +45 -0
  328. package/dist/daemon/cron/disposition.d.ts +19 -0
  329. package/dist/daemon/cron/disposition.js +52 -0
  330. package/dist/daemon/cron/escalation.d.ts +12 -0
  331. package/dist/daemon/cron/escalation.js +124 -0
  332. package/dist/daemon/cron/held.d.ts +4 -0
  333. package/dist/daemon/cron/held.js +20 -0
  334. package/dist/daemon/cron/lease-recovery.d.ts +3 -0
  335. package/dist/daemon/cron/lease-recovery.js +119 -0
  336. package/dist/daemon/cron/live-runs.d.ts +11 -0
  337. package/dist/daemon/cron/live-runs.js +23 -0
  338. package/dist/daemon/cron/passes.d.ts +11 -0
  339. package/dist/daemon/cron/passes.js +78 -0
  340. package/dist/daemon/cron/settle.d.ts +28 -0
  341. package/dist/daemon/cron/settle.js +37 -0
  342. package/dist/daemon/cron/sinks.d.ts +2 -0
  343. package/dist/daemon/cron/sinks.js +100 -0
  344. package/dist/daemon/cron-run.d.ts +5 -41
  345. package/dist/daemon/cron-run.js +193 -882
  346. package/dist/daemon/crtrd-cli.js +2 -1
  347. package/dist/daemon/crtrd.js +22 -22
  348. package/dist/daemon/fleet.js +0 -4
  349. package/dist/daemon/human/deliver-action.js +2 -1
  350. package/dist/daemon/human/sweep.js +15 -4
  351. package/dist/daemon/manage.d.ts +2 -2
  352. package/dist/daemon/manage.js +4 -13
  353. package/dist/daemon/pidfile.js +2 -2
  354. package/dist/daemon/reconcilers/broker-supervision.js +26 -29
  355. package/dist/daemon/reconcilers/dormant-inbox.d.ts +1 -1
  356. package/dist/daemon/reconcilers/dormant-inbox.js +2 -1
  357. package/dist/daemon/reconcilers/live-obligation.js +2 -2
  358. package/dist/daemon/reconcilers/pending-review-submit.d.ts +1 -1
  359. package/dist/daemon/reconcilers/pending-review-submit.js +2 -1
  360. package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -1
  361. package/dist/daemon/reconcilers/storage-maintenance.js +2 -1
  362. package/dist/daemon/review/companion.js +2 -2
  363. package/dist/daemon/review/sweep.js +8 -3
  364. package/dist/migrations/001-surfaces-frontmatter.js +0 -6
  365. package/dist/migrations/corpus.js +2 -5
  366. package/dist/migrations/registry.js +15 -2
  367. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +0 -4
  368. package/dist/pi-extensions/__tests__/pre-command-gate.test.d.ts +1 -0
  369. package/dist/pi-extensions/__tests__/pre-command-gate.test.js +220 -0
  370. package/dist/pi-extensions/broker-local.js +2 -1
  371. package/dist/pi-extensions/canvas-bash-valve.js +3 -17
  372. package/dist/pi-extensions/canvas-context-intro.js +2 -7
  373. package/dist/pi-extensions/canvas-doc-substrate.d.ts +14 -0
  374. package/dist/pi-extensions/canvas-doc-substrate.js +77 -5
  375. package/dist/pi-extensions/canvas-goal-capture.js +2 -1
  376. package/dist/pi-extensions/canvas-inbox-watcher.js +5 -12
  377. package/dist/pi-extensions/canvas-passive-context.js +2 -5
  378. package/dist/pi-extensions/canvas-preview-result.js +2 -1
  379. package/dist/pi-extensions/canvas-prompt-scrub.js +2 -1
  380. package/dist/pi-extensions/canvas-recap.js +3 -16
  381. package/dist/pi-extensions/canvas-review-boundary.js +2 -5
  382. package/dist/pi-extensions/canvas-stophook.js +2 -26
  383. package/dist/pi-extensions/canvas-structured-output.js +2 -1
  384. package/dist/pi-extensions/canvas-tool-guide.js +2 -1
  385. package/dist/shared/__tests__/env-boundary.test.d.ts +1 -0
  386. package/dist/shared/__tests__/env-boundary.test.js +93 -0
  387. package/dist/shared/env.d.ts +68 -0
  388. package/dist/shared/env.js +171 -0
  389. package/package.json +3 -1
  390. package/runtime.lock.json +2 -2
  391. package/dist/core/canvas/render.d.ts +0 -47
  392. package/dist/core/canvas/render.js +0 -245
@@ -11,13 +11,15 @@
11
11
  // the sanctioned place for it.
12
12
  import { existsSync, readdirSync } from 'node:fs';
13
13
  import { join } from 'node:path';
14
- import { listNodes, nowIso, ticketsAcrossCanvas } from '../../../index.js';
15
- import { getNode, pruneNodes, pruneToLimit, rebuildIndex, rosterEdges, rosterNodes, subscriptionsOf } from '../../../core/canvas/canvas.js';
14
+ import { getNode, listNodes, pruneNodes, pruneToLimit, rebuildIndex, rosterEdges, rosterNodes, subscriptionsOf } from '../../../core/canvas/canvas.js';
16
15
  import { activeBackgroundBashJobs } from '../../../core/bash-jobs.js';
17
16
  import { contextDir } from '../../../core/canvas/paths.js';
17
+ import { nowIso } from '../../../core/fs-utils.js';
18
18
  import { isBrokerLive } from '../../../core/runtime/model-swap.js';
19
- import { dashboardRowsAll, enrichRows } from '../../../core/canvas/render.js';
20
- import { ticketCountsForNodes } from '../../../core/canvas/attention.js';
19
+ import { dashboardRowsAllFromSource, enrichRowsFromSource } from '../../../core/canvas/render-source.js';
20
+ import { localCanvasSource } from '../../../core/canvas/source.js';
21
+ import { listFocuses } from '../../../core/canvas/focuses.js';
22
+ import { ticketCountsForNodes, ticketsAcrossCanvas } from '../../../core/canvas/attention.js';
21
23
  import { buildCorpus, resolveRef, } from '../../../core/canvas/history.js';
22
24
  import { nodeDir, nodesRoot } from '../../../core/canvas/paths.js';
23
25
  import { reapEmptyNodes } from '../../../core/runtime/placement.js';
@@ -49,7 +51,6 @@ function handleAttentionCounts(ctx) {
49
51
  const body = { counts: ticketCountsForNodes(rawIds) };
50
52
  return { status: 200, body };
51
53
  }
52
- // ---------------------------------------------------------------------------
53
54
  // history search / grep / read \u2014 the ranked corpus search, the required-
54
55
  // pattern line-hit search, and ref resolution. Lifted verbatim from
55
56
  // `commands/canvas-history/{search,grep,read}.ts`' run() bodies: the pure
@@ -57,7 +58,6 @@ function handleAttentionCounts(ctx) {
57
58
  // now parses+validates flags and POSTs the normalized query). search and grep
58
59
  // share the corpus builder and cursor helpers but are distinct wire contracts
59
60
  // \u2014 no `--grep` flag survives on the search query.
60
- // ---------------------------------------------------------------------------
61
61
  function encodeCursor(offset) {
62
62
  return Buffer.from(String(offset), 'utf8').toString('base64');
63
63
  }
@@ -168,7 +168,7 @@ function handleHistorySearch(ctx) {
168
168
  const limit = Math.min(100, Math.max(1, q.limit ?? 20));
169
169
  const arts = buildCorpusFromQuery(q);
170
170
  const offset = q.cursor !== undefined ? decodeCursor(q.cursor) : 0;
171
- // --- ranked / browse mode ---
171
+ // ranked / browse mode
172
172
  const terms = query.toLowerCase().split(/\s+/).filter((t) => t.length > 0);
173
173
  let pool = arts;
174
174
  let scored;
@@ -264,13 +264,13 @@ function handleHistoryRead(ctx) {
264
264
  };
265
265
  return { status: 200, body };
266
266
  }
267
- // ---------------------------------------------------------------------------
268
267
  // snapshot \u2014 the enriched browser canvas roster + subscribes_to adjacency.
269
268
  // Lifted from `commands/canvas-snapshot.ts` run() (dashboardRowsAll + enrichRows).
270
- // ---------------------------------------------------------------------------
271
- function handleSnapshot() {
272
- const rows = dashboardRowsAll();
273
- enrichRows(rows);
269
+ async function handleSnapshot() {
270
+ const focusedNodeIds = new Set(listFocuses().map((f) => f.node_id));
271
+ const rows = await dashboardRowsAllFromSource(localCanvasSource, focusedNodeIds);
272
+ const asks = ticketCountsForNodes(rows.map((r) => r.node_id));
273
+ await enrichRowsFromSource(localCanvasSource, rows, asks);
274
274
  const nodes = rows.map((row) => {
275
275
  const meta = getNode(row.node_id);
276
276
  const hostKind = meta?.host_kind ?? 'tmux';
@@ -308,13 +308,11 @@ function handleSnapshot() {
308
308
  const body = { generated_at: nowIso(), nodes, subscriptions };
309
309
  return { status: 200, body };
310
310
  }
311
- // ---------------------------------------------------------------------------
312
311
  // roster - the lean, set-based topology read (daemon-starvation fix step 2).
313
312
  // Exactly two indexed queries (rosterNodes() + rosterEdges()), no enrichRows,
314
313
  // no per-row getNode/subscriptionsOf loop, no isStreaming/isPidAlive process
315
314
  // probe. Single-flighted below so a burst of concurrent pollers (attach +
316
315
  // browser, or several attach viewers) shares one DB pass instead of stacking N.
317
- // ---------------------------------------------------------------------------
318
316
  function buildRoster() {
319
317
  const nodes = rosterNodes().map((row) => {
320
318
  const hostKind = row.host_kind ?? 'tmux';
@@ -370,10 +368,8 @@ async function handleRoster() {
370
368
  const body = await rosterCoalesced();
371
369
  return { status: 200, body };
372
370
  }
373
- // ---------------------------------------------------------------------------
374
371
  // prune \u2014 the three exclusive modes (COUNT > EMPTY > TTL sweep) + target-gone
375
372
  // notification. Lifted from `commands/canvas-prune.ts` run().
376
- // ---------------------------------------------------------------------------
377
373
  /** Validate + narrow the prune body (all fields optional). */
378
374
  function parsePruneBody(body) {
379
375
  if (body === undefined || body === null)
@@ -436,10 +432,8 @@ function handlePrune(ctx) {
436
432
  const body = { pruned, dry_run: dryRun, ttl_days: ttlDays };
437
433
  return { status: 200, body };
438
434
  }
439
- // ---------------------------------------------------------------------------
440
435
  // rebuild-index \u2014 re-derive rows from on-disk metas + the fail-loud guard.
441
436
  // Lifted from `commands/canvas-rebuild-index.ts` (countOnDiskMetas + throw).
442
- // ---------------------------------------------------------------------------
443
437
  function countOnDiskMetas() {
444
438
  const root = nodesRoot();
445
439
  if (!existsSync(root))
@@ -18,9 +18,7 @@ import { requireTicketId, resolveTicket } from './inbox.js';
18
18
  import { invalidRequest, objectBody, optionalString, requiredString } from './validate.js';
19
19
  import { toPageFeedbackDTO, toPageFeedbackCommentDTO } from '../map.js';
20
20
  const COMMENT_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
21
- // ---------------------------------------------------------------------------
22
21
  // Shared guards
23
- // ---------------------------------------------------------------------------
24
22
  /** Resolve a mutable page ticket: it must exist, be a page, and not have a
25
23
  * terminal outcome. Passive pages never settle, so they stay commentable.
26
24
  * A terminal ticket refuses every feedback action — settlement won. */
@@ -45,9 +43,7 @@ function requireCommentId(params) {
45
43
  }
46
44
  return commentId;
47
45
  }
48
- // ---------------------------------------------------------------------------
49
46
  // Delivery — the person's turn in the companion conversation
50
- // ---------------------------------------------------------------------------
51
47
  /** The comment as the person's own words: the quoted page content and the
52
48
  * note, nothing else. The companion's briefing rides its bearings and
53
49
  * persona, never the human turn. */
@@ -79,9 +75,7 @@ async function deliverCommentTurn(args) {
79
75
  return { target_node_id: target, status: 'failed', woke: false, error: error instanceof Error ? error.message : String(error) };
80
76
  }
81
77
  }
82
- // ---------------------------------------------------------------------------
83
78
  // POST /v1/human/inbox/:ticket_id/feedback-comments — create
84
- // ---------------------------------------------------------------------------
85
79
  function parseCreate(ctx) {
86
80
  const violations = [];
87
81
  const body = objectBody(ctx.body, ['quote', 'context', 'note'], violations);
@@ -154,9 +148,7 @@ async function handleCreate(ctx) {
154
148
  };
155
149
  return { status: 200, body };
156
150
  }
157
- // ---------------------------------------------------------------------------
158
151
  // POST .../feedback-comments/:comment_id/resolve — the companion's report
159
- // ---------------------------------------------------------------------------
160
152
  function parseResolve(ctx) {
161
153
  const violations = [];
162
154
  const body = objectBody(ctx.body, ['node_id'], violations);
@@ -6,11 +6,12 @@
6
6
  // Both run INSIDE crtrd, so `daemon_up` is trivially true and `daemon_pid` is
7
7
  // this process. Store access is probed by a cheap `listNodes()` — a throw means
8
8
  // the store is inaccessible.
9
- import { listNodes } from '../../../index.js';
9
+ import { listNodes } from '../../../core/canvas/canvas.js';
10
10
  import { apiSocketPath } from '../../../core/canvas/paths.js';
11
11
  import { currentVersion } from '../../../core/self-update.js';
12
12
  import { API_VERSION } from '../../../api/index.js';
13
13
  import { DEFAULT_INTERVAL_MS } from '../../supervise-cadence.js';
14
+ import { envCrtrdTcp } from '../../../shared/env.js';
14
15
  // The daemon's supervise-loop cadence, echoed as an informational field; the
15
16
  // loop itself is unchanged (hard constraint). Derived from the single shared
16
17
  // constant so it can never drift from crtrd's actual interval.
@@ -45,7 +46,7 @@ function handleStatus() {
45
46
  // The store is unreachable — spec §8 store_unavailable.
46
47
  throw { status: 503, code: 'store_unavailable', message: 'canvas store is inaccessible' };
47
48
  }
48
- const tcp = process.env['CRTRD_TCP'];
49
+ const tcp = envCrtrdTcp();
49
50
  const body = {
50
51
  daemon_pid: process.pid,
51
52
  tick_interval_ms: TICK_INTERVAL_MS,
@@ -21,9 +21,7 @@ const REASON_MAX = 1000;
21
21
  const ACTOR_MAX = 200;
22
22
  const DEFAULT_DELIVERY = { placement: 'inline', inbox: true, reply: false };
23
23
  const SOURCE_FIELDS = ['sessionName', 'askedBy', 'emittedAt', 'profileName', 'nodeId'];
24
- // ===========================================================================
25
24
  // Body validation
26
- // ===========================================================================
27
25
  function isPlainObject(value) {
28
26
  return typeof value === 'object' && value !== null && !Array.isArray(value);
29
27
  }
@@ -259,9 +257,7 @@ function requestToDTO(request) {
259
257
  }
260
258
  return dto;
261
259
  }
262
- // ===========================================================================
263
260
  // POST /v1/human/requests — create
264
- // ===========================================================================
265
261
  /** Authoring failure is the caller's malformed page, never a server fault. */
266
262
  function prepareOrReject(dialect, document, source, delivery) {
267
263
  try {
@@ -312,15 +308,11 @@ function handleCreate(ctx) {
312
308
  },
313
309
  };
314
310
  }
315
- // ===========================================================================
316
311
  // GET /v1/human/requests/:request_id — read
317
- // ===========================================================================
318
312
  function handleGet(ctx) {
319
313
  return { status: 200, body: requestToDTO(resolveRequest(ctx)) };
320
314
  }
321
- // ===========================================================================
322
315
  // POST /v1/human/requests/:request_id/replace — revise the pending page
323
- // ===========================================================================
324
316
  function handleReplace(ctx) {
325
317
  const request = resolveRequest(ctx);
326
318
  if (request.result !== null)
@@ -332,9 +324,7 @@ function handleReplace(ctx) {
332
324
  publishPage(request.dir, prepared);
333
325
  return { status: 200, body: requestToDTO({ ...request, manifest: prepared.manifest }) };
334
326
  }
335
- // ===========================================================================
336
327
  // Settlement — respond, dismiss, cancel
337
- // ===========================================================================
338
328
  /** The settlement funnels speak the inbox's error vocabulary; requests speak
339
329
  * the wire contract's. This is the one translation. */
340
330
  function settlementError(error) {
@@ -19,9 +19,7 @@ function requireInteractionTicketId(ctx) {
19
19
  }
20
20
  return ticketId;
21
21
  }
22
- // ===========================================================================
23
22
  // POST /v1/human/bridge — create a terminal bridge without a broker
24
- // ===========================================================================
25
23
  function handleCreateBridge(ctx) {
26
24
  const req = ctx.body;
27
25
  if (req === undefined || typeof req !== 'object') {
@@ -46,9 +44,7 @@ function handleCreateBridge(ctx) {
46
44
  throw new ApiError(400, 'invalid_request', String(error));
47
45
  }
48
46
  }
49
- // ===========================================================================
50
47
  // POST /v1/human/tickets/:ticket_id/resolve and /cancel
51
- // ===========================================================================
52
48
  function reviewSubmitGuidance() {
53
49
  return new ApiError(400, 'invalid_request', 'review approvals use POST /v1/human/reviews/:review_id/submit');
54
50
  }
@@ -100,7 +96,7 @@ async function handleResolve(ctx) {
100
96
  return { status: 200, body: { completed: true, reply_delivered: replyExpected, kind: 'page' } };
101
97
  }
102
98
  function hasPublishedTicket(dir) {
103
- return existsSync(pageManifestPath(dir)) || existsSync(reviewPath(dir)) || readTicketResult(dir) !== null;
99
+ return existsSync(pageManifestPath(dir)) || readTicketResult(dir) !== null;
104
100
  }
105
101
  async function handleCancel(ctx) {
106
102
  const ticketId = requireInteractionTicketId(ctx);
@@ -18,9 +18,7 @@ import { filterTerminalReviewTickets } from '../../../core/review/ticket-filter.
18
18
  const DEFAULT_CANCEL_REASON = 'Canceled from the inbox.';
19
19
  const CANCEL_REASON_MAX = 1000;
20
20
  const TICKET_ID_PATTERN = /^[a-f0-9]{64}$/;
21
- // ===========================================================================
22
21
  // Opaque ticket id resolution
23
- // ===========================================================================
24
22
  function ticketHash(canonicalRoot, ticketBasename) {
25
23
  return createHash('sha256').update(`${canonicalRoot}\0${ticketBasename}`, 'utf8').digest('hex');
26
24
  }
@@ -70,9 +68,7 @@ export function requireTicketId(params) {
70
68
  }
71
69
  return ticketId;
72
70
  }
73
- // ===========================================================================
74
71
  // Projections — humanloop canonical shapes → wire DTOs
75
- // ===========================================================================
76
72
  function pageSlotToDTO(slot) {
77
73
  const dto = {
78
74
  kind: slot.kind,
@@ -166,9 +162,7 @@ const SLOT_VALIDATION_PATTERNS = [
166
162
  function isSlotValidationError(err) {
167
163
  return err instanceof Error && SLOT_VALIDATION_PATTERNS.some((pattern) => pattern.test(err.message));
168
164
  }
169
- // ===========================================================================
170
165
  // GET /v1/human/inbox — enumerate
171
- // ===========================================================================
172
166
  /** The one page-summary projection: the pending list and the per-node history differ only in which tickets they walk. */
173
167
  function pageSummaryToDTO(item, canonicalRoot) {
174
168
  const dto = {
@@ -222,9 +216,7 @@ function handleList() {
222
216
  });
223
217
  return { status: 200, body: { tickets } };
224
218
  }
225
- // ===========================================================================
226
219
  // GET /v1/human/inbox/history?node_id=<id> — page ticket history
227
- // ===========================================================================
228
220
  function handleHistory(ctx) {
229
221
  // Home-wide when `node_id` is absent; an explicitly empty param is a caller bug.
230
222
  const nodeId = ctx.query.get('node_id');
@@ -236,9 +228,7 @@ function handleHistory(ctx) {
236
228
  const tickets = history.map((item) => pageSummaryToDTO(item, canonicalRoot));
237
229
  return { status: 200, body: { tickets } };
238
230
  }
239
- // ===========================================================================
240
231
  // GET /v1/human/inbox/:ticket_id — read a page ticket
241
- // ===========================================================================
242
232
  function handleGetPage(ctx) {
243
233
  const ticketId = requireTicketId(ctx.params);
244
234
  const resolved = resolveTicket(ticketId);
@@ -270,9 +260,7 @@ function handleGetPage(ctx) {
270
260
  },
271
261
  };
272
262
  }
273
- // ===========================================================================
274
263
  // POST /v1/human/inbox/:ticket_id/respond — submit
275
- // ===========================================================================
276
264
  async function handleRespond(ctx) {
277
265
  const ticketId = requireTicketId(ctx.params);
278
266
  const request = validateRespondRequest(ctx.body);
@@ -317,9 +305,7 @@ async function handleRespond(ctx) {
317
305
  throw new ApiError(500, 'internal', 'the ticket could not be finalized');
318
306
  }
319
307
  }
320
- // ===========================================================================
321
308
  // POST /v1/human/inbox/:ticket_id/progress — autosave
322
- // ===========================================================================
323
309
  function handleProgress(ctx) {
324
310
  const ticketId = requireTicketId(ctx.params);
325
311
  const request = validateProgressRequest(ctx.body);
@@ -346,9 +332,7 @@ function handleProgress(ctx) {
346
332
  throw new ApiError(500, 'internal', 'progress could not be saved');
347
333
  }
348
334
  }
349
- // ===========================================================================
350
335
  // POST /v1/human/inbox/:ticket_id/cancel — cancel
351
- // ===========================================================================
352
336
  async function handleCancel(ctx) {
353
337
  const ticketId = requireTicketId(ctx.params);
354
338
  const request = validateCancelRequest(ctx.body);
@@ -378,9 +362,7 @@ async function handleCancel(ctx) {
378
362
  throw new ApiError(500, 'internal', 'the ticket could not be canceled');
379
363
  }
380
364
  }
381
- // ===========================================================================
382
365
  // GET /v1/human/inbox/:ticket_id/response — published response
383
- // ===========================================================================
384
366
  function handleGetResponse(ctx) {
385
367
  const ticketId = requireTicketId(ctx.params);
386
368
  const resolved = resolveTicket(ticketId);
@@ -8,7 +8,7 @@
8
8
  // to different documents for two nodes (each has its own context store, project
9
9
  // stack, and profile). Resolution therefore runs target-addressed —
10
10
  // `resolveMemoryDocForTarget` with the node's cwd/profile/id off canvas.
11
- import { getNode } from '../../../index.js';
11
+ import { getNode } from '../../../core/canvas/canvas.js';
12
12
  import { notFound, usage } from '../../../core/errors.js';
13
13
  import { resolveMemoryDocForTarget } from '../../../core/memory-resolver.js';
14
14
  import { isDocLinkName } from '../../../core/memory/doc-link-grammar.js';
@@ -1,13 +1,13 @@
1
1
  // Message handler (spec §6.2). `POST /v1/nodes/{id}/messages` delivers an
2
2
  // inbox message now (201) or fresh-revives with no inbox entry. `{id}` is the
3
3
  // target node.
4
- import { appendInbox, getNode, reviveNode } from '../../../index.js';
4
+ import { appendInbox, cancelPendingHumanMessages } from '../../../core/feed/inbox.js';
5
+ import { reviveNode } from '../../../core/runtime/revive.js';
5
6
  import { BrokerUnreachableError } from '../../../core/runtime/broker-request.js';
6
7
  import { isBrokerLive } from '../../../core/runtime/model-swap.js';
7
8
  import { deliverLive, interruptLive } from '../../../core/runtime/interactive-deliver.js';
8
- import { cancelPendingHumanMessages } from '../../../core/feed/inbox.js';
9
9
  import { isProfilePaused } from '../../../core/profiles/manifest.js';
10
- import { withFreshTerminalGuard } from '../../../core/canvas/canvas.js';
10
+ import { getNode, withFreshTerminalGuard } from '../../../core/canvas/canvas.js';
11
11
  import { assertNotFinalized, assertFinalizedForReopen, commitReopen, commitReopenResident, } from '../../../core/runtime/reopen.js';
12
12
  import { writeOutputSchema } from '../../../core/runtime/structured-output.js';
13
13
  import { appendSituationalContext, formatSituationalProse } from '../../../core/runtime/situational-context.js';
@@ -17,9 +17,7 @@ import { hasFreshGroundState } from '../../../core/runtime/revive.js';
17
17
  import { notFound, usage } from '../../../core/errors.js';
18
18
  import { InputError } from '../../../core/io.js';
19
19
  import { ApiError } from '../../../api/index.js';
20
- // ---------------------------------------------------------------------------
21
20
  // POST /v1/nodes/{id}/messages
22
- // ---------------------------------------------------------------------------
23
21
  const TIERS = ['critical', 'urgent', 'normal', 'deferred'];
24
22
  /** Validate + narrow one caller-supplied runtime card. A bare kind is crouter's
25
23
  * own closed vocabulary, so a caller must namespace: no product can shadow a
@@ -209,7 +207,7 @@ async function handleMessage(ctx) {
209
207
  const schema = req.output_schema !== undefined && req.output_schema.trim() !== ''
210
208
  ? parseSchema(req.output_schema)
211
209
  : null;
212
- // --- Fresh revive: no inbox entry, resume:false (spec §7.7). ---
210
+ // Fresh revive: no inbox entry, resume:false (spec §7.7).
213
211
  // Mirrors the CLI's immediate --fresh: validate/clear the finalization latch
214
212
  // (--reopen) and upsert the situational sidecar BEFORE the revive, so the
215
213
  // fresh kickoff picks up the update. The goal/roadmap recoverable-state guard
@@ -344,9 +342,7 @@ async function handleMessage(ctx) {
344
342
  };
345
343
  return { status: 201, body };
346
344
  }
347
- // ---------------------------------------------------------------------------
348
345
  // POST /v1/nodes/{id}/interrupt
349
- // ---------------------------------------------------------------------------
350
346
  /** The human Esc, first-class. Cancel pending undelivered human sends FIRST,
351
347
  * then abort the live turn — in that order, so a watcher injection racing
352
348
  * between the two is caught by the abort right behind it. A dormant target is
@@ -6,12 +6,15 @@
6
6
  // map.ts carries no projector — it is frozen under concurrency).
7
7
  //
8
8
  // `{id}` is the target node.
9
+ import { envProfileId } from '../../../shared/env.js';
9
10
  import { readdirSync } from 'node:fs';
10
11
  import { basename } from 'node:path';
11
- import { appendSituationalContext, closeNode, getNode, listNodes, nowIso, reviveNode, } from '../../../index.js';
12
- import { formatSituationalProse } from '../../../core/runtime/situational-context.js';
12
+ import { appendSituationalContext, formatSituationalProse } from '../../../core/runtime/situational-context.js';
13
+ import { closeNode } from '../../../core/runtime/close.js';
14
+ import { reviveNode } from '../../../core/runtime/revive.js';
15
+ import { nowIso } from '../../../core/fs-utils.js';
13
16
  import { assertLaunchModelRegistered, forkNode, spawnChild } from '../../../core/runtime/spawn.js';
14
- import { childrenOf, subscribersOf, subscriptionsOf, setMessageWait, updateNode } from '../../../core/canvas/canvas.js';
17
+ import { childrenOf, getNode, listNodes, subscribersOf, subscriptionsOf, setMessageWait, updateNode } from '../../../core/canvas/canvas.js';
15
18
  import { subtreeIds } from '../../../core/canvas/nav-model.js';
16
19
  import { ticketCountsForNodes } from '../../../core/canvas/attention.js';
17
20
  import { contextDir, reportsDir } from '../../../core/canvas/paths.js';
@@ -40,9 +43,7 @@ import { cronWakeOrigin } from '../../../core/runtime/bearings.js';
40
43
  import { notFound, usage } from '../../../core/errors.js';
41
44
  import { toCloseResultDTO, toNodeDetailDTO, toNodeSummaryDTO, toReviveResultDTO } from '../map.js';
42
45
  import { ApiError } from '../../../api/index.js';
43
- // ---------------------------------------------------------------------------
44
46
  // Shared helpers
45
- // ---------------------------------------------------------------------------
46
47
  function requireMeta(id) {
47
48
  const meta = getNode(id);
48
49
  if (meta === null)
@@ -76,9 +77,7 @@ function countFiles(id) {
76
77
  }
77
78
  return n;
78
79
  }
79
- // ---------------------------------------------------------------------------
80
80
  // POST /v1/nodes — create immediately (201)
81
- // ---------------------------------------------------------------------------
82
81
  /** Validate + narrow the create body (spec §6.2). */
83
82
  function parseCreateBody(body) {
84
83
  if (typeof body !== 'object' || body === null) {
@@ -192,7 +191,7 @@ export async function handleCreate(ctx, deps = {}) {
192
191
  // buildRecipe already defaults `prompt` to ''. The CLI keeps every no_kickoff
193
192
  // guards (root-only / no-prompt / no-orchestrator).
194
193
  const parent = req.parent ?? undefined;
195
- // --- Immediate spawn (201). A managed child needs a parent; a root does not. ---
194
+ // Immediate spawn (201). A managed child needs a parent; a root does not.
196
195
  if (parent == null && req.root !== true) {
197
196
  throw usage('a node create requires a parent (or root: true for an independent root)');
198
197
  }
@@ -233,9 +232,7 @@ export async function handleCreate(ctx, deps = {}) {
233
232
  writeOutputSchema(result.node.node_id, 'terminal', schema);
234
233
  return { status: 201, body: detailOf(result.node.node_id) };
235
234
  }
236
- // ---------------------------------------------------------------------------
237
235
  // GET /v1/nodes — list (filters) ; GET /v1/nodes/{id} — detail
238
- // ---------------------------------------------------------------------------
239
236
  function singleQueryValue(ctx, name) {
240
237
  const values = ctx.query.getAll(name);
241
238
  if (values.length > 1)
@@ -343,9 +340,7 @@ function handleDetail(ctx) {
343
340
  requireMeta(id);
344
341
  return { status: 200, body: detailOf(id) };
345
342
  }
346
- // ---------------------------------------------------------------------------
347
343
  // Read endpoints (snapshot / transcript / context / artifacts)
348
- // ---------------------------------------------------------------------------
349
344
  async function handleSnapshot(ctx) {
350
345
  const id = ctx.params['id'];
351
346
  requireMeta(id);
@@ -458,9 +453,7 @@ function handleArtifacts(ctx) {
458
453
  const body = { node_id: id, artifacts };
459
454
  return { status: 200, body };
460
455
  }
461
- // ---------------------------------------------------------------------------
462
456
  // Lifecycle verbs
463
- // ---------------------------------------------------------------------------
464
457
  async function handleFork(ctx) {
465
458
  const id = ctx.params['id'];
466
459
  requireMeta(id);
@@ -601,9 +594,7 @@ function handleReviveAll() {
601
594
  const body = { revived: [...result.revived], failed: [...result.failed] };
602
595
  return { status: 200, body };
603
596
  }
604
- // ---------------------------------------------------------------------------
605
597
  // PATCH /v1/nodes/{id}/config — model / situational-context (spec §6.2)
606
- // ---------------------------------------------------------------------------
607
598
  export async function handleConfig(ctx, deps = {}) {
608
599
  const id = ctx.params['id'];
609
600
  let meta = requireMeta(id);
@@ -646,7 +637,7 @@ export async function handleConfig(ctx, deps = {}) {
646
637
  // Re-read so the launch-spec rebuild below sees the fresh model pin.
647
638
  meta = requireMeta(id);
648
639
  }
649
- // --- kind / mode / lifecycle: reshape via canonical primitive (CLI parity). ---
640
+ // kind / mode / lifecycle: reshape via canonical primitive (CLI parity).
650
641
  if (patch.kind !== undefined || patch.mode !== undefined || patch.lifecycle !== undefined) {
651
642
  if (patch.kind !== undefined)
652
643
  await assertKindServer(patch.kind);
@@ -671,7 +662,7 @@ export async function handleConfig(ctx, deps = {}) {
671
662
  ...(patch.lifecycle !== undefined ? { lifecycle: newLifecycle } : {}),
672
663
  }, beforePersist);
673
664
  }
674
- // --- name: rename the row and, when it has a live viewer window, that window. ---
665
+ // name: rename the row and, when it has a live viewer window, that window.
675
666
  if (patch.name !== undefined) {
676
667
  meta = updateNode(id, { name: patch.name });
677
668
  if (meta.window)
@@ -685,15 +676,13 @@ export async function handleConfig(ctx, deps = {}) {
685
676
  * ambient configuration; prospective reads validate their resolved target. The
686
677
  * read is subprocess-isolated — crtrd must never resolve config on its own loop. */
687
678
  async function assertKindServer(kind) {
688
- const kinds = Object.keys((await readMergedLaunchConfigAsync(process.cwd(), process.env['CRTR_PROFILE_ID'] || null)).kinds);
679
+ const kinds = Object.keys((await readMergedLaunchConfigAsync(process.cwd(), envProfileId() || null)).kinds);
689
680
  if (!kinds.includes(kind)) {
690
681
  throw usage(`unknown kind: ${kind}`, { received: kind, next: `Valid kinds: ${kinds.sort().join(', ')}.` });
691
682
  }
692
683
  }
693
- // ---------------------------------------------------------------------------
694
684
  // Route table (revive-all registered before `:id` collisions are impossible —
695
685
  // different methods — but ordered defensively).
696
- // ---------------------------------------------------------------------------
697
686
  export const nodeRoutes = [
698
687
  { method: 'POST', pattern: '/v1/nodes', handler: handleCreate },
699
688
  { method: 'GET', pattern: '/v1/nodes', handler: handleList },
@@ -6,7 +6,7 @@
6
6
  // `{id}` is the REPORTING node (client-side = CRTR_NODE_ID).
7
7
  import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
8
8
  import { join } from 'node:path';
9
- import { getNode } from '../../../index.js';
9
+ import { getNode } from '../../../core/canvas/canvas.js';
10
10
  import { push, FinalizationError } from '../../../core/feed/feed.js';
11
11
  import { autoDropCleanManagedWorktree, hasOpenManagedWorktree, missingWorktreeRecoveryHint } from '../../../core/worktree.js';
12
12
  import { reportsDir } from '../../../core/canvas/paths.js';
@@ -1,10 +1,8 @@
1
1
  // Canonical daemon-owned review lifecycle routes. Handlers validate the full
2
2
  // wire request, delegate lifecycle work to review services, and project only
3
3
  // committed daemon state.
4
- import { existsSync } from 'node:fs';
5
- import { ApiError } from '../../../api/index.js';
6
4
  import { isSafeNodeId, reviewResultPath } from '../../../core/canvas/paths.js';
7
- import { responsePath, reviewPath } from '../../../core/human/convention.js';
5
+ import { responsePath } from '../../../core/human/convention.js';
8
6
  import { ticketDir } from '../../../core/human/root.js';
9
7
  import { createReview } from '../../../core/review/birth.js';
10
8
  import { readAnchorBase, getReviewByBridge, listReviews, requireVisibleReview } from '../../../core/review/store.js';
@@ -168,9 +166,6 @@ function handleByBridge(ctx) {
168
166
  const review = getReviewByBridge(bridgeNodeId);
169
167
  if (review !== null)
170
168
  return { status: 200, body: toReviewResponseDTO(review) };
171
- if (existsSync(reviewPath(ticketDir(bridgeNodeId)))) {
172
- throw new ApiError(409, 'review_predates_system', 'this review predates canonical review records; cancel it and re-file the review', { bridge_node_id: bridgeNodeId });
173
- }
174
169
  throw new ReviewOperationError('unknown_review', 'review was not found', { received: bridgeNodeId });
175
170
  }
176
171
  async function handleSubmit(ctx) {
@@ -20,9 +20,7 @@ import { ExitCode } from '../../types.js';
20
20
  import { sinkDisplay } from '../cron-sink.js';
21
21
  import { responsePath } from '../../core/human/convention.js';
22
22
  import { ticketDir } from '../../core/human/root.js';
23
- // ---------------------------------------------------------------------------
24
23
  // Node projections
25
- // ---------------------------------------------------------------------------
26
24
  /** Project the queryable row (what `listNodes` yields) into a summary DTO. */
27
25
  export function toNodeSummaryDTO(row) {
28
26
  return {
@@ -144,9 +142,7 @@ export function toNodeDetailDTO(meta, edges) {
144
142
  dto.worktree = toNodeWorktreeDTO(meta.managed_worktree);
145
143
  return dto;
146
144
  }
147
- // ---------------------------------------------------------------------------
148
145
  // Action-result projections
149
- // ---------------------------------------------------------------------------
150
146
  /** Project a `reviveNode` result. `revived` is true only when a fresh launch
151
147
  * actually happened — the double-revive no-op (already-alive) returns without a
152
148
  * `launch` handle, so its absence is the "nothing relaunched" signal. `status`
@@ -398,9 +394,7 @@ export function toFeedbackResultDTO(result) {
398
394
  }
399
395
  const _exitIntentParity = true;
400
396
  void _exitIntentParity;
401
- // ---------------------------------------------------------------------------
402
397
  // Error → HTTP status mapping (spec §8)
403
- // ---------------------------------------------------------------------------
404
398
  /** The only internal review-error to public HTTP projection. Every internal
405
399
  * review failure is listed explicitly so handlers never need to invent a status
406
400
  * or public code. */
@@ -102,9 +102,7 @@ export class Router {
102
102
  }
103
103
  }
104
104
  }
105
- // ---------------------------------------------------------------------------
106
105
  // Matching
107
- // ---------------------------------------------------------------------------
108
106
  /** Split a path/pattern into non-empty segments (leading/trailing '/' ignored). */
109
107
  function splitPath(p) {
110
108
  return p.split('/').filter((s) => s.length > 0);
@@ -127,9 +125,7 @@ function matchSegments(pattern, actual) {
127
125
  }
128
126
  return params;
129
127
  }
130
- // ---------------------------------------------------------------------------
131
128
  // Body + response I/O
132
- // ---------------------------------------------------------------------------
133
129
  class BodyTooLargeError extends Error {
134
130
  }
135
131
  /** Read and JSON-parse the request body. Returns `undefined` for an empty body.
@@ -16,6 +16,7 @@ import { createServer } from 'node:http';
16
16
  import { chmodSync, existsSync, unlinkSync } from 'node:fs';
17
17
  import { apiSocketPath } from '../../core/canvas/paths.js';
18
18
  import { emitEvent } from '../../core/events/emit.js';
19
+ import { envCrtrdTcp } from '../../shared/env.js';
19
20
  import { Router } from './router.js';
20
21
  import { handleAttachUpgrade } from './bridge.js';
21
22
  import { attachRoutes } from './handlers/attach.js';
@@ -204,10 +205,8 @@ export function createApiServer(opts = {}) {
204
205
  emitEvent({ event: 'api.server.failed', level: 'error', error: err });
205
206
  });
206
207
  };
207
- // -------------------------------------------------------------------------
208
208
  // Unix socket — ALWAYS bound. Unlink any stale socket first (mirror
209
209
  // broker.ts's listener setup), listen, then chmod 0600 once the file exists.
210
- // -------------------------------------------------------------------------
211
210
  const socketServer = createServer(onRequest);
212
211
  socketServer.on('upgrade', onUpgrade);
213
212
  bindErrorHandler(socketServer);
@@ -230,11 +229,9 @@ export function createApiServer(opts = {}) {
230
229
  });
231
230
  }
232
231
  });
233
- // -------------------------------------------------------------------------
234
232
  // TCP — opt-in only. A SECOND http.Server sharing the same handlers.
235
- // -------------------------------------------------------------------------
236
233
  let tcpServer;
237
- const tcpSpec = opts.tcp ?? process.env['CRTRD_TCP'];
234
+ const tcpSpec = opts.tcp ?? envCrtrdTcp();
238
235
  if (tcpSpec !== undefined && tcpSpec !== '') {
239
236
  const parsed = parseTcp(tcpSpec);
240
237
  if (parsed === null) {
@@ -0,0 +1,14 @@
1
+ export interface BootMigrationResult {
2
+ changed: boolean;
3
+ summary: Record<string, unknown>;
4
+ }
5
+ export interface BootMigration {
6
+ readonly id: string;
7
+ readonly description: string;
8
+ /** Runs unconditionally at every daemon boot. Must be safe to re-run every
9
+ * time (idempotent via its own convergence, not a version gate) and must
10
+ * isolate its own per-item failures — a thrown error here is NOT caught by
11
+ * the boot sequence and would abort daemon startup. */
12
+ apply(): BootMigrationResult;
13
+ }
14
+ export declare const BOOT_MIGRATIONS: readonly BootMigration[];