@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
@@ -0,0 +1,598 @@
1
+ // tmux driver — low-level tmux invocation, pane/window placement, and viewer state.
2
+ //
3
+ // This module owns the raw tmux process boundary. Higher-level binding
4
+ // reconciliation lives in tmux-bindings.ts; placement remains the sanctioned
5
+ // runtime facade for consumers that need these verbs.
6
+ import { execFile, spawnSync } from 'node:child_process';
7
+ import { encodeAttachControlInput, } from '../keybindings/index.js';
8
+ import { bundledPiCommandForShell } from './pi-cli.js';
9
+ // ---------------------------------------------------------------------------
10
+ // Shell quoting + tmux invocation
11
+ // ---------------------------------------------------------------------------
12
+ /** POSIX single-quote escaping for one shell word. */
13
+ export function shellQuote(s) {
14
+ return `'${s.replace(/'/g, `'\\''`)}'`;
15
+ }
16
+ function tmux(args) {
17
+ const r = spawnSync('tmux', args, { encoding: 'utf8' });
18
+ return {
19
+ ok: r.status === 0,
20
+ stdout: (r.stdout ?? '').trim(),
21
+ stderr: (r.stderr ?? '').trim(),
22
+ };
23
+ }
24
+ function tmuxOnSocket(socket, args) {
25
+ return socket === undefined || socket === '' ? tmux(args) : tmux(['-S', socket, ...args]);
26
+ }
27
+ export function inTmux() {
28
+ return process.env['TMUX'] !== undefined && process.env['TMUX'] !== '';
29
+ }
30
+ /** The pane currently displaying `nodeId`, found by the authoritative `@crtr_node`
31
+ * pane tag — set by EVERY viewer (a bare `surface attach`, a focus split, a
32
+ * spawned viewer) on connect. Scans all panes (`list-panes -a`); the reverse of
33
+ * `nodeInPane`. Unlike the focus TABLE (which only `registerViewerFocus` writes,
34
+ * so it misses attach-viewed nodes), the tag is on any pane showing the node.
35
+ * Returns the pane id, or null when no pane shows it. Works headless (no $TMUX). */
36
+ export function paneOfNode(nodeId) {
37
+ if (nodeId === '')
38
+ return null;
39
+ const r = tmux(['list-panes', '-a', '-F', '#{pane_id}\t#{@crtr_node}']);
40
+ if (!r.ok)
41
+ return null;
42
+ for (const line of r.stdout.split('\n')) {
43
+ const tab = line.indexOf('\t');
44
+ if (tab < 0)
45
+ continue;
46
+ if (line.slice(tab + 1) === nodeId) {
47
+ const pane = line.slice(0, tab);
48
+ if (pane !== '')
49
+ return pane;
50
+ }
51
+ }
52
+ return null;
53
+ }
54
+ /** Where the caller currently is, or null if not inside tmux. */
55
+ export function currentTmux() {
56
+ if (!inTmux())
57
+ return null;
58
+ const r = tmux([
59
+ 'display-message',
60
+ '-p',
61
+ '#{session_name}\t#{window_id}\t#{pane_id}',
62
+ ]);
63
+ if (!r.ok)
64
+ return null;
65
+ const [session, window, pane] = r.stdout.split('\t');
66
+ return { session, window, pane };
67
+ }
68
+ // ---------------------------------------------------------------------------
69
+ // Sessions + windows
70
+ // ---------------------------------------------------------------------------
71
+ export function sessionExists(name) {
72
+ return tmux(['has-session', '-t', name]).ok;
73
+ }
74
+ /** Force bracketed-paste capabilities on for every terminal on this tmux server.
75
+ *
76
+ * Many terminfo entries lack the Enbp/Dsbp (enable/disable bracketed paste)
77
+ * capabilities. Without them tmux never asks the outer terminal to wrap pastes,
78
+ * so a multi-line paste arrives as raw `\r` and the inner app (pi, zsh, …)
79
+ * submits on the first newline — i.e. one paste lands as several messages.
80
+ * Declaring the caps for `*` restores bracketed paste so pastes stay atomic.
81
+ *
82
+ * `terminal-overrides` is a server option, so this is set once per server and
83
+ * is idempotent when a valid escaped Enbp capability is already present,
84
+ * including a user's own override. Must run only once a server exists —
85
+ * set-option errors out with no server running — so callers invoke it AFTER
86
+ * ensuring a session. */
87
+ function ensureBracketedPaste() {
88
+ const current = tmux(['show-options', '-s', 'terminal-overrides']).stdout;
89
+ if (/Enbp=\\+E/.test(current))
90
+ return;
91
+ // Emit a LITERAL backslash-E (`\\E`) so tmux's option parser resolves it to ESC.
92
+ // A single `\E` in this JS source collapses to the letter `E`, which stores a
93
+ // broken `Enbp=E[?2004h` (no ESC) and silently disables bracketed paste.
94
+ tmux(['set-option', '-sga', 'terminal-overrides', '*:Enbp=\\E[?2004h:Dsbp=\\E[?2004l']);
95
+ }
96
+ /** Server-level tmux prerequisites for crtr's viewer surfaces, applied once a
97
+ * server exists (callers invoke via ensureSession). Currently: bracketed paste
98
+ * capability (above) and `focus-events on`, which forwards terminal focus
99
+ * in/out (DECSET 1004) to the program in each pane — the attach viewer uses it
100
+ * to hollow out the editor cursor in blurred panes. */
101
+ function ensureServerOptions() {
102
+ ensureBracketedPaste();
103
+ tmux(['set-option', '-s', 'focus-events', 'on']);
104
+ }
105
+ /** Create a detached session rooted at `cwd` if it doesn't exist. The session
106
+ * name is a root's tmux home; every node under that root is a window in it. */
107
+ export function ensureSession(name, cwd) {
108
+ if (!sessionExists(name)) {
109
+ tmux(['new-session', '-d', '-s', name, '-c', cwd]);
110
+ }
111
+ ensureServerOptions();
112
+ }
113
+ function envFlags(env) {
114
+ const out = [];
115
+ for (const [k, v] of Object.entries(env))
116
+ out.push('-e', `${k}=${v}`);
117
+ return out;
118
+ }
119
+ /** Open a background window for a node and run `command` in it. `-d` keeps it
120
+ * detached so it doesn't steal focus or become the current window. Returns the
121
+ * new window id AND the pane id it created (the durable `%pane_id`, LOCATION's
122
+ * anchor) — callers that only need the window destructure `.window`.
123
+ *
124
+ * Target is `${session}:` (trailing colon = the session, no window index) plus
125
+ * `-a` (insert after the current window) so tmux allocates the next free index.
126
+ * Passing a bare session name resolves to the session's *active window*, which
127
+ * makes new-window try to create AT that occupied index and fail with
128
+ * "create window failed: index N in use" whenever the active window is not the
129
+ * last one (common when base-index is 0 but the live window sits at index 1).
130
+ * `-a` also keeps node windows off index 0, which is reserved for the optional
131
+ * dashboard. The explicit `-t ${session}:` target is the §2.2 HARD DRIVER
132
+ * INVARIANT — never let new-window fall back to tmux's global current session. */
133
+ export function openNodeWindow(opts) {
134
+ const r = tmux([
135
+ 'new-window',
136
+ '-d',
137
+ '-a',
138
+ '-P',
139
+ '-F',
140
+ '#{window_id}\t#{pane_id}',
141
+ '-t',
142
+ `${opts.session}:`,
143
+ '-n',
144
+ opts.name,
145
+ '-c',
146
+ opts.cwd,
147
+ ...envFlags(opts.env),
148
+ opts.command,
149
+ ]);
150
+ if (!r.ok)
151
+ return null;
152
+ const [window, pane] = r.stdout.split('\t');
153
+ if (window === undefined || window === '' || pane === undefined || pane === '') {
154
+ return null;
155
+ }
156
+ return { window, pane };
157
+ }
158
+ /** Split `targetPane`'s window, opening a NEW pane beside it running `command`,
159
+ * and return the new pane id (the durable `%id`). The ONLY new-pane-beside verb
160
+ * (Q3: a focus opened side-by-side). `-d` keeps the caller's pane active; `-h`
161
+ * makes the split side-by-side (left/right), the default for a focus viewport.
162
+ *
163
+ * §2.2 HARD DRIVER INVARIANT: `targetPane` is REQUIRED — a bare `split-window`
164
+ * would split tmux's global current pane, which can leak a pane into an
165
+ * unrelated user session (the exact bug this design kills). The explicit
166
+ * `-t <targetPane>` makes the destination structurally un-leakable. Returns
167
+ * null if tmux fails. */
168
+ export function splitWindow(targetPane, opts) {
169
+ const r = tmux([
170
+ 'split-window',
171
+ '-d',
172
+ ...(opts.vertical === true ? [] : ['-h']),
173
+ ...(opts.before === true ? ['-b'] : []),
174
+ ...(opts.size !== undefined ? ['-l', String(opts.size)] : []),
175
+ '-P',
176
+ '-F',
177
+ '#{pane_id}',
178
+ '-t',
179
+ targetPane,
180
+ '-c',
181
+ opts.cwd,
182
+ ...envFlags(opts.env),
183
+ opts.command,
184
+ ]);
185
+ return r.ok && r.stdout !== '' ? r.stdout : null;
186
+ }
187
+ /** Bring a node's window forefront. Switches client across roots when needed. */
188
+ export function focusWindow(session, window) {
189
+ const here = currentTmux();
190
+ const sameRoot = here?.session === session;
191
+ if (!sameRoot) {
192
+ if (!tmux(['switch-client', '-t', session]).ok)
193
+ return false;
194
+ }
195
+ return tmux(['select-window', '-t', window]).ok;
196
+ }
197
+ /** Close a node's window (drop it from the UI). */
198
+ export function closeWindow(window) {
199
+ return tmux(['kill-window', '-t', window]).ok;
200
+ }
201
+ /** Rename a window (`tmux rename-window -t <window> <name>`). Used by the
202
+ * root relaunch to re-title the viewer window when its pane is re-pointed at
203
+ * the freshly-minted node. Best-effort; false if tmux fails. */
204
+ export function renameWindow(window, name) {
205
+ return tmux(['rename-window', '-t', window, name]).ok;
206
+ }
207
+ /** Break a single PANE out into a BRAND-NEW window of its own (`tmux break-pane
208
+ * -d`). `-d` keeps the new window in the background (does not switch the client
209
+ * to it); `-s <pane>` names the source pane — the §2.2 HARD DRIVER INVARIANT, so
210
+ * the break never falls back to tmux's global current pane. The pane keeps its
211
+ * durable `%id` across the move (only its window changes), so callers can keep
212
+ * using the same pane handle. Returns the new `{window, pane}` location, or null
213
+ * if tmux fails. Used by `surface tmux-spread` to lift the caller's viewer into a
214
+ * fresh window before tiling sibling viewers beside it. */
215
+ export function breakPane(pane) {
216
+ const r = tmux([
217
+ 'break-pane',
218
+ '-d',
219
+ '-P',
220
+ '-F',
221
+ '#{window_id}\t#{pane_id}',
222
+ '-s',
223
+ pane,
224
+ ]);
225
+ if (!r.ok)
226
+ return null;
227
+ const [window, p] = r.stdout.split('\t');
228
+ if (window === undefined || window === '' || p === undefined || p === '')
229
+ return null;
230
+ return { window, pane: p };
231
+ }
232
+ /** Close a single PANE. Its window closes automatically once this was the last
233
+ * pane, but sibling panes survive — so co-located nodes (several agents sharing
234
+ * one window via swap-pane focus) are torn down one at a time instead of all
235
+ * at once by a window kill. Pane ids are the stable vehicle handle; windows
236
+ * shift under swap-pane focus, so pane-granular teardown is the correct unit. */
237
+ export function closePane(pane) {
238
+ return tmux(['kill-pane', '-t', pane]).ok;
239
+ }
240
+ /** Open a command in a tmux popup anchored to a pane. The command is a shell
241
+ * string because tmux executes popup payloads through the user's shell. */
242
+ export function displayPopup(pane, cwd, command) {
243
+ return tmux(['display-popup', '-E', '-t', pane, '-d', cwd, '-w', '90%', '-h', '90%', command]).ok;
244
+ }
245
+ /** The active pane id of a window. Node windows are single-pane, so this is the
246
+ * node's pane. Returns null if the window is gone or tmux fails. */
247
+ export function paneOfWindow(session, window) {
248
+ const r = tmux(['display-message', '-p', '-t', `${session}:${window}`, '#{pane_id}']);
249
+ return r.ok && r.stdout !== '' ? r.stdout : null;
250
+ }
251
+ /** The window a pane currently lives in. Used after a swap-pane to learn which
252
+ * slot the caller's pane occupied — pane ids are stable across swaps, windows
253
+ * are not, so the node→window mapping must be re-derived from the pane. Returns
254
+ * null if the pane is gone or tmux fails. */
255
+ export function windowOfPane(pane) {
256
+ const r = tmux(['display-message', '-p', '-t', pane, '#{window_id}']);
257
+ return r.ok && r.stdout !== '' ? r.stdout : null;
258
+ }
259
+ /** The session + window a pane currently lives in (`display-message -p -t %id`).
260
+ * The §2.4 reconciliation read-back: resolve a node's/focus's CURRENT
261
+ * window/session from its durable pane id before any act, so crtr follows a
262
+ * manual `move-pane`/`join-pane`/`break-pane` instead of fighting it. Null if
263
+ * the pane is gone or tmux fails. */
264
+ export function paneLocation(pane) {
265
+ const r = tmux(['display-message', '-p', '-t', pane, '#{session_name}\t#{window_id}']);
266
+ if (!r.ok)
267
+ return null;
268
+ const [session, window] = r.stdout.split('\t');
269
+ if (session === undefined || session === '' || window === undefined || window === '')
270
+ return null;
271
+ return { session, window };
272
+ }
273
+ /** Does this pane id still exist? A `display-message` probe on the `%id` — the
274
+ * v3 PRIMARY liveness probe (§1.2/§2.2), replacing window-existence so a user
275
+ * moving a pane to another window/session never reads as "gone". True iff tmux
276
+ * knows the pane.
277
+ *
278
+ * NOTE: `display-message -p -t <gone-pane>` EXITS 0 with EMPTY output (it does
279
+ * not error on an unresolvable pane target) — so an `.ok` check alone would
280
+ * report a dead pane as alive, defeating the whole point of pane-existence
281
+ * liveness. We therefore require the echoed `#{pane_id}` to equal the requested
282
+ * pane: a live pane echoes its own id, a gone/bogus one yields empty. */
283
+ export function paneExists(pane) {
284
+ const r = tmux(['display-message', '-p', '-t', pane, '#{pane_id}']);
285
+ return r.ok && r.stdout === pane;
286
+ }
287
+ /** Does this pane exist AND have its command still RUNNING (`#{pane_dead}` = 0)?
288
+ * Distinguishes a pane genuinely hosting a live process from a remain-on-exit
289
+ * corpse frozen after exit (`pane_dead` = 1). Node viewer panes run `crtr surface attach`
290
+ * as the pane command, so pane-running ⟹ a live viewer occupies it. */
291
+ export function paneRunning(pane) {
292
+ const r = tmux(['display-message', '-p', '-t', pane, '#{pane_id}\t#{pane_dead}']);
293
+ return r.ok && r.stdout === `${pane}\t0`;
294
+ }
295
+ /** Every live pane id on the server (`list-panes -a`), as a Set for membership
296
+ * probes. Returns null when tmux is unreachable (no server / transient failure)
297
+ * so callers can tell "no panes" apart from "can't tell" — a GC pass must skip,
298
+ * never mass-delete, on a failed probe. One subprocess call total, so batch
299
+ * liveness sweeps (e.g. the daemon's stale-focus GC) don't pay a per-pane
300
+ * display-message each. */
301
+ export function listLivePanes() {
302
+ const r = tmux(['list-panes', '-a', '-F', '#{pane_id}']);
303
+ if (!r.ok)
304
+ return null;
305
+ return new Set(r.stdout.split('\n').filter((p) => p !== ''));
306
+ }
307
+ /** The working directory of a pane (`display-message -p -t <pane>
308
+ * '#{pane_current_path}'`). Null if tmux fails. */
309
+ export function paneCurrentPath(pane) {
310
+ const r = tmux(['display-message', '-p', '-t', pane, '#{pane_current_path}']);
311
+ return r.ok && r.stdout !== '' ? r.stdout : null;
312
+ }
313
+ /** The pane's current cell dimensions, or null when tmux cannot describe it. */
314
+ export function paneSize(pane) {
315
+ const r = tmux(['display-message', '-p', '-t', pane, '#{pane_width}\t#{pane_height}']);
316
+ if (!r.ok)
317
+ return null;
318
+ const [colsStr, rowsStr] = r.stdout.split('\t');
319
+ const cols = Number.parseInt(colsStr, 10);
320
+ const rows = Number.parseInt(rowsStr, 10);
321
+ if (Number.isInteger(cols) && cols > 0 && Number.isInteger(rows) && rows > 0) {
322
+ return { cols, rows };
323
+ }
324
+ return null;
325
+ }
326
+ /** Flash a transient status-line toast on the client showing `pane` (or the
327
+ * current client when `pane` is omitted). `ms` sets the display duration. Used
328
+ * by `crtr canvas issue new` to confirm a capture from inside its popup.
329
+ * Best-effort; never throws. */
330
+ export function displayMessage(message, pane, ms = 4000) {
331
+ const args = ['display-message', '-d', String(ms)];
332
+ if (pane !== undefined && pane !== '')
333
+ args.push('-t', pane);
334
+ args.push(message);
335
+ return tmux(args).ok;
336
+ }
337
+ /** Set a PANE-scoped tmux option (`tmux set-option -p -t <pane> <name> <value>`).
338
+ * Best-effort; never throws. */
339
+ export function setPaneOption(pane, name, value) {
340
+ return tmux(['set-option', '-p', '-t', pane, name, value]).ok;
341
+ }
342
+ /** Read a PANE-scoped tmux option value (`tmux show-options -p -t <pane> -q -v
343
+ * <name>`): `-v` prints only the value, `-q` suppresses the unknown-option
344
+ * error so an unset option yields an empty string. undefined if tmux fails. */
345
+ export function getPaneOption(pane, name) {
346
+ const r = tmux(['show-options', '-p', '-t', pane, '-q', '-v', name]);
347
+ return r.ok ? r.stdout : undefined;
348
+ }
349
+ /** Pane option recording when an attach viewer was last started or focused.
350
+ * `liveViewerPanes` uses it to select the most recently used viewer. */
351
+ export const VIEWER_STAMP_OPTION = '@crtr_viewer_at';
352
+ let lastViewerStampMs = 0;
353
+ let viewerStampQueue = Promise.resolve();
354
+ /** Stamp a viewer pane without blocking the input path that observed focus.
355
+ * Stamps are monotonically increasing and their tmux writes are serialized, so
356
+ * two rapid focus events cannot leave an older pane with the newer stamp. */
357
+ export function stampViewerPaneAsync(pane) {
358
+ if (pane === '')
359
+ return;
360
+ const stampMs = Math.max(Date.now(), lastViewerStampMs + 1);
361
+ lastViewerStampMs = stampMs;
362
+ viewerStampQueue = viewerStampQueue.then(() => new Promise((resolve) => {
363
+ try {
364
+ execFile('tmux', ['set-option', '-p', '-t', pane, VIEWER_STAMP_OPTION, String(stampMs)], () => resolve());
365
+ }
366
+ catch {
367
+ resolve();
368
+ }
369
+ }));
370
+ }
371
+ function escapeRegex(text) {
372
+ return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
373
+ }
374
+ function looksLikeViewerCommand(command, nodeId) {
375
+ const unquoted = command.replace(/^"|"$/g, '');
376
+ return new RegExp(`(?:^|\\s)surface\\s+attach\\s+to\\s+${escapeRegex(nodeId)}(?:\\s|$)`).test(unquoted);
377
+ }
378
+ function readProcessTree() {
379
+ const result = spawnSync('ps', ['-ax', '-o', 'pid=,ppid=,command='], { encoding: 'utf8' });
380
+ if (result.status !== 0 || typeof result.stdout !== 'string')
381
+ return null;
382
+ const childrenOf = new Map();
383
+ const commandOf = new Map();
384
+ for (const line of result.stdout.split('\n')) {
385
+ const match = /^\s*(\d+)\s+(\d+)\s+(.*)$/.exec(line);
386
+ if (match === null)
387
+ continue;
388
+ const pid = Number(match[1]);
389
+ const parentPid = Number(match[2]);
390
+ commandOf.set(pid, match[3]);
391
+ const children = childrenOf.get(parentPid) ?? [];
392
+ children.push(pid);
393
+ childrenOf.set(parentPid, children);
394
+ }
395
+ return { childrenOf, commandOf };
396
+ }
397
+ function processTreeHasViewer(tree, rootPid, nodeId) {
398
+ const pending = [rootPid];
399
+ while (pending.length > 0) {
400
+ const pid = pending.pop();
401
+ if (looksLikeViewerCommand(tree.commandOf.get(pid) ?? '', nodeId))
402
+ return true;
403
+ const children = tree.childrenOf.get(pid);
404
+ if (children !== undefined)
405
+ pending.push(...children);
406
+ }
407
+ return false;
408
+ }
409
+ /** List viewer panes tagged by a running local attach viewer. Pane tags can
410
+ * survive a killed process, so every tag must match a viewer for the same node.
411
+ * Shell-hosted viewers are recognized through their live child process. Unstamped
412
+ * valid viewers remain eligible at stamp zero while an older viewer rolls forward. */
413
+ export function liveViewerPanes(socket) {
414
+ const listed = tmuxOnSocket(socket, [
415
+ 'list-panes', '-a', '-F',
416
+ '#{pane_id}\t#{session_name}\t#{@crtr_node}\t#{@crtr_viewer_at}',
417
+ ]);
418
+ if (!listed.ok || listed.stdout === '')
419
+ return [];
420
+ const viewers = [];
421
+ let processTree;
422
+ for (const line of listed.stdout.split('\n')) {
423
+ const [pane, session, nodeId, stamp] = line.split('\t');
424
+ if (pane === undefined || pane === '' || session === undefined || session === '' || nodeId === undefined || nodeId === '')
425
+ continue;
426
+ const command = tmuxOnSocket(socket, [
427
+ 'display-message', '-p', '-t', pane,
428
+ '#{pane_current_command}\t#{pane_start_command}\t#{pane_pid}',
429
+ ]);
430
+ if (!command.ok)
431
+ continue;
432
+ const [currentCommand = '', startCommand = '', pid] = command.stdout.split('\t');
433
+ const directViewer = looksLikeViewerCommand(currentCommand, nodeId) || looksLikeViewerCommand(startCommand, nodeId);
434
+ if (!directViewer) {
435
+ processTree ??= readProcessTree();
436
+ const rootPid = Number.parseInt(pid, 10);
437
+ if (processTree === null || !Number.isInteger(rootPid) || rootPid <= 0 || !processTreeHasViewer(processTree, rootPid, nodeId))
438
+ continue;
439
+ }
440
+ const parsedStamp = Number.parseInt(stamp ?? '', 10);
441
+ viewers.push({
442
+ pane,
443
+ session,
444
+ nodeId,
445
+ stampMs: Number.isSafeInteger(parsedStamp) && parsedStamp >= 0 ? parsedStamp : 0,
446
+ });
447
+ }
448
+ return viewers;
449
+ }
450
+ /** Deliver one private attach-control sequence literally into a viewer pane.
451
+ * `-l` bypasses tmux key-table lookup, so delivery cannot re-trigger a root
452
+ * binding that initiated it. */
453
+ export function sendAttachControl(socket, pane, actionId) {
454
+ return tmuxOnSocket(socket, ['send-keys', '-l', '-t', pane, encodeAttachControlInput(actionId)]).ok;
455
+ }
456
+ /** Show a tmux status-line message on a specific client when one is known. */
457
+ export function displayClientMessage(socket, client, text) {
458
+ const args = ['display-message'];
459
+ if (client !== undefined && client !== '')
460
+ args.push('-c', client);
461
+ args.push(text);
462
+ return tmuxOnSocket(socket, args).ok;
463
+ }
464
+ /** The `respawn-pane -k` argv for `opts`. `-k` kills the pane's current process
465
+ * (e.g. a yielding pi) and re-execs `command` in the SAME pane, preserving its
466
+ * `%id` (§1.5 F3: a frozen focus pane resumes in place, no new window). The
467
+ * explicit `-t opts.pane` is the §2.2 HARD DRIVER INVARIANT — respawn must name
468
+ * its target pane, never tmux's global current pane. */
469
+ function respawnPaneArgs(opts) {
470
+ return [
471
+ 'respawn-pane',
472
+ '-k',
473
+ '-c',
474
+ opts.cwd,
475
+ ...envFlags(opts.env),
476
+ '-t',
477
+ opts.pane,
478
+ opts.command,
479
+ ];
480
+ }
481
+ /** Re-exec a command in an EXISTING pane, in place — SYNCHRONOUS. Runs the
482
+ * `respawn-pane` to completion and reports the real exit status. Used when the
483
+ * caller is NOT the pane being respawned (e.g. the daemon resuming a frozen
484
+ * focus pane), so it can confirm the respawn landed. Returns true on success. */
485
+ export function respawnPaneSync(opts) {
486
+ return tmux(respawnPaneArgs(opts)).ok;
487
+ }
488
+ /** Queue an in-place respawn through the tmux server. A program running IN the
489
+ * target pane must use this instead of `respawnPaneSync`: `respawn-pane -k`
490
+ * terminates that program, while this server-owned shell outlives the pane
491
+ * process long enough to run the respawn. The returned status only confirms
492
+ * tmux accepted the queued command. */
493
+ export function respawnPaneInBackground(opts) {
494
+ const command = `tmux ${respawnPaneArgs(opts).map(shellQuote).join(' ')} >/dev/null 2>&1`;
495
+ return tmux(['run-shell', '-b', command]).ok;
496
+ }
497
+ /** The command line a pane was originally started with (`#{pane_start_command}`)
498
+ * — the exact command `respawn-pane` with no argument re-runs. undefined when
499
+ * tmux is unreachable or the pane is gone. */
500
+ export function paneStartCommand(pane) {
501
+ const r = tmux(['display-message', '-p', '-t', pane, '#{pane_start_command}']);
502
+ return r.ok ? r.stdout : undefined;
503
+ }
504
+ /** The pane's root process pid (`#{pane_pid}`) — the process tmux launched in
505
+ * the pane (the viewer itself, or the login shell hosting it). undefined when
506
+ * tmux is unreachable or the pane is gone. */
507
+ export function panePid(pane) {
508
+ const r = tmux(['display-message', '-p', '-t', pane, '#{pane_pid}']);
509
+ if (!r.ok)
510
+ return undefined;
511
+ const pid = Number.parseInt(r.stdout, 10);
512
+ return Number.isInteger(pid) && pid > 0 ? pid : undefined;
513
+ }
514
+ /** Kill a pane's current process and re-run the SAME command line it was
515
+ * started with (`respawn-pane -k` with no command reuses the pane's original
516
+ * command). Used to hot-reload a viewer pane in place: the fresh process
517
+ * re-resolves `crtr` and picks up the currently selected runtime generation,
518
+ * while the pane id, geometry, and the node's broker are untouched. */
519
+ export function respawnPaneInPlace(pane) {
520
+ return tmux(['respawn-pane', '-k', '-t', pane]).ok;
521
+ }
522
+ // ---------------------------------------------------------------------------
523
+ // pi command assembly
524
+ // ---------------------------------------------------------------------------
525
+ /** Turn a pi argv array into a single shell command string.
526
+ *
527
+ * The binary defaults to `CRTR_PI_BINARY` when that env var is set, else the
528
+ * bundled pi CLI launched with the current Node binary. CRTR_PI_BINARY is a
529
+ * TEST-ONLY substitution seam: the integration-test harness points it at a
530
+ * deterministic fake-pi vehicle so a real `crtr node new` reaches the fake
531
+ * instead of the LLM pi, without depending on tmux/shell PATH inheritance. An
532
+ * explicit `binary` arg still overrides the env. The value may be a multi-word
533
+ * launcher (e.g. `node --import tsx/esm host.ts`); only argv entries are
534
+ * shell-quoted, so a multi-word binary is spliced verbatim ahead of them. */
535
+ export function piCommand(argv, binary = process.env['CRTR_PI_BINARY'] ?? bundledPiCommandForShell(shellQuote)) {
536
+ return [binary, ...argv.map(shellQuote)].join(' ');
537
+ }
538
+ // ---------------------------------------------------------------------------
539
+ // Window liveness helpers (used by the supervisor daemon)
540
+ // ---------------------------------------------------------------------------
541
+ /** List all window ids present in `session`. Returns [] if the session does
542
+ * not exist or tmux fails for any reason. Each entry is the raw window id
543
+ * string reported by tmux (e.g. `@1`, `@2`, …). */
544
+ export function listWindowIds(session) {
545
+ const r = tmux(['list-windows', '-t', session, '-F', '#{window_id}']);
546
+ if (!r.ok || r.stdout === '')
547
+ return [];
548
+ return r.stdout.split('\n').filter((s) => s !== '');
549
+ }
550
+ /** True when both `session` and `window` are present (non-null/undefined) and
551
+ * the window currently exists inside the session. False whenever either arg
552
+ * is absent, the session is gone, or tmux does not know the window. */
553
+ export function windowAlive(session, window) {
554
+ if (session == null || window == null)
555
+ return false;
556
+ return listWindowIds(session).includes(window);
557
+ }
558
+ // ---------------------------------------------------------------------------
559
+ // Focus helpers (used by the placement layer)
560
+ // ---------------------------------------------------------------------------
561
+ /** Activate a window within its session (same-session navigation). Equivalent
562
+ * to `tmux select-window -t <session>:<window>`. Best-effort; never throws. */
563
+ export function selectWindow(session, window) {
564
+ return tmux(['select-window', '-t', `${session}:${window}`]).ok;
565
+ }
566
+ /** Apply a named tmux layout to a window (`tmux select-layout -t <window>
567
+ * <layout>`). `surface tmux-spread` calls it with `tiled` to evenly grid every
568
+ * viewer pane in the spread window (and between splits, to redistribute space so
569
+ * the next split has room). Best-effort; false if tmux fails. */
570
+ export function selectLayout(window, layout) {
571
+ return tmux(['select-layout', '-t', window, layout]).ok;
572
+ }
573
+ /** Make a pane the ACTIVE pane in its window (`tmux select-pane -t <pane>`). A
574
+ * `split-window -d` keeps the CALLER active, so a freshly-opened viewer pane is
575
+ * not focused until this runs — `focus` calls it so picking a node (e.g. from the
576
+ * alt+g graph) lands the keyboard on the new viewer. Best-effort; false if tmux
577
+ * fails. */
578
+ export function selectPane(pane) {
579
+ return tmux(['select-pane', '-t', pane]).ok;
580
+ }
581
+ /** Switch the tmux client to a different session (cross-session focus). Runs
582
+ * `tmux switch-client -t <session>`. Best-effort; never throws. The caller is
583
+ * responsible for following up with selectWindow to land on the right window. */
584
+ export function switchClient(session) {
585
+ return tmux(['switch-client', '-t', session]).ok;
586
+ }
587
+ // ---------------------------------------------------------------------------
588
+ // send-keys (chrome — used by the prefix menu + nav bindings)
589
+ // ---------------------------------------------------------------------------
590
+ /** Type a literal (e.g. a `/graph` slash command) into a pane and press Enter
591
+ * (`tmux send-keys -t <pane> '<text>' Enter`). Requires the pane's editor be
592
+ * empty, same limitation as the menu's `/promote` item. Best-effort. */
593
+ export function sendKeysEnter(pane, text) {
594
+ return tmux(['send-keys', '-t', pane, text, 'Enter']).ok;
595
+ }
596
+ // Binding reconciliation needs the raw tmux invocation primitive but no other
597
+ // module may reach around the driver boundary.
598
+ export { tmux as runTmux };
@@ -0,0 +1,14 @@
1
+ /** The shared cold-start deadline (ms) a freshly-opened viewer waits for its
2
+ * broker's view.sock — one source of truth for CRTR_ATTACH_WAIT_MS. */
3
+ export declare const BROKER_VIEW_SOCKET_WAIT_MS = 30000;
4
+ /** Resolve true exactly when `sockPath` accepts a connection within `timeoutMs`. */
5
+ export declare function probeViewSocket(sockPath: string, timeoutMs: number): Promise<boolean>;
6
+ /** Bounded retry for the revive leaf, which has no launch handle to observe. */
7
+ export declare function waitForViewSocketReady(nodeId: string): Promise<boolean>;
8
+ /** Wait for a launched broker's view.sock, failing fast when its launch handle
9
+ * exits. `exited` remains optional for existing callers that only need the same
10
+ * bounded readiness deadline without a handle. */
11
+ export declare function waitForBrokerViewSocket(nodeId: string, exited?: Promise<{
12
+ code: number | null;
13
+ signal: NodeJS.Signals | null;
14
+ }>): Promise<boolean>;