@north-light/crouter 0.3.173 → 0.3.175

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 (674) hide show
  1. package/bin/runtime-selector.mjs +8 -1
  2. package/dist/api/__tests__/{client.test.js → serial/client.test.js} +2 -135
  3. package/dist/api/client.d.ts +12 -21
  4. package/dist/api/client.js +22 -31
  5. package/dist/api/dto/broker-ops.d.ts +158 -0
  6. package/dist/api/dto/broker-ops.js +6 -0
  7. package/dist/api/dto/crons.d.ts +6 -0
  8. package/dist/api/dto/human.d.ts +7 -1
  9. package/dist/api/dto/inbox.d.ts +1 -71
  10. package/dist/api/dto/inbox.js +1 -9
  11. package/dist/api/dto/nodes.d.ts +6 -7
  12. package/dist/api/dto/reviews.d.ts +1 -11
  13. package/dist/api/routes.d.ts +7 -4
  14. package/dist/api/routes.js +8 -5
  15. package/dist/build-root.js +3 -3
  16. package/dist/builtin-memory/04-base-worker.md +1 -4
  17. package/dist/builtin-memory/05-kinds/advisor/00-base.md +1 -5
  18. package/dist/builtin-memory/05-kinds/advisor/01-orchestrator.md +2 -7
  19. package/dist/builtin-memory/05-kinds/design/00-base.md +1 -6
  20. package/dist/builtin-memory/05-kinds/developer/00-base.md +1 -6
  21. package/dist/builtin-memory/05-kinds/explore/00-base.md +1 -4
  22. package/dist/builtin-memory/05-kinds/explore/01-orchestrator.md +1 -2
  23. package/dist/builtin-memory/05-kinds/general/00-base.md +1 -3
  24. package/dist/builtin-memory/05-kinds/plan/00-base.md +1 -6
  25. package/dist/builtin-memory/05-kinds/plan/reviewers/00-base.md +1 -2
  26. package/dist/builtin-memory/05-kinds/plan/reviewers/architecture-fit.md +1 -3
  27. package/dist/builtin-memory/05-kinds/plan/reviewers/code-smells.md +1 -3
  28. package/dist/builtin-memory/05-kinds/plan/reviewers/pattern-consistency.md +1 -3
  29. package/dist/builtin-memory/05-kinds/plan/reviewers/requirements-coverage.md +1 -3
  30. package/dist/builtin-memory/05-kinds/plan/reviewers/security.md +1 -4
  31. package/dist/builtin-memory/05-kinds/review/companion/00-base.md +2 -3
  32. package/dist/builtin-memory/05-kinds/spec/00-base.md +1 -2
  33. package/dist/builtin-memory/advisor/council.md +1 -6
  34. package/dist/builtin-memory/design.md +2 -7
  35. package/dist/builtin-memory/development.md +9 -14
  36. package/dist/builtin-memory/internal/marketplaces.md +2 -6
  37. package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
  38. package/dist/builtin-memory/internal/plugins.md +2 -8
  39. package/dist/builtin-memory/internal/storage-tiers.md +1 -2
  40. package/dist/builtin-memory/testing.md +41 -0
  41. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/{provider-rotation.test.ts → serial/provider-rotation.test.ts} +27 -179
  42. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/claude-plugin-commands.ts +5 -15
  43. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/frontmatter-rules/index.ts +1 -28
  44. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +43 -88
  45. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +7 -1
  46. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +9 -1
  47. package/dist/cli.js +2 -2
  48. package/dist/clients/attach/__tests__/attach-remote-readonly.test.js +37 -131
  49. package/dist/clients/attach/__tests__/chat-view-snapshot-ordering.test.js +71 -152
  50. package/dist/clients/attach/__tests__/context-message.test.js +16 -174
  51. package/dist/clients/attach/__tests__/crtr-output.test.js +36 -2069
  52. package/dist/clients/attach/__tests__/diagram.test.js +2 -2
  53. package/dist/clients/attach/__tests__/edit-diff.test.js +0 -4
  54. package/dist/clients/attach/__tests__/file-review-focus.test.js +2 -1
  55. package/dist/clients/attach/__tests__/group-activity.test.js +40 -229
  56. package/dist/clients/attach/__tests__/oauth-dialog-lifecycle.test.js +26 -76
  57. package/dist/clients/attach/__tests__/prompt-preview.test.js +4 -70
  58. package/dist/clients/attach/__tests__/ref-autocomplete.test.js +11 -125
  59. package/dist/clients/attach/__tests__/titled-editor-preview.test.js +14 -205
  60. package/dist/clients/attach/command.d.ts +2 -1
  61. package/dist/clients/attach/command.js +81 -76
  62. package/dist/clients/attach/input/capabilities.d.ts +27 -0
  63. package/dist/clients/attach/input/capabilities.js +96 -0
  64. package/dist/clients/attach/input/controller.d.ts +20 -182
  65. package/dist/clients/attach/input/controller.js +128 -537
  66. package/dist/clients/attach/input/overlay-owner.d.ts +41 -0
  67. package/dist/clients/attach/input/overlay-owner.js +199 -0
  68. package/dist/clients/attach/overlays/file-review.d.ts +0 -4
  69. package/dist/clients/attach/overlays/file-review.js +13 -5
  70. package/dist/clients/attach/overlays/graph.js +2 -10
  71. package/dist/clients/attach/render/chat-view.d.ts +4 -3
  72. package/dist/clients/attach/render/chat-view.js +39 -33
  73. package/dist/clients/attach/render/group-activity.d.ts +1 -0
  74. package/dist/clients/attach/render/group-activity.js +20 -13
  75. package/dist/clients/attach/render/group-recap.js +12 -3
  76. package/dist/clients/attach/session/connection.js +9 -15
  77. package/dist/clients/attach/session/editor-inventory.d.ts +6 -5
  78. package/dist/clients/attach/session/editor-inventory.js +7 -8
  79. package/dist/clients/attach/session/file-links.d.ts +13 -0
  80. package/dist/clients/attach/session/file-links.js +107 -0
  81. package/dist/clients/attach/session/frame.d.ts +3 -0
  82. package/dist/clients/attach/session/frame.js +10 -1
  83. package/dist/clients/attach/session/frames.js +2 -3
  84. package/dist/clients/attach/session/input-wiring.d.ts +4 -1
  85. package/dist/clients/attach/session/input-wiring.js +15 -14
  86. package/dist/clients/attach/session/mouse.d.ts +6 -1
  87. package/dist/clients/attach/session/mouse.js +8 -5
  88. package/dist/clients/attach/session/profile-files.js +18 -12
  89. package/dist/clients/attach/session/reconnect.js +1 -1
  90. package/dist/clients/attach/session/state-sync.js +1 -2
  91. package/dist/clients/attach/session/surface-host.d.ts +3 -2
  92. package/dist/clients/attach/session/surface-host.js +4 -4
  93. package/dist/clients/attach/slash/dispatch.d.ts +8 -31
  94. package/dist/clients/attach/slash/dispatch.js +34 -81
  95. package/dist/clients/attach/viewer.js +820 -860
  96. package/dist/clients/conversation/projection.d.ts +79 -0
  97. package/dist/clients/conversation/projection.js +341 -0
  98. package/dist/clients/inbox/__tests__/serial/inbox-controller.test.js +159 -0
  99. package/dist/clients/inbox/__tests__/serial/mount-panel.test.js +151 -0
  100. package/dist/clients/inbox/controller.d.ts +0 -4
  101. package/dist/clients/inbox/controller.js +0 -2
  102. package/dist/clients/inbox/review/__tests__/review-core.test.js +4 -293
  103. package/dist/clients/inbox/review/__tests__/teardown-notice.test.js +100 -0
  104. package/dist/clients/inbox/review/comments-client.d.ts +3 -2
  105. package/dist/clients/inbox/review/comments-client.js +12 -12
  106. package/dist/clients/inbox/review/companion-pane.d.ts +30 -0
  107. package/dist/clients/inbox/review/companion-pane.js +86 -0
  108. package/dist/clients/inbox/review/document-surface.d.ts +182 -0
  109. package/dist/clients/inbox/review/{document-region.js → document-surface.js} +252 -48
  110. package/dist/clients/inbox/review/frame.js +5 -4
  111. package/dist/clients/inbox/review/launch.d.ts +8 -8
  112. package/dist/clients/inbox/review/launch.js +52 -92
  113. package/dist/clients/inbox/review/nvim.d.ts +2 -0
  114. package/dist/clients/inbox/review/nvim.js +14 -12
  115. package/dist/clients/inbox/review/review-client.d.ts +12 -8
  116. package/dist/clients/inbox/review/review-client.js +46 -35
  117. package/dist/clients/inbox/review-adapter.d.ts +3 -10
  118. package/dist/clients/inbox/review-adapter.js +27 -19
  119. package/dist/clients/inbox/surface.d.ts +0 -4
  120. package/dist/clients/inbox/surface.js +0 -2
  121. package/dist/clients/surfaces/host.d.ts +11 -3
  122. package/dist/commands/__tests__/api-client-cold-start-diagnostic.test.js +7 -34
  123. package/dist/commands/__tests__/human.test.js +11 -322
  124. package/dist/commands/api-client.d.ts +5 -5
  125. package/dist/commands/api-client.js +6 -85
  126. package/dist/commands/canvas-browse.js +3 -29
  127. package/dist/commands/canvas-config.js +1 -1
  128. package/dist/commands/canvas-use.js +3 -3
  129. package/dist/commands/canvas.js +1 -1
  130. package/dist/commands/cron.js +5 -1
  131. package/dist/commands/human/queue.d.ts +0 -4
  132. package/dist/commands/human/queue.js +7 -40
  133. package/dist/commands/memory/list.d.ts +14 -0
  134. package/dist/commands/memory/list.js +35 -31
  135. package/dist/commands/memory/read.d.ts +7 -0
  136. package/dist/commands/memory/read.js +14 -8
  137. package/dist/commands/memory/write.js +13 -12
  138. package/dist/commands/node/bash.d.ts +1 -0
  139. package/dist/commands/node/bash.js +198 -0
  140. package/dist/commands/node/create.d.ts +23 -0
  141. package/dist/commands/node/create.js +207 -0
  142. package/dist/commands/node/inspect.d.ts +2 -0
  143. package/dist/commands/node/inspect.js +302 -0
  144. package/dist/commands/node/lifecycle.d.ts +4 -0
  145. package/dist/commands/node/lifecycle.js +415 -0
  146. package/dist/commands/node/message.d.ts +1 -0
  147. package/dist/commands/node/message.js +164 -0
  148. package/dist/commands/node/pyramid.d.ts +2 -0
  149. package/dist/commands/node/pyramid.js +79 -0
  150. package/dist/commands/node/subscription.d.ts +1 -0
  151. package/dist/commands/node/subscription.js +82 -0
  152. package/dist/commands/node/wait.d.ts +1 -0
  153. package/dist/commands/node/wait.js +159 -0
  154. package/dist/commands/node-lifecycle-revive.js +10 -57
  155. package/dist/commands/node.d.ts +0 -42
  156. package/dist/commands/node.js +11 -2065
  157. package/dist/commands/search.js +1 -1
  158. package/dist/commands/surface/node/cycle.d.ts +1 -0
  159. package/dist/commands/surface/node/cycle.js +83 -0
  160. package/dist/commands/surface/node/focus.d.ts +1 -0
  161. package/dist/commands/surface/node/focus.js +67 -0
  162. package/dist/commands/surface/node/id.d.ts +1 -0
  163. package/dist/commands/surface/node/id.js +38 -0
  164. package/dist/commands/surface/node/pin.d.ts +1 -0
  165. package/dist/commands/surface/node/pin.js +42 -0
  166. package/dist/commands/surface/node/placement.d.ts +46 -0
  167. package/dist/commands/surface/node/placement.js +124 -0
  168. package/dist/commands/surface-node.js +4 -1
  169. package/dist/commands/surface-reload.js +1 -2
  170. package/dist/commands/surface-tmux-spread.js +1 -1
  171. package/dist/commands/surface.js +5 -20
  172. package/dist/commands/sys/__tests__/setup-core.test.js +18 -271
  173. package/dist/commands/sys/config.js +6 -6
  174. package/dist/commands/sys/logs.js +1 -1
  175. package/dist/commands/sys/panels/broker-limits-panel.d.ts +17 -0
  176. package/dist/commands/sys/panels/broker-limits-panel.js +104 -0
  177. package/dist/commands/sys/panels/dependencies-panel.d.ts +14 -0
  178. package/dist/commands/sys/panels/dependencies-panel.js +80 -0
  179. package/dist/commands/sys/panels/keybindings-panel.d.ts +56 -0
  180. package/dist/commands/sys/panels/keybindings-panel.js +703 -0
  181. package/dist/commands/sys/panels/keys-panel.d.ts +16 -0
  182. package/dist/commands/sys/panels/keys-panel.js +60 -0
  183. package/dist/commands/sys/panels/models-panel.d.ts +77 -0
  184. package/dist/commands/sys/panels/models-panel.js +647 -0
  185. package/dist/commands/sys/panels/panel.d.ts +45 -0
  186. package/dist/commands/sys/panels/panel.js +137 -0
  187. package/dist/commands/sys/panels/plugins-panel.d.ts +16 -0
  188. package/dist/commands/sys/panels/plugins-panel.js +80 -0
  189. package/dist/commands/sys/panels/prefs-panel.d.ts +21 -0
  190. package/dist/commands/sys/panels/prefs-panel.js +85 -0
  191. package/dist/commands/sys/panels/provider-panel.d.ts +62 -0
  192. package/dist/commands/sys/panels/provider-panel.js +538 -0
  193. package/dist/commands/sys/settings-shell.d.ts +55 -0
  194. package/dist/commands/sys/settings-shell.js +400 -0
  195. package/dist/commands/sys/settings.d.ts +2 -0
  196. package/dist/commands/sys/settings.js +31 -0
  197. package/dist/commands/sys/setup-core.d.ts +3 -33
  198. package/dist/commands/sys/setup-core.js +27 -78
  199. package/dist/commands/sys/setup-settings-runner.d.ts +24 -0
  200. package/dist/commands/sys/setup-settings-runner.js +63 -0
  201. package/dist/commands/sys/setup-wizard.d.ts +26 -125
  202. package/dist/commands/sys/setup-wizard.js +209 -2473
  203. package/dist/commands/sys/setup.js +5 -7
  204. package/dist/commands/sys.js +3 -2
  205. package/dist/core/__tests__/broker-extension-canvas-db-boundary.test.js +50 -0
  206. package/dist/core/__tests__/broker-launch-candidates.test.js +20 -9
  207. package/dist/core/__tests__/broker-preflight.test.js +1 -1
  208. package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +108 -27
  209. package/dist/core/__tests__/canvas-inbox-watcher.test.js +14 -0
  210. package/dist/core/__tests__/canvas.test.js +2 -36
  211. package/dist/core/__tests__/close.test.js +14 -3
  212. package/dist/core/__tests__/context-intro.test.js +32 -143
  213. package/dist/core/__tests__/cron-broker-capacity.test.js +22 -3
  214. package/dist/core/__tests__/daemon-boot.test.js +2 -20
  215. package/dist/core/__tests__/daemon-wedge.test.js +1 -1
  216. package/dist/core/__tests__/dead-node-policy-table.test.js +1 -18
  217. package/dist/core/__tests__/fixtures/fake-engine.d.ts +1 -1
  218. package/dist/core/__tests__/fixtures/fake-engine.js +2 -2
  219. package/dist/core/__tests__/fixtures/fake-pi-host.js +2 -2
  220. package/dist/core/__tests__/focuses.test.js +4 -98
  221. package/dist/core/__tests__/helpers/broker-clients.d.ts +0 -3
  222. package/dist/core/__tests__/helpers/broker-clients.js +0 -14
  223. package/dist/core/__tests__/helpers/harness.d.ts +0 -8
  224. package/dist/core/__tests__/helpers/harness.js +7 -87
  225. package/dist/core/__tests__/helpers/viewer-panes.js +1 -1
  226. package/dist/core/__tests__/inline-memory-refs.test.js +5 -134
  227. package/dist/core/__tests__/kickoff.test.js +1 -1
  228. package/dist/core/__tests__/memory-resolver-precedence.test.js +29 -1
  229. package/dist/core/__tests__/migration.test.js +35 -48
  230. package/dist/core/__tests__/on-read-dedup-resume.test.js +22 -12
  231. package/dist/core/__tests__/passive-subscription.test.js +26 -49
  232. package/dist/core/__tests__/preview-registry-sync.test.js +1 -2
  233. package/dist/core/__tests__/prune.test.js +94 -1
  234. package/dist/core/__tests__/review-model-floor.test.js +0 -32
  235. package/dist/core/__tests__/seam/broker-attach-multiclient.test.js +255 -0
  236. package/dist/core/__tests__/{full → seam}/broker-attach-stream.test.js +39 -7
  237. package/dist/core/__tests__/{full → seam}/broker-crash-teardown.test.js +30 -29
  238. package/dist/core/__tests__/{full → seam}/broker-pane-resolution.test.js +54 -5
  239. package/dist/core/__tests__/{full → seam}/broker-provider-retry.test.js +134 -82
  240. package/dist/core/__tests__/{full → seam}/broker-whip-interrupt.test.js +15 -4
  241. package/dist/core/__tests__/{full/idle-release-settlement.test.js → seam/dormancy-release.test.js} +69 -17
  242. package/dist/core/__tests__/{full/yield-message-transaction.test.js → seam/yield-refresh-transaction.test.js} +31 -9
  243. package/dist/core/__tests__/secrets.test.js +1 -7
  244. package/dist/core/__tests__/{broker-fork-seam.test.js → serial/broker-fork-seam.test.js} +58 -7
  245. package/dist/core/__tests__/{broker-sdk-wiring.test.js → serial/broker-sdk-wiring.test.js} +18 -162
  246. package/dist/core/__tests__/{broker-snapshot-history.test.js → serial/broker-snapshot-history.test.js} +9 -9
  247. package/dist/core/__tests__/{command-plugins.test.js → serial/command-plugins.test.js} +105 -15
  248. package/dist/core/__tests__/{deferred-no-wake.test.js → serial/deferred-no-wake.test.js} +23 -20
  249. package/dist/core/__tests__/{flagship-lifecycle.test.js → serial/flagship-lifecycle.test.js} +7 -7
  250. package/dist/core/__tests__/{host-teardown-process-group.test.js → serial/host-teardown-process-group.test.js} +6 -6
  251. package/dist/core/__tests__/{human-deliver-e2e.test.js → serial/human-deliver-e2e.test.js} +12 -12
  252. package/dist/core/__tests__/{live-mutation.test.js → serial/live-mutation.test.js} +5 -5
  253. package/dist/core/__tests__/{refresh-stall-recycle.test.js → serial/refresh-stall-recycle.test.js} +5 -14
  254. package/dist/core/__tests__/{revive.test.js → serial/revive.test.js} +15 -100
  255. package/dist/core/__tests__/{spawn-root.test.js → serial/spawn-root.test.js} +32 -15
  256. package/dist/core/__tests__/serial/subscription-delivery.test.js +126 -0
  257. package/dist/core/__tests__/serial/tmux-surface.test.js +256 -0
  258. package/dist/core/__tests__/{worktree.test.js → serial/worktree.test.js} +15 -15
  259. package/dist/core/__tests__/session-model.test.js +0 -18
  260. package/dist/core/__tests__/spawn-worktree-id-conflict.test.js +9 -0
  261. package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +50 -0
  262. package/dist/core/broker-client/__tests__/transport-relay.test.js +15 -16
  263. package/dist/core/broker-client/__tests__/transport-socket.test.js +28 -0
  264. package/dist/core/broker-client/client.d.ts +2 -2
  265. package/dist/core/broker-client/client.js +4 -7
  266. package/dist/core/broker-client/transport-relay.d.ts +13 -19
  267. package/dist/core/broker-client/transport-relay.js +19 -34
  268. package/dist/core/broker-client/transport-socket.d.ts +2 -2
  269. package/dist/core/broker-client/transport-socket.js +9 -2
  270. package/dist/core/broker-client/transport.d.ts +7 -3
  271. package/dist/core/broker-client/transport.js +4 -4
  272. package/dist/core/canvas/__tests__/attention.test.js +1 -18
  273. package/dist/core/canvas/__tests__/remote-canvas-source.test.js +7 -64
  274. package/dist/core/canvas/__tests__/remote-transport.test.js +2 -3
  275. package/dist/core/canvas/__tests__/render-remote.test.js +7 -52
  276. package/dist/core/canvas/browse/app.d.ts +2 -17
  277. package/dist/core/canvas/browse/app.js +16 -88
  278. package/dist/core/canvas/browse/model.d.ts +0 -4
  279. package/dist/core/canvas/browse/model.js +1 -12
  280. package/dist/core/canvas/browse/render.js +6 -3
  281. package/dist/core/canvas/crons.d.ts +8 -5
  282. package/dist/core/canvas/crons.js +7 -6
  283. package/dist/core/canvas/extensions.d.ts +7 -3
  284. package/dist/core/canvas/extensions.js +16 -4
  285. package/dist/core/canvas/nav-model.d.ts +0 -4
  286. package/dist/core/canvas/nav-model.js +2 -14
  287. package/dist/core/canvas/node-order.d.ts +3 -0
  288. package/dist/core/canvas/node-order.js +12 -0
  289. package/dist/core/canvas/remote-canvas-source.d.ts +3 -6
  290. package/dist/core/canvas/remote-canvas-source.js +8 -15
  291. package/dist/core/command.js +11 -4
  292. package/dist/core/config.js +3 -1
  293. package/dist/core/events/envelope.js +1 -1
  294. package/dist/core/events/read.js +7 -21
  295. package/dist/core/events/source.d.ts +0 -2
  296. package/dist/core/events/source.js +0 -16
  297. package/dist/core/events/types.d.ts +1 -1
  298. package/dist/core/fault-classifier.d.ts +1 -1
  299. package/dist/core/feed/passive.d.ts +0 -11
  300. package/dist/core/feed/passive.js +1 -62
  301. package/dist/core/human/__tests__/{inbox-core.test.js → serial/inbox-core.test.js} +6 -6
  302. package/dist/core/keybindings/__tests__/resolve.test.js +1 -96
  303. package/dist/core/keybindings/background-bash.js +3 -4
  304. package/dist/core/keybindings/catalog.js +1 -1
  305. package/dist/core/memory/inline-ref-grammar.js +3 -3
  306. package/dist/core/memory-resolver.d.ts +11 -25
  307. package/dist/core/memory-resolver.js +51 -33
  308. package/dist/core/model-routes.d.ts +15 -0
  309. package/dist/core/model-routes.js +12 -0
  310. package/dist/core/pool-credential-store.js +1 -1
  311. package/dist/core/preview-registry.js +8 -9
  312. package/dist/core/profiles/__tests__/root-profile.test.js +4 -14
  313. package/dist/core/review/realize.d.ts +0 -13
  314. package/dist/core/review/realize.js +0 -40
  315. package/dist/core/review/types.d.ts +1 -1
  316. package/dist/core/runtime/__tests__/engine-route.test.js +2 -2
  317. package/dist/core/runtime/bearings.js +1 -11
  318. package/dist/core/runtime/broker/client-registry.d.ts +33 -0
  319. package/dist/core/runtime/broker/client-registry.js +164 -0
  320. package/dist/core/runtime/broker/daemon-ops.d.ts +19 -0
  321. package/dist/core/runtime/broker/daemon-ops.js +49 -0
  322. package/dist/core/runtime/broker/event-projection.d.ts +42 -0
  323. package/dist/core/runtime/broker/event-projection.js +178 -0
  324. package/dist/core/runtime/broker/fault-retry.d.ts +39 -0
  325. package/dist/core/runtime/broker/fault-retry.js +277 -0
  326. package/dist/core/runtime/broker/frame-dispatch.d.ts +238 -0
  327. package/dist/core/runtime/broker/frame-dispatch.js +1537 -0
  328. package/dist/core/runtime/broker/inbox.d.ts +22 -0
  329. package/dist/core/runtime/broker/inbox.js +167 -0
  330. package/dist/core/runtime/broker/passive.d.ts +16 -0
  331. package/dist/core/runtime/broker/passive.js +44 -0
  332. package/dist/core/runtime/broker/read-ops.d.ts +23 -0
  333. package/dist/core/runtime/broker/read-ops.js +150 -0
  334. package/dist/core/runtime/broker/rebind.d.ts +74 -0
  335. package/dist/core/runtime/broker/rebind.js +211 -0
  336. package/dist/core/runtime/broker/tool-groups.d.ts +39 -0
  337. package/dist/core/runtime/broker/tool-groups.js +244 -0
  338. package/dist/core/runtime/broker-extension-render.d.ts +11 -0
  339. package/dist/core/runtime/broker-extension-render.js +181 -0
  340. package/dist/core/runtime/broker-persona-guidance.d.ts +13 -0
  341. package/dist/core/runtime/broker-persona-guidance.js +58 -0
  342. package/dist/core/runtime/broker-protocol.d.ts +1 -1
  343. package/dist/core/runtime/broker-protocol.js +1 -1
  344. package/dist/core/runtime/broker.d.ts +5 -196
  345. package/dist/core/runtime/broker.js +276 -3059
  346. package/dist/core/runtime/canvas-extensions.js +11 -2
  347. package/dist/core/runtime/fault.js +1 -1
  348. package/dist/core/runtime/model-selection.d.ts +9 -0
  349. package/dist/core/runtime/model-selection.js +12 -0
  350. package/dist/core/runtime/model-swap.d.ts +3 -3
  351. package/dist/core/runtime/model-swap.js +33 -25
  352. package/dist/core/runtime/placement-tmux.d.ts +3 -14
  353. package/dist/core/runtime/placement-tmux.js +11 -80
  354. package/dist/core/runtime/placement.d.ts +4 -2
  355. package/dist/core/runtime/placement.js +7 -12
  356. package/dist/core/runtime/promote.d.ts +14 -1
  357. package/dist/core/runtime/promote.js +1 -1
  358. package/dist/core/runtime/reset.d.ts +1 -1
  359. package/dist/core/runtime/roadmap.js +1 -1
  360. package/dist/core/runtime/spawn.d.ts +8 -0
  361. package/dist/core/runtime/spawn.js +36 -6
  362. package/dist/core/runtime/stop-guard.d.ts +4 -3
  363. package/dist/core/runtime/stop-guard.js +36 -18
  364. package/dist/core/runtime/stop-signals.d.ts +4 -1
  365. package/dist/core/runtime/stream-watchdog.js +4 -5
  366. package/dist/core/runtime/structured-output.d.ts +15 -2
  367. package/dist/core/runtime/structured-output.js +35 -12
  368. package/dist/core/runtime/tmux-bindings.d.ts +25 -0
  369. package/dist/core/runtime/tmux-bindings.js +682 -0
  370. package/dist/core/runtime/tmux-chrome.d.ts +2 -1
  371. package/dist/core/runtime/tmux-chrome.js +3 -2
  372. package/dist/core/runtime/{tmux.d.ts → tmux-driver.d.ts} +18 -26
  373. package/dist/core/runtime/tmux-driver.js +598 -0
  374. package/dist/core/runtime/view-socket.d.ts +14 -0
  375. package/dist/core/runtime/view-socket.js +83 -0
  376. package/dist/core/session-model/session-state.d.ts +1 -2
  377. package/dist/core/session-model/session-state.js +5 -8
  378. package/dist/core/spawn.d.ts +1 -1
  379. package/dist/core/spawn.js +2 -2
  380. package/dist/core/substrate/gate.d.ts +1 -1
  381. package/dist/core/substrate/on-read-pure.d.ts +7 -0
  382. package/dist/core/substrate/on-read-pure.js +272 -0
  383. package/dist/core/termrender/termrender.js +32 -2
  384. package/dist/core/user-settings.d.ts +23 -1
  385. package/dist/core/user-settings.js +18 -1
  386. package/dist/daemon/api/__tests__/node-model-validation.test.js +134 -0
  387. package/dist/daemon/api/__tests__/review-terminal-conflict.test.js +98 -0
  388. package/dist/daemon/api/__tests__/{full → seam}/api-server.test.js +6 -48
  389. package/dist/daemon/api/__tests__/{full → seam}/b10-attach-modelauth.test.js +17 -44
  390. package/dist/daemon/api/__tests__/{full/push-parity.test.js → seam/leaf-api-parity.test.js} +61 -42
  391. package/dist/daemon/api/bridge.js +40 -81
  392. package/dist/daemon/api/handlers/broker-ops.d.ts +2 -0
  393. package/dist/daemon/api/handlers/broker-ops.js +383 -0
  394. package/dist/daemon/api/handlers/crons.js +9 -4
  395. package/dist/daemon/api/handlers/files.js +6 -7
  396. package/dist/daemon/api/handlers/inbox.js +2 -340
  397. package/dist/daemon/api/handlers/nodes.d.ts +10 -1
  398. package/dist/daemon/api/handlers/nodes.js +74 -39
  399. package/dist/daemon/api/handlers/review-comments.js +5 -1
  400. package/dist/daemon/api/handlers/reviews.js +0 -19
  401. package/dist/daemon/api/map.js +25 -4
  402. package/dist/daemon/api/router.js +2 -3
  403. package/dist/daemon/api/server.js +5 -7
  404. package/dist/daemon/cron-run.d.ts +4 -0
  405. package/dist/daemon/cron-run.js +30 -13
  406. package/dist/daemon/crtrd.d.ts +3 -58
  407. package/dist/daemon/crtrd.js +28 -1244
  408. package/dist/daemon/manage.js +0 -1
  409. package/dist/daemon/reconcilers/broker-supervision.d.ts +50 -0
  410. package/dist/daemon/reconcilers/broker-supervision.js +549 -0
  411. package/dist/daemon/reconcilers/cron-lane.d.ts +10 -0
  412. package/dist/daemon/reconcilers/cron-lane.js +32 -0
  413. package/dist/daemon/reconcilers/dormant-inbox.d.ts +18 -0
  414. package/dist/daemon/reconcilers/dormant-inbox.js +143 -0
  415. package/dist/daemon/reconcilers/storage-maintenance.d.ts +22 -0
  416. package/dist/daemon/reconcilers/storage-maintenance.js +213 -0
  417. package/dist/daemon/review/finish.js +2 -5
  418. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +34 -53
  419. package/dist/pi-extensions/__tests__/canvas-recap.test.js +16 -113
  420. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +72 -99
  421. package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.js +29 -12
  422. package/dist/pi-extensions/broker-local.d.ts +20 -0
  423. package/dist/pi-extensions/broker-local.js +89 -0
  424. package/dist/pi-extensions/canvas-context-intro.d.ts +3 -3
  425. package/dist/pi-extensions/canvas-context-intro.js +22 -11
  426. package/dist/pi-extensions/canvas-doc-substrate.js +17 -34
  427. package/dist/pi-extensions/canvas-goal-capture.js +7 -12
  428. package/dist/pi-extensions/canvas-inbox-watcher.js +124 -139
  429. package/dist/pi-extensions/canvas-passive-context.d.ts +3 -3
  430. package/dist/pi-extensions/canvas-passive-context.js +22 -18
  431. package/dist/pi-extensions/canvas-recap.d.ts +2 -2
  432. package/dist/pi-extensions/canvas-recap.js +48 -21
  433. package/dist/pi-extensions/canvas-review-boundary.js +10 -4
  434. package/dist/pi-extensions/canvas-stophook.d.ts +0 -5
  435. package/dist/pi-extensions/canvas-stophook.js +149 -431
  436. package/dist/pi-extensions/canvas-structured-output.js +52 -30
  437. package/dist/pi-extensions/envelope-merge.d.ts +13 -0
  438. package/dist/pi-extensions/envelope-merge.js +29 -0
  439. package/dist/shared/working-activity.d.ts +3 -2
  440. package/dist/shared/working-activity.js +3 -2
  441. package/dist/types.d.ts +6 -5
  442. package/dist/types.js +2 -2
  443. package/docs/compat/hearth-crtr-v1.md +4 -12
  444. package/docs/compat/hearth-crtr-v2.md +3 -11
  445. package/docs/compat/hearth-crtr-v3.md +4 -12
  446. package/docs/compat/hearth-crtr-v4.md +3 -11
  447. package/docs/compat/hearth-crtr-v5.md +3 -11
  448. package/docs/public-api.md +3 -7
  449. package/package.json +7 -49
  450. package/runtime.lock.json +2766 -14533
  451. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/claude-plugin-commands.test.ts +0 -49
  452. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/memory-slash-commands.test.ts +0 -194
  453. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/statusline.test.ts +0 -68
  454. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/frontmatter-rules/test.ts +0 -119
  455. package/dist/clients/attach/__tests__/attach-chrome-remote.test.js +0 -439
  456. package/dist/clients/attach/__tests__/attach-keybindings.test.js +0 -170
  457. package/dist/clients/attach/__tests__/crtr-output-coverage.test.js +0 -57
  458. package/dist/clients/attach/__tests__/editor-frame-title.test.js +0 -19
  459. package/dist/clients/attach/__tests__/input-controller-extension-command.test.js +0 -32
  460. package/dist/clients/attach/__tests__/markdown-headings.test.js +0 -35
  461. package/dist/clients/attach/__tests__/session-identity-refresh.test.js +0 -32
  462. package/dist/clients/conversation/conversation.d.ts +0 -65
  463. package/dist/clients/conversation/conversation.js +0 -318
  464. package/dist/clients/conversation/frames.d.ts +0 -30
  465. package/dist/clients/conversation/frames.js +0 -52
  466. package/dist/clients/conversation/region.d.ts +0 -51
  467. package/dist/clients/conversation/region.js +0 -265
  468. package/dist/clients/inbox/__tests__/inbox-controller.test.js +0 -247
  469. package/dist/clients/inbox/__tests__/mount-panel.test.js +0 -776
  470. package/dist/clients/inbox/review/__tests__/remap.test.js +0 -196
  471. package/dist/clients/inbox/review/columns.d.ts +0 -22
  472. package/dist/clients/inbox/review/columns.js +0 -40
  473. package/dist/clients/inbox/review/composition.d.ts +0 -60
  474. package/dist/clients/inbox/review/composition.js +0 -278
  475. package/dist/clients/inbox/review/document-region.d.ts +0 -120
  476. package/dist/clients/surfaces/region.d.ts +0 -16
  477. package/dist/clients/web/__tests__/push-engine.test.js +0 -158
  478. package/dist/clients/web/__tests__/push-registry.test.d.ts +0 -1
  479. package/dist/clients/web/__tests__/push-registry.test.js +0 -177
  480. package/dist/clients/web/dev-server.d.ts +0 -7
  481. package/dist/clients/web/dev-server.js +0 -46
  482. package/dist/clients/web/events.d.ts +0 -19
  483. package/dist/clients/web/events.js +0 -163
  484. package/dist/clients/web/push-engine.d.ts +0 -44
  485. package/dist/clients/web/push-engine.js +0 -125
  486. package/dist/clients/web/push-registry.d.ts +0 -85
  487. package/dist/clients/web/push-registry.js +0 -373
  488. package/dist/clients/web/server.d.ts +0 -19
  489. package/dist/clients/web/server.js +0 -661
  490. package/dist/clients/web/web-client/shared/protocol.d.ts +0 -214
  491. package/dist/clients/web/web-client/shared/protocol.js +0 -8
  492. package/dist/clients/web/web-cmd.d.ts +0 -2
  493. package/dist/clients/web/web-cmd.js +0 -141
  494. package/dist/commands/__tests__/api-canvas-source.test.d.ts +0 -1
  495. package/dist/commands/__tests__/api-canvas-source.test.js +0 -37
  496. package/dist/commands/__tests__/canvas-config.test.d.ts +0 -1
  497. package/dist/commands/__tests__/canvas-config.test.js +0 -107
  498. package/dist/commands/__tests__/node-no-kickoff-flag.test.d.ts +0 -1
  499. package/dist/commands/__tests__/node-no-kickoff-flag.test.js +0 -73
  500. package/dist/commands/__tests__/node-worktree-flag.test.d.ts +0 -1
  501. package/dist/commands/__tests__/node-worktree-flag.test.js +0 -49
  502. package/dist/commands/__tests__/search-contents.test.d.ts +0 -1
  503. package/dist/commands/__tests__/search-contents.test.js +0 -52
  504. package/dist/commands/memory/__tests__/lint.test.d.ts +0 -1
  505. package/dist/commands/memory/__tests__/lint.test.js +0 -15
  506. package/dist/commands/sys/__tests__/config-broker-thresholds.test.d.ts +0 -1
  507. package/dist/commands/sys/__tests__/config-broker-thresholds.test.js +0 -95
  508. package/dist/commands/sys/__tests__/config-keybindings.test.d.ts +0 -1
  509. package/dist/commands/sys/__tests__/config-keybindings.test.js +0 -55
  510. package/dist/commands/sys/__tests__/helpers/setup-runtime.d.ts +0 -5
  511. package/dist/commands/sys/__tests__/helpers/setup-runtime.js +0 -19
  512. package/dist/commands/sys/__tests__/setup-front-door.test.d.ts +0 -1
  513. package/dist/commands/sys/__tests__/setup-front-door.test.js +0 -102
  514. package/dist/commands/sys/__tests__/setup-models.test.d.ts +0 -1
  515. package/dist/commands/sys/__tests__/setup-models.test.js +0 -205
  516. package/dist/commands/sys/__tests__/setup-providers-viewport.test.d.ts +0 -1
  517. package/dist/commands/sys/__tests__/setup-providers-viewport.test.js +0 -155
  518. package/dist/commands/sys/__tests__/sync-deps.test.d.ts +0 -1
  519. package/dist/commands/sys/__tests__/sync-deps.test.js +0 -179
  520. package/dist/commands/sys/__tests__/sync-import.test.d.ts +0 -1
  521. package/dist/commands/sys/__tests__/sync-import.test.js +0 -315
  522. package/dist/core/__tests__/base-worker-prompt.test.d.ts +0 -1
  523. package/dist/core/__tests__/base-worker-prompt.test.js +0 -57
  524. package/dist/core/__tests__/command-plugins-surfaces.test.d.ts +0 -1
  525. package/dist/core/__tests__/command-plugins-surfaces.test.js +0 -359
  526. package/dist/core/__tests__/connection-reconnect-resume.test.d.ts +0 -1
  527. package/dist/core/__tests__/connection-reconnect-resume.test.js +0 -36
  528. package/dist/core/__tests__/finalization-migration.test.d.ts +0 -1
  529. package/dist/core/__tests__/finalization-migration.test.js +0 -38
  530. package/dist/core/__tests__/fixtures/extra-extension.d.ts +0 -1
  531. package/dist/core/__tests__/fixtures/extra-extension.js +0 -3
  532. package/dist/core/__tests__/fixtures/spawn-proof-target.test.d.ts +0 -1
  533. package/dist/core/__tests__/fixtures/spawn-proof-target.test.js +0 -15
  534. package/dist/core/__tests__/fork.test.d.ts +0 -1
  535. package/dist/core/__tests__/fork.test.js +0 -108
  536. package/dist/core/__tests__/full/broker-attach-limits.test.d.ts +0 -1
  537. package/dist/core/__tests__/full/broker-attach-limits.test.js +0 -147
  538. package/dist/core/__tests__/full/broker-deliver-ack.test.d.ts +0 -1
  539. package/dist/core/__tests__/full/broker-deliver-ack.test.js +0 -73
  540. package/dist/core/__tests__/full/broker-dialogs.test.d.ts +0 -1
  541. package/dist/core/__tests__/full/broker-dialogs.test.js +0 -180
  542. package/dist/core/__tests__/full/broker-display-snapshot.test.d.ts +0 -1
  543. package/dist/core/__tests__/full/broker-display-snapshot.test.js +0 -75
  544. package/dist/core/__tests__/full/broker-dormant-wake.test.d.ts +0 -1
  545. package/dist/core/__tests__/full/broker-dormant-wake.test.js +0 -130
  546. package/dist/core/__tests__/full/broker-model-changed-broadcast.test.d.ts +0 -1
  547. package/dist/core/__tests__/full/broker-model-changed-broadcast.test.js +0 -57
  548. package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.d.ts +0 -1
  549. package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.js +0 -80
  550. package/dist/core/__tests__/full/cascade-close.test.d.ts +0 -1
  551. package/dist/core/__tests__/full/cascade-close.test.js +0 -240
  552. package/dist/core/__tests__/full/detach-focus.test.d.ts +0 -1
  553. package/dist/core/__tests__/full/detach-focus.test.js +0 -126
  554. package/dist/core/__tests__/full/idle-release-settlement.test.d.ts +0 -1
  555. package/dist/core/__tests__/full/issue-146-yield-spawn-focus.test.d.ts +0 -1
  556. package/dist/core/__tests__/full/issue-146-yield-spawn-focus.test.js +0 -107
  557. package/dist/core/__tests__/full/park-clock-release.test.d.ts +0 -1
  558. package/dist/core/__tests__/full/park-clock-release.test.js +0 -56
  559. package/dist/core/__tests__/full/yield-message-transaction.test.d.ts +0 -1
  560. package/dist/core/__tests__/memory-index-render.test.d.ts +0 -1
  561. package/dist/core/__tests__/memory-index-render.test.js +0 -60
  562. package/dist/core/__tests__/model-routes.test.d.ts +0 -1
  563. package/dist/core/__tests__/model-routes.test.js +0 -41
  564. package/dist/core/__tests__/on-read-identity.test.d.ts +0 -1
  565. package/dist/core/__tests__/on-read-identity.test.js +0 -61
  566. package/dist/core/__tests__/phase4-review-migration.test.d.ts +0 -1
  567. package/dist/core/__tests__/phase4-review-migration.test.js +0 -100
  568. package/dist/core/__tests__/prune-to-limit.test.d.ts +0 -1
  569. package/dist/core/__tests__/prune-to-limit.test.js +0 -126
  570. package/dist/core/__tests__/reset.test.d.ts +0 -1
  571. package/dist/core/__tests__/reset.test.js +0 -69
  572. package/dist/core/__tests__/spawn-no-kickoff.test.d.ts +0 -1
  573. package/dist/core/__tests__/spawn-no-kickoff.test.js +0 -115
  574. package/dist/core/__tests__/steer-note.test.d.ts +0 -1
  575. package/dist/core/__tests__/steer-note.test.js +0 -41
  576. package/dist/core/__tests__/subcommand-tier.test.d.ts +0 -1
  577. package/dist/core/__tests__/subcommand-tier.test.js +0 -99
  578. package/dist/core/__tests__/subscription-delivery.test.js +0 -211
  579. package/dist/core/__tests__/test-runner-cheap-sharding.test.d.ts +0 -1
  580. package/dist/core/__tests__/test-runner-cheap-sharding.test.js +0 -97
  581. package/dist/core/__tests__/tmux-surface.test.js +0 -484
  582. package/dist/core/__tests__/wake-bearings.test.d.ts +0 -1
  583. package/dist/core/__tests__/wake-bearings.test.js +0 -102
  584. package/dist/core/canvas/__tests__/remote-event-stream.test.d.ts +0 -1
  585. package/dist/core/canvas/__tests__/remote-event-stream.test.js +0 -146
  586. package/dist/core/canvas/__tests__/source-resolve.test.d.ts +0 -1
  587. package/dist/core/canvas/__tests__/source-resolve.test.js +0 -77
  588. package/dist/core/canvas/browse/__tests__/model.test.d.ts +0 -1
  589. package/dist/core/canvas/browse/__tests__/model.test.js +0 -290
  590. package/dist/core/canvas/browse/__tests__/rebuild-coalescer.test.d.ts +0 -1
  591. package/dist/core/canvas/browse/__tests__/rebuild-coalescer.test.js +0 -134
  592. package/dist/core/canvas/browse/__tests__/render.test.d.ts +0 -1
  593. package/dist/core/canvas/browse/__tests__/render.test.js +0 -111
  594. package/dist/core/canvas/browse/rebuild-coalescer.d.ts +0 -7
  595. package/dist/core/canvas/browse/rebuild-coalescer.js +0 -61
  596. package/dist/core/canvas/remote-event-stream.d.ts +0 -24
  597. package/dist/core/canvas/remote-event-stream.js +0 -94
  598. package/dist/core/feed/__tests__/coalesce-human.test.d.ts +0 -1
  599. package/dist/core/feed/__tests__/coalesce-human.test.js +0 -36
  600. package/dist/core/feed/__tests__/empty-node-guard.test.d.ts +0 -1
  601. package/dist/core/feed/__tests__/empty-node-guard.test.js +0 -45
  602. package/dist/core/host-exports/__tests__/export-prunes-boot-skill.test.d.ts +0 -1
  603. package/dist/core/host-exports/__tests__/export-prunes-boot-skill.test.js +0 -84
  604. package/dist/core/human/__tests__/visible-paths.test.d.ts +0 -1
  605. package/dist/core/human/__tests__/visible-paths.test.js +0 -28
  606. package/dist/core/keybindings/__tests__/inbox-affordance.test.d.ts +0 -1
  607. package/dist/core/keybindings/__tests__/inbox-affordance.test.js +0 -38
  608. package/dist/core/review/__tests__/project.test.d.ts +0 -1
  609. package/dist/core/review/__tests__/project.test.js +0 -71
  610. package/dist/core/runtime/__tests__/command-expansion.test.d.ts +0 -1
  611. package/dist/core/runtime/__tests__/command-expansion.test.js +0 -25
  612. package/dist/core/runtime/__tests__/session-visibility.test.d.ts +0 -1
  613. package/dist/core/runtime/__tests__/session-visibility.test.js +0 -119
  614. package/dist/core/runtime/__tests__/spawn-at-given-id.test.d.ts +0 -1
  615. package/dist/core/runtime/__tests__/spawn-at-given-id.test.js +0 -34
  616. package/dist/core/runtime/tmux.js +0 -1314
  617. package/dist/daemon/api/__tests__/full/push-parity.test.d.ts +0 -1
  618. package/dist/daemon/api/__tests__/full/worktree-parity.test.d.ts +0 -1
  619. package/dist/daemon/api/__tests__/full/worktree-parity.test.js +0 -160
  620. package/dist/daemon/api/__tests__/inbox.test.d.ts +0 -1
  621. package/dist/daemon/api/__tests__/inbox.test.js +0 -489
  622. package/dist/web-client/apple-touch-icon.png +0 -0
  623. package/dist/web-client/assets/fragment-mono-latin-400-normal-BYwT3kSJ.woff +0 -0
  624. package/dist/web-client/assets/fragment-mono-latin-400-normal-yxdJ5AmL.woff2 +0 -0
  625. package/dist/web-client/assets/fragment-mono-latin-ext-400-normal-BbKYyvR9.woff2 +0 -0
  626. package/dist/web-client/assets/fragment-mono-latin-ext-400-normal-CT4YFKeK.woff +0 -0
  627. package/dist/web-client/assets/index-CCPaLeW7.css +0 -2
  628. package/dist/web-client/assets/index-kyOWsnZK.js +0 -86
  629. package/dist/web-client/assets/martian-mono-cyrillic-wght-normal-B84CD5C_.woff2 +0 -0
  630. package/dist/web-client/assets/martian-mono-latin-ext-wght-normal-DlL6xMw5.woff2 +0 -0
  631. package/dist/web-client/assets/martian-mono-latin-wght-normal-5W32yIyr.woff2 +0 -0
  632. package/dist/web-client/assets/workbox-window.prod.es5-Bd17z0YL.js +0 -2
  633. package/dist/web-client/icon-192.png +0 -0
  634. package/dist/web-client/icon-512.png +0 -0
  635. package/dist/web-client/icon-maskable-512.png +0 -0
  636. package/dist/web-client/index.html +0 -17
  637. package/dist/web-client/manifest.webmanifest +0 -1
  638. package/dist/web-client/sw.js +0 -1
  639. /package/dist/api/__tests__/{client.test.d.ts → serial/client.test.d.ts} +0 -0
  640. /package/dist/clients/inbox/__tests__/{inbox-controller.test.d.ts → serial/inbox-controller.test.d.ts} +0 -0
  641. /package/dist/clients/inbox/__tests__/{mount-panel.test.d.ts → serial/mount-panel.test.d.ts} +0 -0
  642. /package/dist/clients/{attach/__tests__/attach-chrome-remote.test.d.ts → inbox/review/__tests__/teardown-notice.test.d.ts} +0 -0
  643. /package/dist/{clients/attach/__tests__/attach-keybindings.test.d.ts → core/__tests__/broker-extension-canvas-db-boundary.test.d.ts} +0 -0
  644. /package/dist/{clients/attach/__tests__/crtr-output-coverage.test.d.ts → core/__tests__/seam/broker-attach-multiclient.test.d.ts} +0 -0
  645. /package/dist/core/__tests__/{full → seam}/broker-attach-stream.test.d.ts +0 -0
  646. /package/dist/core/__tests__/{full → seam}/broker-crash-teardown.test.d.ts +0 -0
  647. /package/dist/core/__tests__/{full → seam}/broker-pane-resolution.test.d.ts +0 -0
  648. /package/dist/core/__tests__/{full → seam}/broker-provider-retry.test.d.ts +0 -0
  649. /package/dist/core/__tests__/{full → seam}/broker-whip-interrupt.test.d.ts +0 -0
  650. /package/dist/{clients/attach/__tests__/editor-frame-title.test.d.ts → core/__tests__/seam/dormancy-release.test.d.ts} +0 -0
  651. /package/dist/{clients/attach/__tests__/input-controller-extension-command.test.d.ts → core/__tests__/seam/yield-refresh-transaction.test.d.ts} +0 -0
  652. /package/dist/core/__tests__/{broker-fork-seam.test.d.ts → serial/broker-fork-seam.test.d.ts} +0 -0
  653. /package/dist/core/__tests__/{broker-sdk-wiring.test.d.ts → serial/broker-sdk-wiring.test.d.ts} +0 -0
  654. /package/dist/core/__tests__/{broker-snapshot-history.test.d.ts → serial/broker-snapshot-history.test.d.ts} +0 -0
  655. /package/dist/core/__tests__/{command-plugins.test.d.ts → serial/command-plugins.test.d.ts} +0 -0
  656. /package/dist/core/__tests__/{deferred-no-wake.test.d.ts → serial/deferred-no-wake.test.d.ts} +0 -0
  657. /package/dist/core/__tests__/{flagship-lifecycle.test.d.ts → serial/flagship-lifecycle.test.d.ts} +0 -0
  658. /package/dist/core/__tests__/{host-teardown-process-group.test.d.ts → serial/host-teardown-process-group.test.d.ts} +0 -0
  659. /package/dist/core/__tests__/{human-deliver-e2e.test.d.ts → serial/human-deliver-e2e.test.d.ts} +0 -0
  660. /package/dist/core/__tests__/{live-mutation.test.d.ts → serial/live-mutation.test.d.ts} +0 -0
  661. /package/dist/core/__tests__/{refresh-stall-recycle.test.d.ts → serial/refresh-stall-recycle.test.d.ts} +0 -0
  662. /package/dist/core/__tests__/{revive.test.d.ts → serial/revive.test.d.ts} +0 -0
  663. /package/dist/core/__tests__/{spawn-root.test.d.ts → serial/spawn-root.test.d.ts} +0 -0
  664. /package/dist/core/__tests__/{subscription-delivery.test.d.ts → serial/subscription-delivery.test.d.ts} +0 -0
  665. /package/dist/core/__tests__/{tmux-surface.test.d.ts → serial/tmux-surface.test.d.ts} +0 -0
  666. /package/dist/core/__tests__/{worktree.test.d.ts → serial/worktree.test.d.ts} +0 -0
  667. /package/dist/{clients/attach/__tests__/markdown-headings.test.d.ts → core/__tests__/watchdog-abort-arms-retry.test.d.ts} +0 -0
  668. /package/dist/{clients/attach/__tests__/session-identity-refresh.test.d.ts → core/broker-client/__tests__/transport-socket.test.d.ts} +0 -0
  669. /package/dist/core/human/__tests__/{inbox-core.test.d.ts → serial/inbox-core.test.d.ts} +0 -0
  670. /package/dist/{clients/inbox/review/__tests__/remap.test.d.ts → daemon/api/__tests__/node-model-validation.test.d.ts} +0 -0
  671. /package/dist/{clients/surfaces/region.js → daemon/api/__tests__/review-terminal-conflict.test.d.ts} +0 -0
  672. /package/dist/daemon/api/__tests__/{full → seam}/api-server.test.d.ts +0 -0
  673. /package/dist/daemon/api/__tests__/{full → seam}/b10-attach-modelauth.test.d.ts +0 -0
  674. /package/dist/{clients/web/__tests__/push-engine.test.d.ts → daemon/api/__tests__/seam/leaf-api-parity.test.d.ts} +0 -0
@@ -1,147 +0,0 @@
1
- // Run with: node --import tsx/esm --test src/core/__tests__/full/broker-attach-limits.test.ts
2
- //
3
- // FULL TIER (real-boot-bound): tmux-free, but it boots a REAL broker process
4
- // (~5s pi-SDK load), so it lives in full/ (CI), not the fast local loop.
5
- //
6
- // T8 — the `crtr surface attach` acceptance gate for G4/G7/G8: multi-writer
7
- // admission, decoder overflow isolation, and backpressure shedding.
8
- //
9
- // 3-PART HEADER (headless):
10
- // (1) CONTRACT — every client that hellos as `controller` is welcomed writable,
11
- // simultaneously and independently; each writable client may submit, and
12
- // every connected client (both writers plus a read-only observer) receives
13
- // the merged stream of both submissions, while a client that hellos as
14
- // `observer` is rejected with error{read_only} when it tries to drive (G4).
15
- // An oversized client line is capped and dropped with frame_overflow while
16
- // the broker and other clients continue operating (G7). A stalled
17
- // non-reading viewer is shed at the 32 MiB backpressure HWM while the
18
- // broker and fast viewers remain unaffected (G8).
19
- // (2) WHY BROKER/SOCKET-LEVEL, NOT PANE/WINDOW — role admission, decoder limits,
20
- // and the backpressure HWM are broker-process and view.sock contracts. They
21
- // are exercised over a pure Unix socket using the production ViewSocketClient
22
- // and raw node:net peers, with a real broker process and no tmux pane or
23
- // window.
24
- // (3) HOW THE HEADLESS DRIVE ASSERTS THE CONTRACT — the real socket responses
25
- // provide the G4 welcome roles, per-writer relay frames and the read-only
26
- // rejection, the G7 frame-overflow drop and broker survival, and the G8
27
- // HWM-shed log line and broker survival.
28
- //
29
- // One shared broker is booted in before() and reused across all three gates. There
30
- // is no writer slot to hand off, so every gate simply attaches at the role it
31
- // wants.
32
- import { test, before, after, afterEach } from 'node:test';
33
- import assert from 'node:assert/strict';
34
- import { createHeadlessHarness } from '../helpers/harness.js';
35
- import { isPidAlive } from '../../canvas/pid.js';
36
- import { createAttachKit, delay, tok, frameHas, brokerLogText, } from '../helpers/broker-clients.js';
37
- let h;
38
- let id; // ONE shared broker, reused across G4/G7/G8 (1 real boot, not 3)
39
- const kit = createAttachKit(() => h);
40
- const { attach, connectRaw } = kit;
41
- before(async () => {
42
- h = await createHeadlessHarness({ sessionPrefix: 'crtr-brklim' });
43
- const root = h.spawnRoot('broker-attach-limits suite root');
44
- id = await h.spawnHeadlessChild(root, 'headless worker — attach-limits gates');
45
- });
46
- after(async () => {
47
- if (h !== undefined)
48
- await h.dispose();
49
- });
50
- afterEach(() => {
51
- kit.closeAll();
52
- });
53
- const brokerPid = () => h.node(id).pi_pid;
54
- // ---------------------------------------------------------------------------
55
- // G4 — multi-writer admission + read-only gating. Guards: two simultaneous
56
- // `controller` hellos are BOTH welcomed writable, each one's own submission
57
- // reaches the engine, and every connected client sees BOTH turns; an explicit
58
- // observer that tries to drive is rejected with error{read_only}.
59
- // Failure mode: a singleton writer slot demoting the second client, a writer
60
- // whose prompt is silently dropped, fan-out that misses a viewer, or a
61
- // read-only client that can drive the engine.
62
- // ---------------------------------------------------------------------------
63
- test('G4 — two simultaneous clients are both welcomed controller, each submits, and both see both turns; an observer drive → error{read_only}', async () => {
64
- const [w1, w2] = await Promise.all([
65
- attach(id, 'controller', 'g4-writer-1'),
66
- attach(id, 'controller', 'g4-writer-2'),
67
- ]);
68
- assert.equal(w1.welcome.role, 'controller', 'first client is welcomed writable');
69
- assert.equal(w2.welcome.role, 'controller', 'second SIMULTANEOUS client is ALSO welcomed writable (no singleton slot)');
70
- const observer = await attach(id, 'observer', 'g4-observer');
71
- assert.equal(observer.welcome.role, 'observer', 'an explicit observer hello stays read-only');
72
- // A read-only client may not drive the engine — the role is per-client and
73
- // fixed by its own hello, so this rejection is independent of who else is
74
- // attached.
75
- observer.send({ type: 'prompt', text: 'a read-only client must not drive' });
76
- const err = await observer.waitFrame((f) => f.type === 'error', 'G4 observer prompt rejected');
77
- assert.equal(err.code, 'read_only', 'G4: observer prompt → error{read_only}');
78
- // Each writer submits its OWN token. Submissions are sequenced (a prompt sent
79
- // mid-stream routes as a steer and produces no second turn), so each turn is
80
- // driven to its terminal agent_end before the next writer submits.
81
- const tokenA = tok('G4-WRITER-1');
82
- w1.send({ type: 'prompt', text: tokenA });
83
- await w1.waitFrame((f) => f.type === 'agent_end' && frameHas(f, tokenA), 'G4 writer 1 saw its own turn');
84
- const tokenB = tok('G4-WRITER-2');
85
- w2.send({ type: 'prompt', text: tokenB });
86
- await w2.waitFrame((f) => f.type === 'agent_end' && frameHas(f, tokenB), 'G4 writer 2 saw its own turn');
87
- // The merged stream: EVERY connected client — both writers and the read-only
88
- // observer — receives BOTH writers' turns.
89
- await w2.waitFrame((f) => f.type === 'agent_end' && frameHas(f, tokenA), 'G4 writer 2 ALSO received writer 1 turn');
90
- await w1.waitFrame((f) => f.type === 'agent_end' && frameHas(f, tokenB), 'G4 writer 1 ALSO received writer 2 turn');
91
- await observer.waitFrame((f) => f.type === 'agent_end' && frameHas(f, tokenA), 'G4 observer received writer 1 turn');
92
- await observer.waitFrame((f) => f.type === 'agent_end' && frameHas(f, tokenB), 'G4 observer received writer 2 turn');
93
- });
94
- // ---------------------------------------------------------------------------
95
- // G7 — decoder overflow (guards C5 OOM). A client line over BROKER_READ_CAPS is
96
- // cap-and-dropped; the broker survives and other clients are unaffected. Failure
97
- // mode: an unbounded decoder buffer growing the broker to OOM.
98
- // ---------------------------------------------------------------------------
99
- test('G7 — an oversized client line is dropped (frame_overflow), the broker survives, other clients unaffected', { timeout: 30_000 }, async () => {
100
- const pid = brokerPid();
101
- const boots = h.bootCount(id);
102
- const survivor = await attach(id, 'observer', 'g7-survivor');
103
- // 26 MiB with NO newline > BROKER_READ_CAPS.maxLineBytes (24 MiB) → the bounded
104
- // FrameDecoder throws FrameOverflowError; the broker drops the peer.
105
- const bad = await connectRaw(id, { read: true });
106
- bad.writeRaw(Buffer.alloc(26 * 1024 * 1024, 0x78));
107
- await bad.waitClosed('G7 oversized peer dropped by the broker');
108
- await h.waitFor(() => /frame overflow/.test(brokerLogText(h, id)) || null, { label: 'G7 broker logged the frame-overflow drop' });
109
- // The broker survives and the other client is unaffected: a fresh turn relays.
110
- const token = tok('G7-AFTER');
111
- h.fakeCmd(id, { cmd: 'stream', text: token });
112
- await survivor.waitFrame((f) => f.type === 'agent_end' && frameHas(f, token), 'G7 survivor still receives live frames');
113
- assert.equal(isPidAlive(pid), true, 'G7: the broker survived the overflow');
114
- assert.equal(brokerPid(), pid, 'G7: broker pid unchanged');
115
- assert.equal(h.bootCount(id), boots, 'G7: no reboot');
116
- });
117
- // ---------------------------------------------------------------------------
118
- // G8 — backpressure leak (guards M1). A stalled (non-reading) viewer is shed at
119
- // the HWM (32 MiB byte cap) while the broker + other viewers are unaffected.
120
- // Failure mode: an indefinitely-growing per-viewer queue (broker OOM) or a slow
121
- // viewer back-pressuring the shared engine.
122
- // ---------------------------------------------------------------------------
123
- test('G8 — a stalled viewer is dropped at the backpressure HWM; the broker + fast viewers are unaffected', { timeout: 30_000 }, async () => {
124
- const pid = brokerPid();
125
- const fast = await attach(id, 'observer', 'g8-fast'); // reads normally
126
- // A helloed viewer that NEVER reads (paused socket). It must be in the broadcast
127
- // set before the flood; hello, then a short beat for the broker to process it.
128
- const stalled = await connectRaw(id, { read: false });
129
- stalled.send({ type: 'hello', role: 'observer', client_id: 'g8-stalled' });
130
- await delay(400);
131
- // A fast event stream: ~60 MiB across 240 message_update frames. The stalled
132
- // viewer's per-viewer backlog crosses the 32 MiB byte cap → dropped; the fast
133
- // viewer drains between frames (per-update yield) and survives.
134
- //
135
- // The DROP SIGNAL is the broker's own log line, NOT the stalled socket's 'close':
136
- // a PAUSED node socket does not surface the peer FIN/close until it is resumed,
137
- // so the broker-side `backpressure high-water mark exceeded` line is the
138
- // deterministic, race-free proof that the slow viewer was shed at the HWM.
139
- const token = tok('G8-FLOOD');
140
- h.fakeCmd(id, { cmd: 'stream', text: token, updates: 240, padBytes: 256 * 1024, tool: false });
141
- await h.waitFor(() => /backpressure high-water mark exceeded/.test(brokerLogText(h, id)) || null, { label: 'G8 broker shed the stalled viewer at the HWM', timeoutMs: 30_000 });
142
- // The fast viewer drained the WHOLE stream (agent_end is the terminal frame) —
143
- // proving only the stalled viewer was shed, while the fast one was unaffected.
144
- await fast.waitFrame((f) => f.type === 'agent_end' && frameHas(f, token), 'G8 fast viewer received the whole stream', 30_000);
145
- assert.equal(isPidAlive(pid), true, 'G8: the broker survived the slow-viewer flood');
146
- assert.equal(brokerPid(), pid, 'G8: broker pid unchanged (the engine was not back-pressured into a restart)');
147
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,73 +0,0 @@
1
- // Run with: node --import tsx/esm --test src/core/__tests__/full/broker-deliver-ack.test.ts
2
- //
3
- // Regression for the interactive `deliver` ack (broker.ts `case 'deliver'`):
4
- // the ack must report the ENGINE CALL's real outcome, not the fact that a call
5
- // was routed. A `session.prompt()` that REJECTS outright — the shape a broker
6
- // whose model resolved but whose provider has no installed credential produces
7
- // ("No API key found for anthropic") — used to still ack ok:true, so crtrd
8
- // returned `delivered:true, delivered_via:engine` for a message the engine had
9
- // refused, and the one-shot client closed before the error frame arrived: the
10
- // message vanished with no trace. Now the deliver ack races acceptance (the
11
- // engine's own agent_start) against rejection, acks ok:false on rejection, and
12
- // records `broker.prompt.deliver_failed` in the node's job/log.jsonl.
13
- import { test, before, after, afterEach } from 'node:test';
14
- import assert from 'node:assert/strict';
15
- import { readFileSync } from 'node:fs';
16
- import { join } from 'node:path';
17
- import { createHeadlessHarness } from '../helpers/harness.js';
18
- import { createAttachKit, brokerLogText } from '../helpers/broker-clients.js';
19
- import { REJECT_PROMPT_CALL } from '../fixtures/fake-engine.js';
20
- let h;
21
- const kit = createAttachKit(() => h);
22
- // Fired lifecycle hooks land one line each in fake-pi.events.jsonl.
23
- function eventCount(id, name) {
24
- try {
25
- return readFileSync(join(h.home, 'nodes', id, 'fake-pi.events.jsonl'), 'utf8')
26
- .split('\n')
27
- .filter((l) => {
28
- try {
29
- return JSON.parse(l).event === name;
30
- }
31
- catch {
32
- return false;
33
- }
34
- }).length;
35
- }
36
- catch {
37
- return 0;
38
- }
39
- }
40
- before(async () => {
41
- h = await createHeadlessHarness({ sessionPrefix: 'crtr-deliver-ack' });
42
- });
43
- after(async () => {
44
- if (h !== undefined)
45
- await h.dispose();
46
- });
47
- afterEach(() => {
48
- kit.closeAll();
49
- });
50
- test('a deliver whose prompt rejects acks ok:false and records deliver_failed; a succeeding deliver still acks ok:true via prompt', { timeout: 30_000 }, async () => {
51
- const parent = h.spawnRoot('deliver ack parent');
52
- const child = await h.spawnHeadlessChild(parent, 'deliver ack child');
53
- // Let the kickoff turn fully settle so both delivers route as `prompt`
54
- // (idle), never `steer` — the steer route legitimately acks at routing time.
55
- await h.waitFor(() => (eventCount(child, 'agent_end') >= 1 ? true : null), {
56
- label: 'kickoff turn settled',
57
- });
58
- const ctrl = await kit.attach(child, 'controller', 'deliver-ack-test');
59
- // FAILURE: the engine refuses the call itself. Before the fix this acked
60
- // ok:true and the rejection left no trace in the node's log.
61
- ctrl.send({ type: 'deliver', id: 'd-fail', text: `do a thing ${REJECT_PROMPT_CALL}` });
62
- const failAck = await ctrl.waitFrame((f) => f.type === 'ack' && f.for === 'deliver' && f.id === 'd-fail', 'rejected deliver ack');
63
- assert.equal(failAck.type === 'ack' && failAck.ok, false, 'a rejected prompt must not ack delivered:true');
64
- assert.match((failAck.type === 'ack' ? failAck.detail : undefined) ?? '', /No API key found/, 'the ack detail carries the engine rejection');
65
- await h.waitFor(() => (brokerLogText(h, child).includes('broker.prompt.deliver_failed') ? true : null), { label: 'broker.prompt.deliver_failed recorded in job/log.jsonl' });
66
- // POSITIVE CONTROL: an ordinary deliver still acks ok:true from acceptance
67
- // (the engine's agent_start), detail naming the prompt route.
68
- ctrl.send({ type: 'deliver', id: 'd-ok', text: 'an ordinary interactive message' });
69
- const okAck = await ctrl.waitFrame((f) => f.type === 'ack' && f.for === 'deliver' && f.id === 'd-ok', 'accepted deliver ack');
70
- assert.equal(okAck.type === 'ack' && okAck.ok, true, 'an accepted prompt acks delivered:true');
71
- assert.equal(okAck.type === 'ack' ? okAck.detail : undefined, 'prompt');
72
- ctrl.close();
73
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,180 +0,0 @@
1
- // Run with: node --import tsx/esm --test src/core/__tests__/full/broker-dialogs.test.ts
2
- //
3
- // FULL TIER (real-boot-bound): tmux-free, but it boots a REAL broker process
4
- // (~5s pi-SDK load), so it lives in full/ (CI), not the fast local loop.
5
- //
6
- // Broker dialog handling under MULTI-WRITER attachments — the T8 attach gates
7
- // G5/G5b/G6 cover fan-out + first-response settlement, mid-dialog attach replay,
8
- // and attended-dialog timeout behavior.
9
- //
10
- // 3-PART HEADER (headless):
11
- // (1) CONTRACT — every client whose `hello` claimed the writable role is fanned a
12
- // blocking dialog as extension_ui_request; the FIRST extension_ui_response
13
- // settles it with that answer (not the default), every fanned client receives
14
- // the correlated extension_ui_dismiss, and a later peer response for the same
15
- // id is a silent no-op (G5). A dialog stays pending through a peer's detach and
16
- // is handed to any writable client attaching mid-dialog via
17
- // welcome.pending_dialog; observers never receive an answerable dialog (G5b).
18
- // An attended dialog nobody answers resolves on the short per-dialog timeout
19
- // with the default answer and a correlated dismiss to EVERY writable peer (G6).
20
- // (2) WHY BROKER/SOCKET-LEVEL, NOT PANE/WINDOW — the dialog round-trip is an async
21
- // promise inside makeBrokerUiContext, fanned out and answered over view.sock to
22
- // the production ViewSocketClient. The real broker process provides the
23
- // uiContext and timeout machinery without a tmux pane, window, or pi-session
24
- // read.
25
- // (3) HOW THE HEADLESS DRIVE ASSERTS THE CONTRACT — the fake engine raises real
26
- // confirm() dialogs through the broker, and the tests assert on the frames of
27
- // several concurrently attached clients plus the value and latency recorded in
28
- // fake-pi.dialog.jsonl.
29
- //
30
- // One shared broker is booted in before() and reused across all three gates. Because
31
- // fake-pi.dialog.jsonl is append-only across the shared broker, each gate snapshots
32
- // the count before it drives (`base`) and asserts on its newly appended entry. Role
33
- // is fixed by `hello` and never reassigned, so every writable attach is a plain
34
- // attach — there is no control handoff to wait out.
35
- import { test, before, after, afterEach } from 'node:test';
36
- import assert from 'node:assert/strict';
37
- import { createHeadlessHarness } from '../helpers/harness.js';
38
- import { isPidAlive } from '../../canvas/pid.js';
39
- import { createAttachKit } from '../helpers/broker-clients.js';
40
- let h;
41
- let id; // ONE shared broker, reused across G5/G5b/G6 (1 real boot, not 3)
42
- const kit = createAttachKit(() => h);
43
- const { attach, attachUntil } = kit;
44
- // Attach a writable client. Every `hello` claiming `controller` is admitted
45
- // writable — attaching a peer never demotes an already-attached one.
46
- const writer = async (cid) => {
47
- const a = await attach(id, 'controller', cid);
48
- assert.equal(a.welcome.role, 'controller', `${cid}: admitted writable, not demoted by an existing peer`);
49
- return a;
50
- };
51
- const observer = async (cid) => {
52
- const a = await attach(id, 'observer', cid);
53
- assert.equal(a.welcome.role, 'observer', `${cid}: an observer hello stays read-only`);
54
- return a;
55
- };
56
- // The broker handles one client's frames in order, so an `ack` for a get_commands
57
- // sent AFTER some other frame proves that earlier frame was already processed.
58
- // Used to make "a late peer answer changed nothing" a deterministic assertion
59
- // instead of a sleep.
60
- const barrier = async (c, label) => {
61
- c.send({ type: 'get_commands' });
62
- await c.waitFrame((f) => f.type === 'ack' && f.for === 'get_commands', label);
63
- };
64
- const isRequest = (f) => f.type === 'extension_ui_request';
65
- const dismissFor = (reqId) => (f) => f.type === 'extension_ui_dismiss' && f.id === reqId;
66
- // dialog.jsonl is append-only across the shared broker — snapshot the count, then
67
- // wait for AT LEAST `want` new entries and return the full (cumulative) array.
68
- const dialogCount = () => h.dialogResults(id).length;
69
- const awaitDialogs = (atLeast, label) => h.waitFor(() => (h.dialogResults(id).length >= atLeast ? h.dialogResults(id) : null), { label, timeoutMs: 15_000 });
70
- before(async () => {
71
- h = await createHeadlessHarness({ sessionPrefix: 'crtr-brkdlg' });
72
- const root = h.spawnRoot('broker-dialogs suite root');
73
- id = await h.spawnHeadlessChild(root, 'headless worker — dialog gates');
74
- });
75
- after(async () => {
76
- if (h !== undefined)
77
- await h.dispose();
78
- });
79
- afterEach(() => {
80
- kit.closeAll();
81
- });
82
- const brokerPid = () => h.node(id).pi_pid;
83
- // ---------------------------------------------------------------------------
84
- // G5 — fan-out + first-response settlement. Guards: ONE blocking dialog reaches
85
- // EVERY writable client (never a single owner), the first answer unblocks the
86
- // engine with ITS value (not the default), every fanned client gets the correlated
87
- // extension_ui_dismiss, and a peer answering afterwards is a no-op. Failure modes:
88
- // a dialog only one viewer can see (the others sit blind), peers left holding an
89
- // overlay nothing can answer, or a late peer answer re-settling a dead dialog.
90
- // ---------------------------------------------------------------------------
91
- test('G5 — one dialog fans out to both writable clients, the first response settles it, both are dismissed, and a late peer response is a no-op', async () => {
92
- const base = dialogCount();
93
- const a = await writer('g5-A');
94
- const b = await writer('g5-B');
95
- const obs = await observer('g5-obs'); // must never be fanned an answerable dialog
96
- h.fakeCmd(id, { cmd: 'dialog', timeout: 20_000 }); // generous: a writable client answers first
97
- const reqA = await a.waitFrame(isRequest, 'G5 dialog fanned out to writable A');
98
- const reqB = await b.waitFrame(isRequest, 'G5 dialog fanned out to writable B');
99
- const reqId = reqA.id;
100
- assert.equal(reqB.id, reqId, 'G5: both writable clients were fanned the SAME dialog id, not two dialogs');
101
- assert.equal(reqA.method, 'confirm', 'G5: the fanned dialog is the confirm() the engine raised');
102
- // A answers first — the engine must proceed with A's true, not the false default.
103
- a.send({ type: 'extension_ui_response', id: reqId, confirmed: true });
104
- await a.waitFrame(dismissFor(reqId), 'G5 answerer A receives the correlated dismiss');
105
- await b.waitFrame(dismissFor(reqId), 'G5 peer B receives the correlated dismiss for the dialog it never answered');
106
- const results = await awaitDialogs(base + 1, 'G5 dialog settled by the first response');
107
- assert.equal(results[base].resolved, true, 'G5: the engine proceeded with the first answer (true), not the default (false)');
108
- // The observer was attached the whole time: it saw the broadcast dismiss but was
109
- // never handed the answerable request.
110
- await obs.waitFrame(dismissFor(reqId), 'G5 observer sees the broadcast dismiss (ordering barrier)');
111
- assert.equal(obs.frames.filter(isRequest).length, 0, 'G5: an observer is never fanned an answerable dialog');
112
- assert.equal(obs.welcome.pending_dialog, null, 'G5: an observer welcome never carries a pending dialog');
113
- // B answers the already-settled dialog. The broker deleted the entry on the first
114
- // response, so this finds nothing and is a silent no-op: no second engine
115
- // resolution, and the recorded answer stays A's.
116
- b.send({ type: 'extension_ui_response', id: reqId, confirmed: false });
117
- await barrier(b, 'G5 broker processed B late response (ordered ack)');
118
- const settled = h.dialogResults(id);
119
- assert.equal(settled.length, base + 1, 'G5: the late peer response resolved nothing — no second dialog entry');
120
- assert.equal(settled[base].resolved, true, "G5: the late peer response did not overwrite the first answerer's value");
121
- assert.equal(isPidAlive(brokerPid()), true, 'G5: the late no-op response did not fault the broker');
122
- });
123
- // ---------------------------------------------------------------------------
124
- // G5b (mid-dialog attach) — Guards: a pending dialog survives a writable peer's
125
- // detach (M2) and is handed to a writable client that attaches MID-dialog via
126
- // welcome.pending_dialog, which makes it a full peer in the race to answer. An
127
- // observer attaching mid-dialog gets nothing answerable. Failure modes: a pending
128
- // dialog lost when the raising viewer detaches, a late-joining writable viewer
129
- // blind to an in-flight dialog, or an observer handed one it cannot answer.
130
- // ---------------------------------------------------------------------------
131
- test('G5b — a writable client attaching MID-dialog receives the pending dialog; an observer does not', async () => {
132
- const base = dialogCount();
133
- const a = await writer('g5b-A');
134
- h.fakeCmd(id, { cmd: 'dialog', timeout: 30_000 }); // stays pending long enough for the late attach
135
- const reqA = await a.waitFrame(isRequest, 'G5b dialog fanned out to writable A');
136
- const reqId = reqA.id;
137
- a.send({ type: 'bye' });
138
- a.close(); // M2: a writable peer detaching does NOT cancel the pending dialog
139
- // An observer attaching mid-dialog is never handed it.
140
- const obs = await observer('g5b-obs');
141
- assert.equal(obs.welcome.pending_dialog, null, 'G5b: an observer attaching mid-dialog gets no pending dialog');
142
- // A writable client attaching mid-dialog IS handed it (retry covers the beat
143
- // between the raise and this attach) and can settle it.
144
- const b = await attachUntil(id, 'controller', 'g5b-B', (x) => x.welcome.role === 'controller' && x.welcome.pending_dialog != null, 'G5b writable B attaches mid-dialog and is handed the pending dialog');
145
- assert.equal(b.welcome.pending_dialog.id, reqId, 'G5b: welcome.pending_dialog is the same dialog raised while A was attached');
146
- assert.equal(b.welcome.pending_dialog.method, 'confirm', 'G5b: the pending dialog is the confirm()');
147
- b.send({ type: 'extension_ui_response', id: reqId, confirmed: true });
148
- const results = await awaitDialogs(base + 1, 'G5b dialog settled by the mid-dialog joiner');
149
- assert.equal(results[base].resolved, true, 'G5b: the mid-dialog joiner answered and the engine proceeded');
150
- await obs.waitFrame(dismissFor(reqId), 'G5b dismiss broadcast follows the settlement (ordering barrier)');
151
- assert.equal(obs.frames.filter(isRequest).length, 0, 'G5b: the observer was never fanned the dialog it saw dismissed');
152
- });
153
- // ---------------------------------------------------------------------------
154
- // G6 — anti-deadlock. An ATTENDED dialog NO writable client answers resolves on a
155
- // SHORT per-dialog broker timeout, and every fanned peer is dismissed by id.
156
- // Guards: the engine never hangs on a dialog whose viewers all stay silent.
157
- // Failure mode: a forever-blocked turn, or overlays left up on every viewer.
158
- // ---------------------------------------------------------------------------
159
- test('G6 — an attended dialog no writable client answers resolves on the broker timeout and dismisses every peer', async () => {
160
- const pid = brokerPid();
161
- const base = dialogCount();
162
- // Two writable clients attached but silent → the broker resolves on the SHORT
163
- // explicit per-dialog timeout (800ms), never the 120s default. On timeout it
164
- // broadcasts a correlated `extension_ui_dismiss` keyed to the dialog's id, so
165
- // EVERY peer's overlay (none has an independent timer) is torn down by id.
166
- const a = await writer('g6-A');
167
- const b = await writer('g6-B');
168
- h.fakeCmd(id, { cmd: 'dialog', timeout: 800 });
169
- const reqA = await a.waitFrame(isRequest, 'G6 dialog fanned out to writable A'); // received, deliberately NOT answered
170
- const reqB = await b.waitFrame(isRequest, 'G6 dialog fanned out to writable B'); // received, deliberately NOT answered
171
- const reqId = reqA.id;
172
- assert.equal(reqB.id, reqId, 'G6: both silent peers hold the SAME dialog id');
173
- const dismissA = await a.waitFrame(dismissFor(reqId), 'G6 broker emits a correlated dismiss to A on timeout');
174
- await b.waitFrame(dismissFor(reqId), 'G6 broker emits the same correlated dismiss to peer B');
175
- assert.equal(dismissA.id, reqId, 'G6: the dismiss frame carries the timed-out dialog id, not another');
176
- const results = await awaitDialogs(base + 1, 'G6 attended dialog resolved on timeout');
177
- assert.equal(results[base].resolved, false, 'G6: a dialog no writable client answered resolves to the default (deny)');
178
- assert.ok(results[base].ms >= 600 && results[base].ms < 5000, `G6: resolved on the ~800ms per-dialog timeout, not instantly and not the 120s default — got ${results[base].ms}ms`);
179
- assert.equal(isPidAlive(pid), true, 'G6: the engine made forward progress (still alive)');
180
- });
@@ -1,75 +0,0 @@
1
- // Run with: node --import tsx/esm --test src/core/__tests__/full/broker-display-snapshot.test.ts
2
- //
3
- // FULL TIER (real-boot-bound): tmux-free, but it boots a REAL broker process
4
- // (~5s pi-SDK load), so it lives in full/ (CI), not the fast local loop.
5
- //
6
- // 3-PART HEADER (headless):
7
- // (1) CONTRACT — catch-up is ONE atomic frame. `ctx.ui.setStatus/setWidget/
8
- // setTitle` are LEVELS with no pi getter, so the broker is their only holder;
9
- // it ships that held state as `welcome.snapshot.display` and sends NO
10
- // `display_*` frames after the welcome. A late joiner therefore renders
11
- // complete chrome on its FIRST paint.
12
- // (2) WHY BROKER/SOCKET-LEVEL, NOT PANE/WINDOW — the retention lives in the real
13
- // broker process (displayStatuses/displayWidgets/displayTitle, painted through
14
- // the real makeBrokerUiContext relay) and the catch-up shape is a wire fact on
15
- // view.sock. No tmux pane, window, or pi-session read is involved.
16
- // (3) HOW THE HEADLESS DRIVE ASSERTS THE CONTRACT — the fake engine paints through
17
- // the broker's REAL uiContext with NO viewer attached (so nothing is observed
18
- // live and only retention can carry it), then a viewer attaches and we assert
19
- // on its welcome payload and on the ABSENCE of any post-welcome display frame.
20
- //
21
- // This is the regression guard for the pre-2026-07-24 shape, where `sendWelcome`
22
- // re-emitted N synthetic `display_*` edge frames after the snapshot: catch-up was
23
- // non-atomic, the viewer had to clear-and-rebuild (painting blank chrome in the
24
- // gap), and `applySnapshot(welcome) === fold(reduce, events)` was false by
25
- // construction. Deleting the replay without adding `snapshot.display` would drop
26
- // the chrome entirely; adding `snapshot.display` without deleting the replay would
27
- // leave catch-up non-atomic. Both halves fail this test.
28
- import { test, before, after, afterEach } from 'node:test';
29
- import assert from 'node:assert/strict';
30
- import { createHeadlessHarness } from '../helpers/harness.js';
31
- import { createAttachKit, delay } from '../helpers/broker-clients.js';
32
- let h;
33
- let id;
34
- const kit = createAttachKit(() => h);
35
- before(async () => {
36
- h = await createHeadlessHarness({ sessionPrefix: 'crtr-brkdisp' });
37
- const root = h.spawnRoot('broker-display-snapshot suite root');
38
- id = await h.spawnHeadlessChild(root, 'headless worker — display catch-up');
39
- });
40
- after(async () => {
41
- if (h !== undefined)
42
- await h.dispose();
43
- });
44
- afterEach(() => {
45
- kit.closeAll();
46
- });
47
- /** The three display METHODS of pi's uniform `extension_ui_request` envelope. */
48
- const DISPLAY_METHODS = new Set(['setStatus', 'setWidget', 'setTitle']);
49
- const isDisplayFrame = (f) => f.type === 'extension_ui_request' && f.method !== undefined && DISPLAY_METHODS.has(f.method);
50
- test('retained extension display state rides IN welcome.snapshot.display — and no display edge follows', async () => {
51
- // Paint with ZERO viewers attached: the only path from here to a viewer is the
52
- // broker's retained last-value, so nothing about this test can pass by luck of
53
- // having observed the live edge.
54
- h.fakeCmd(id, { cmd: 'display', text: 'crtr-brief', reason: 'painted while detached' });
55
- const a = await kit.attachUntil(id, 'observer', 'disp-late-joiner', (at) => at.welcome.snapshot.display?.statuses['crtr-brief'] !== undefined, 'welcome.snapshot.display carries the retained status');
56
- const display = a.welcome.snapshot.display;
57
- assert.equal(display.statuses['crtr-brief'], 'painted while detached', 'setStatus level survived in the snapshot');
58
- assert.deepEqual(display.widgets['crtr-brief'], { lines: ['painted while detached'], placement: 'aboveEditor' }, 'setWidget level survived in the snapshot, placement included');
59
- assert.equal(display.title, 'painted while detached', 'setTitle level survived in the snapshot');
60
- // Atomicity: the welcome is COMPLETE. Give the broker a generous beat to emit a
61
- // replay it must not emit, then assert nothing display-shaped arrived at all.
62
- await delay(500);
63
- assert.deepEqual(a.frames.filter((f) => isDisplayFrame(f)).map((f) => f.method), [], 'catch-up is the welcome alone — no synthetic display edges replayed after it');
64
- // A LIVE paint still arrives as an edge frame: the snapshot replaces the replay,
65
- // not the ongoing relay.
66
- h.fakeCmd(id, { cmd: 'display', text: 'crtr-live', reason: 'painted while attached' });
67
- const live = (await a.waitFrame((f) => f.type === 'extension_ui_request' && f.statusKey === 'crtr-live', 'a live setStatus still relays as an extension_ui_request edge'));
68
- assert.equal(live.method, 'setStatus');
69
- assert.equal(live.statusText, 'painted while attached');
70
- // And a viewer attaching AFTER that sees the union of both keys in one frame.
71
- const b = await kit.attachUntil(id, 'observer', 'disp-second-joiner', (at) => at.welcome.snapshot.display?.statuses['crtr-live'] !== undefined, 'the second welcome carries both retained keys');
72
- const bDisplay = b.welcome.snapshot.display;
73
- assert.equal(bDisplay.statuses['crtr-brief'], 'painted while detached');
74
- assert.equal(bDisplay.statuses['crtr-live'], 'painted while attached');
75
- });
@@ -1,130 +0,0 @@
1
- // Run with: node --import tsx/esm --test src/core/__tests__/full/broker-dormant-wake.test.ts
2
- //
3
- // Full-tier model-less broker coverage: a real model-less boot receives auth and
4
- // re-drives launch through the broker's login path.
5
- import { test, before, after, afterEach } from 'node:test';
6
- import assert from 'node:assert/strict';
7
- import { join } from 'node:path';
8
- import { readFileSync, writeFileSync, rmSync } from 'node:fs';
9
- import { createHarness } from '../helpers/harness.js';
10
- import { createAttachKit } from '../helpers/broker-clients.js';
11
- let h;
12
- const kit = createAttachKit(() => h);
13
- const { attachUntil } = kit;
14
- before(async () => {
15
- h = await createHarness({ headless: true, sessionPrefix: 'crtr-brkdorm' });
16
- });
17
- after(async () => {
18
- if (h !== undefined)
19
- await h.dispose();
20
- });
21
- afterEach(() => {
22
- kit.closeAll();
23
- });
24
- // The zero-auth test seam: while <CRTR_HOME>/fake-pi.no-auth exists, the fake
25
- // engine's modelRegistry reports a GENUINE zero-auth boot (nothing registered,
26
- // nothing authenticated). HOME-global (not per-node-dir) is deliberate — the
27
- // test arms it BEFORE spawning (race-free vs the broker's boot-time registry
28
- // read), and DELETING it mid-test flips auth ON, which a reload_auth
29
- // modelRegistry.refresh() re-reads live. See fake-engine.ts createAgentSessionServices.
30
- const noAuthSentinel = () => join(h.home, 'fake-pi.no-auth');
31
- // The node's recorded model (fake-pi.model.json, written by the fake's
32
- // recordModel) — `null` for a model-less boot. A disk read, so it survives the
33
- // broker exiting after its kickoff turn idle-releases.
34
- function model(id) {
35
- return JSON.parse(readFileSync(join(h.home, 'nodes', id, 'fake-pi.model.json'), 'utf8'));
36
- }
37
- // Every fired lifecycle event lands in fake-pi.events.jsonl. A kickoff turn is a
38
- // session.prompt → emitTurn, which fires one 'agent_start'; counting them proves
39
- // whether the deferred kickoff ran. Also a disk read (survives broker exit).
40
- function agentStartCount(id) {
41
- try {
42
- return readFileSync(join(h.home, 'nodes', id, 'fake-pi.events.jsonl'), 'utf8')
43
- .split('\n')
44
- .filter((l) => {
45
- try {
46
- return JSON.parse(l).event === 'agent_start';
47
- }
48
- catch {
49
- return false;
50
- }
51
- }).length;
52
- }
53
- catch {
54
- return 0;
55
- }
56
- }
57
- // ===========================================================================
58
- // REAL-BOOT (tsx source broker, fake engine). Tier-3 model-less launch + the
59
- // reload_auth re-drive that resolves a model once auth arrives. These lock the
60
- // two broker.ts launch-model fixes:
61
- // 0b (unknown-stub detection) — the real SDK gives a model-less session an
62
- // unknown-stub model (never `undefined`); sessionHasNoModel() must treat it
63
- // as no-model so the kickoff DEFERS instead of prompting a keyless engine.
64
- // 0a (self-healing model-less registry) — the construction-time mask that
65
- // suppresses the SDK's own findInitialModel MUST reveal() the instant
66
- // construction returns, or list_models/cycle_model stay broken forever for
67
- // a model-less-booted node even after a /login resolves a model.
68
- // ===========================================================================
69
- // login/reload re-drive. Two proofs, ordered to dodge the kickoff-shutdown race:
70
- // (0a self-heal, list_models) — the construction-time mask reveal()s the SAME
71
- // retained proxy the instant construction returns, so getAvailable() passes
72
- // through LIVE. We prove it by flipping auth ON and querying list_models
73
- // BEFORE any reload_auth: the broker is still model-less-idle (no turn has
74
- // run, so it hasn't idle-released) and definitely alive. With the persistent
75
- // mask (reveal() removed) getAvailable()→[] forever, so availableIds stays []
76
- // even after the flip — the ONLY assertion here that discriminates the bug.
77
- // (re-drive) — reload_auth then re-runs the SAME launch policy against the
78
- // now-authenticated registry: a model resolves and the deferred kickoff
79
- // fires. Those are disk reads (fake-pi.model.json / .events.jsonl), so they
80
- // hold even after the kickoff turn ends and the broker idle-releases — no
81
- // dependence on the socket surviving.
82
- //
83
- // MODEL CHOICE — the child is pinned to `fake/fake-model`, a NON-managed provider
84
- // and this is deliberate. The
85
- // zero-auth sentinel gates the fake registry's find/getAll/getAvailable AND its
86
- // hasConfiguredAuth, so removing it is a genuine, LIVE auth-on flip for a
87
- // non-managed model: resolveLaunchModel authenticates a non-managed candidate off
88
- // hasConfiguredAuth(), which the sentinel controls. A MANAGED pin (anthropic)
89
- // instead authenticates off subscription-pool OCCUPANCY (readSubscriptionPool),
90
- // which the fake registry cannot express and which the test process cannot seed —
91
- // the pool file is `homedir()/.pi/agent/...` frozen at import, and the test
92
- // process keeps the REAL HOME while the broker runs under the harness's tmpHome,
93
- // so a seed would land in the wrong file (and pollute real user state). The
94
- // re-drive mechanism under test (reload_auth re-runs resolveLaunchModel → adopts
95
- // the model → fires the deferred kickoff) is provider-agnostic; the managed
96
- // subscription-pool auth path is out of this test's scope (covered by
97
- // broker-launch-candidates / broker-sdk-wiring). fake/fake-model is a faithful
98
- // analog: a node pinned to model X boots before X's auth exists, then X's auth
99
- // arrives and the re-drive resolves X.
100
- test('login re-drive → list_models self-heals (0a) and reload_auth resolves a model + fires the deferred kickoff', async () => {
101
- writeFileSync(noAuthSentinel(), '1');
102
- try {
103
- const parent = h.spawnRoot('login re-drive parent');
104
- const child = await h.spawnHeadlessChild(parent, 'login re-drive', { model: 'fake/fake-model' });
105
- assert.equal(model(child), null, 'boots model-less under zero-auth');
106
- assert.equal(agentStartCount(child), 0, 'kickoff deferred at boot');
107
- const c = await attachUntil(child, 'controller', 'redrive-ctrl', (a) => a.welcome.role === 'controller', 'redrive controller admitted');
108
- // A read-op reply is a correlated `data` frame the client swallows into
109
- // request()'s by-id resolver (NEVER a generic 'frame'), so we MUST use
110
- // client.request(), not send()+waitFrame.
111
- // Baseline: under zero-auth the registry reports nothing available.
112
- const lm0 = await c.client.request({ type: 'list_models' });
113
- assert.ok(lm0.kind === 'list_models' && lm0.availableIds.length === 0, 'zero-auth: no models available');
114
- // FLIP AUTH ON, then re-query while the broker is still alive (no turn has run
115
- // yet). getAvailable() flows through the revealed construction proxy →
116
- // NON-empty. With the mask never revealed it would still be [].
117
- rmSync(noAuthSentinel(), { force: true });
118
- const lm1 = await c.client.request({ type: 'list_models' });
119
- assert.ok(lm1.kind === 'list_models' && lm1.availableIds.length > 0, 'auth on: list_models reports an available model (0a self-heal — the construction mask revealed)');
120
- // reload_auth re-drives the launch policy → resolves a model and fires the
121
- // deferred kickoff. Disk reads, so they survive the broker idle-releasing
122
- // once that kickoff turn ends.
123
- c.send({ type: 'reload_auth' });
124
- await h.waitFor(() => model(child) !== null, { label: 're-drive selected a model' });
125
- await h.waitFor(() => agentStartCount(child) >= 1, { label: 'deferred kickoff fired after re-drive' });
126
- }
127
- finally {
128
- rmSync(noAuthSentinel(), { force: true });
129
- }
130
- });