@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
@@ -43,9 +43,7 @@ export const FAIL_BEFORE_SESSION_START_ONCE = '__FAIL_BEFORE_SESSION_START_ONCE_
43
43
  * no turn) — the shape a broker whose model resolved but whose provider has
44
44
  * no installed credential produces ("No API key found for <provider>"). */
45
45
  export const REJECT_PROMPT_CALL = '__REJECT_PROMPT_CALL__';
46
- // ---------------------------------------------------------------------------
47
46
  // node dir / proof helpers
48
- // ---------------------------------------------------------------------------
49
47
  function nodeDirFromEnv() {
50
48
  const home = (process.env['CRTR_HOME'] ?? '').trim();
51
49
  const nodeId = (process.env['CRTR_NODE_ID'] ?? '').trim();
@@ -70,12 +68,10 @@ function recordError(dir, msg) {
70
68
  /* ignore */
71
69
  }
72
70
  }
73
- // ---------------------------------------------------------------------------
74
71
  // SessionManager — the broker calls .open(path) (resume) or .create(cwd) (fresh)
75
72
  // and hands the result to createAgentSession. sessionId/sessionFile round-trip
76
73
  // through it, so a resume (`--session <pi_session_file>`) re-opens the SAME
77
74
  // .jsonl the fresh start created — the load-bearing identity for revive.
78
- // ---------------------------------------------------------------------------
79
75
  export class SessionManager {
80
76
  sessionId;
81
77
  sessionFile;
@@ -138,7 +134,6 @@ export class SessionManager {
138
134
  return this.leafId;
139
135
  }
140
136
  }
141
- // ---------------------------------------------------------------------------
142
137
  // AgentSessionEvent stream synthesis. The fake emits a
143
138
  // REALISTIC streaming assistant turn through session.subscribe — the SAME channel
144
139
  // the real pi engine feeds the broker's fan-out — so the frames a `crtr surface attach`
@@ -150,7 +145,6 @@ export class SessionManager {
150
145
  // union, so a drift in the shape of any variant emitTurn() constructs (the
151
146
  // streaming subset: the message_*, tool_execution_*, agent/turn start+end events)
152
147
  // fails the build, not a test.
153
- // ---------------------------------------------------------------------------
154
148
  /** A minimal but fully-typed AssistantMessage. `pad` bytes of filler text let a
155
149
  * test size a single frame to multiple MiB (G8 backpressure flood). */
156
150
  function assistantMessage(text, pad = 0) {
@@ -403,7 +397,7 @@ class FakeSession {
403
397
  this.recordModel();
404
398
  return Promise.resolve();
405
399
  }
406
- // --- list_models / cycle_model read surface (real-SDK parity) ----------------
400
+ // list_models / cycle_model read surface (real-SDK parity)
407
401
  /** The broker's read-op picker data (buildListModelsData → registryOf(session))
408
402
  * reads this. For a model-less boot it is the self-healing mask proxy — see
409
403
  * modelRt. */
@@ -448,11 +442,11 @@ class FakeSession {
448
442
  /* best effort */
449
443
  }
450
444
  }
451
- // --- naming is cosmetic (broker calls it in a try/catch) ---------------------
445
+ // naming is cosmetic (broker calls it in a try/catch)
452
446
  setSessionName(_name) {
453
447
  /* no-op recording stub */
454
448
  }
455
- // --- controller-drive stubs (no controller connects in these tests) ----------
449
+ // controller-drive stubs (no controller connects in these tests)
456
450
  prompt(text, _options) {
457
451
  // Rejection seam: the engine refuses the call itself (pi's no-provider-
458
452
  // credential shape) — the promise rejects and NO lifecycle event fires.
@@ -865,7 +859,7 @@ class FakeSession {
865
859
  /* best effort */
866
860
  }
867
861
  }
868
- // --- the ctx passed to fired handlers (union across both focus extensions) ---
862
+ // the ctx passed to fired handlers (union across both focus extensions)
869
863
  buildCtx() {
870
864
  return {
871
865
  sessionManager: {
@@ -1250,16 +1244,12 @@ export async function createAgentSessionRuntime(createRuntime, options) {
1250
1244
  const initial = await createRuntime(options);
1251
1245
  return new FakeAgentSessionRuntime(createRuntime, options.cwd, options.agentDir, initial.session, initial.services);
1252
1246
  }
1253
- // ---------------------------------------------------------------------------
1254
1247
  // VERSION — set to the SDK's published version so assertEngineVersion (which
1255
1248
  // only logs, never throws) emits no spurious mismatch warning.
1256
- // ---------------------------------------------------------------------------
1257
1249
  export const VERSION = '0.78.1';
1258
- // ---------------------------------------------------------------------------
1259
1250
  // Parse the broker-launch.json recipe the host serialized (the PiInvocation
1260
1251
  // buildPiArgv produced) for the proof shape — the same `-e`/`-n`/positional
1261
1252
  // vocabulary fake-pi-host parses off its argv.
1262
- // ---------------------------------------------------------------------------
1263
1253
  function readLaunch(dir) {
1264
1254
  let argv = [];
1265
1255
  try {
@@ -61,7 +61,7 @@ if (home === '')
61
61
  fail('CRTR_HOME missing in env');
62
62
  const nodeDir = join(home, 'nodes', nodeId);
63
63
  mkdirSync(nodeDir, { recursive: true });
64
- // --- parse the argv the runtime built (buildPiArgv → piCommand) ------------
64
+ // parse the argv the runtime built (buildPiArgv → piCommand)
65
65
  const extPaths = [];
66
66
  let sessionArg;
67
67
  let label;
@@ -167,7 +167,7 @@ const ctx = {
167
167
  /* spike: no-op */
168
168
  },
169
169
  };
170
- // --- load the REAL extension modules from the -e paths ----------------------
170
+ // load the REAL extension modules from the -e paths
171
171
  const loaded = [];
172
172
  const failedExt = [];
173
173
  for (const p of extPaths) {
@@ -187,9 +187,9 @@ for (const p of extPaths) {
187
187
  recordError(`import ${p} failed: ${String(e)}`);
188
188
  }
189
189
  }
190
- // --- session_start: the real boot-confirm hook captures session id + pid -----
190
+ // session_start: the real boot-confirm hook captures session id + pid
191
191
  await fire('session_start', { reason: resuming ? 'resume' : 'startup' }, ctx);
192
- // --- the boot proof the harness asserts on ----------------------------------
192
+ // the boot proof the harness asserts on
193
193
  const boot = {
194
194
  pid: process.pid,
195
195
  nodeId,
@@ -226,7 +226,7 @@ try {
226
226
  catch {
227
227
  /* best effort */
228
228
  }
229
- // --- control loop: poll for one harness command at a time -------------------
229
+ // control loop: poll for one harness command at a time
230
230
  const cmdFile = join(nodeDir, 'fake-pi.cmd');
231
231
  const ackFile = join(nodeDir, 'fake-pi.ack');
232
232
  function ack(id, body) {
@@ -38,17 +38,13 @@ after(() => {
38
38
  rmSync(home, { recursive: true, force: true });
39
39
  delete process.env['CRTR_HOME'];
40
40
  });
41
- // ---------------------------------------------------------------------------
42
41
  // Migration v6 — the additive `focuses` table.
43
- // ---------------------------------------------------------------------------
44
42
  test('a fresh db migrates to the latest version and has the focuses table', () => {
45
43
  const db = openDb();
46
44
  assert.equal(userVersion(db), MIGRATIONS.length);
47
45
  assert.ok(tableNames(db).includes('focuses'), 'focuses table exists on a fresh db');
48
46
  });
49
- // ---------------------------------------------------------------------------
50
47
  // Canvas setters / reads — open / setOccupant / setPane / close round-trip.
51
- // ---------------------------------------------------------------------------
52
48
  test('open / setOccupant / close round-trip with the reads', () => {
53
49
  openDb();
54
50
  openFocusRow('f1', '%a', 'Sa', 'A');
@@ -85,7 +81,6 @@ test('independent focus rows do not contend', () => {
85
81
  assert.deepEqual(getFocusByNode('B'), { focus_id: 'f2', pane: '%b', session: 'Sb', node_id: 'B' });
86
82
  assert.deepEqual(listFocuses().map((f) => f.focus_id), ['f2']);
87
83
  });
88
- // ---------------------------------------------------------------------------
89
84
  // Placement reads — focusOf / isFocused / focusByPane / focusedNodes /
90
85
  // listFocuses GC dead-pane viewer rows on read (broker-host cut: liveOrPrune).
91
86
  // A row whose viewer pane no longer exists is pruned the next time it is read,
@@ -93,7 +88,6 @@ test('independent focus rows do not contend', () => {
93
88
  // registered-but-not-yet-realized viewer) is passed through. A live tmux pane
94
89
  // can't be fabricated in the ordinary suite, so we cover the prune + null-pane paths
95
90
  // here; the live-pane read is covered in the compiled-seam broker lifecycle suite.
96
- // ---------------------------------------------------------------------------
97
91
  test('placement reads GC dead-pane viewer rows and keep null-pane rows', () => {
98
92
  openDb();
99
93
  openFocusRow('f1', '%a', 'Sa', 'A'); // %a is not a live tmux pane → pruned on read
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,50 @@
1
+ import { test, before, after } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { mkdtempSync, mkdirSync, rmSync, readdirSync, statSync, writeFileSync } from 'node:fs';
4
+ import { tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
6
+ import { atomicWriteJson, atomicWriteText, readJson } from '../fs-utils.js';
7
+ let dir;
8
+ before(() => {
9
+ dir = mkdtempSync(join(tmpdir(), 'crtr-fs-utils-'));
10
+ });
11
+ after(() => {
12
+ rmSync(dir, { recursive: true, force: true });
13
+ });
14
+ test('atomicWriteText defaults a new file to 0o600', () => {
15
+ const path = join(dir, 'new-file.txt');
16
+ atomicWriteText(path, 'hello');
17
+ const mode = statSync(path).mode & 0o777;
18
+ assert.equal(mode, 0o600);
19
+ });
20
+ test('atomicWriteText preserves an existing file\'s mode on rewrite', () => {
21
+ const path = join(dir, 'existing-file.txt');
22
+ writeFileSync(path, 'first', { mode: 0o640 });
23
+ atomicWriteText(path, 'second');
24
+ const mode = statSync(path).mode & 0o777;
25
+ assert.equal(mode, 0o640);
26
+ });
27
+ test('atomicWriteText opts.mode forces a mode regardless of the existing file', () => {
28
+ const path = join(dir, 'forced-mode.txt');
29
+ writeFileSync(path, 'first', { mode: 0o640 });
30
+ atomicWriteText(path, 'second', { mode: 0o600 });
31
+ const mode = statSync(path).mode & 0o777;
32
+ assert.equal(mode, 0o600);
33
+ });
34
+ test('atomicWriteJson round-trips data and leaves no temp file after success', () => {
35
+ const path = join(dir, 'data.json');
36
+ atomicWriteJson(path, { hello: 'world' });
37
+ assert.deepEqual(readJson(path), { hello: 'world' });
38
+ const leftovers = readdirSync(dir).filter((name) => name.includes('.tmp'));
39
+ assert.deepEqual(leftovers, []);
40
+ });
41
+ test('atomicWriteText leaves no temp file behind after a forced rename failure', () => {
42
+ // Target an existing directory as the write path so ensureDir succeeds, the
43
+ // temp file is actually created, and only the rename step fails (EISDIR),
44
+ // exercising the finally-block cleanup path.
45
+ const path = join(dir, 'a-directory');
46
+ mkdirSync(path);
47
+ assert.throws(() => atomicWriteText(path, 'nope'));
48
+ const leftovers = readdirSync(dir).filter((name) => name.includes('.tmp'));
49
+ assert.deepEqual(leftovers, []);
50
+ });
@@ -36,7 +36,7 @@ import { bindDaemonEventSource, resetEventSourceForTests } from '../../events/so
36
36
  import { bindFleet, resetFleetForTests } from '../../runtime/fleet.js';
37
37
  import { readInboxSince } from '../../feed/inbox.js';
38
38
  import { capturePidCommand, recordedPidLiveness } from '../../canvas/pid.js';
39
- // --- locations --------------------------------------------------------------
39
+ // locations
40
40
  const HERE = dirname(fileURLToPath(import.meta.url));
41
41
  const TREE_ROOT = join(HERE, '..', '..', '..'); // src/ or dist/
42
42
  const CROUTER = join(TREE_ROOT, '..'); // package root
@@ -15,14 +15,12 @@ import { clearSessionCache } from '../substrate/session-cache.js';
15
15
  import { memoryDir as nodeMemoryDir } from '../runtime/memory.js';
16
16
  import { buildRefInventory } from '../memory/inline-ref-inventory.js';
17
17
  import { gatewayMemoryRows } from '../runtime/chat-inventory-rows.js';
18
- // ---------------------------------------------------------------------------
19
18
  // Wave C4 — buildRefInventory: the authoritative corpus builder. Fixture-
20
19
  // backed (node/project/user scope docs on disk), since precedence dedup,
21
20
  // referenceability-ignores-gate/slash, and directory browse names are all corpus-shape
22
21
  // facts that a pure in-memory test can't exercise. Fixture names are prefixed
23
22
  // to avoid any collision with the real shipped builtin/user corpus that
24
23
  // listAllMemoryDocs() also picks up in this environment.
25
- // ---------------------------------------------------------------------------
26
24
  describe('buildRefInventory (fixture-backed corpus)', () => {
27
25
  const NODE_ID = 'crtr-inline-ref-fixture-node';
28
26
  const PROJECT_NAMESPACE = 'crtr-inline-ref-fixture-project';
@@ -118,11 +118,9 @@ test('D2 broker fork branch: buildBrokerSession(cfg.forkFrom) yields a NEW id +
118
118
  session.dispose();
119
119
  }
120
120
  });
121
- // ---------------------------------------------------------------------------
122
121
  // resolveForkSource — a reference that resolves to no forkable session file
123
122
  // must fail loudly BEFORE launch, rather than hand the broker a source it
124
123
  // cannot fork.
125
- // ---------------------------------------------------------------------------
126
124
  function nodeRow(id, over = {}) {
127
125
  return {
128
126
  node_id: id,
@@ -27,9 +27,10 @@ import { join, dirname } from 'node:path';
27
27
  import { fileURLToPath } from 'node:url';
28
28
  import { createAgentSessionServices, createAgentSessionFromServices, SessionManager, VERSION, } from '../../runtime/broker-sdk.js';
29
29
  import { buildBrokerSession, makeBrokerUiContext, snapshotMessages } from '../../runtime/broker.js';
30
- import { isLeadingEngineCommand, resolveSteerCall, chooseGuidanceDeliveryMode, promptWithNextTurnGuidance, promptWithAdvertisedCommandInvocation, isHiddenJsonlBranchEntry, stripHiddenEntriesFromJsonlExport, engineLeadingCommandTokens, } from '../../runtime/broker/frame-dispatch.js';
30
+ import { isLeadingEngineCommand, resolveSteerCall, chooseGuidanceDeliveryMode, promptWithNextTurnGuidance, engineLeadingCommandTokens, } from '../../runtime/broker/engine-routing.js';
31
+ import { isHiddenJsonlBranchEntry, stripHiddenEntriesFromJsonlExport, } from '../../runtime/broker/frame-session.js';
31
32
  import { CANVAS_EXTENSIONS } from '../../runtime/launch.js';
32
- import { prepareAdvertisedCommandPersistence } from '../../runtime/advertised-command-invocation.js';
33
+ import { prepareAdvertisedCommandPersistence, promptWithAdvertisedCommandInvocation, } from '../../runtime/advertised-command-invocation.js';
33
34
  // The REAL engine, assembled from broker-sdk's static SDK re-exports — bypasses
34
35
  // the CRTR_BROKER_ENGINE seam entirely so these tests can never accidentally hit
35
36
  // the fake (the whole point: prove the wiring the mock hid).
@@ -74,11 +75,9 @@ function brokerExts() {
74
75
  function cfg(cwd, extra = {}) {
75
76
  return { cwd, extensionPaths: brokerExts(), ...extra };
76
77
  }
77
- // ===========================================================================
78
78
  // C3 — the SERVICES path registers an extension's custom model provider, so the
79
79
  // broker resolves a model that plain createAgentSession (no registerProvider)
80
80
  // would never see.
81
- // ===========================================================================
82
81
  test('C3 — services path registers an extension model provider; the broker session gets it', async () => {
83
82
  const cwd = mkdtempSync(join(tmpdir(), 'crtr-c3-'));
84
83
  try {
@@ -283,12 +282,10 @@ test('C3h — a cooling managed launch target boots model-less rather than falli
283
282
  // `noContextFiles: true` in buildBrokerSession, and buildContextIntro's
284
283
  // `<project_context>` block is environment-only. Covered by
285
284
  // context-intro.test.ts's environment-only regression.)
286
- // ===========================================================================
287
285
  // C2 — zero-writable dialogs resolve to deny/cancel IMMEDIATELY (noOp), never
288
286
  // hanging the turn and never waiting on a per-dialog timeout. Drives the REAL
289
287
  // makeBrokerUiContext (the exact ExtensionUIContext the SDK hands extensions),
290
288
  // with a writable() snapshot that reports zero writable viewers.
291
- // ===========================================================================
292
289
  test('C2 — zero-writable UI context resolves dialogs to deny/cancel immediately (noOp, no hang)', async () => {
293
290
  const ctx = makeBrokerUiContext({
294
291
  writable: () => [], // ZERO writable viewers attached
@@ -315,14 +312,12 @@ test('C2 — zero-writable UI context resolves dialogs to deny/cancel immediatel
315
312
  assert.equal(await ctx.input('name'), undefined, 'C2: input() cancels (undefined)');
316
313
  assert.equal(await ctx.editor('edit'), undefined, 'C2: editor() cancels (undefined)');
317
314
  });
318
- // ===========================================================================
319
315
  // M2 (review mq5wkqep / T4) — REPLACES the Wave-0 M-1 cancel-on-detach. A dialog
320
316
  // forwarded to a writable viewer that then DETACHES must NOT be cancelled: it
321
317
  // stays pending so a brief detach/reattach (or another writable viewer joining)
322
318
  // does not lose an answerable dialog. The broker-side default timeout is the ONLY
323
319
  // non-answer resolution (proven here with a short per-dialog timeout standing in
324
320
  // for the 120s default). Guards against regressing to the over-eager cancel.
325
- // ===========================================================================
326
321
  test('M2 — a forwarded dialog stays pending when its writable viewer detaches, resolving only on the broker-side timeout', async () => {
327
322
  const pending = new Map();
328
323
  let attached = true;
@@ -355,7 +350,6 @@ test('M2 — a forwarded dialog stays pending when its writable viewer detaches,
355
350
  assert.equal(resolved, false, 'M2: resolves to deny on the broker-side timeout, never hangs');
356
351
  assert.equal(pending.size, 0, 'M2: the pending registry is drained after the timeout');
357
352
  });
358
- // ===========================================================================
359
353
  // C5 — exact leading engine-command suppression and hidden display:false
360
354
  // guidance delivery ordering.
361
355
  //
@@ -374,7 +368,6 @@ test('M2 — a forwarded dialog stays pending when its writable viewer detaches,
374
368
  // verbatim sibling of the compiled-seam-covered `list_models` dispatch whose only
375
369
  // non-trivial input, `engineLeadingCommandTokens(session)`, is proven below
376
370
  // against a real session.
377
- // ===========================================================================
378
371
  test('a streaming extension command uses prompt preflight instead of the rejecting steer queue', () => {
379
372
  const session = { extensionRunner: { getCommand: (name) => (name === 'recap' ? { name: 'recap' } : undefined) } };
380
373
  assert.equal(resolveSteerCall('/recap', session), 'prompt');
@@ -555,14 +548,12 @@ test('C5 — fake-engine sendCustomMessage records the call in order without cra
555
548
  rmSync(cwd, { recursive: true, force: true });
556
549
  }
557
550
  });
558
- // ===========================================================================
559
551
  // Review fix (Major 1) — promptWithNextTurnGuidance atomically clears its own
560
552
  // pending nextTurn guidance if the prompt it rode alongside never reaches pi's
561
553
  // internal drain point (agent-session.js `prompt()` step 8) — an extension-
562
554
  // command interception (step 1, `_tryExecuteExtensionCommand`) is a genuine,
563
555
  // fully offline SDK early-return that proves the exact leak window the review
564
556
  // flagged, without touching model/auth/network.
565
- // ===========================================================================
566
557
  test('Major 1 fix — promptWithNextTurnGuidance clears its own pending guidance when the human prompt is intercepted by an extension command (never reaches pi\'s drain)', async () => {
567
558
  const cwd = mkdtempSync(join(tmpdir(), 'crtr-m1-atomic-'));
568
559
  try {
@@ -628,13 +619,11 @@ test('Major 1 fix — promptWithNextTurnGuidance leaves the queue drained (not d
628
619
  rmSync(cwd, { recursive: true, force: true });
629
620
  }
630
621
  });
631
- // ===========================================================================
632
622
  // Review fix (Major 2) — JSONL export (`session.exportToJsonl` via the broker
633
623
  // `case 'export'` handler) must honor the general `display:false` boundary,
634
624
  // not just `crtr-memory-refs` guidance. `stripHiddenEntriesFromJsonlExport`
635
625
  // rewrites the exported file in place; covers ACTUAL exported JSONL bytes,
636
626
  // not `transcriptMarkdown`.
637
- // ===========================================================================
638
627
  test('Major 2 fix — isHiddenJsonlBranchEntry recognizes both persisted display:false shapes', () => {
639
628
  assert.equal(isHiddenJsonlBranchEntry({ type: 'custom_message', display: false }), true, 'a hidden custom_message entry matches');
640
629
  assert.equal(isHiddenJsonlBranchEntry({ type: 'custom_message', display: true }), false, 'a visible custom_message entry does not match');
@@ -684,12 +673,10 @@ test('Major 2 fix — exportToJsonl (via the broker export path) strips display:
684
673
  rmSync(cwd, { recursive: true, force: true });
685
674
  }
686
675
  });
687
- // ===========================================================================
688
676
  // Review fix (Major 6, broker/protocol half) — the `list_memory_refs` read-op
689
677
  // publishes `engineLeadingCommandNames` as metadata SEPARATE from `refs`
690
678
  // (RefMeta rows), exactly matching `isLeadingEngineCommand`'s three sources,
691
679
  // so viewers can combine it with their own locally-consumed commands.
692
- // ===========================================================================
693
680
  test('Major 6 (broker half) — engineLeadingCommandTokens degrades to empty per-source without throwing, and never touches refs/RefMeta shape', () => {
694
681
  assert.deepEqual(engineLeadingCommandTokens({}), [], 'a bare session with no accessors at all degrades to an empty enumeration');
695
682
  const throwingExtButRealTemplate = {
@@ -45,10 +45,8 @@ import { pluginDisable, pluginEnable, pluginInstall } from '../../../commands/pk
45
45
  // import the real SUBTREE_NAMES (build-root.ts pulls the whole tree); a small
46
46
  // explicit set is enough for the collision contract and keeps the test cheap.
47
47
  const RESERVED = new Set(['push', 'node', 'canvas', 'sys', 'memory']);
48
- // ---------------------------------------------------------------------------
49
48
  // Fixture executable: reads one JSON request on stdin, writes one envelope.
50
49
  // Behavior is selected by req.input.mode so one binary drives the whole table.
51
- // ---------------------------------------------------------------------------
52
50
  const FIXTURE_EXEC = `#!/usr/bin/env node
53
51
  const fs = require('fs');
54
52
  let data = '';
@@ -163,9 +161,7 @@ function installPlugin(scopeRoot, name, opts = {}) {
163
161
  }
164
162
  return root;
165
163
  }
166
- // ---------------------------------------------------------------------------
167
164
  // Isolated home + workspace
168
- // ---------------------------------------------------------------------------
169
165
  let home; // becomes HOME → user scope root = $HOME/.crouter
170
166
  let userRoot;
171
167
  let projectDir; // a workspace with its own .crouter (project scope)
@@ -219,9 +215,7 @@ function leafOf(branch, name) {
219
215
  assert.ok(c !== undefined && c.kind === 'leaf', `expected leaf ${name}`);
220
216
  return c;
221
217
  }
222
- // ---------------------------------------------------------------------------
223
218
  // 1. Registry composition
224
- // ---------------------------------------------------------------------------
225
219
  describe('registry composition', () => {
226
220
  test('a fixture top-level branch composes with plugin-owned help, schema, effects, stable order', () => {
227
221
  installPlugin(userRoot, 'deploy-tools');
@@ -258,9 +252,7 @@ describe('registry composition', () => {
258
252
  assert.match(leafOut, /None\. Read-only\./);
259
253
  });
260
254
  });
261
- // ---------------------------------------------------------------------------
262
255
  // 2. Core collision
263
- // ---------------------------------------------------------------------------
264
256
  describe('core collision', () => {
265
257
  test('a fixture claiming a core top-level name is skipped + recorded', () => {
266
258
  installPlugin(userRoot, 'rogue', { manifest: commandsJson('push') });
@@ -274,9 +266,7 @@ describe('core collision', () => {
274
266
  assert.equal(collision.contributor.name, 'rogue');
275
267
  });
276
268
  });
277
- // ---------------------------------------------------------------------------
278
269
  // 3. Scope / shadowing
279
- // ---------------------------------------------------------------------------
280
270
  describe('scope shadowing', () => {
281
271
  test('a project copy shadows a user copy of the same plugin name', () => {
282
272
  installPlugin(userRoot, 'deploy-tools');
@@ -298,9 +288,7 @@ describe('scope shadowing', () => {
298
288
  assert.equal(effective.length, 0, 'the disabled higher-precedence copy must suppress the user copy');
299
289
  });
300
290
  });
301
- // ---------------------------------------------------------------------------
302
291
  // 4. Protocol integration (table-driven)
303
- // ---------------------------------------------------------------------------
304
292
  describe('protocol integration', () => {
305
293
  function showLeaf() {
306
294
  installPlugin(userRoot, 'deploy-tools');
@@ -368,9 +356,7 @@ describe('protocol integration', () => {
368
356
  });
369
357
  }
370
358
  });
371
- // ---------------------------------------------------------------------------
372
359
  // 4b. True end-to-end CLI invocation (argv → parseArgv → adapter → renderer)
373
- // ---------------------------------------------------------------------------
374
360
  describe('end-to-end CLI invocation', () => {
375
361
  // dist/cli.js is up 4 from src/core/__tests__/integration/. Requires a prior
376
362
  // `npm run build` (the harness/CI builds before tests). Drives the WHOLE seam: the
@@ -398,9 +384,7 @@ describe('end-to-end CLI invocation', () => {
398
384
  assert.equal(obj.status, 'running');
399
385
  });
400
386
  });
401
- // ---------------------------------------------------------------------------
402
387
  // 5. Lifecycle without restart (per-invocation discovery)
403
- // ---------------------------------------------------------------------------
404
388
  describe('lifecycle without restart', () => {
405
389
  test('install → appears; disable → gone; edit → visible; remove → gone', () => {
406
390
  const discover = () => {
@@ -425,9 +409,7 @@ describe('lifecycle without restart', () => {
425
409
  assert.equal(discover().length, 0);
426
410
  });
427
411
  });
428
- // ---------------------------------------------------------------------------
429
412
  // 6/7. Typed issues without executing the binary
430
- // ---------------------------------------------------------------------------
431
413
  describe('typed validation issues', () => {
432
414
  function validate(manifest, extra = {}) {
433
415
  installPlugin(userRoot, 'p', { manifest, ...extra });
@@ -513,7 +495,6 @@ describe('typed validation issues', () => {
513
495
  assert.equal(v.contributions[0].node.name, 'app');
514
496
  });
515
497
  });
516
- // ---------------------------------------------------------------------------
517
498
  // Plugin help addenda — the append-only product-guidance seam. An addendum
518
499
  // that quietly stops rendering is exactly the silent-absence class: pin that a
519
500
  // valid entry survives validation and is collected attributed, and that the
@@ -522,7 +503,6 @@ describe('typed validation issues', () => {
522
503
  // plugin's tree. The help-render lookup receives the gate's exact inputs, so a
523
504
  // map rejected at ingress renders nothing — render never disagrees with the
524
505
  // install report.
525
- // ---------------------------------------------------------------------------
526
506
  describe('plugin help addenda', () => {
527
507
  const gate = (paths) => ({
528
508
  reservedCoreNames: RESERVED,
@@ -599,11 +579,9 @@ describe('plugin help addenda', () => {
599
579
  assert.ok(out.includes('ADDENDUM RENDERED THROUGH THE REAL HELP PATH'), out.slice(-400));
600
580
  });
601
581
  });
602
- // ---------------------------------------------------------------------------
603
582
  // Lifecycle surfaces — the validator's verdict must reach the caller WITHOUT
604
583
  // executing the plugin binary, and a cross-plugin top-level collision must
605
584
  // preserve every claimant under its origin-qualified command name.
606
- // ---------------------------------------------------------------------------
607
585
  describe('lifecycle surfaces report validation without executing the plugin', () => {
608
586
  // Records the fact it ran. No validation surface may ever spawn it.
609
587
  const SENTINEL_EXEC = `#!/usr/bin/env node
@@ -664,14 +642,12 @@ process.stdout.write(JSON.stringify({ protocolVersion: 1, ok: true, result: { ap
664
642
  assertNotExecuted();
665
643
  });
666
644
  });
667
- // ---------------------------------------------------------------------------
668
645
  // Memory-corpus gate across the plugin lifecycle — install, and enable of a
669
646
  // package installed while disabled, both converge the candidate's memory store
670
647
  // onto exact canonical identity BEFORE it can mount. A local-path install stays
671
648
  // a live link, so the caller's own directory is the corpus that gets rewritten;
672
649
  // a corpus that cannot converge writes nothing and changes no config. Update
673
650
  // runs the same gate through the same helper, so it needs no cases of its own.
674
- // ---------------------------------------------------------------------------
675
651
  describe('memory corpus gate across the plugin lifecycle', () => {
676
652
  let realCwd;
677
653
  beforeEach(() => {
@@ -145,9 +145,7 @@ after(() => {
145
145
  process.env['CRTR_NODE_ID'] = prevNodeId;
146
146
  resetFleetForTests();
147
147
  });
148
- // ---------------------------------------------------------------------------
149
148
  // Command layer — the immediate-delivery wake block in node.ts
150
- // ---------------------------------------------------------------------------
151
149
  test('node message send --tier deferred to an ordinary dormant (idle-released) target does not revive it — appended and held for the next natural cycle', { timeout: 30_000 }, async () => {
152
150
  const id = 'idleReleaseTarget';
153
151
  createNode(node(id, { status: 'idle', intent: 'idle-release' }));
@@ -286,12 +284,10 @@ test('#343 (immediate path): `node message send --tier deferred --reopen` agains
286
284
  assert.equal(readInboxSince(id, undefined).length, inboxBefore, 'a rejected reopen+deferred retask must not append an inbox entry');
287
285
  assert.equal(getNode(id)?.final_report, firstFinal, 'the canonical final must survive untouched — assertFinalizedForReopen/commitReopen never ran on the rejected path');
288
286
  });
289
- // ---------------------------------------------------------------------------
290
287
  // The shared `withFreshTerminalGuard` primitive itself (Major, gh #341/#343
291
288
  // review). Every caller that needs a fresh terminal-status check and a
292
289
  // dependent write to share one transaction — the immediate deferred path
293
290
  // above, and any future arm/schedule doorway — rides this one function.
294
- // ---------------------------------------------------------------------------
295
291
  // #343 review, Major 1: the fresh terminal-status check and a guarded write
296
292
  // that depends on it must share ONE transaction, or a concurrent finish/
297
293
  // cancel/finalization can land in the gap and silently strand the write. This
@@ -366,9 +362,7 @@ test("withFreshTerminalGuard reports 'missing' — never runs the guarded body
366
362
  assert.deepEqual(outcome, { kind: 'missing' }, "the guard reports a distinct 'missing' outcome, not 'terminal' (nothing to report) and not a fabricated 'ran'");
367
363
  assert.equal(existsSync(nodeDir(targetId)), false, 'the guarded appendInbox never ran, so no orphan node dir was recreated for the deleted target');
368
364
  });
369
- // ---------------------------------------------------------------------------
370
365
  // Daemon second pass — crtrd.ts's idle-release inbox loop
371
- // ---------------------------------------------------------------------------
372
366
  // Deterministic: `headlessBrokerHost.launch` is fully STUBBED (never delegates
373
367
  // to the real launcher) so `reviveNode` cannot spawn a real detached broker/pi
374
368
  // process as a side effect of this decision test — the stubbed HostHandle's