@north-light/crouter 0.3.233 → 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 (379) hide show
  1. package/dist/api/client.js +16 -15
  2. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/integration/provider-rotation.test.ts +1 -1
  3. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/claude-plugin-commands.ts +14 -17
  4. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/crtr-commands/index.ts +7 -11
  5. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/frontmatter-rules/index.ts +8 -8
  6. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +10 -11
  7. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/pi-shell-runner.ts +2 -2
  8. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +3 -3
  9. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +7 -7
  10. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +8 -8
  11. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/statusline.ts +6 -6
  12. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/sysprompt-window.ts +3 -3
  13. package/dist/builtin-pi-packages/pi-crtr-extensions/lib/subscription-state.ts +1 -1
  14. package/dist/clients/attach/chrome/ticket-panel.js +15 -2
  15. package/dist/clients/attach/overlays/graph.js +0 -3
  16. package/dist/clients/attach/overlays/mcp.js +1 -2
  17. package/dist/clients/attach/render/chat-view.js +0 -12
  18. package/dist/clients/attach/render/crtr-output.js +0 -2
  19. package/dist/clients/attach/render/tool-calls.js +0 -6
  20. package/dist/clients/attach/slash/dispatch.js +8 -11
  21. package/dist/clients/attach/viewer.js +532 -534
  22. package/dist/clients/conversation/projection.js +0 -2
  23. package/dist/clients/inbox/controller.js +22 -3
  24. package/dist/clients/inbox/review/companion-pane.js +0 -4
  25. package/dist/clients/inbox/review-adapter.js +0 -7
  26. package/dist/clients/inbox/tui/slots.d.ts +3 -3
  27. package/dist/clients/inbox/tui/types.d.ts +2 -2
  28. package/dist/commands/api-client.js +0 -8
  29. package/dist/commands/attention.js +0 -8
  30. package/dist/commands/canvas-browse.js +2 -1
  31. package/dist/commands/canvas-config.js +0 -10
  32. package/dist/commands/canvas-history.js +2 -1
  33. package/dist/commands/cron.js +5 -18
  34. package/dist/commands/dashboard.js +0 -2
  35. package/dist/commands/human/feedback.js +2 -1
  36. package/dist/commands/human/prompts.js +2 -5
  37. package/dist/commands/human/queue.js +2 -7
  38. package/dist/commands/human/request.js +0 -14
  39. package/dist/commands/human/review.js +2 -1
  40. package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +4 -4
  41. package/dist/commands/memory/find.js +2 -2
  42. package/dist/commands/memory/lint.js +2 -1
  43. package/dist/commands/memory/read.d.ts +2 -7
  44. package/dist/commands/memory/read.js +5 -16
  45. package/dist/commands/memory/shared.js +4 -7
  46. package/dist/commands/memory/write.js +4 -3
  47. package/dist/commands/node/bash.js +2 -1
  48. package/dist/commands/node/create.js +2 -1
  49. package/dist/commands/node/inspect.js +0 -6
  50. package/dist/commands/node/lifecycle.js +4 -13
  51. package/dist/commands/node/message.js +3 -2
  52. package/dist/commands/node/subscription.js +2 -1
  53. package/dist/commands/node/wait.js +4 -3
  54. package/dist/commands/node-context.js +2 -1
  55. package/dist/commands/node-lifecycle-revive.js +0 -2
  56. package/dist/commands/node-worktree.js +2 -1
  57. package/dist/commands/pkg/browse/actions.d.ts +1 -1
  58. package/dist/commands/pkg/browse/actions.js +4 -4
  59. package/dist/commands/pkg/browse/catalog.d.ts +1 -1
  60. package/dist/commands/pkg/browse/catalog.js +15 -15
  61. package/dist/commands/pkg/browse/command-view.d.ts +1 -1
  62. package/dist/commands/pkg/browse/command-view.js +3 -3
  63. package/dist/commands/pkg/browse/detail-panel.d.ts +1 -1
  64. package/dist/commands/pkg/browse/detail-panel.js +8 -8
  65. package/dist/commands/pkg/browse/doc-view.d.ts +1 -1
  66. package/dist/commands/pkg/browse/doc-view.js +3 -3
  67. package/dist/commands/pkg/browse/list-panel.d.ts +1 -1
  68. package/dist/commands/pkg/browse/list-panel.js +3 -3
  69. package/dist/commands/pkg/browse/model.d.ts +3 -3
  70. package/dist/commands/pkg/browse/shell.d.ts +2 -2
  71. package/dist/commands/pkg/browse/shell.js +13 -13
  72. package/dist/commands/pkg/plugin-manage.js +2 -1
  73. package/dist/commands/pkg/shared.js +0 -2
  74. package/dist/commands/profile/delete.js +2 -1
  75. package/dist/commands/push.js +2 -3
  76. package/dist/commands/revive.js +0 -2
  77. package/dist/commands/surface/node/placement.js +2 -1
  78. package/dist/commands/surface-edit.js +2 -1
  79. package/dist/commands/sys/config.js +0 -4
  80. package/dist/commands/sys/daemon.js +0 -10
  81. package/dist/commands/sys/doctor.js +3 -2
  82. package/dist/commands/sys/panels/broker-limits-panel.d.ts +2 -2
  83. package/dist/commands/sys/panels/broker-limits-panel.js +4 -4
  84. package/dist/commands/sys/panels/dependencies-panel.d.ts +2 -2
  85. package/dist/commands/sys/panels/dependencies-panel.js +2 -2
  86. package/dist/commands/sys/panels/keybindings-panel.d.ts +1 -1
  87. package/dist/commands/sys/panels/keybindings-panel.js +5 -5
  88. package/dist/commands/sys/panels/models-panel.d.ts +4 -4
  89. package/dist/commands/sys/panels/models-panel.js +11 -10
  90. package/dist/commands/sys/panels/plugins-panel.d.ts +2 -2
  91. package/dist/commands/sys/panels/plugins-panel.js +2 -2
  92. package/dist/commands/sys/panels/prefs-panel.d.ts +2 -2
  93. package/dist/commands/sys/panels/prefs-panel.js +4 -4
  94. package/dist/commands/sys/panels/profiles-panel.d.ts +1 -1
  95. package/dist/commands/sys/panels/profiles-panel.js +14 -13
  96. package/dist/commands/sys/panels/provider-panel.d.ts +3 -3
  97. package/dist/commands/sys/panels/provider-panel.js +8 -8
  98. package/dist/commands/sys/settings-shell.d.ts +3 -3
  99. package/dist/commands/sys/settings-shell.js +15 -15
  100. package/dist/commands/sys/setup-settings-runner.d.ts +3 -3
  101. package/dist/commands/sys/setup-settings-runner.js +5 -5
  102. package/dist/commands/sys/setup-wizard.d.ts +4 -4
  103. package/dist/commands/sys/setup-wizard.js +8 -8
  104. package/dist/commands/sys/support/prepare.js +4 -4
  105. package/dist/commands/sys/support/submit.js +2 -2
  106. package/dist/commands/sys/sync-deps.js +0 -2
  107. package/dist/commands/sys/sync-project-guidance.js +2 -1
  108. package/dist/commands/sys/sysprompt.js +2 -1
  109. package/dist/core/__tests__/boot.test.js +0 -8
  110. package/dist/core/__tests__/broker-extension-canvas-db-boundary.test.js +23 -1
  111. package/dist/core/__tests__/canvas-db-boundary.test.d.ts +1 -0
  112. package/dist/core/__tests__/canvas-db-boundary.test.js +46 -0
  113. package/dist/core/__tests__/canvas.test.js +1 -1
  114. package/dist/core/__tests__/child-death-wake.test.js +0 -2
  115. package/dist/core/__tests__/cron-armed-context-failure.test.d.ts +1 -0
  116. package/dist/core/__tests__/cron-armed-context-failure.test.js +145 -0
  117. package/dist/core/__tests__/daemon-wedge.test.js +0 -4
  118. package/dist/core/__tests__/dead-node-policy-table.test.js +0 -4
  119. package/dist/core/__tests__/fixtures/fake-engine.js +4 -14
  120. package/dist/core/__tests__/fixtures/fake-pi-host.js +5 -5
  121. package/dist/core/__tests__/focuses.test.js +0 -6
  122. package/dist/core/__tests__/fs-utils.test.d.ts +1 -0
  123. package/dist/core/__tests__/fs-utils.test.js +50 -0
  124. package/dist/core/__tests__/helpers/harness.js +1 -1
  125. package/dist/core/__tests__/inline-memory-refs.test.js +0 -2
  126. package/dist/core/__tests__/integration/broker-fork-seam.test.js +0 -2
  127. package/dist/core/__tests__/integration/broker-sdk-wiring.test.js +3 -16
  128. package/dist/core/__tests__/integration/command-plugins.test.js +0 -24
  129. package/dist/core/__tests__/integration/deferred-no-wake.test.js +0 -6
  130. package/dist/core/__tests__/integration/flagship-lifecycle.test.js +0 -26
  131. package/dist/core/__tests__/integration/live-mutation-verbs.test.js +0 -4
  132. package/dist/core/__tests__/integration/live-mutation.test.js +1 -5
  133. package/dist/core/__tests__/integration/refresh-stall-recycle.test.js +1 -5
  134. package/dist/core/__tests__/integration/revive.test.js +0 -12
  135. package/dist/core/__tests__/integration/subscription-delivery.test.js +0 -6
  136. package/dist/core/__tests__/integration/tmux-surface.test.js +24 -8
  137. package/dist/core/__tests__/integration/worktree-reap.test.js +0 -6
  138. package/dist/core/__tests__/lifecycle.test.js +0 -18
  139. package/dist/core/__tests__/memory-resolver-precedence.test.js +1 -1
  140. package/dist/core/__tests__/migration.test.js +2 -2
  141. package/dist/core/__tests__/on-read-dedup-resume.test.js +3 -3
  142. package/dist/core/__tests__/pid-identity-match.test.js +1 -1
  143. package/dist/core/__tests__/plugin-kinds.test.js +1 -1
  144. package/dist/core/__tests__/plugin-page-components.test.js +1 -1
  145. package/dist/core/__tests__/preview-registry-sync.test.js +42 -1
  146. package/dist/core/__tests__/respawn-throttle.test.js +0 -4
  147. package/dist/core/__tests__/revive-all.test.js +5 -5
  148. package/dist/core/__tests__/revive-parked-fresh.test.js +62 -11
  149. package/dist/core/__tests__/seam/broker-attach-multiclient.test.js +0 -8
  150. package/dist/core/__tests__/seam/broker-attach-stream.test.js +0 -8
  151. package/dist/core/__tests__/seam/broker-crash-teardown.test.js +0 -2
  152. package/dist/core/__tests__/tmux-driver-boundary.test.d.ts +1 -0
  153. package/dist/core/__tests__/tmux-driver-boundary.test.js +50 -0
  154. package/dist/core/activity-signal.d.ts +7 -0
  155. package/dist/core/activity-signal.js +38 -0
  156. package/dist/core/auto-update.js +2 -1
  157. package/dist/core/bootstrap.js +2 -1
  158. package/dist/core/canvas/__tests__/remote-canvas-source.test.js +1 -1
  159. package/dist/core/canvas/__tests__/remote-transport.test.js +1 -1
  160. package/dist/core/canvas/__tests__/render-remote.test.js +1 -1
  161. package/dist/core/canvas/browse/app.js +3 -2
  162. package/dist/core/canvas/browse/model.d.ts +1 -1
  163. package/dist/core/canvas/browse/model.js +0 -4
  164. package/dist/core/canvas/canvas.d.ts +22 -0
  165. package/dist/core/canvas/canvas.js +50 -18
  166. package/dist/core/canvas/crons.js +0 -6
  167. package/dist/core/canvas/db.d.ts +14 -20
  168. package/dist/core/canvas/db.js +30 -1332
  169. package/dist/core/canvas/focuses.js +0 -4
  170. package/dist/core/canvas/history.js +2 -1
  171. package/dist/core/canvas/migrations.d.ts +20 -0
  172. package/dist/core/canvas/migrations.js +1339 -0
  173. package/dist/core/canvas/nav-model.js +1 -11
  174. package/dist/core/canvas/nav-render.js +0 -8
  175. package/dist/core/canvas/remote-canvas-source.js +0 -2
  176. package/dist/core/canvas/render-source.js +31 -13
  177. package/dist/core/command-manifests/manifest.js +0 -10
  178. package/dist/core/command-manifests/schema.js +0 -4
  179. package/dist/core/command-plugins/transport/http-invoke.js +0 -14
  180. package/dist/core/command.js +0 -4
  181. package/dist/core/config.js +2 -1
  182. package/dist/core/feed/inbox.d.ts +10 -0
  183. package/dist/core/feed/inbox.js +18 -12
  184. package/dist/core/fs-utils.d.ts +9 -2
  185. package/dist/core/fs-utils.js +7 -15
  186. package/dist/core/help.js +0 -8
  187. package/dist/core/host-exports/export.d.ts +2 -2
  188. package/dist/core/host-exports/export.js +9 -12
  189. package/dist/core/human/answer.d.ts +2 -2
  190. package/dist/core/human/convention.d.ts +2 -5
  191. package/dist/core/human/convention.js +3 -13
  192. package/dist/core/human/page-schema.d.ts +2 -2
  193. package/dist/core/human/page-schema.js +2 -2
  194. package/dist/core/human/root.js +6 -23
  195. package/dist/core/human/scan.js +24 -7
  196. package/dist/core/human/tickets.d.ts +4 -1
  197. package/dist/core/human/tickets.js +20 -6
  198. package/dist/core/io.js +0 -12
  199. package/dist/core/memory/identity.js +0 -4
  200. package/dist/core/memory/inline-ref-inventory.js +3 -2
  201. package/dist/core/memory/lint.js +3 -6
  202. package/dist/core/memory-resolver.d.ts +5 -0
  203. package/dist/core/memory-resolver.js +14 -12
  204. package/dist/core/pagination.js +0 -2
  205. package/dist/core/preview-registry.d.ts +14 -0
  206. package/dist/core/preview-registry.js +2 -4
  207. package/dist/core/preview-result-path.js +2 -1
  208. package/dist/core/profiles/manifest.d.ts +37 -5
  209. package/dist/core/profiles/manifest.js +44 -24
  210. package/dist/core/profiles/select.js +0 -4
  211. package/dist/core/review/signal.js +4 -23
  212. package/dist/core/review/ticket-filter.d.ts +3 -3
  213. package/dist/core/review/ticket-filter.js +4 -9
  214. package/dist/core/runtime/__tests__/engine-route.test.js +1 -1
  215. package/dist/core/runtime/__tests__/spawn-env.test.js +0 -8
  216. package/dist/core/runtime/bearings-render.d.ts +56 -0
  217. package/dist/core/runtime/bearings-render.js +241 -0
  218. package/dist/core/runtime/bearings.d.ts +2 -17
  219. package/dist/core/runtime/bearings.js +12 -198
  220. package/dist/core/runtime/broker/auth-reload.d.ts +39 -0
  221. package/dist/core/runtime/broker/auth-reload.js +149 -0
  222. package/dist/core/runtime/broker/engine-drive.d.ts +26 -0
  223. package/dist/core/runtime/broker/engine-drive.js +257 -0
  224. package/dist/core/runtime/broker/engine-routing.d.ts +143 -0
  225. package/dist/core/runtime/broker/engine-routing.js +211 -0
  226. package/dist/core/runtime/broker/event-projection.js +3 -2
  227. package/dist/core/runtime/broker/fault-retry.js +5 -4
  228. package/dist/core/runtime/broker/frame-client.d.ts +38 -0
  229. package/dist/core/runtime/broker/frame-client.js +129 -0
  230. package/dist/core/runtime/broker/frame-dispatch.d.ts +12 -189
  231. package/dist/core/runtime/broker/frame-dispatch.js +89 -1476
  232. package/dist/core/runtime/broker/frame-engine-control.d.ts +20 -0
  233. package/dist/core/runtime/broker/frame-engine-control.js +231 -0
  234. package/dist/core/runtime/broker/frame-memory-refs.d.ts +19 -0
  235. package/dist/core/runtime/broker/frame-memory-refs.js +41 -0
  236. package/dist/core/runtime/broker/frame-model-query.d.ts +13 -0
  237. package/dist/core/runtime/broker/frame-model-query.js +69 -0
  238. package/dist/core/runtime/broker/frame-read.d.ts +19 -0
  239. package/dist/core/runtime/broker/frame-read.js +116 -0
  240. package/dist/core/runtime/broker/frame-replies.d.ts +24 -0
  241. package/dist/core/runtime/broker/frame-replies.js +64 -0
  242. package/dist/core/runtime/broker/frame-session.d.ts +34 -0
  243. package/dist/core/runtime/broker/frame-session.js +203 -0
  244. package/dist/core/runtime/broker/turn-ignition.d.ts +42 -0
  245. package/dist/core/runtime/broker/turn-ignition.js +74 -0
  246. package/dist/core/runtime/broker-extension-render.js +9 -85
  247. package/dist/core/runtime/broker-protocol.js +0 -4
  248. package/dist/core/runtime/broker-sdk.js +2 -1
  249. package/dist/core/runtime/broker.d.ts +1 -1
  250. package/dist/core/runtime/broker.js +5 -23
  251. package/dist/core/runtime/fault.js +3 -2
  252. package/dist/core/runtime/headless-pi.js +3 -2
  253. package/dist/core/runtime/host.js +2 -3
  254. package/dist/core/runtime/kickoff.js +0 -4
  255. package/dist/core/runtime/launch-target.js +2 -1
  256. package/dist/core/runtime/launch.js +3 -6
  257. package/dist/core/runtime/lifecycle.js +17 -26
  258. package/dist/core/runtime/managed-provider-cooling.d.ts +1 -1
  259. package/dist/core/runtime/naming.js +0 -2
  260. package/dist/core/runtime/nodes.js +2 -1
  261. package/dist/core/runtime/persona.js +0 -6
  262. package/dist/core/runtime/placement-tmux.js +2 -5
  263. package/dist/core/runtime/placement.js +4 -11
  264. package/dist/core/runtime/recap.js +4 -3
  265. package/dist/core/runtime/reopen.js +4 -7
  266. package/dist/core/runtime/reset.js +0 -4
  267. package/dist/core/runtime/resume-root.js +0 -2
  268. package/dist/core/runtime/revive.js +17 -13
  269. package/dist/core/runtime/session-list-cache.js +2 -2
  270. package/dist/core/runtime/shell-expansion.js +0 -2
  271. package/dist/core/runtime/spawn.js +0 -2
  272. package/dist/core/runtime/stream-watchdog.d.ts +0 -1
  273. package/dist/core/runtime/stream-watchdog.js +13 -18
  274. package/dist/core/runtime/tmux-bindings.js +0 -2
  275. package/dist/core/runtime/tmux-driver.d.ts +12 -0
  276. package/dist/core/runtime/tmux-driver.js +18 -13
  277. package/dist/core/runtime/warm-pool.js +0 -4
  278. package/dist/core/scope.js +4 -3
  279. package/dist/core/spawn.js +2 -3
  280. package/dist/core/subscription-state.js +10 -17
  281. package/dist/core/substrate/__tests__/surface-match-pre-command.test.js +3 -3
  282. package/dist/core/substrate/render.js +0 -12
  283. package/dist/core/substrate/schema.js +0 -12
  284. package/dist/core/substrate/surface-match.js +0 -2
  285. package/dist/core/termrender/display.js +2 -1
  286. package/dist/core/tui/page-host.d.ts +3 -3
  287. package/dist/core/tui/page-host.js +4 -4
  288. package/dist/core/tui/panel.js +3 -3
  289. package/dist/core/wake.js +0 -12
  290. package/dist/core/worktree.js +0 -2
  291. package/dist/daemon/__tests__/reconciler-signature.test.d.ts +1 -0
  292. package/dist/daemon/__tests__/reconciler-signature.test.js +36 -0
  293. package/dist/daemon/api/__tests__/seam/api-server.test.js +2 -16
  294. package/dist/daemon/api/__tests__/seam/b10-attach-modelauth.test.js +3 -11
  295. package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +0 -6
  296. package/dist/daemon/api/handlers/attach.js +2 -1
  297. package/dist/daemon/api/handlers/broker-ops.js +3 -6
  298. package/dist/daemon/api/handlers/canvas.js +12 -18
  299. package/dist/daemon/api/handlers/feedback-comments.js +0 -8
  300. package/dist/daemon/api/handlers/health.js +3 -2
  301. package/dist/daemon/api/handlers/human-requests.js +0 -10
  302. package/dist/daemon/api/handlers/human.js +1 -5
  303. package/dist/daemon/api/handlers/inbox.js +0 -18
  304. package/dist/daemon/api/handlers/memory.js +1 -1
  305. package/dist/daemon/api/handlers/messages.js +4 -8
  306. package/dist/daemon/api/handlers/nodes.js +10 -21
  307. package/dist/daemon/api/handlers/reports.js +1 -1
  308. package/dist/daemon/api/handlers/reviews.js +1 -6
  309. package/dist/daemon/api/map.js +0 -6
  310. package/dist/daemon/api/router.js +0 -4
  311. package/dist/daemon/api/server.js +2 -5
  312. package/dist/daemon/boot-migrations.d.ts +14 -0
  313. package/dist/daemon/boot-migrations.js +31 -0
  314. package/dist/daemon/cron/armed-context.d.ts +21 -0
  315. package/dist/daemon/cron/armed-context.js +100 -0
  316. package/dist/daemon/cron/capture.d.ts +20 -0
  317. package/dist/daemon/cron/capture.js +45 -0
  318. package/dist/daemon/cron/disposition.d.ts +19 -0
  319. package/dist/daemon/cron/disposition.js +52 -0
  320. package/dist/daemon/cron/escalation.d.ts +12 -0
  321. package/dist/daemon/cron/escalation.js +124 -0
  322. package/dist/daemon/cron/held.d.ts +4 -0
  323. package/dist/daemon/cron/held.js +20 -0
  324. package/dist/daemon/cron/lease-recovery.d.ts +3 -0
  325. package/dist/daemon/cron/lease-recovery.js +119 -0
  326. package/dist/daemon/cron/live-runs.d.ts +11 -0
  327. package/dist/daemon/cron/live-runs.js +23 -0
  328. package/dist/daemon/cron/passes.d.ts +11 -0
  329. package/dist/daemon/cron/passes.js +78 -0
  330. package/dist/daemon/cron/settle.d.ts +28 -0
  331. package/dist/daemon/cron/settle.js +37 -0
  332. package/dist/daemon/cron/sinks.d.ts +2 -0
  333. package/dist/daemon/cron/sinks.js +100 -0
  334. package/dist/daemon/cron-run.d.ts +5 -41
  335. package/dist/daemon/cron-run.js +193 -882
  336. package/dist/daemon/crtrd-cli.js +2 -1
  337. package/dist/daemon/crtrd.js +22 -22
  338. package/dist/daemon/fleet.js +0 -4
  339. package/dist/daemon/human/deliver-action.js +2 -1
  340. package/dist/daemon/human/sweep.js +15 -4
  341. package/dist/daemon/manage.d.ts +2 -2
  342. package/dist/daemon/manage.js +4 -13
  343. package/dist/daemon/pidfile.js +2 -2
  344. package/dist/daemon/reconcilers/broker-supervision.js +26 -29
  345. package/dist/daemon/reconcilers/dormant-inbox.d.ts +1 -1
  346. package/dist/daemon/reconcilers/dormant-inbox.js +2 -1
  347. package/dist/daemon/reconcilers/live-obligation.js +2 -2
  348. package/dist/daemon/reconcilers/pending-review-submit.d.ts +1 -1
  349. package/dist/daemon/reconcilers/pending-review-submit.js +2 -1
  350. package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -1
  351. package/dist/daemon/reconcilers/storage-maintenance.js +2 -1
  352. package/dist/daemon/review/companion.js +2 -2
  353. package/dist/daemon/review/sweep.js +8 -3
  354. package/dist/migrations/001-surfaces-frontmatter.js +0 -6
  355. package/dist/migrations/corpus.js +2 -5
  356. package/dist/migrations/registry.js +15 -2
  357. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +0 -4
  358. package/dist/pi-extensions/broker-local.js +2 -1
  359. package/dist/pi-extensions/canvas-bash-valve.js +3 -17
  360. package/dist/pi-extensions/canvas-context-intro.js +2 -7
  361. package/dist/pi-extensions/canvas-doc-substrate.js +2 -3
  362. package/dist/pi-extensions/canvas-goal-capture.js +2 -1
  363. package/dist/pi-extensions/canvas-inbox-watcher.js +5 -12
  364. package/dist/pi-extensions/canvas-passive-context.js +2 -5
  365. package/dist/pi-extensions/canvas-preview-result.js +2 -1
  366. package/dist/pi-extensions/canvas-prompt-scrub.js +2 -1
  367. package/dist/pi-extensions/canvas-recap.js +3 -16
  368. package/dist/pi-extensions/canvas-review-boundary.js +2 -5
  369. package/dist/pi-extensions/canvas-stophook.js +2 -26
  370. package/dist/pi-extensions/canvas-structured-output.js +2 -1
  371. package/dist/pi-extensions/canvas-tool-guide.js +2 -1
  372. package/dist/shared/__tests__/env-boundary.test.d.ts +1 -0
  373. package/dist/shared/__tests__/env-boundary.test.js +93 -0
  374. package/dist/shared/env.d.ts +68 -0
  375. package/dist/shared/env.js +171 -0
  376. package/package.json +3 -1
  377. package/runtime.lock.json +2 -2
  378. package/dist/core/canvas/render.d.ts +0 -47
  379. package/dist/core/canvas/render.js +0 -245
@@ -20,6 +20,7 @@
20
20
  //
21
21
  // Plain TS-with-types — no imports from @earendil-works/* so this compiles inside
22
22
  // crouter's own tsc build without a dep on the pi packages.
23
+ import { envNodeId } from '../shared/env.js';
23
24
  import { writeFileSync, mkdirSync, existsSync, readFileSync } from 'node:fs';
24
25
  import { join } from 'node:path';
25
26
  import { contextDir, jobDir } from '../core/canvas/paths.js';
@@ -79,9 +80,7 @@ function flushTelemetry(jobDirPath, tokensIn, tokensOut, model, contextTokens, a
79
80
  /* telemetry is best-effort; never surface */
80
81
  }
81
82
  }
82
- // ---------------------------------------------------------------------------
83
83
  // Message-extraction helpers
84
- // ---------------------------------------------------------------------------
85
84
  /** Walk backwards through the agent_end messages array to find the last
86
85
  * assistant turn. */
87
86
  function lastAssistantMessage(messages) {
@@ -117,7 +116,6 @@ function currentReviewBoundaryIds(ctx) {
117
116
  return [];
118
117
  }
119
118
  }
120
- // ---------------------------------------------------------------------------
121
119
  // Context-size steering bands — a single shared schedule of thresholds that
122
120
  // ESCALATE in tone as input context grows. The first band is a gentle
123
121
  // "consider it"; a later band turns firm. The schedule TIGHTENS as it climbs:
@@ -150,7 +148,6 @@ function currentReviewBoundaryIds(ctx) {
150
148
  // worthwhile parallel work. Only a terminal node is ever told `push final` (a
151
149
  // resident finishes by yielding or being closed); only an orchestrator already
152
150
  // HAS a roadmap to checkpoint before it yields.
153
- // ---------------------------------------------------------------------------
154
151
  const STEER_STEP = 10_000;
155
152
  // Shared escalation schedule (both lifecycles). Tightens as it climbs:
156
153
  // 130k, 150k, 170k, 185k, 200k, then every 10k (210k, 220k, …).
@@ -233,9 +230,7 @@ export function steerNote(at, lifecycle, mode) {
233
230
  }
234
231
  return `Context ~${k}k — this is getting long. Wrap up now before this context overflows: \`crtr push final\` if you're close, otherwise \`crtr node yield\` immediately to continue in a fresh window against your goal and your note.`;
235
232
  }
236
- // ---------------------------------------------------------------------------
237
233
  // Extension
238
- // ---------------------------------------------------------------------------
239
234
  /**
240
235
  * Register the canvas turn and settlement handlers on `pi`.
241
236
  *
@@ -245,7 +240,7 @@ export function steerNote(at, lifecycle, mode) {
245
240
  * per node lifecycle, matching how pi loads extensions).
246
241
  */
247
242
  export function registerCanvasStophook(pi) {
248
- const nodeId = process.env['CRTR_NODE_ID'];
243
+ const nodeId = envNodeId();
249
244
  if (nodeId === undefined || nodeId.trim() === '')
250
245
  return; // not a canvas node
251
246
  const jobDirPath = jobDir(nodeId);
@@ -310,7 +305,6 @@ export function registerCanvasStophook(pi) {
310
305
  touchBusy(nodeId);
311
306
  clearFault(nodeId, { link: 'daemon→node' });
312
307
  };
313
- // ---------------------------------------------------------------------------
314
308
  // session_start — capture pi's session id, and detect `/new`.
315
309
  //
316
310
  // pi tags each session_start with a `reason`: 'startup' on boot (a fresh
@@ -327,7 +321,6 @@ export function registerCanvasStophook(pi) {
327
321
  //
328
322
  // `/new` splits by who ran it: crtrd derives rootness from the node row and
329
323
  // either directs a root relaunch or resets a child's session coordinates.
330
- // ---------------------------------------------------------------------------
331
324
  pi.on('session_start', async (event, ctx) => {
332
325
  try {
333
326
  const id = ctx?.sessionManager?.getSessionId?.();
@@ -390,11 +383,9 @@ export function registerCanvasStophook(pi) {
390
383
  });
391
384
  }
392
385
  });
393
- // ---------------------------------------------------------------------------
394
386
  // agent_start — pi entered a turn. Mark the node mid-turn (busy) so a
395
387
  // focus-away while it is genuinely working backstages it (Invariant F2)
396
388
  // rather than reaping it. Cleared only after the whole run settles.
397
- // ---------------------------------------------------------------------------
398
389
  pi.on('agent_start', () => {
399
390
  // A fresh turn started. Keep any active fault marker in place so the daemon's
400
391
  // retry accounting survives a failed retry cycle; just mark the turn busy.
@@ -403,7 +394,6 @@ export function registerCanvasStophook(pi) {
403
394
  }
404
395
  catch { /* best-effort */ }
405
396
  });
406
- // ---------------------------------------------------------------------------
407
397
  // input — a new user-directed run is beginning. This is the ONLY place stop
408
398
  // signals are cleared: `agent_start` re-fires for pi's automatic retries and
409
399
  // post-compaction continuations within the SAME run, so clearing there would
@@ -413,18 +403,15 @@ export function registerCanvasStophook(pi) {
413
403
  // `agent_settled` consumes them; a leftover from an errored or interrupted run
414
404
  // of this same broker is discarded here, when the next prompt arrives (the pid
415
405
  // stamp only rules out a PRIOR broker's markers, not this broker's own).
416
- // ---------------------------------------------------------------------------
417
406
  pi.on('input', () => {
418
407
  try {
419
408
  clearStopSignals(nodeId);
420
409
  }
421
410
  catch { /* best-effort */ }
422
411
  });
423
- // ---------------------------------------------------------------------------
424
412
  // tool_execution_start — capture the live "what is it doing" cue. Writes the
425
413
  // one-line tool summary to telemetry.json so out-of-process readers (the nav
426
414
  // chrome) show it inline without a second file or any extra read on their side.
427
- // ---------------------------------------------------------------------------
428
415
  pi.on('tool_execution_start', (event) => {
429
416
  try {
430
417
  lastActivity = summarizeActivity(String(event?.toolName ?? ''), event?.args);
@@ -434,7 +421,6 @@ export function registerCanvasStophook(pi) {
434
421
  }
435
422
  catch { /* best-effort */ }
436
423
  });
437
- // ---------------------------------------------------------------------------
438
424
  // tool_execution_update — wedge heartbeat + fault clear only. Fired with
439
425
  // partial/streaming tool output (when a tool reports progress); throttled via
440
426
  // `heartbeat()` since it can arrive many times per second. Most tools (e.g.
@@ -442,27 +428,23 @@ export function registerCanvasStophook(pi) {
442
428
  // for them — it exists so any tool that DOES stream partial output (now or in
443
429
  // the future) counts as live progress instead of tripping the wedge detector,
444
430
  // AND clears any wedge notice that already fired before this progress resumed.
445
- // ---------------------------------------------------------------------------
446
431
  pi.on('tool_execution_update', () => {
447
432
  try {
448
433
  heartbeat();
449
434
  }
450
435
  catch { /* best-effort */ }
451
436
  });
452
- // ---------------------------------------------------------------------------
453
437
  // message_update — wedge heartbeat + fault clear only. Fired token-by-token
454
438
  // while the assistant is actively streaming a reply — genuine progress,
455
439
  // throttled the same way, and equally clears a stale wedge notice if streaming
456
440
  // resumes before a coarser boundary. A node stuck streaming forever without
457
441
  // ever firing this is exactly the daemon's busy+quiet wedge signature.
458
- // ---------------------------------------------------------------------------
459
442
  pi.on('message_update', () => {
460
443
  try {
461
444
  heartbeat();
462
445
  }
463
446
  catch { /* best-effort */ }
464
447
  });
465
- // ---------------------------------------------------------------------------
466
448
  // tool_execution_end — IMMEDIATE refresh-yield. When a tool this turn set
467
449
  // intent='refresh' (the node ran `crtr node yield`), shut the broker down NOW
468
450
  // instead of letting the model keep burning its bloated context to the turn's
@@ -494,11 +476,9 @@ export function registerCanvasStophook(pi) {
494
476
  }
495
477
  catch { /* best-effort */ }
496
478
  });
497
- // ---------------------------------------------------------------------------
498
479
  // session_shutdown — Pi's clean /quit fact goes to crtrd, which owns the
499
480
  // finish transition, focus teardown, presence clear, and fault clear. Other
500
481
  // session swaps keep the same node and need no durable settlement.
501
- // ---------------------------------------------------------------------------
502
482
  pi.on('session_shutdown', async (event, ctx) => {
503
483
  clearBusy(nodeId); // turn marker is meaningless once Pi is exiting
504
484
  if (event?.reason !== 'quit')
@@ -525,10 +505,8 @@ export function registerCanvasStophook(pi) {
525
505
  if (typeof msg.model === 'string' && msg.model !== '')
526
506
  model = msg.model;
527
507
  };
528
- // ---------------------------------------------------------------------------
529
508
  // turn_end — live telemetry refresh.
530
509
  // event shape: { message: AssistantMessage, ... }
531
- // ---------------------------------------------------------------------------
532
510
  pi.on('turn_end', async (event, ctx) => {
533
511
  accumulate(event?.message);
534
512
  // The CURRENT context size via ctx.getContextUsage() — the exact figure pi's
@@ -615,10 +593,8 @@ export function registerCanvasStophook(pi) {
615
593
  }
616
594
  catch { /* best-effort */ }
617
595
  });
618
- // ---------------------------------------------------------------------------
619
596
  // agent_settled — Pi supplies stop facts; crtrd commits every canvas effect
620
597
  // and returns the one Pi-side consequence to enact.
621
- // ---------------------------------------------------------------------------
622
598
  pi.on('agent_settled', async (_event, ctx) => {
623
599
  const event = stagedAgentEnd;
624
600
  stagedAgentEnd = null;
@@ -3,6 +3,7 @@
3
3
  // Loaded into every canvas node. Inert unless nodes/<id>/output-schema.json exists
4
4
  // and is valid. If the request file is malformed, the tool is not registered — the
5
5
  // stop-guard will reprompt the node with an explicit error about the invalid file.
6
+ import { envNodeId } from '../shared/env.js';
6
7
  import { mkdirSync, writeFileSync } from 'node:fs';
7
8
  import { dirname } from 'node:path';
8
9
  import { validateToolArguments } from '@earendil-works/pi-ai';
@@ -168,7 +169,7 @@ function toolDescription(request) {
168
169
  return 'Submit the requested one-off structured result. Calling this records the result, pushes an update report automatically, frees you from the structured-output gate, and lets you continue working.';
169
170
  }
170
171
  export function registerCanvasStructuredOutput(pi) {
171
- const nodeId = process.env['CRTR_NODE_ID'];
172
+ const nodeId = envNodeId();
172
173
  if (nodeId === undefined || nodeId.trim() === '')
173
174
  return;
174
175
  let registeredKey = null;
@@ -3,6 +3,7 @@
3
3
  // Capturing `crtr -h` builds the full configured command tree, including commands
4
4
  // discovered from the node's cwd. It runs only at session start; before_agent_start
5
5
  // injects the last successful capture without starting work or waiting.
6
+ import { envNodeId } from '../shared/env.js';
6
7
  import { execFile } from 'node:child_process';
7
8
  import { createHash } from 'node:crypto';
8
9
  import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
@@ -25,7 +26,7 @@ function injectToolGuide(systemPrompt, helpText) {
25
26
  }
26
27
  /** Register the root crtr tool-guide injection for a canvas node. */
27
28
  export function registerCanvasToolGuide(pi) {
28
- const nodeId = process.env['CRTR_NODE_ID'];
29
+ const nodeId = envNodeId();
29
30
  if (nodeId === undefined || nodeId.trim() === '')
30
31
  return;
31
32
  let helpText = '';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,93 @@
1
+ // `shared/env.ts` is the reader-side surface for the env vars listed below —
2
+ // every one of them was migrated off a scattered `process.env` read onto a
3
+ // named accessor there. This grep-enforces that boundary: outside the owner
4
+ // module itself, a read of any migrated var may live only in an explicitly
5
+ // documented exemption — a distinct, non-read use of the SAME var. Exemptions
6
+ // are itemized below so a new stray read fails loud instead of silently
7
+ // reintroducing the var outside its accessor.
8
+ import { test } from 'node:test';
9
+ import assert from 'node:assert/strict';
10
+ import { readdirSync, readFileSync, statSync } from 'node:fs';
11
+ import { join, resolve, relative } from 'node:path';
12
+ const SRC_ROOT = resolve(process.cwd(), 'src');
13
+ // Every var migrated onto an accessor in `shared/env.ts`. Complete: every
14
+ // forbidden-file sweep has landed, so this is the full migrated set.
15
+ const MIGRATED_VARS = [
16
+ 'CRTR_NODE_ID',
17
+ 'CRTR_PROFILE_ID',
18
+ 'CRTR_NODE_CWD',
19
+ 'CRTR_MODEL_INTENT',
20
+ 'CRTR_HOME',
21
+ 'CRTR_STREAM_WATCHDOG_MS',
22
+ 'CRTR_WATCHER_TICK_MS',
23
+ 'CRTR_WATCHER_DEBOUNCE_MS',
24
+ 'CRTR_RECAP_IDLE_MS',
25
+ 'CRTR_RECAP_MODEL',
26
+ 'CRTR_BASH_VALVE_MS',
27
+ 'CRTR_PIDFILE',
28
+ 'CRTR_BROKER_ENGINE',
29
+ 'CRTR_PI_BINARY',
30
+ 'CRTR_NO_DAEMON_AUTOSTART',
31
+ 'CRTRD_TCP',
32
+ 'CRTR_NO_EXPORTS',
33
+ 'CRTR_DEBUG',
34
+ 'CRTR_MAX_LIVE_BROKERS',
35
+ 'CRTR_WARN_LIVE_BROKERS',
36
+ 'CRTR_TEST_UNATTENDED_PARK_MS',
37
+ 'CRTR_TEST_PARK_SUMMARY_GRACE_MS',
38
+ ];
39
+ // Matches `process.env['VAR']`, `process.env.VAR`, or `process.env[\`VAR\`]`
40
+ // for exactly one of MIGRATED_VARS — not a longer name that merely starts
41
+ // with it (e.g. `CRTR_DEBUG_PID_LIVENESS` must NOT match `CRTR_DEBUG`).
42
+ const VAR_PATTERN = MIGRATED_VARS.join('|');
43
+ const READ_RE = new RegExp(String.raw `process\.env(?:\.(?:${VAR_PATTERN})\b|\[['"\`](?:${VAR_PATTERN})['"\`]\])`);
44
+ // Relative to src/, forward-slash form. Each entry is a genuinely distinct
45
+ // use of the SAME var name that the migration deliberately leaves in place —
46
+ // not an unmigrated read.
47
+ const EXEMPTIONS = new Map([
48
+ [
49
+ 'core/canvas/paths.ts',
50
+ 'crtrHome() is the canonical resolved-path accessor for CRTR_HOME; ' +
51
+ 'envHomeOverride() in shared/env.ts is for callers that want the raw ' +
52
+ 'override itself (see the header comment there).',
53
+ ],
54
+ [
55
+ 'core/runtime/broker.ts',
56
+ "clears CRTR_MODEL_INTENT via `delete process.env[...]` — a mutation, " +
57
+ 'not a read, so it stays here per shared/env.ts\'s header comment.',
58
+ ],
59
+ ]);
60
+ function tsFilesUnder(dir) {
61
+ const out = [];
62
+ for (const entry of readdirSync(dir)) {
63
+ const path = join(dir, entry);
64
+ const stat = statSync(path);
65
+ if (stat.isDirectory()) {
66
+ if (entry === '__tests__')
67
+ continue;
68
+ out.push(...tsFilesUnder(path));
69
+ }
70
+ else if (entry.endsWith('.ts') && !entry.endsWith('.test.ts')) {
71
+ out.push(path);
72
+ }
73
+ }
74
+ return out;
75
+ }
76
+ test('every migrated env var is read only through shared/env.ts or an explicit exemption', () => {
77
+ const offenders = [];
78
+ for (const file of tsFilesUnder(SRC_ROOT)) {
79
+ const relPath = relative(SRC_ROOT, file).split('\\').join('/');
80
+ if (relPath === 'shared/env.ts')
81
+ continue;
82
+ if (EXEMPTIONS.has(relPath))
83
+ continue;
84
+ const source = readFileSync(file, 'utf8');
85
+ const lines = source.split('\n');
86
+ lines.forEach((line, index) => {
87
+ if (READ_RE.test(line)) {
88
+ offenders.push(`${relPath}:${index + 1}: ${line.trim()}`);
89
+ }
90
+ });
91
+ }
92
+ assert.deepEqual(offenders, [], `migrated env var read(s) outside shared/env.ts and its exemptions:\n${offenders.join('\n')}`);
93
+ });
@@ -0,0 +1,68 @@
1
+ /** The current node's id (`CRTR_NODE_ID`), or undefined outside a node. */
2
+ export declare function envNodeId(): string | undefined;
3
+ /** The current node's target profile id (`CRTR_PROFILE_ID`), or undefined. */
4
+ export declare function envProfileId(): string | undefined;
5
+ /** The current node's working directory (`CRTR_NODE_CWD`), or undefined. */
6
+ export declare function envNodeCwd(): string | undefined;
7
+ /** An explicit model-routing override for this turn (`CRTR_MODEL_INTENT`), or
8
+ * undefined. Cleared (not read) via `delete process.env['CRTR_MODEL_INTENT']`
9
+ * in `runtime/broker.ts` — a mutation, not a read, so it stays there. */
10
+ export declare function envModelIntent(): string | undefined;
11
+ /** The raw `CRTR_HOME` override, unresolved. Use `crtrHome()`
12
+ * (`core/canvas/paths.ts`) to get the resolved canvas-home path; use this
13
+ * only when a caller needs the override itself — to check whether one is
14
+ * set, or to propagate it verbatim into a child process's env. */
15
+ export declare function envHomeOverride(): string | undefined;
16
+ /** Dead-provider watchdog timeout (`CRTR_STREAM_WATCHDOG_MS`), 5 minutes by
17
+ * default. See `runtime/stream-watchdog.ts` for what it guards. */
18
+ export declare function envStreamWatchdogMs(): number;
19
+ /** The canvas inbox watcher's poll tick (`CRTR_WATCHER_TICK_MS`). */
20
+ export declare function envWatcherTickMs(): number;
21
+ /** The canvas inbox watcher's debounce window (`CRTR_WATCHER_DEBOUNCE_MS`). */
22
+ export declare function envWatcherDebounceMs(): number;
23
+ /** No-new-message window before a recap is shown (`CRTR_RECAP_IDLE_MS`), 60s
24
+ * by default. */
25
+ export declare function envRecapIdleMs(): number;
26
+ /** Explicit recap-model override (`CRTR_RECAP_MODEL`), trimmed; undefined if
27
+ * unset or blank. */
28
+ export declare function envRecapModelOverride(): string | undefined;
29
+ /** The bash safety-valve deadline (`CRTR_BASH_VALVE_MS`), 5 minutes by
30
+ * default; undocumented test-only override so the E2E valve check doesn't
31
+ * sleep 5 minutes. */
32
+ export declare function envBashValveMs(): number;
33
+ /** Explicit pidfile path override (`CRTR_PIDFILE`, tests only); undefined if
34
+ * unset or blank. */
35
+ export declare function envPidfileOverride(): string | undefined;
36
+ /** The broker engine module spec (`CRTR_BROKER_ENGINE`, the T11 test seam),
37
+ * defaulting to the real SDK. `runtime/host.ts` layers `inv.env` ahead of
38
+ * this (a launch-time override mirrored into the child's env, since
39
+ * spawn-env.ts's default-deny allowlist strips `CRTR_*` from ambient env). */
40
+ export declare function envBrokerEngine(): string;
41
+ /** Test-only pi-binary substitution (`CRTR_PI_BINARY`) so the integration
42
+ * harness can point a real `crtr node new` at a deterministic fake-pi
43
+ * vehicle. Undefined in production. */
44
+ export declare function envPiBinaryOverride(): string | undefined;
45
+ /** Whether implicit daemon autostart is suppressed for this invocation
46
+ * (`CRTR_NO_DAEMON_AUTOSTART=1`). */
47
+ export declare function envNoDaemonAutostart(): boolean;
48
+ /** The `--tcp` fallback for crtrd's opt-in TCP listener (`CRTRD_TCP`), raw
49
+ * (`host:port` or undefined — absent means unix socket only). */
50
+ export declare function envCrtrdTcp(): string | undefined;
51
+ /** Kill switch for the host-exports writer/pruner (`CRTR_NO_EXPORTS=1`). */
52
+ export declare function envNoExports(): boolean;
53
+ /** Verbose-diagnostics gate for otherwise-silent best-effort catches
54
+ * (`CRTR_DEBUG=1`). Distinct from `CRTR_DEBUG_PID_LIVENESS`
55
+ * (`core/canvas/pid.ts`), a different, unrelated var. */
56
+ export declare function envDebug(): boolean;
57
+ /** Live-broker automatic-revive cap override (`CRTR_MAX_LIVE_BROKERS`); wins
58
+ * over `readConfig('user').brokerThresholds.automaticReviveCap` when set. */
59
+ export declare function envMaxLiveBrokers(): number | undefined;
60
+ /** Live-broker warning threshold override (`CRTR_WARN_LIVE_BROKERS`); wins
61
+ * over `readConfig('user').brokerThresholds.warning` when set. */
62
+ export declare function envWarnLiveBrokers(): number | undefined;
63
+ /** Test-only unattended-park interval override (`CRTR_TEST_UNATTENDED_PARK_MS`),
64
+ * gated by `envNoDaemonAutostart()` at the call site; no production default. */
65
+ export declare function envTestUnattendedParkMs(): number | undefined;
66
+ /** Test-only park-summary grace-period override
67
+ * (`CRTR_TEST_PARK_SUMMARY_GRACE_MS`); no production default. */
68
+ export declare function envTestParkSummaryGraceMs(): number | undefined;
@@ -0,0 +1,171 @@
1
+ // The reader-side surface for every environment variable crouter reads back
2
+ // out of `process.env`, outside `core/runtime/spawn-env.ts`'s writer
3
+ // allowlist. That module documents what a broker child is ADMITTED to see;
4
+ // this one documents what crouter itself reads. Two families:
5
+ //
6
+ // - Identity: raw passthrough (`string | undefined`, exactly what
7
+ // `process.env[name]` returns). Every existing call site keeps its own
8
+ // established fallback (`?? ''`, `|| null`, `?? cfg.cwd`, a presence
9
+ // check, ...) — the fallback has always been call-site-owned, not
10
+ // var-owned, so centralizing it here would be a behavior change, not a
11
+ // dedup. `CRTR_HOME` also has a resolved-path accessor, `crtrHome()` in
12
+ // `core/canvas/paths.ts`; that stays the canonical way to get the
13
+ // resolved canvas home; `envHomeOverride()` here is for the handful of
14
+ // sites that want the raw override value itself (to check presence or
15
+ // propagate it verbatim to a child env).
16
+ //
17
+ // - Tuning: parsed, with the default baked into the accessor. Each of
18
+ // these had exactly one parse site before this module existed; the
19
+ // parse logic moved here unchanged so a second site, if one appears,
20
+ // reads the single implementation instead of re-deriving it.
21
+ //
22
+ // `CRTR_DIR_NAME` is NOT here — it is a plain exported string constant
23
+ // (`types.ts`), never read off `process.env`.
24
+ // Identity
25
+ /** The current node's id (`CRTR_NODE_ID`), or undefined outside a node. */
26
+ export function envNodeId() {
27
+ return process.env['CRTR_NODE_ID'];
28
+ }
29
+ /** The current node's target profile id (`CRTR_PROFILE_ID`), or undefined. */
30
+ export function envProfileId() {
31
+ return process.env['CRTR_PROFILE_ID'];
32
+ }
33
+ /** The current node's working directory (`CRTR_NODE_CWD`), or undefined. */
34
+ export function envNodeCwd() {
35
+ return process.env['CRTR_NODE_CWD'];
36
+ }
37
+ /** An explicit model-routing override for this turn (`CRTR_MODEL_INTENT`), or
38
+ * undefined. Cleared (not read) via `delete process.env['CRTR_MODEL_INTENT']`
39
+ * in `runtime/broker.ts` — a mutation, not a read, so it stays there. */
40
+ export function envModelIntent() {
41
+ return process.env['CRTR_MODEL_INTENT'];
42
+ }
43
+ /** The raw `CRTR_HOME` override, unresolved. Use `crtrHome()`
44
+ * (`core/canvas/paths.ts`) to get the resolved canvas-home path; use this
45
+ * only when a caller needs the override itself — to check whether one is
46
+ * set, or to propagate it verbatim into a child process's env. */
47
+ export function envHomeOverride() {
48
+ return process.env['CRTR_HOME'];
49
+ }
50
+ // Tuning
51
+ /** Generic `Number(raw)` parse with a positive-finite guard, shared by every
52
+ * millisecond tuning var below (each previously reimplemented this locally,
53
+ * identically). */
54
+ function parsePositiveMs(raw, fallback) {
55
+ if (raw === undefined)
56
+ return fallback;
57
+ const n = Number(raw);
58
+ return Number.isFinite(n) && n > 0 ? n : fallback;
59
+ }
60
+ const DEFAULT_STREAM_WATCHDOG_MS = 5 * 60_000; // 5 minutes.
61
+ /** Dead-provider watchdog timeout (`CRTR_STREAM_WATCHDOG_MS`), 5 minutes by
62
+ * default. See `runtime/stream-watchdog.ts` for what it guards. */
63
+ export function envStreamWatchdogMs() {
64
+ return parsePositiveMs(process.env['CRTR_STREAM_WATCHDOG_MS'], DEFAULT_STREAM_WATCHDOG_MS);
65
+ }
66
+ const DEFAULT_WATCHER_TICK_MS = 800;
67
+ /** The canvas inbox watcher's poll tick (`CRTR_WATCHER_TICK_MS`). */
68
+ export function envWatcherTickMs() {
69
+ return parsePositiveMs(process.env['CRTR_WATCHER_TICK_MS'], DEFAULT_WATCHER_TICK_MS);
70
+ }
71
+ const DEFAULT_WATCHER_DEBOUNCE_MS = 1000;
72
+ /** The canvas inbox watcher's debounce window (`CRTR_WATCHER_DEBOUNCE_MS`). */
73
+ export function envWatcherDebounceMs() {
74
+ return parsePositiveMs(process.env['CRTR_WATCHER_DEBOUNCE_MS'], DEFAULT_WATCHER_DEBOUNCE_MS);
75
+ }
76
+ const DEFAULT_RECAP_IDLE_MS = 60_000;
77
+ /** No-new-message window before a recap is shown (`CRTR_RECAP_IDLE_MS`), 60s
78
+ * by default. */
79
+ export function envRecapIdleMs() {
80
+ return parsePositiveMs(process.env['CRTR_RECAP_IDLE_MS'], DEFAULT_RECAP_IDLE_MS);
81
+ }
82
+ /** Explicit recap-model override (`CRTR_RECAP_MODEL`), trimmed; undefined if
83
+ * unset or blank. */
84
+ export function envRecapModelOverride() {
85
+ const raw = process.env['CRTR_RECAP_MODEL'];
86
+ return raw !== undefined && raw.trim() !== '' ? raw.trim() : undefined;
87
+ }
88
+ const DEFAULT_BASH_VALVE_MS = 5 * 60 * 1000;
89
+ /** The bash safety-valve deadline (`CRTR_BASH_VALVE_MS`), 5 minutes by
90
+ * default; undocumented test-only override so the E2E valve check doesn't
91
+ * sleep 5 minutes. */
92
+ export function envBashValveMs() {
93
+ return parsePositiveMs(process.env['CRTR_BASH_VALVE_MS'], DEFAULT_BASH_VALVE_MS);
94
+ }
95
+ /** Explicit pidfile path override (`CRTR_PIDFILE`, tests only); undefined if
96
+ * unset or blank. */
97
+ export function envPidfileOverride() {
98
+ const raw = process.env['CRTR_PIDFILE'];
99
+ return raw !== undefined && raw !== '' ? raw : undefined;
100
+ }
101
+ const DEFAULT_BROKER_ENGINE = '@earendil-works/pi-coding-agent';
102
+ /** The broker engine module spec (`CRTR_BROKER_ENGINE`, the T11 test seam),
103
+ * defaulting to the real SDK. `runtime/host.ts` layers `inv.env` ahead of
104
+ * this (a launch-time override mirrored into the child's env, since
105
+ * spawn-env.ts's default-deny allowlist strips `CRTR_*` from ambient env). */
106
+ export function envBrokerEngine() {
107
+ return process.env['CRTR_BROKER_ENGINE'] ?? DEFAULT_BROKER_ENGINE;
108
+ }
109
+ /** Test-only pi-binary substitution (`CRTR_PI_BINARY`) so the integration
110
+ * harness can point a real `crtr node new` at a deterministic fake-pi
111
+ * vehicle. Undefined in production. */
112
+ export function envPiBinaryOverride() {
113
+ return process.env['CRTR_PI_BINARY'];
114
+ }
115
+ /** Whether implicit daemon autostart is suppressed for this invocation
116
+ * (`CRTR_NO_DAEMON_AUTOSTART=1`). */
117
+ export function envNoDaemonAutostart() {
118
+ return process.env['CRTR_NO_DAEMON_AUTOSTART'] === '1';
119
+ }
120
+ /** The `--tcp` fallback for crtrd's opt-in TCP listener (`CRTRD_TCP`), raw
121
+ * (`host:port` or undefined — absent means unix socket only). */
122
+ export function envCrtrdTcp() {
123
+ return process.env['CRTRD_TCP'];
124
+ }
125
+ /** Kill switch for the host-exports writer/pruner (`CRTR_NO_EXPORTS=1`). */
126
+ export function envNoExports() {
127
+ return process.env['CRTR_NO_EXPORTS'] === '1';
128
+ }
129
+ /** Verbose-diagnostics gate for otherwise-silent best-effort catches
130
+ * (`CRTR_DEBUG=1`). Distinct from `CRTR_DEBUG_PID_LIVENESS`
131
+ * (`core/canvas/pid.ts`), a different, unrelated var. */
132
+ export function envDebug() {
133
+ return process.env['CRTR_DEBUG'] === '1';
134
+ }
135
+ // Precedence — broker-supervision.ts's threshold/interval overrides. Each
136
+ // returns the raw parsed value with NO default: the caller (config for the
137
+ // thresholds, a hardcoded production constant for the intervals) supplies
138
+ // the default, and env wins over it when set. Undefined, unparseable, or
139
+ // non-positive all mean "no override" — the caller's own default applies.
140
+ function parsePositiveInteger(raw) {
141
+ if (raw === undefined || raw === '')
142
+ return undefined;
143
+ const n = Number(raw);
144
+ return Number.isSafeInteger(n) && n >= 1 ? n : undefined;
145
+ }
146
+ /** Live-broker automatic-revive cap override (`CRTR_MAX_LIVE_BROKERS`); wins
147
+ * over `readConfig('user').brokerThresholds.automaticReviveCap` when set. */
148
+ export function envMaxLiveBrokers() {
149
+ return parsePositiveInteger(process.env['CRTR_MAX_LIVE_BROKERS']);
150
+ }
151
+ /** Live-broker warning threshold override (`CRTR_WARN_LIVE_BROKERS`); wins
152
+ * over `readConfig('user').brokerThresholds.warning` when set. */
153
+ export function envWarnLiveBrokers() {
154
+ return parsePositiveInteger(process.env['CRTR_WARN_LIVE_BROKERS']);
155
+ }
156
+ function parsePositiveMsNoDefault(raw) {
157
+ if (raw === undefined)
158
+ return undefined;
159
+ const n = Number(raw);
160
+ return Number.isFinite(n) && n > 0 ? n : undefined;
161
+ }
162
+ /** Test-only unattended-park interval override (`CRTR_TEST_UNATTENDED_PARK_MS`),
163
+ * gated by `envNoDaemonAutostart()` at the call site; no production default. */
164
+ export function envTestUnattendedParkMs() {
165
+ return parsePositiveMsNoDefault(process.env['CRTR_TEST_UNATTENDED_PARK_MS']);
166
+ }
167
+ /** Test-only park-summary grace-period override
168
+ * (`CRTR_TEST_PARK_SUMMARY_GRACE_MS`); no production default. */
169
+ export function envTestParkSummaryGraceMs() {
170
+ return parsePositiveMsNoDefault(process.env['CRTR_TEST_PARK_SUMMARY_GRACE_MS']);
171
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.233",
3
+ "version": "0.3.234",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -74,6 +74,8 @@
74
74
  "typecheck:pi-packages": "npx tsc -p src/builtin-pi-packages/pi-crtr-extensions/tsconfig.json",
75
75
  "test:build-output": "node scripts/build-concurrency-test.mjs",
76
76
  "check:cli-no-canvas": "node scripts/check-cli-no-canvas.mjs",
77
+ "check:daemon-no-barrel": "node scripts/check-daemon-no-barrel.mjs",
78
+ "check:quote-style": "node scripts/check-quote-style.mjs",
77
79
  "postinstall": "node scripts/postinstall.mjs",
78
80
  "install-runtime": "node scripts/install-runtime.mjs",
79
81
  "prepack": "node scripts/runtime-lock.mjs prepack",
package/runtime.lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.233",
3
+ "version": "0.3.234",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/crouter",
9
- "version": "0.3.233",
9
+ "version": "0.3.234",
10
10
  "hasInstallScript": true,
11
11
  "license": "MIT",
12
12
  "dependencies": {
@@ -1,47 +0,0 @@
1
- import { type DashboardRow } from './render-source.js';
2
- export * from './render-source.js';
3
- /**
4
- * Render the subscription sub-DAG rooted at `rootId` as an ASCII tree.
5
- * The root is the first line (no connector prefix); children are indented.
6
- *
7
- * Each line: `<glyph> <name> [<kind>/<mode>] ctx <Nk>[ ⚑<asks>]`
8
- *
9
- * Returns a multi-line string (no trailing newline).
10
- */
11
- export declare function renderTree(rootId: string): string;
12
- /**
13
- * Render all canvas roots as a forest. A root is a node with no subscribers
14
- * (no one subscribes to it = it has no managers in the org chart).
15
- *
16
- * If there are no roots on the canvas, returns a placeholder string.
17
- */
18
- export declare function renderForest(): string;
19
- /** One row per node visible in the sub-DAG of `rootId` (including root). */
20
- export declare function dashboardRows(rootId: string): DashboardRow[];
21
- /**
22
- * CHEAP boot builder — one row per node across the entire canvas, with only the
23
- * fields that need no per-node meta/telemetry/session read. Two db queries total:
24
- * `listNodes()` + `listFocuses()` (the focus set replaces per-node getFocusByNode
25
- * calls). See {@link dashboardRowFromNodeRow} for the per-row projection, and
26
- * {@link enrichRow}/{@link enrichRows}/{@link loadPreview} for the lazy fields.
27
- */
28
- export declare function dashboardRowsAll(): DashboardRow[];
29
- /** Fold the cheap-boot row's deferred fields in for ONE row: the full label
30
- * (meta.description → fullName), ctx tokens (telemetry.json), and ⚑ asks. One
31
- * meta read + one telemetry read + one ticket scan. Idempotent (no-op once enriched).
32
- * For a batch, prefer {@link enrichRows} — it scans each cwd's ticket inbox once. */
33
- export declare function enrichRow(row: DashboardRow): DashboardRow;
34
- /** Batch {@link enrichRow}: enrich every not-yet-enriched row, scanning each
35
- * distinct cwd's ticket inbox exactly ONCE (via `ticketCountsForNodes`) instead
36
- * of per row. Use this for a whole viewport / the full forest; mutates each row in place. */
37
- export declare function enrichRows(rows: DashboardRow[]): void;
38
- /** Load the SELECTED row's preview text: the spawn `goal` (initial-prompt.md) plus
39
- * the whole-conversation `prompts` and the `lastAssistant` reply — the latter two
40
- * folded into ONE session-file read (see {@link readSessionParts}). Mutates the row
41
- * in place; idempotent. Call only for the cursor row (and lazily/in-background to
42
- * warm the prompt super-search corpus), never on the boot path. */
43
- export declare function loadPreview(row: DashboardRow): DashboardRow;
44
- /** {@link isStreaming} keyed by node id alone — hydrates the broker pid off the
45
- * db row. The exported "is this node actively generating right now?" guard so a
46
- * reap never nukes a node mid-first-turn before its output lands on disk. */
47
- export declare function isNodeStreaming(nodeId: string): boolean;