@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
@@ -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.232",
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.232",
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.232",
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;
@@ -1,245 +0,0 @@
1
- // render.ts — the db-backed (sync, `openDb`) half of canvas rendering.
2
- //
3
- // Holds the SYNC renderers that read the local canvas.db directly
4
- // (renderTree/renderForest/dashboardRows/dashboardRowsAll/enrichRow(s)/loadPreview
5
- // /isNodeStreaming). The openDb-FREE `*FromSource` variants + every pure/disk
6
- // helper they share live in ./render-source.ts; this module imports those helpers
7
- // (one direction) and RE-EXPORTS the whole render-source module, so existing
8
- // importers of `render.js` keep resolving both the sync and the FromSource APIs
9
- // unchanged. A caller that must stay off openDb imports from ./render-source.js
10
- // directly instead.
11
- //
12
- // `subscriptionsOf(nodeId)` returns the nodes a node subscribes to (its reports /
13
- // children); walking it recursively walks DOWN the org chart.
14
- import { getNode, listNodes, subscriptionsOf, view } from './canvas.js';
15
- import { fullName } from './labels.js';
16
- import { countTickets, ticketCountsForNodes } from './attention.js';
17
- import { listFocuses } from './focuses.js';
18
- import { resolveNodeVisual, faultSummary } from './status-glyph.js';
19
- import { readNodeTelemetry, fmtCtx, hangingFor, isStreaming, dashboardRowFromNodeRow, readGoalText, readSessionParts, } from './render-source.js';
20
- // Re-export the openDb-free half so `render.js` importers keep resolving the
21
- // FromSource variants + shared types/helpers unchanged.
22
- export * from './render-source.js';
23
- // ---------------------------------------------------------------------------
24
- // Tree builder (sync, db-backed)
25
- // ---------------------------------------------------------------------------
26
- /** Build one line of the ASCII tree. */
27
- function nodeLine(nodeId, indent, connector) {
28
- const node = getNode(nodeId);
29
- if (node === null) {
30
- // Node id is in the db but meta.json is gone — paranoid guard.
31
- return `${indent}${connector}? <missing meta: ${nodeId}>`;
32
- }
33
- const hanging = hangingFor(node);
34
- const glyph = resolveNodeVisual(node.status, { hanging }).glyph;
35
- const tel = readNodeTelemetry(nodeId);
36
- const ctx = fmtCtx(tel.tokens_in);
37
- const asks = countTickets(nodeId);
38
- const askSuffix = asks > 0 ? ` ⚑${asks}` : '';
39
- const faultSuffix = hanging !== null ? ` · ${faultSummary(hanging)}` : '';
40
- return `${indent}${connector}${glyph} ${fullName(node)} [${node.kind}/${node.mode}] ctx ${ctx}${askSuffix}${faultSuffix}`;
41
- }
42
- /**
43
- * Recursively walk the subscription sub-DAG rooted at `nodeId`, appending
44
- * rendered lines to `out`. Cycle-safe via `visited`.
45
- */
46
- function walkTree(nodeId, indent, isLast, visited, out) {
47
- // Guard: if we have already rendered this node in this traversal, emit a
48
- // back-ref marker instead of recursing (prevents infinite loops in graphs
49
- // with cycles introduced by manual edge manipulation).
50
- if (visited.has(nodeId)) {
51
- // The line for this node was already emitted by the caller; just return.
52
- return;
53
- }
54
- visited.add(nodeId);
55
- const connector = isLast ? '└─ ' : '├─ ';
56
- out.push(nodeLine(nodeId, indent, connector));
57
- const children = subscriptionsOf(nodeId);
58
- const childIndent = indent + (isLast ? ' ' : '│ ');
59
- for (let i = 0; i < children.length; i++) {
60
- const child = children[i];
61
- const childIsLast = i === children.length - 1;
62
- if (visited.has(child.node_id)) {
63
- // Cycle reference — show the back-edge without recursing.
64
- const cycleConnector = childIsLast ? '└─ ' : '├─ ';
65
- out.push(`${childIndent}${cycleConnector}↺ <cycle: ${child.node_id}>`);
66
- continue;
67
- }
68
- walkTree(child.node_id, childIndent, childIsLast, visited, out);
69
- }
70
- }
71
- // ---------------------------------------------------------------------------
72
- // Public API (sync)
73
- // ---------------------------------------------------------------------------
74
- /**
75
- * Render the subscription sub-DAG rooted at `rootId` as an ASCII tree.
76
- * The root is the first line (no connector prefix); children are indented.
77
- *
78
- * Each line: `<glyph> <name> [<kind>/<mode>] ctx <Nk>[ ⚑<asks>]`
79
- *
80
- * Returns a multi-line string (no trailing newline).
81
- */
82
- export function renderTree(rootId) {
83
- const node = getNode(rootId);
84
- if (node === null)
85
- return `? <missing node: ${rootId}>`;
86
- const tel = readNodeTelemetry(rootId);
87
- const ctx = fmtCtx(tel.tokens_in);
88
- const asks = countTickets(rootId);
89
- const askSuffix = asks > 0 ? ` ⚑${asks}` : '';
90
- const hanging = hangingFor(node);
91
- const glyph = resolveNodeVisual(node.status, { hanging }).glyph;
92
- const faultSuffix = hanging !== null ? ` · ${faultSummary(hanging)}` : '';
93
- const out = [];
94
- out.push(`${glyph} ${fullName(node)} [${node.kind}/${node.mode}] ctx ${ctx}${askSuffix}${faultSuffix}`);
95
- // visited starts with root already rendered (walkTree doesn't re-emit root).
96
- const visited = new Set([rootId]);
97
- const children = subscriptionsOf(rootId);
98
- for (let i = 0; i < children.length; i++) {
99
- const child = children[i];
100
- const isLast = i === children.length - 1;
101
- walkTree(child.node_id, '', isLast, visited, out);
102
- }
103
- return out.join('\n');
104
- }
105
- /**
106
- * Render all canvas roots as a forest. A root is a node with no subscribers
107
- * (no one subscribes to it = it has no managers in the org chart).
108
- *
109
- * If there are no roots on the canvas, returns a placeholder string.
110
- */
111
- export function renderForest() {
112
- const all = listNodes();
113
- if (all.length === 0)
114
- return '(canvas is empty)';
115
- // A root has no subscribers (nobody is watching it). We discover this by
116
- // looking for nodes whose node_id never appears as a "to" side of a
117
- // subscribes_to edge — equivalently, nodes with parent === null are the
118
- // authoritative roots per the spawn contract (spawn sets parent and records
119
- // a spawned_by edge + subscribe). Fall back to parent===null because querying
120
- // the full edge table would require opening the db here.
121
- //
122
- // Fine to use parent===null: roots are created by bare `crtr` / `node new --root`
123
- // without a parent; non-roots always have a parent.
124
- //
125
- // Filter to LIVE roots: each `/new` parks a `done` root (option C relaunch)
126
- // with parent===null, so an unfiltered forest would render every parked root
127
- // as a sibling tree and clutter the dashboard. Showing only active|idle roots
128
- // drops parked (`done`) roots and, as a bonus, stray `dead`/`canceled` roots.
129
- // Parked roots stay reachable by id (inspect / revive / focus).
130
- const roots = all.filter((n) => n.parent === null && (n.status === 'active' || n.status === 'idle'));
131
- // No LIVE roots: render an empty/placeholder forest rather than resurrecting
132
- // parked (`done`) / dead / canceled roots. The live-only filter is the intent;
133
- // falling back to all-status roots would re-clutter the dashboard with the very
134
- // parked trees the filter drops (e.g. a sole root `/quit`'d with no `/new`).
135
- // Parked roots stay reachable by id (inspect / revive / focus).
136
- if (roots.length === 0)
137
- return '(no live roots)';
138
- const parts = [];
139
- for (const r of roots) {
140
- parts.push(renderTree(r.node_id));
141
- }
142
- return parts.join('\n\n');
143
- }
144
- // ---------------------------------------------------------------------------
145
- // Structured row builder (sync, db-backed)
146
- // ---------------------------------------------------------------------------
147
- /** One row per node visible in the sub-DAG of `rootId` (including root). */
148
- export function dashboardRows(rootId) {
149
- const ids = [rootId, ...view(rootId)];
150
- return ids.flatMap((id) => {
151
- const node = getNode(id);
152
- if (node === null)
153
- return [];
154
- const tel = readNodeTelemetry(id);
155
- return [{
156
- node_id: id,
157
- name: fullName(node),
158
- handle: node.name,
159
- description: node.description,
160
- status: node.status,
161
- kind: node.kind,
162
- mode: node.mode,
163
- ctx_tokens: tel.tokens_in ?? 0,
164
- asks: countTickets(id),
165
- cwd: node.cwd,
166
- created: node.created,
167
- }];
168
- });
169
- }
170
- /**
171
- * CHEAP boot builder — one row per node across the entire canvas, with only the
172
- * fields that need no per-node meta/telemetry/session read. Two db queries total:
173
- * `listNodes()` + `listFocuses()` (the focus set replaces per-node getFocusByNode
174
- * calls). See {@link dashboardRowFromNodeRow} for the per-row projection, and
175
- * {@link enrichRow}/{@link enrichRows}/{@link loadPreview} for the lazy fields.
176
- */
177
- export function dashboardRowsAll() {
178
- const focusedNodeIds = new Set(listFocuses().map((f) => f.node_id));
179
- return listNodes().map((row) => dashboardRowFromNodeRow(row, focusedNodeIds, false));
180
- }
181
- // ---------------------------------------------------------------------------
182
- // Lazy enrichment API (sync, db-backed) — fold the expensive per-node reads into
183
- // rows on demand, for the VISIBLE viewport / top tiers only (never all up front).
184
- // Each function mutates the row in place and is idempotent via a guard flag.
185
- // ---------------------------------------------------------------------------
186
- /** Fold the cheap-boot row's deferred fields in for ONE row: the full label
187
- * (meta.description → fullName), ctx tokens (telemetry.json), and ⚑ asks. One
188
- * meta read + one telemetry read + one ticket scan. Idempotent (no-op once enriched).
189
- * For a batch, prefer {@link enrichRows} — it scans each cwd's ticket inbox once. */
190
- export function enrichRow(row) {
191
- if (row.enriched === true)
192
- return row;
193
- const meta = getNode(row.node_id);
194
- if (meta !== null) {
195
- row.name = fullName(meta);
196
- row.handle = meta.name;
197
- row.description = meta.description;
198
- }
199
- row.ctx_tokens = readNodeTelemetry(row.node_id).tokens_in ?? 0;
200
- row.asks = countTickets(row.node_id);
201
- row.enriched = true;
202
- return row;
203
- }
204
- /** Batch {@link enrichRow}: enrich every not-yet-enriched row, scanning each
205
- * distinct cwd's ticket inbox exactly ONCE (via `ticketCountsForNodes`) instead
206
- * of per row. Use this for a whole viewport / the full forest; mutates each row in place. */
207
- export function enrichRows(rows) {
208
- const todo = rows.filter((r) => r.enriched !== true);
209
- if (todo.length === 0)
210
- return;
211
- const asks = ticketCountsForNodes(todo.map((r) => r.node_id));
212
- for (const row of todo) {
213
- const meta = getNode(row.node_id);
214
- if (meta !== null) {
215
- row.name = fullName(meta);
216
- row.handle = meta.name;
217
- row.description = meta.description;
218
- }
219
- row.ctx_tokens = readNodeTelemetry(row.node_id).tokens_in ?? 0;
220
- row.asks = asks[row.node_id] ?? 0;
221
- row.enriched = true;
222
- }
223
- }
224
- /** Load the SELECTED row's preview text: the spawn `goal` (initial-prompt.md) plus
225
- * the whole-conversation `prompts` and the `lastAssistant` reply — the latter two
226
- * folded into ONE session-file read (see {@link readSessionParts}). Mutates the row
227
- * in place; idempotent. Call only for the cursor row (and lazily/in-background to
228
- * warm the prompt super-search corpus), never on the boot path. */
229
- export function loadPreview(row) {
230
- if (row.previewLoaded === true)
231
- return row;
232
- row.goal = readGoalText(row.node_id);
233
- const meta = getNode(row.node_id);
234
- const { prompts, lastAssistant } = readSessionParts(meta?.pi_session_file);
235
- row.prompts = prompts;
236
- row.lastAssistant = lastAssistant;
237
- row.previewLoaded = true;
238
- return row;
239
- }
240
- /** {@link isStreaming} keyed by node id alone — hydrates the broker pid off the
241
- * db row. The exported "is this node actively generating right now?" guard so a
242
- * reap never nukes a node mid-first-turn before its output lands on disk. */
243
- export function isNodeStreaming(nodeId) {
244
- return isStreaming(nodeId, getNode(nodeId)?.pi_pid ?? null);
245
- }