@north-light/crouter 0.3.172 → 0.3.174

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 (673) 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} +106 -177
  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 +55 -0
  46. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +60 -0
  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/node/bash.d.ts +1 -0
  138. package/dist/commands/node/bash.js +198 -0
  139. package/dist/commands/node/create.d.ts +23 -0
  140. package/dist/commands/node/create.js +207 -0
  141. package/dist/commands/node/inspect.d.ts +2 -0
  142. package/dist/commands/node/inspect.js +302 -0
  143. package/dist/commands/node/lifecycle.d.ts +4 -0
  144. package/dist/commands/node/lifecycle.js +415 -0
  145. package/dist/commands/node/message.d.ts +1 -0
  146. package/dist/commands/node/message.js +164 -0
  147. package/dist/commands/node/pyramid.d.ts +2 -0
  148. package/dist/commands/node/pyramid.js +79 -0
  149. package/dist/commands/node/subscription.d.ts +1 -0
  150. package/dist/commands/node/subscription.js +82 -0
  151. package/dist/commands/node/wait.d.ts +1 -0
  152. package/dist/commands/node/wait.js +159 -0
  153. package/dist/commands/node-lifecycle-revive.js +10 -57
  154. package/dist/commands/node.d.ts +0 -42
  155. package/dist/commands/node.js +11 -2065
  156. package/dist/commands/search.js +1 -1
  157. package/dist/commands/surface/node/cycle.d.ts +1 -0
  158. package/dist/commands/surface/node/cycle.js +83 -0
  159. package/dist/commands/surface/node/focus.d.ts +1 -0
  160. package/dist/commands/surface/node/focus.js +67 -0
  161. package/dist/commands/surface/node/id.d.ts +1 -0
  162. package/dist/commands/surface/node/id.js +38 -0
  163. package/dist/commands/surface/node/pin.d.ts +1 -0
  164. package/dist/commands/surface/node/pin.js +42 -0
  165. package/dist/commands/surface/node/placement.d.ts +46 -0
  166. package/dist/commands/surface/node/placement.js +124 -0
  167. package/dist/commands/surface-node.js +4 -1
  168. package/dist/commands/surface-reload.js +1 -2
  169. package/dist/commands/surface-tmux-spread.js +1 -1
  170. package/dist/commands/surface.js +5 -20
  171. package/dist/commands/sys/__tests__/setup-core.test.js +18 -271
  172. package/dist/commands/sys/config.js +6 -6
  173. package/dist/commands/sys/logs.js +1 -1
  174. package/dist/commands/sys/panels/broker-limits-panel.d.ts +17 -0
  175. package/dist/commands/sys/panels/broker-limits-panel.js +104 -0
  176. package/dist/commands/sys/panels/dependencies-panel.d.ts +14 -0
  177. package/dist/commands/sys/panels/dependencies-panel.js +80 -0
  178. package/dist/commands/sys/panels/keybindings-panel.d.ts +56 -0
  179. package/dist/commands/sys/panels/keybindings-panel.js +703 -0
  180. package/dist/commands/sys/panels/keys-panel.d.ts +16 -0
  181. package/dist/commands/sys/panels/keys-panel.js +60 -0
  182. package/dist/commands/sys/panels/models-panel.d.ts +77 -0
  183. package/dist/commands/sys/panels/models-panel.js +647 -0
  184. package/dist/commands/sys/panels/panel.d.ts +45 -0
  185. package/dist/commands/sys/panels/panel.js +137 -0
  186. package/dist/commands/sys/panels/plugins-panel.d.ts +16 -0
  187. package/dist/commands/sys/panels/plugins-panel.js +80 -0
  188. package/dist/commands/sys/panels/prefs-panel.d.ts +21 -0
  189. package/dist/commands/sys/panels/prefs-panel.js +85 -0
  190. package/dist/commands/sys/panels/provider-panel.d.ts +62 -0
  191. package/dist/commands/sys/panels/provider-panel.js +538 -0
  192. package/dist/commands/sys/settings-shell.d.ts +55 -0
  193. package/dist/commands/sys/settings-shell.js +400 -0
  194. package/dist/commands/sys/settings.d.ts +2 -0
  195. package/dist/commands/sys/settings.js +31 -0
  196. package/dist/commands/sys/setup-core.d.ts +3 -33
  197. package/dist/commands/sys/setup-core.js +27 -78
  198. package/dist/commands/sys/setup-settings-runner.d.ts +24 -0
  199. package/dist/commands/sys/setup-settings-runner.js +63 -0
  200. package/dist/commands/sys/setup-wizard.d.ts +26 -125
  201. package/dist/commands/sys/setup-wizard.js +209 -2473
  202. package/dist/commands/sys/setup.js +5 -7
  203. package/dist/commands/sys.js +3 -2
  204. package/dist/core/__tests__/broker-extension-canvas-db-boundary.test.js +50 -0
  205. package/dist/core/__tests__/broker-launch-candidates.test.js +20 -9
  206. package/dist/core/__tests__/broker-preflight.test.js +1 -1
  207. package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +108 -27
  208. package/dist/core/__tests__/canvas-inbox-watcher.test.js +14 -0
  209. package/dist/core/__tests__/canvas.test.js +2 -36
  210. package/dist/core/__tests__/close.test.js +14 -3
  211. package/dist/core/__tests__/context-intro.test.js +32 -143
  212. package/dist/core/__tests__/cron-broker-capacity.test.js +22 -3
  213. package/dist/core/__tests__/daemon-boot.test.js +2 -20
  214. package/dist/core/__tests__/daemon-wedge.test.js +1 -1
  215. package/dist/core/__tests__/dead-node-policy-table.test.js +1 -18
  216. package/dist/core/__tests__/fixtures/fake-engine.d.ts +1 -1
  217. package/dist/core/__tests__/fixtures/fake-engine.js +2 -2
  218. package/dist/core/__tests__/fixtures/fake-pi-host.js +2 -2
  219. package/dist/core/__tests__/focuses.test.js +4 -98
  220. package/dist/core/__tests__/helpers/broker-clients.d.ts +0 -3
  221. package/dist/core/__tests__/helpers/broker-clients.js +0 -14
  222. package/dist/core/__tests__/helpers/harness.d.ts +0 -8
  223. package/dist/core/__tests__/helpers/harness.js +7 -87
  224. package/dist/core/__tests__/helpers/viewer-panes.js +1 -1
  225. package/dist/core/__tests__/inline-memory-refs.test.js +5 -134
  226. package/dist/core/__tests__/kickoff.test.js +1 -1
  227. package/dist/core/__tests__/memory-resolver-precedence.test.js +29 -1
  228. package/dist/core/__tests__/migration.test.js +35 -48
  229. package/dist/core/__tests__/on-read-dedup-resume.test.js +22 -12
  230. package/dist/core/__tests__/passive-subscription.test.js +26 -49
  231. package/dist/core/__tests__/preview-registry-sync.test.js +1 -2
  232. package/dist/core/__tests__/prune.test.js +94 -1
  233. package/dist/core/__tests__/review-model-floor.test.js +0 -32
  234. package/dist/core/__tests__/seam/broker-attach-multiclient.test.js +255 -0
  235. package/dist/core/__tests__/{full → seam}/broker-attach-stream.test.js +39 -7
  236. package/dist/core/__tests__/{full → seam}/broker-crash-teardown.test.js +30 -29
  237. package/dist/core/__tests__/{full → seam}/broker-pane-resolution.test.js +54 -5
  238. package/dist/core/__tests__/{full → seam}/broker-provider-retry.test.js +134 -82
  239. package/dist/core/__tests__/{full → seam}/broker-whip-interrupt.test.js +15 -4
  240. package/dist/core/__tests__/{full/idle-release-settlement.test.js → seam/dormancy-release.test.js} +69 -17
  241. package/dist/core/__tests__/{full/yield-message-transaction.test.js → seam/yield-refresh-transaction.test.js} +31 -9
  242. package/dist/core/__tests__/secrets.test.js +1 -7
  243. package/dist/core/__tests__/{broker-fork-seam.test.js → serial/broker-fork-seam.test.js} +58 -7
  244. package/dist/core/__tests__/{broker-sdk-wiring.test.js → serial/broker-sdk-wiring.test.js} +18 -162
  245. package/dist/core/__tests__/{broker-snapshot-history.test.js → serial/broker-snapshot-history.test.js} +9 -9
  246. package/dist/core/__tests__/{command-plugins.test.js → serial/command-plugins.test.js} +105 -15
  247. package/dist/core/__tests__/{deferred-no-wake.test.js → serial/deferred-no-wake.test.js} +23 -20
  248. package/dist/core/__tests__/{flagship-lifecycle.test.js → serial/flagship-lifecycle.test.js} +7 -7
  249. package/dist/core/__tests__/{host-teardown-process-group.test.js → serial/host-teardown-process-group.test.js} +6 -6
  250. package/dist/core/__tests__/{human-deliver-e2e.test.js → serial/human-deliver-e2e.test.js} +12 -12
  251. package/dist/core/__tests__/{live-mutation.test.js → serial/live-mutation.test.js} +5 -5
  252. package/dist/core/__tests__/{refresh-stall-recycle.test.js → serial/refresh-stall-recycle.test.js} +5 -14
  253. package/dist/core/__tests__/{revive.test.js → serial/revive.test.js} +15 -100
  254. package/dist/core/__tests__/{spawn-root.test.js → serial/spawn-root.test.js} +32 -15
  255. package/dist/core/__tests__/serial/subscription-delivery.test.js +126 -0
  256. package/dist/core/__tests__/serial/tmux-surface.test.js +256 -0
  257. package/dist/core/__tests__/{worktree.test.js → serial/worktree.test.js} +15 -15
  258. package/dist/core/__tests__/session-model.test.js +0 -18
  259. package/dist/core/__tests__/spawn-worktree-id-conflict.test.js +9 -0
  260. package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +50 -0
  261. package/dist/core/broker-client/__tests__/transport-relay.test.js +15 -16
  262. package/dist/core/broker-client/__tests__/transport-socket.test.js +28 -0
  263. package/dist/core/broker-client/client.d.ts +2 -2
  264. package/dist/core/broker-client/client.js +4 -7
  265. package/dist/core/broker-client/transport-relay.d.ts +13 -19
  266. package/dist/core/broker-client/transport-relay.js +19 -34
  267. package/dist/core/broker-client/transport-socket.d.ts +2 -2
  268. package/dist/core/broker-client/transport-socket.js +9 -2
  269. package/dist/core/broker-client/transport.d.ts +7 -3
  270. package/dist/core/broker-client/transport.js +4 -4
  271. package/dist/core/canvas/__tests__/attention.test.js +1 -18
  272. package/dist/core/canvas/__tests__/remote-canvas-source.test.js +7 -64
  273. package/dist/core/canvas/__tests__/remote-transport.test.js +2 -3
  274. package/dist/core/canvas/__tests__/render-remote.test.js +7 -52
  275. package/dist/core/canvas/browse/app.d.ts +2 -17
  276. package/dist/core/canvas/browse/app.js +16 -88
  277. package/dist/core/canvas/browse/model.d.ts +0 -4
  278. package/dist/core/canvas/browse/model.js +1 -12
  279. package/dist/core/canvas/browse/render.js +6 -3
  280. package/dist/core/canvas/crons.d.ts +8 -5
  281. package/dist/core/canvas/crons.js +7 -6
  282. package/dist/core/canvas/extensions.d.ts +7 -3
  283. package/dist/core/canvas/extensions.js +16 -4
  284. package/dist/core/canvas/nav-model.d.ts +0 -4
  285. package/dist/core/canvas/nav-model.js +2 -14
  286. package/dist/core/canvas/node-order.d.ts +3 -0
  287. package/dist/core/canvas/node-order.js +12 -0
  288. package/dist/core/canvas/remote-canvas-source.d.ts +3 -6
  289. package/dist/core/canvas/remote-canvas-source.js +8 -15
  290. package/dist/core/command.js +11 -4
  291. package/dist/core/config.js +3 -1
  292. package/dist/core/events/envelope.js +1 -1
  293. package/dist/core/events/read.js +7 -21
  294. package/dist/core/events/source.d.ts +0 -2
  295. package/dist/core/events/source.js +0 -16
  296. package/dist/core/events/types.d.ts +1 -1
  297. package/dist/core/fault-classifier.d.ts +1 -1
  298. package/dist/core/feed/passive.d.ts +0 -11
  299. package/dist/core/feed/passive.js +1 -62
  300. package/dist/core/human/__tests__/{inbox-core.test.js → serial/inbox-core.test.js} +6 -6
  301. package/dist/core/keybindings/__tests__/resolve.test.js +1 -96
  302. package/dist/core/keybindings/background-bash.js +3 -4
  303. package/dist/core/keybindings/catalog.js +1 -1
  304. package/dist/core/memory/inline-ref-grammar.js +3 -3
  305. package/dist/core/memory-resolver.d.ts +11 -25
  306. package/dist/core/memory-resolver.js +51 -33
  307. package/dist/core/model-routes.d.ts +15 -0
  308. package/dist/core/model-routes.js +12 -0
  309. package/dist/core/pool-credential-store.js +1 -1
  310. package/dist/core/preview-registry.js +8 -9
  311. package/dist/core/profiles/__tests__/root-profile.test.js +4 -14
  312. package/dist/core/review/realize.d.ts +0 -13
  313. package/dist/core/review/realize.js +0 -40
  314. package/dist/core/review/types.d.ts +1 -1
  315. package/dist/core/runtime/__tests__/engine-route.test.js +2 -2
  316. package/dist/core/runtime/bearings.js +1 -11
  317. package/dist/core/runtime/broker/client-registry.d.ts +33 -0
  318. package/dist/core/runtime/broker/client-registry.js +164 -0
  319. package/dist/core/runtime/broker/daemon-ops.d.ts +19 -0
  320. package/dist/core/runtime/broker/daemon-ops.js +49 -0
  321. package/dist/core/runtime/broker/event-projection.d.ts +42 -0
  322. package/dist/core/runtime/broker/event-projection.js +178 -0
  323. package/dist/core/runtime/broker/fault-retry.d.ts +39 -0
  324. package/dist/core/runtime/broker/fault-retry.js +277 -0
  325. package/dist/core/runtime/broker/frame-dispatch.d.ts +238 -0
  326. package/dist/core/runtime/broker/frame-dispatch.js +1537 -0
  327. package/dist/core/runtime/broker/inbox.d.ts +22 -0
  328. package/dist/core/runtime/broker/inbox.js +167 -0
  329. package/dist/core/runtime/broker/passive.d.ts +16 -0
  330. package/dist/core/runtime/broker/passive.js +44 -0
  331. package/dist/core/runtime/broker/read-ops.d.ts +23 -0
  332. package/dist/core/runtime/broker/read-ops.js +150 -0
  333. package/dist/core/runtime/broker/rebind.d.ts +74 -0
  334. package/dist/core/runtime/broker/rebind.js +211 -0
  335. package/dist/core/runtime/broker/tool-groups.d.ts +39 -0
  336. package/dist/core/runtime/broker/tool-groups.js +244 -0
  337. package/dist/core/runtime/broker-extension-render.d.ts +11 -0
  338. package/dist/core/runtime/broker-extension-render.js +181 -0
  339. package/dist/core/runtime/broker-persona-guidance.d.ts +13 -0
  340. package/dist/core/runtime/broker-persona-guidance.js +58 -0
  341. package/dist/core/runtime/broker-protocol.d.ts +1 -1
  342. package/dist/core/runtime/broker-protocol.js +1 -1
  343. package/dist/core/runtime/broker.d.ts +5 -196
  344. package/dist/core/runtime/broker.js +276 -3059
  345. package/dist/core/runtime/canvas-extensions.js +11 -2
  346. package/dist/core/runtime/fault.js +1 -1
  347. package/dist/core/runtime/model-selection.d.ts +9 -0
  348. package/dist/core/runtime/model-selection.js +12 -0
  349. package/dist/core/runtime/model-swap.d.ts +3 -3
  350. package/dist/core/runtime/model-swap.js +33 -25
  351. package/dist/core/runtime/placement-tmux.d.ts +3 -14
  352. package/dist/core/runtime/placement-tmux.js +11 -80
  353. package/dist/core/runtime/placement.d.ts +4 -2
  354. package/dist/core/runtime/placement.js +7 -12
  355. package/dist/core/runtime/promote.d.ts +14 -1
  356. package/dist/core/runtime/promote.js +1 -1
  357. package/dist/core/runtime/reset.d.ts +1 -1
  358. package/dist/core/runtime/roadmap.js +1 -1
  359. package/dist/core/runtime/spawn.d.ts +8 -0
  360. package/dist/core/runtime/spawn.js +36 -6
  361. package/dist/core/runtime/stop-guard.d.ts +4 -3
  362. package/dist/core/runtime/stop-guard.js +36 -18
  363. package/dist/core/runtime/stop-signals.d.ts +4 -1
  364. package/dist/core/runtime/stream-watchdog.js +4 -5
  365. package/dist/core/runtime/structured-output.d.ts +15 -2
  366. package/dist/core/runtime/structured-output.js +35 -12
  367. package/dist/core/runtime/tmux-bindings.d.ts +25 -0
  368. package/dist/core/runtime/tmux-bindings.js +682 -0
  369. package/dist/core/runtime/tmux-chrome.d.ts +2 -1
  370. package/dist/core/runtime/tmux-chrome.js +3 -2
  371. package/dist/core/runtime/{tmux.d.ts → tmux-driver.d.ts} +18 -26
  372. package/dist/core/runtime/tmux-driver.js +598 -0
  373. package/dist/core/runtime/view-socket.d.ts +14 -0
  374. package/dist/core/runtime/view-socket.js +83 -0
  375. package/dist/core/session-model/session-state.d.ts +1 -2
  376. package/dist/core/session-model/session-state.js +5 -8
  377. package/dist/core/spawn.d.ts +1 -1
  378. package/dist/core/spawn.js +2 -2
  379. package/dist/core/substrate/gate.d.ts +1 -1
  380. package/dist/core/substrate/on-read-pure.d.ts +7 -0
  381. package/dist/core/substrate/on-read-pure.js +272 -0
  382. package/dist/core/termrender/termrender.js +32 -2
  383. package/dist/core/user-settings.d.ts +23 -1
  384. package/dist/core/user-settings.js +18 -1
  385. package/dist/daemon/api/__tests__/node-model-validation.test.js +134 -0
  386. package/dist/daemon/api/__tests__/review-terminal-conflict.test.js +98 -0
  387. package/dist/daemon/api/__tests__/{full → seam}/api-server.test.js +6 -48
  388. package/dist/daemon/api/__tests__/{full → seam}/b10-attach-modelauth.test.js +17 -44
  389. package/dist/daemon/api/__tests__/{full/push-parity.test.js → seam/leaf-api-parity.test.js} +61 -42
  390. package/dist/daemon/api/bridge.js +40 -81
  391. package/dist/daemon/api/handlers/broker-ops.d.ts +2 -0
  392. package/dist/daemon/api/handlers/broker-ops.js +383 -0
  393. package/dist/daemon/api/handlers/crons.js +9 -4
  394. package/dist/daemon/api/handlers/files.js +6 -7
  395. package/dist/daemon/api/handlers/inbox.js +2 -340
  396. package/dist/daemon/api/handlers/nodes.d.ts +10 -1
  397. package/dist/daemon/api/handlers/nodes.js +74 -39
  398. package/dist/daemon/api/handlers/review-comments.js +5 -1
  399. package/dist/daemon/api/handlers/reviews.js +0 -19
  400. package/dist/daemon/api/map.js +25 -4
  401. package/dist/daemon/api/router.js +2 -3
  402. package/dist/daemon/api/server.js +5 -7
  403. package/dist/daemon/cron-run.d.ts +4 -0
  404. package/dist/daemon/cron-run.js +30 -13
  405. package/dist/daemon/crtrd.d.ts +3 -58
  406. package/dist/daemon/crtrd.js +28 -1244
  407. package/dist/daemon/manage.js +0 -1
  408. package/dist/daemon/reconcilers/broker-supervision.d.ts +50 -0
  409. package/dist/daemon/reconcilers/broker-supervision.js +549 -0
  410. package/dist/daemon/reconcilers/cron-lane.d.ts +10 -0
  411. package/dist/daemon/reconcilers/cron-lane.js +32 -0
  412. package/dist/daemon/reconcilers/dormant-inbox.d.ts +18 -0
  413. package/dist/daemon/reconcilers/dormant-inbox.js +143 -0
  414. package/dist/daemon/reconcilers/storage-maintenance.d.ts +22 -0
  415. package/dist/daemon/reconcilers/storage-maintenance.js +213 -0
  416. package/dist/daemon/review/finish.js +2 -5
  417. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +34 -53
  418. package/dist/pi-extensions/__tests__/canvas-recap.test.js +16 -113
  419. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +72 -99
  420. package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.js +29 -12
  421. package/dist/pi-extensions/broker-local.d.ts +20 -0
  422. package/dist/pi-extensions/broker-local.js +89 -0
  423. package/dist/pi-extensions/canvas-context-intro.d.ts +3 -3
  424. package/dist/pi-extensions/canvas-context-intro.js +22 -11
  425. package/dist/pi-extensions/canvas-doc-substrate.js +17 -34
  426. package/dist/pi-extensions/canvas-goal-capture.js +7 -12
  427. package/dist/pi-extensions/canvas-inbox-watcher.js +124 -139
  428. package/dist/pi-extensions/canvas-passive-context.d.ts +3 -3
  429. package/dist/pi-extensions/canvas-passive-context.js +22 -18
  430. package/dist/pi-extensions/canvas-recap.d.ts +2 -2
  431. package/dist/pi-extensions/canvas-recap.js +48 -21
  432. package/dist/pi-extensions/canvas-review-boundary.js +10 -4
  433. package/dist/pi-extensions/canvas-stophook.d.ts +0 -5
  434. package/dist/pi-extensions/canvas-stophook.js +149 -431
  435. package/dist/pi-extensions/canvas-structured-output.js +52 -30
  436. package/dist/pi-extensions/envelope-merge.d.ts +13 -0
  437. package/dist/pi-extensions/envelope-merge.js +29 -0
  438. package/dist/shared/working-activity.d.ts +3 -2
  439. package/dist/shared/working-activity.js +3 -2
  440. package/dist/types.d.ts +6 -5
  441. package/dist/types.js +2 -2
  442. package/docs/compat/hearth-crtr-v1.md +4 -12
  443. package/docs/compat/hearth-crtr-v2.md +3 -11
  444. package/docs/compat/hearth-crtr-v3.md +4 -12
  445. package/docs/compat/hearth-crtr-v4.md +3 -11
  446. package/docs/compat/hearth-crtr-v5.md +3 -11
  447. package/docs/public-api.md +3 -7
  448. package/package.json +7 -49
  449. package/runtime.lock.json +2766 -14533
  450. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/claude-plugin-commands.test.ts +0 -49
  451. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/memory-slash-commands.test.ts +0 -194
  452. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/statusline.test.ts +0 -68
  453. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/frontmatter-rules/test.ts +0 -119
  454. package/dist/clients/attach/__tests__/attach-chrome-remote.test.js +0 -439
  455. package/dist/clients/attach/__tests__/attach-keybindings.test.js +0 -170
  456. package/dist/clients/attach/__tests__/crtr-output-coverage.test.js +0 -57
  457. package/dist/clients/attach/__tests__/editor-frame-title.test.js +0 -19
  458. package/dist/clients/attach/__tests__/input-controller-extension-command.test.js +0 -32
  459. package/dist/clients/attach/__tests__/markdown-headings.test.js +0 -35
  460. package/dist/clients/attach/__tests__/session-identity-refresh.test.js +0 -32
  461. package/dist/clients/conversation/conversation.d.ts +0 -65
  462. package/dist/clients/conversation/conversation.js +0 -318
  463. package/dist/clients/conversation/frames.d.ts +0 -30
  464. package/dist/clients/conversation/frames.js +0 -52
  465. package/dist/clients/conversation/region.d.ts +0 -51
  466. package/dist/clients/conversation/region.js +0 -265
  467. package/dist/clients/inbox/__tests__/inbox-controller.test.js +0 -247
  468. package/dist/clients/inbox/__tests__/mount-panel.test.js +0 -776
  469. package/dist/clients/inbox/review/__tests__/remap.test.js +0 -196
  470. package/dist/clients/inbox/review/columns.d.ts +0 -22
  471. package/dist/clients/inbox/review/columns.js +0 -40
  472. package/dist/clients/inbox/review/composition.d.ts +0 -60
  473. package/dist/clients/inbox/review/composition.js +0 -278
  474. package/dist/clients/inbox/review/document-region.d.ts +0 -120
  475. package/dist/clients/surfaces/region.d.ts +0 -16
  476. package/dist/clients/web/__tests__/push-engine.test.js +0 -158
  477. package/dist/clients/web/__tests__/push-registry.test.d.ts +0 -1
  478. package/dist/clients/web/__tests__/push-registry.test.js +0 -177
  479. package/dist/clients/web/dev-server.d.ts +0 -7
  480. package/dist/clients/web/dev-server.js +0 -46
  481. package/dist/clients/web/events.d.ts +0 -19
  482. package/dist/clients/web/events.js +0 -163
  483. package/dist/clients/web/push-engine.d.ts +0 -44
  484. package/dist/clients/web/push-engine.js +0 -125
  485. package/dist/clients/web/push-registry.d.ts +0 -85
  486. package/dist/clients/web/push-registry.js +0 -373
  487. package/dist/clients/web/server.d.ts +0 -19
  488. package/dist/clients/web/server.js +0 -661
  489. package/dist/clients/web/web-client/shared/protocol.d.ts +0 -214
  490. package/dist/clients/web/web-client/shared/protocol.js +0 -8
  491. package/dist/clients/web/web-cmd.d.ts +0 -2
  492. package/dist/clients/web/web-cmd.js +0 -141
  493. package/dist/commands/__tests__/api-canvas-source.test.d.ts +0 -1
  494. package/dist/commands/__tests__/api-canvas-source.test.js +0 -37
  495. package/dist/commands/__tests__/canvas-config.test.d.ts +0 -1
  496. package/dist/commands/__tests__/canvas-config.test.js +0 -107
  497. package/dist/commands/__tests__/node-no-kickoff-flag.test.d.ts +0 -1
  498. package/dist/commands/__tests__/node-no-kickoff-flag.test.js +0 -73
  499. package/dist/commands/__tests__/node-worktree-flag.test.d.ts +0 -1
  500. package/dist/commands/__tests__/node-worktree-flag.test.js +0 -49
  501. package/dist/commands/__tests__/search-contents.test.d.ts +0 -1
  502. package/dist/commands/__tests__/search-contents.test.js +0 -52
  503. package/dist/commands/memory/__tests__/lint.test.d.ts +0 -1
  504. package/dist/commands/memory/__tests__/lint.test.js +0 -15
  505. package/dist/commands/sys/__tests__/config-broker-thresholds.test.d.ts +0 -1
  506. package/dist/commands/sys/__tests__/config-broker-thresholds.test.js +0 -95
  507. package/dist/commands/sys/__tests__/config-keybindings.test.d.ts +0 -1
  508. package/dist/commands/sys/__tests__/config-keybindings.test.js +0 -55
  509. package/dist/commands/sys/__tests__/helpers/setup-runtime.d.ts +0 -5
  510. package/dist/commands/sys/__tests__/helpers/setup-runtime.js +0 -19
  511. package/dist/commands/sys/__tests__/setup-front-door.test.d.ts +0 -1
  512. package/dist/commands/sys/__tests__/setup-front-door.test.js +0 -102
  513. package/dist/commands/sys/__tests__/setup-models.test.d.ts +0 -1
  514. package/dist/commands/sys/__tests__/setup-models.test.js +0 -205
  515. package/dist/commands/sys/__tests__/setup-providers-viewport.test.d.ts +0 -1
  516. package/dist/commands/sys/__tests__/setup-providers-viewport.test.js +0 -155
  517. package/dist/commands/sys/__tests__/sync-deps.test.d.ts +0 -1
  518. package/dist/commands/sys/__tests__/sync-deps.test.js +0 -179
  519. package/dist/commands/sys/__tests__/sync-import.test.d.ts +0 -1
  520. package/dist/commands/sys/__tests__/sync-import.test.js +0 -315
  521. package/dist/core/__tests__/base-worker-prompt.test.d.ts +0 -1
  522. package/dist/core/__tests__/base-worker-prompt.test.js +0 -57
  523. package/dist/core/__tests__/command-plugins-surfaces.test.d.ts +0 -1
  524. package/dist/core/__tests__/command-plugins-surfaces.test.js +0 -359
  525. package/dist/core/__tests__/connection-reconnect-resume.test.d.ts +0 -1
  526. package/dist/core/__tests__/connection-reconnect-resume.test.js +0 -36
  527. package/dist/core/__tests__/finalization-migration.test.d.ts +0 -1
  528. package/dist/core/__tests__/finalization-migration.test.js +0 -38
  529. package/dist/core/__tests__/fixtures/extra-extension.d.ts +0 -1
  530. package/dist/core/__tests__/fixtures/extra-extension.js +0 -3
  531. package/dist/core/__tests__/fixtures/spawn-proof-target.test.d.ts +0 -1
  532. package/dist/core/__tests__/fixtures/spawn-proof-target.test.js +0 -15
  533. package/dist/core/__tests__/fork.test.d.ts +0 -1
  534. package/dist/core/__tests__/fork.test.js +0 -108
  535. package/dist/core/__tests__/full/broker-attach-limits.test.d.ts +0 -1
  536. package/dist/core/__tests__/full/broker-attach-limits.test.js +0 -147
  537. package/dist/core/__tests__/full/broker-deliver-ack.test.d.ts +0 -1
  538. package/dist/core/__tests__/full/broker-deliver-ack.test.js +0 -73
  539. package/dist/core/__tests__/full/broker-dialogs.test.d.ts +0 -1
  540. package/dist/core/__tests__/full/broker-dialogs.test.js +0 -180
  541. package/dist/core/__tests__/full/broker-display-snapshot.test.d.ts +0 -1
  542. package/dist/core/__tests__/full/broker-display-snapshot.test.js +0 -75
  543. package/dist/core/__tests__/full/broker-dormant-wake.test.d.ts +0 -1
  544. package/dist/core/__tests__/full/broker-dormant-wake.test.js +0 -130
  545. package/dist/core/__tests__/full/broker-model-changed-broadcast.test.d.ts +0 -1
  546. package/dist/core/__tests__/full/broker-model-changed-broadcast.test.js +0 -57
  547. package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.d.ts +0 -1
  548. package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.js +0 -80
  549. package/dist/core/__tests__/full/cascade-close.test.d.ts +0 -1
  550. package/dist/core/__tests__/full/cascade-close.test.js +0 -240
  551. package/dist/core/__tests__/full/detach-focus.test.d.ts +0 -1
  552. package/dist/core/__tests__/full/detach-focus.test.js +0 -126
  553. package/dist/core/__tests__/full/idle-release-settlement.test.d.ts +0 -1
  554. package/dist/core/__tests__/full/issue-146-yield-spawn-focus.test.d.ts +0 -1
  555. package/dist/core/__tests__/full/issue-146-yield-spawn-focus.test.js +0 -107
  556. package/dist/core/__tests__/full/park-clock-release.test.d.ts +0 -1
  557. package/dist/core/__tests__/full/park-clock-release.test.js +0 -56
  558. package/dist/core/__tests__/full/yield-message-transaction.test.d.ts +0 -1
  559. package/dist/core/__tests__/memory-index-render.test.d.ts +0 -1
  560. package/dist/core/__tests__/memory-index-render.test.js +0 -60
  561. package/dist/core/__tests__/model-routes.test.d.ts +0 -1
  562. package/dist/core/__tests__/model-routes.test.js +0 -41
  563. package/dist/core/__tests__/on-read-identity.test.d.ts +0 -1
  564. package/dist/core/__tests__/on-read-identity.test.js +0 -61
  565. package/dist/core/__tests__/phase4-review-migration.test.d.ts +0 -1
  566. package/dist/core/__tests__/phase4-review-migration.test.js +0 -100
  567. package/dist/core/__tests__/prune-to-limit.test.d.ts +0 -1
  568. package/dist/core/__tests__/prune-to-limit.test.js +0 -126
  569. package/dist/core/__tests__/reset.test.d.ts +0 -1
  570. package/dist/core/__tests__/reset.test.js +0 -69
  571. package/dist/core/__tests__/spawn-no-kickoff.test.d.ts +0 -1
  572. package/dist/core/__tests__/spawn-no-kickoff.test.js +0 -115
  573. package/dist/core/__tests__/steer-note.test.d.ts +0 -1
  574. package/dist/core/__tests__/steer-note.test.js +0 -41
  575. package/dist/core/__tests__/subcommand-tier.test.d.ts +0 -1
  576. package/dist/core/__tests__/subcommand-tier.test.js +0 -99
  577. package/dist/core/__tests__/subscription-delivery.test.js +0 -211
  578. package/dist/core/__tests__/test-runner-cheap-sharding.test.d.ts +0 -1
  579. package/dist/core/__tests__/test-runner-cheap-sharding.test.js +0 -97
  580. package/dist/core/__tests__/tmux-surface.test.js +0 -484
  581. package/dist/core/__tests__/wake-bearings.test.d.ts +0 -1
  582. package/dist/core/__tests__/wake-bearings.test.js +0 -102
  583. package/dist/core/canvas/__tests__/remote-event-stream.test.d.ts +0 -1
  584. package/dist/core/canvas/__tests__/remote-event-stream.test.js +0 -146
  585. package/dist/core/canvas/__tests__/source-resolve.test.d.ts +0 -1
  586. package/dist/core/canvas/__tests__/source-resolve.test.js +0 -77
  587. package/dist/core/canvas/browse/__tests__/model.test.d.ts +0 -1
  588. package/dist/core/canvas/browse/__tests__/model.test.js +0 -290
  589. package/dist/core/canvas/browse/__tests__/rebuild-coalescer.test.d.ts +0 -1
  590. package/dist/core/canvas/browse/__tests__/rebuild-coalescer.test.js +0 -134
  591. package/dist/core/canvas/browse/__tests__/render.test.d.ts +0 -1
  592. package/dist/core/canvas/browse/__tests__/render.test.js +0 -111
  593. package/dist/core/canvas/browse/rebuild-coalescer.d.ts +0 -7
  594. package/dist/core/canvas/browse/rebuild-coalescer.js +0 -61
  595. package/dist/core/canvas/remote-event-stream.d.ts +0 -24
  596. package/dist/core/canvas/remote-event-stream.js +0 -94
  597. package/dist/core/feed/__tests__/coalesce-human.test.d.ts +0 -1
  598. package/dist/core/feed/__tests__/coalesce-human.test.js +0 -36
  599. package/dist/core/feed/__tests__/empty-node-guard.test.d.ts +0 -1
  600. package/dist/core/feed/__tests__/empty-node-guard.test.js +0 -45
  601. package/dist/core/host-exports/__tests__/export-prunes-boot-skill.test.d.ts +0 -1
  602. package/dist/core/host-exports/__tests__/export-prunes-boot-skill.test.js +0 -84
  603. package/dist/core/human/__tests__/visible-paths.test.d.ts +0 -1
  604. package/dist/core/human/__tests__/visible-paths.test.js +0 -28
  605. package/dist/core/keybindings/__tests__/inbox-affordance.test.d.ts +0 -1
  606. package/dist/core/keybindings/__tests__/inbox-affordance.test.js +0 -38
  607. package/dist/core/review/__tests__/project.test.d.ts +0 -1
  608. package/dist/core/review/__tests__/project.test.js +0 -71
  609. package/dist/core/runtime/__tests__/command-expansion.test.d.ts +0 -1
  610. package/dist/core/runtime/__tests__/command-expansion.test.js +0 -25
  611. package/dist/core/runtime/__tests__/session-visibility.test.d.ts +0 -1
  612. package/dist/core/runtime/__tests__/session-visibility.test.js +0 -119
  613. package/dist/core/runtime/__tests__/spawn-at-given-id.test.d.ts +0 -1
  614. package/dist/core/runtime/__tests__/spawn-at-given-id.test.js +0 -34
  615. package/dist/core/runtime/tmux.js +0 -1314
  616. package/dist/daemon/api/__tests__/full/push-parity.test.d.ts +0 -1
  617. package/dist/daemon/api/__tests__/full/worktree-parity.test.d.ts +0 -1
  618. package/dist/daemon/api/__tests__/full/worktree-parity.test.js +0 -160
  619. package/dist/daemon/api/__tests__/inbox.test.d.ts +0 -1
  620. package/dist/daemon/api/__tests__/inbox.test.js +0 -489
  621. package/dist/web-client/apple-touch-icon.png +0 -0
  622. package/dist/web-client/assets/fragment-mono-latin-400-normal-BYwT3kSJ.woff +0 -0
  623. package/dist/web-client/assets/fragment-mono-latin-400-normal-yxdJ5AmL.woff2 +0 -0
  624. package/dist/web-client/assets/fragment-mono-latin-ext-400-normal-BbKYyvR9.woff2 +0 -0
  625. package/dist/web-client/assets/fragment-mono-latin-ext-400-normal-CT4YFKeK.woff +0 -0
  626. package/dist/web-client/assets/index-CCPaLeW7.css +0 -2
  627. package/dist/web-client/assets/index-kyOWsnZK.js +0 -86
  628. package/dist/web-client/assets/martian-mono-cyrillic-wght-normal-B84CD5C_.woff2 +0 -0
  629. package/dist/web-client/assets/martian-mono-latin-ext-wght-normal-DlL6xMw5.woff2 +0 -0
  630. package/dist/web-client/assets/martian-mono-latin-wght-normal-5W32yIyr.woff2 +0 -0
  631. package/dist/web-client/assets/workbox-window.prod.es5-Bd17z0YL.js +0 -2
  632. package/dist/web-client/icon-192.png +0 -0
  633. package/dist/web-client/icon-512.png +0 -0
  634. package/dist/web-client/icon-maskable-512.png +0 -0
  635. package/dist/web-client/index.html +0 -17
  636. package/dist/web-client/manifest.webmanifest +0 -1
  637. package/dist/web-client/sw.js +0 -1
  638. /package/dist/api/__tests__/{client.test.d.ts → serial/client.test.d.ts} +0 -0
  639. /package/dist/clients/inbox/__tests__/{inbox-controller.test.d.ts → serial/inbox-controller.test.d.ts} +0 -0
  640. /package/dist/clients/inbox/__tests__/{mount-panel.test.d.ts → serial/mount-panel.test.d.ts} +0 -0
  641. /package/dist/clients/{attach/__tests__/attach-chrome-remote.test.d.ts → inbox/review/__tests__/teardown-notice.test.d.ts} +0 -0
  642. /package/dist/{clients/attach/__tests__/attach-keybindings.test.d.ts → core/__tests__/broker-extension-canvas-db-boundary.test.d.ts} +0 -0
  643. /package/dist/{clients/attach/__tests__/crtr-output-coverage.test.d.ts → core/__tests__/seam/broker-attach-multiclient.test.d.ts} +0 -0
  644. /package/dist/core/__tests__/{full → seam}/broker-attach-stream.test.d.ts +0 -0
  645. /package/dist/core/__tests__/{full → seam}/broker-crash-teardown.test.d.ts +0 -0
  646. /package/dist/core/__tests__/{full → seam}/broker-pane-resolution.test.d.ts +0 -0
  647. /package/dist/core/__tests__/{full → seam}/broker-provider-retry.test.d.ts +0 -0
  648. /package/dist/core/__tests__/{full → seam}/broker-whip-interrupt.test.d.ts +0 -0
  649. /package/dist/{clients/attach/__tests__/editor-frame-title.test.d.ts → core/__tests__/seam/dormancy-release.test.d.ts} +0 -0
  650. /package/dist/{clients/attach/__tests__/input-controller-extension-command.test.d.ts → core/__tests__/seam/yield-refresh-transaction.test.d.ts} +0 -0
  651. /package/dist/core/__tests__/{broker-fork-seam.test.d.ts → serial/broker-fork-seam.test.d.ts} +0 -0
  652. /package/dist/core/__tests__/{broker-sdk-wiring.test.d.ts → serial/broker-sdk-wiring.test.d.ts} +0 -0
  653. /package/dist/core/__tests__/{broker-snapshot-history.test.d.ts → serial/broker-snapshot-history.test.d.ts} +0 -0
  654. /package/dist/core/__tests__/{command-plugins.test.d.ts → serial/command-plugins.test.d.ts} +0 -0
  655. /package/dist/core/__tests__/{deferred-no-wake.test.d.ts → serial/deferred-no-wake.test.d.ts} +0 -0
  656. /package/dist/core/__tests__/{flagship-lifecycle.test.d.ts → serial/flagship-lifecycle.test.d.ts} +0 -0
  657. /package/dist/core/__tests__/{host-teardown-process-group.test.d.ts → serial/host-teardown-process-group.test.d.ts} +0 -0
  658. /package/dist/core/__tests__/{human-deliver-e2e.test.d.ts → serial/human-deliver-e2e.test.d.ts} +0 -0
  659. /package/dist/core/__tests__/{live-mutation.test.d.ts → serial/live-mutation.test.d.ts} +0 -0
  660. /package/dist/core/__tests__/{refresh-stall-recycle.test.d.ts → serial/refresh-stall-recycle.test.d.ts} +0 -0
  661. /package/dist/core/__tests__/{revive.test.d.ts → serial/revive.test.d.ts} +0 -0
  662. /package/dist/core/__tests__/{spawn-root.test.d.ts → serial/spawn-root.test.d.ts} +0 -0
  663. /package/dist/core/__tests__/{subscription-delivery.test.d.ts → serial/subscription-delivery.test.d.ts} +0 -0
  664. /package/dist/core/__tests__/{tmux-surface.test.d.ts → serial/tmux-surface.test.d.ts} +0 -0
  665. /package/dist/core/__tests__/{worktree.test.d.ts → serial/worktree.test.d.ts} +0 -0
  666. /package/dist/{clients/attach/__tests__/markdown-headings.test.d.ts → core/__tests__/watchdog-abort-arms-retry.test.d.ts} +0 -0
  667. /package/dist/{clients/attach/__tests__/session-identity-refresh.test.d.ts → core/broker-client/__tests__/transport-socket.test.d.ts} +0 -0
  668. /package/dist/core/human/__tests__/{inbox-core.test.d.ts → serial/inbox-core.test.d.ts} +0 -0
  669. /package/dist/{clients/inbox/review/__tests__/remap.test.d.ts → daemon/api/__tests__/node-model-validation.test.d.ts} +0 -0
  670. /package/dist/{clients/surfaces/region.js → daemon/api/__tests__/review-terminal-conflict.test.d.ts} +0 -0
  671. /package/dist/daemon/api/__tests__/{full → seam}/api-server.test.d.ts +0 -0
  672. /package/dist/daemon/api/__tests__/{full → seam}/b10-attach-modelauth.test.d.ts +0 -0
  673. /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,682 @@
1
+ // tmux bindings — crouter-owned keybinding manifest persistence and reconciliation.
2
+ //
3
+ // Raw tmux process invocation stays in tmux-driver.ts. This module owns the
4
+ // persistent binding manifest, key parsing, and installation.
5
+ import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
6
+ import { tmpdir } from 'node:os';
7
+ import { join } from 'node:path';
8
+ import { ATTACH_CONTROL_BINDINGS, BINDING_CATALOG, BINDING_IDS, encodeAttachControlInput, formatGesture, isAttachPaneBinding, resolveUserKeybindingSettings, } from '../keybindings/index.js';
9
+ import { normalizeTmuxPassthrough } from '../config.js';
10
+ import { withExclusiveDirectoryLock } from '../human/convention.js';
11
+ import { surfaceTmuxStyleArgs } from './surface-bg.js';
12
+ import { runTmux as tmux, shellQuote } from './tmux-driver.js';
13
+ // ---------------------------------------------------------------------------
14
+ // Crouter-owned tmux bindings
15
+ // ---------------------------------------------------------------------------
16
+ const TMUX_BINDING_MANIFEST = '@crtr_keybindings_manifest';
17
+ const ROOT_TABLE = 'root';
18
+ const LEAF_MENU_ACTIONS = {
19
+ 'crtr.tmux.menu.promote': { description: 'promote to orchestrator', action: { kind: 'keys', keys: '/promote' } },
20
+ 'crtr.tmux.menu.resume': { description: 'find node', action: { kind: 'keys', keys: '/resume-node' } },
21
+ 'crtr.tmux.menu.fork': { description: 'fork into idle root', action: { kind: 'direct', run: 'node fork --pane {pane}' } },
22
+ 'crtr.tmux.menu.demote': { description: 'demote (finish when done)', action: { kind: 'command', run: 'node lifecycle demote --pane {pane}' } },
23
+ 'crtr.tmux.menu.detach': { description: 'demote + close viewer', action: { kind: 'command', run: 'node lifecycle demote --pane {pane} --detach' } },
24
+ 'crtr.tmux.menu.close-subtree': { description: 'close agent + subtree', action: { kind: 'command', run: 'node lifecycle close --pane {pane}' } },
25
+ 'crtr.tmux.menu.background-bash': { description: 'background running bash', action: { kind: 'direct', run: 'node bash background --pane {pane}' } },
26
+ // M-S-r, not M-R: with extended-keys csi-u tmux encodes M-R as alt+uppercase-R
27
+ // WITHOUT the shift modifier bit, which pi-tui's `alt+shift+r` matcher rejects;
28
+ // M-S-r carries shift+alt and lands as the same chord the keyboard produces.
29
+ 'crtr.tmux.menu.file-review': { description: 'review a file', action: { kind: 'raw-keys', keys: 'M-S-r' } },
30
+ 'crtr.tmux.menu.metadata': { description: 'metadata', action: { kind: 'keys', keys: '/node-metadata' } },
31
+ 'crtr.tmux.menu.fold-tools': { description: 'fold finished tool calls', action: { kind: 'keys', keys: '/fold-tools' } },
32
+ 'crtr.tmux.menu.context': { description: 'context + reports', action: { kind: 'keys', keys: '/context' } },
33
+ // The settings page lays out a grouped rail beside a content panel; the
34
+ // default dialog-sized popup clipped both the rail and the models matrix.
35
+ 'crtr.tmux.menu.providers': { description: 'settings', action: { kind: 'popup', run: 'sys settings', size: { w: '90%', h: '85%' } } },
36
+ 'crtr.tmux.menu.graph': { description: 'canvas graph', action: { kind: 'keys', keys: '/graph' } },
37
+ 'crtr.tmux.menu.focus-manager': { description: 'go to manager', action: { kind: 'command', run: 'surface node focus {manager}' } },
38
+ 'crtr.tmux.menu.copy-id': { description: 'copy node id', action: { kind: 'command', run: 'surface node id --pane {pane}' } },
39
+ 'crtr.tmux.menu.reload-viewer': { description: 'reload viewer', action: { kind: 'direct', run: 'surface reload --pane {pane}' } },
40
+ 'crtr.tmux.menu.recap': { description: 'generate recap', action: { kind: 'keys', keys: '/recap' } },
41
+ 'crtr.tmux.menu.pin': { description: 'pin conversation', action: { kind: 'direct', run: 'surface node pin --pane {pane}' } },
42
+ 'crtr.tmux.menu.issue.idea': { description: 'idea', action: { kind: 'popup', run: 'canvas issue new --type idea' } },
43
+ 'crtr.tmux.menu.issue.bug': { description: 'bug', action: { kind: 'popup', run: 'canvas issue new --type bug' } },
44
+ };
45
+ function escapeTmuxFormats(value) {
46
+ return value.replace(/#/g, '##');
47
+ }
48
+ function tmuxCommand(args) {
49
+ return args.map(shellQuote).join(' ');
50
+ }
51
+ /** Popups default to a small dialog. A surface that has to lay out its own
52
+ * navigation and a content panel side by side asks for the larger size. */
53
+ const DEFAULT_POPUP_SIZE = { w: '60%', h: '50%' };
54
+ function chordCommand(run, interactive = false, size = DEFAULT_POPUP_SIZE) {
55
+ const command = `crtr canvas chord --pane '#{pane_id}' --run ${shellQuote(escapeTmuxFormats(run))}${interactive ? ' --interactive' : ''}`;
56
+ return interactive
57
+ ? {
58
+ argv: ['display-popup', '-E', '-w', size.w, '-h', size.h, '-d', '#{pane_current_path}', command],
59
+ menu: `display-popup -E -w ${size.w} -h ${size.h} -d "#{pane_current_path}" ${shellQuote(command)}`,
60
+ }
61
+ : {
62
+ argv: ['run-shell', `${command} >/dev/null 2>&1`],
63
+ menu: `run-shell ${shellQuote(`${command} >/dev/null 2>&1`)}`,
64
+ };
65
+ }
66
+ /** Dispatch an action straight to a `crtr` invocation, skipping the
67
+ * `canvas chord` hop entirely. Only sound for an action whose sole
68
+ * interpolation need is `{pane}` — tmux expands it natively as `#{pane_id}` at
69
+ * keypress time (a real tmux format, substituted AFTER escaping the static
70
+ * run text so the `#` here is never doubled), so chord's node-resolution
71
+ * round trip buys nothing. `-b` keeps dispatch non-blocking. */
72
+ function directCommand(run) {
73
+ const argv = escapeTmuxFormats(run).replace('{pane}', '#{pane_id}');
74
+ const command = `crtr ${argv} >/dev/null 2>&1`;
75
+ return {
76
+ argv: ['run-shell', '-b', command],
77
+ menu: `run-shell -b ${shellQuote(command)}`,
78
+ };
79
+ }
80
+ /** One command constructor serves both display-menu selections and direct root
81
+ * shortcuts. Each result carries the argv bind-key needs plus the stable menu
82
+ * serialization existing Alt+C installs already use. */
83
+ function menuActionCommand(action) {
84
+ switch (action.kind) {
85
+ case 'disabled': return null;
86
+ case 'separator': return null;
87
+ // Choosing any menu item closes it; refresh-client is the deliberately
88
+ // inert command that lets the prefix shortcut choose this close row.
89
+ case 'dismiss': return { argv: ['refresh-client'], menu: 'refresh-client' };
90
+ case 'keys': {
91
+ const keys = escapeTmuxFormats(action.keys);
92
+ return {
93
+ // A root binding already runs in the pressed key's pane context. Its
94
+ // target must stay implicit: bind-key does not expand `#{pane_id}` in
95
+ // send-keys' target argument. A menu command is serialized later and
96
+ // does need the pane captured when the menu opened.
97
+ argv: ['send-keys', keys, 'Enter'],
98
+ menu: `send-keys -t '#{pane_id}' ${shellQuote(keys)} Enter`,
99
+ };
100
+ }
101
+ case 'raw-keys': {
102
+ const keys = escapeTmuxFormats(action.keys);
103
+ return {
104
+ argv: ['send-keys', keys],
105
+ menu: `send-keys -t '#{pane_id}' ${shellQuote(keys)}`,
106
+ };
107
+ }
108
+ case 'literal-input': {
109
+ const input = escapeTmuxFormats(action.input);
110
+ return {
111
+ argv: ['send-keys', '-l', input],
112
+ menu: `send-keys -l -t '#{pane_id}' ${shellQuote(input)}`,
113
+ };
114
+ }
115
+ case 'command': return chordCommand(action.run);
116
+ case 'direct': return directCommand(action.run);
117
+ case 'popup': return chordCommand(action.run, true, action.size);
118
+ case 'submenu': {
119
+ const argv = buildMenuArgs(action.title, action.items);
120
+ return { argv, menu: tmuxCommand(argv) };
121
+ }
122
+ }
123
+ }
124
+ function renderMenuAction(action) {
125
+ return menuActionCommand(action)?.menu ?? '';
126
+ }
127
+ /** Visible width of a menu item name: style markup (`#[...]`) takes no cells. */
128
+ function menuItemWidth(description) {
129
+ return description.replace(/#\[[^\]]*\]/g, '').length;
130
+ }
131
+ function buildMenuArgs(title, items) {
132
+ const safeTitle = escapeTmuxFormats(title);
133
+ const widestItem = items.reduce((width, item) => Math.max(width, menuItemWidth(item.description)), 0);
134
+ const args = ['display-menu', '-T', `#[align=centre]${safeTitle}`, ...surfaceTmuxStyleArgs()];
135
+ args.push('-x', `#{e|-:#{pane_right},${Math.max(safeTitle.length, widestItem) + 7}}`, '-y', '#{e|+:#{pane_top},3}', '--');
136
+ for (const item of items) {
137
+ // A separator is a single empty name with key and command omitted; tmux
138
+ // draws it as a horizontal rule. A header (disabled) name is a crouter-owned
139
+ // literal carrying `#[...]` style markup, so it skips format escaping.
140
+ if (item.action.kind === 'separator') {
141
+ args.push('');
142
+ continue;
143
+ }
144
+ const name = item.action.kind === 'disabled' ? item.description : escapeTmuxFormats(item.description);
145
+ args.push(name, item.selector, renderMenuAction(item.action));
146
+ }
147
+ args.push('', '-esc / q to close', '', '');
148
+ return args;
149
+ }
150
+ const TMUX_NAMED_KEYS = {
151
+ enter: 'Enter', escape: 'Escape', tab: 'Tab', backspace: 'BSpace', delete: 'DC',
152
+ space: 'Space', up: 'Up', down: 'Down', left: 'Left', right: 'Right',
153
+ pageup: 'PPage', pagedown: 'NPage', home: 'Home', end: 'End',
154
+ };
155
+ function normalizedStrokeParts(stroke) {
156
+ if (stroke === '+')
157
+ return { key: '+', modifiers: [] };
158
+ if (stroke.endsWith('++'))
159
+ return { key: '+', modifiers: stroke.slice(0, -2).split('+') };
160
+ const parts = stroke.split('+');
161
+ return { key: parts.pop(), modifiers: parts };
162
+ }
163
+ function tmuxKey(stroke) {
164
+ let { key, modifiers: modifierParts } = normalizedStrokeParts(stroke);
165
+ const modifiers = new Set(modifierParts);
166
+ if (modifiers.has('shift') && key.length === 1 && /[a-z]/.test(key)) {
167
+ // tmux names a shifted printable with its uppercase character even when an
168
+ // extended-key terminal also preserves Shift as a modifier: Alt+Shift+F is
169
+ // `M-S-F`. Shift by itself needs only the uppercase character (`F`).
170
+ key = key.toUpperCase();
171
+ if (!modifiers.has('ctrl') && !modifiers.has('alt'))
172
+ modifiers.delete('shift');
173
+ }
174
+ key = TMUX_NAMED_KEYS[key] ?? key;
175
+ const prefix = [
176
+ modifiers.has('ctrl') ? 'C-' : '',
177
+ modifiers.has('alt') ? 'M-' : '',
178
+ modifiers.has('shift') ? 'S-' : '',
179
+ ].join('');
180
+ return `${prefix}${key}`;
181
+ }
182
+ function menuSelector(stroke) {
183
+ const { key, modifiers } = normalizedStrokeParts(stroke);
184
+ return modifiers.includes('shift') && /[a-z]/.test(key) ? key.toUpperCase() : key === 'space' ? ' ' : key;
185
+ }
186
+ function boundMenuItems(ids, entries, bindings) {
187
+ const items = [];
188
+ for (const id of ids) {
189
+ const entry = entries.get(id);
190
+ if (entry === undefined)
191
+ continue;
192
+ for (const gesture of bindings.gestures(id)) {
193
+ items.push({ description: entry.description, selector: menuSelector(gesture), action: entry.action });
194
+ }
195
+ }
196
+ return items;
197
+ }
198
+ /** Resolve the complete action descriptor set once. Submenu openers point at
199
+ * the same child MenuItems the prefix menu renders, so their direct global
200
+ * shortcuts cannot drift from the menu path. */
201
+ function resolvedMenuActions(bindings) {
202
+ const entries = new Map();
203
+ for (const [id, entry] of Object.entries(LEAF_MENU_ACTIONS)) {
204
+ if (entry !== undefined)
205
+ entries.set(id, entry);
206
+ }
207
+ for (const { menuId, actionId } of ATTACH_CONTROL_BINDINGS) {
208
+ const definition = BINDING_CATALOG.find((candidate) => candidate.id === actionId);
209
+ if (definition === undefined)
210
+ throw new Error(`missing attach binding definition ${actionId}`);
211
+ entries.set(menuId, {
212
+ description: definition.name.toLowerCase(),
213
+ action: { kind: 'literal-input', input: encodeAttachControlInput(actionId) },
214
+ });
215
+ }
216
+ const attachItems = boundMenuItems(ATTACH_CONTROL_BINDINGS.map(({ menuId }) => menuId), entries, bindings);
217
+ if (attachItems.length > 0) {
218
+ entries.set('crtr.tmux.menu.attach', {
219
+ description: 'attach viewer ›',
220
+ action: { kind: 'submenu', title: ' attach viewer ', items: attachItems },
221
+ });
222
+ }
223
+ const showItems = boundMenuItems([
224
+ 'crtr.tmux.menu.metadata',
225
+ 'crtr.tmux.menu.context',
226
+ ], entries, bindings);
227
+ entries.set('crtr.tmux.menu.show', {
228
+ description: 'inspect ›',
229
+ action: { kind: 'submenu', title: ' inspect node ', items: showItems },
230
+ });
231
+ // How this viewer PAINTS the transcript, as opposed to what it shows. Each item
232
+ // is a toggle the viewer applies to its own render state (a `/`-command sent to
233
+ // the pane); a tmux menu is built once and cannot show live state, so the item
234
+ // reads as the action and the viewer answers with a notice.
235
+ const viewSettingsItems = boundMenuItems(['crtr.tmux.menu.fold-tools'], entries, bindings);
236
+ entries.set('crtr.tmux.menu.view-settings', {
237
+ description: 'display ›',
238
+ action: { kind: 'submenu', title: ' display ', items: viewSettingsItems },
239
+ });
240
+ const issueItems = boundMenuItems([
241
+ 'crtr.tmux.menu.issue.idea',
242
+ 'crtr.tmux.menu.issue.bug',
243
+ ], entries, bindings);
244
+ entries.set('crtr.tmux.menu.issues', {
245
+ description: 'create ›',
246
+ action: { kind: 'submenu', title: ' create ', items: issueItems },
247
+ });
248
+ return entries;
249
+ }
250
+ function menuItems(bindings, entries) {
251
+ const boundItems = (ids) => boundMenuItems(ids, entries, bindings);
252
+ const items = [];
253
+ const addGroup = (heading, groupItems) => {
254
+ if (groupItems.length === 0)
255
+ return;
256
+ if (items.length > 0)
257
+ items.push({ description: '', selector: '', action: { kind: 'separator' } });
258
+ items.push({ description: `-#[bold]${heading}`, selector: '', action: { kind: 'disabled' } }, ...groupItems);
259
+ };
260
+ // Explore changes what is in view or opens a canvas-level browser. Current
261
+ // node acts on the agent in this pane without changing its lifecycle.
262
+ addGroup('Explore', boundItems([
263
+ 'crtr.tmux.menu.resume',
264
+ 'crtr.tmux.menu.graph',
265
+ 'crtr.tmux.menu.focus-manager',
266
+ 'crtr.tmux.menu.show',
267
+ 'crtr.tmux.menu.view-settings',
268
+ ]));
269
+ addGroup('Current node', boundItems([
270
+ 'crtr.tmux.menu.attach',
271
+ 'crtr.tmux.menu.background-bash',
272
+ 'crtr.tmux.menu.file-review',
273
+ 'crtr.tmux.menu.pin',
274
+ 'crtr.tmux.menu.copy-id',
275
+ 'crtr.tmux.menu.reload-viewer',
276
+ 'crtr.tmux.menu.recap',
277
+ ]));
278
+ addGroup('Lifecycle', boundItems([
279
+ 'crtr.tmux.menu.fork',
280
+ 'crtr.tmux.menu.promote',
281
+ 'crtr.tmux.menu.demote',
282
+ 'crtr.tmux.menu.detach',
283
+ 'crtr.tmux.menu.close-subtree',
284
+ ]));
285
+ addGroup('System', boundItems([
286
+ 'crtr.tmux.menu.providers',
287
+ 'crtr.tmux.menu.issues',
288
+ ]));
289
+ const prefixGestures = bindings.gestures('crtr.tmux.menu.open');
290
+ if (prefixGestures.length > 0 && items.length > 0) {
291
+ items.push({ description: '', selector: '', action: { kind: 'separator' } });
292
+ for (const gesture of prefixGestures) {
293
+ items.push({
294
+ description: `${formatGesture(gesture)} to close`,
295
+ // Menu selectors accept tmux key notation, including modifiers. This
296
+ // is intentionally the exact binding that opened the menu.
297
+ selector: tmuxKey(gesture),
298
+ action: { kind: 'dismiss' },
299
+ });
300
+ }
301
+ }
302
+ return items;
303
+ }
304
+ /** Read one token from tmux's sourceable `list-keys` output. Key names that
305
+ * contain punctuation are quoted, so splitting on whitespace would make their
306
+ * displayed token differ from the key name accepted by bind/unbind commands. */
307
+ function readTmuxToken(line, from) {
308
+ let index = from;
309
+ while (index < line.length && /\s/.test(line[index]))
310
+ index += 1;
311
+ if (index >= line.length)
312
+ return null;
313
+ let quote = null;
314
+ let value = '';
315
+ while (index < line.length) {
316
+ const char = line[index];
317
+ if (quote === null && /\s/.test(char))
318
+ break;
319
+ if (quote === null && (char === "'" || char === '"')) {
320
+ quote = char;
321
+ index += 1;
322
+ continue;
323
+ }
324
+ if (quote === char) {
325
+ quote = null;
326
+ index += 1;
327
+ continue;
328
+ }
329
+ if (char === '\\' && quote !== "'" && index + 1 < line.length) {
330
+ value += line[index + 1];
331
+ index += 2;
332
+ continue;
333
+ }
334
+ value += char;
335
+ index += 1;
336
+ }
337
+ return { value, end: index };
338
+ }
339
+ function parseTmuxBinding(line) {
340
+ const commandName = readTmuxToken(line, 0);
341
+ if (commandName?.value !== 'bind-key')
342
+ return null;
343
+ let cursor = commandName.end;
344
+ let repeat = false;
345
+ while (true) {
346
+ const token = readTmuxToken(line, cursor);
347
+ if (token === null)
348
+ return null;
349
+ cursor = token.end;
350
+ if (token.value === '-r') {
351
+ repeat = true;
352
+ continue;
353
+ }
354
+ if (token.value !== '-T')
355
+ continue;
356
+ const table = readTmuxToken(line, cursor);
357
+ if (table === null)
358
+ return null;
359
+ const key = readTmuxToken(line, table.end);
360
+ if (key === null)
361
+ return null;
362
+ return {
363
+ table: table.value,
364
+ key: key.value,
365
+ command: line.slice(key.end).trimStart(),
366
+ repeat,
367
+ };
368
+ }
369
+ }
370
+ function bindingAt(table, key) {
371
+ const result = tmux(['list-keys', '-T', table]);
372
+ if (!result.ok)
373
+ return null;
374
+ return result.stdout.split('\n').find((line) => {
375
+ const parsed = parseTmuxBinding(line);
376
+ return parsed?.table === table && parsed.key === key;
377
+ }) ?? null;
378
+ }
379
+ /** Effective crouter gestures that tmux's root table currently consumes before
380
+ * pane input can see them. One list-keys snapshot serves the whole query. */
381
+ export function occupiedTmuxRootGestures(gestures) {
382
+ const result = tmux(['list-keys', '-T', ROOT_TABLE]);
383
+ if (!result.ok)
384
+ return [];
385
+ const occupied = new Set(result.stdout.split('\n').flatMap((line) => {
386
+ const parsed = parseTmuxBinding(line);
387
+ return parsed?.table === ROOT_TABLE ? [parsed.key] : [];
388
+ }));
389
+ return gestures.filter((gesture) => !gesture.includes(' > ') && occupied.has(tmuxKey(gesture)));
390
+ }
391
+ function isInstalledPair(value) {
392
+ return typeof value === 'object' && value !== null
393
+ && typeof value.table === 'string'
394
+ && typeof value.key === 'string';
395
+ }
396
+ function isWrappedRootBinding(value) {
397
+ if (typeof value !== 'object' || value === null)
398
+ return false;
399
+ const wrapper = value;
400
+ return typeof wrapper.bindingId === 'string'
401
+ && BINDING_IDS.has(wrapper.bindingId)
402
+ && typeof wrapper.gesture === 'string'
403
+ && typeof wrapper.key === 'string'
404
+ && (typeof wrapper.original === 'string' || wrapper.original === null)
405
+ && typeof wrapper.wrapper === 'string'
406
+ && (wrapper.state === 'owned' || wrapper.state === 'relinquished');
407
+ }
408
+ function readManifest() {
409
+ const option = tmux(['show-options', '-s', '-q', TMUX_BINDING_MANIFEST]);
410
+ if (!option.ok)
411
+ return null;
412
+ if (option.stdout === '')
413
+ return { pairs: [], wrappers: [] };
414
+ const result = tmux(['show-options', '-s', '-qv', TMUX_BINDING_MANIFEST]);
415
+ if (!result.ok)
416
+ return null;
417
+ try {
418
+ const value = JSON.parse(result.stdout);
419
+ // Before passthrough wrappers, the manifest was the pair array itself.
420
+ if (Array.isArray(value))
421
+ return value.every(isInstalledPair) ? { pairs: value, wrappers: [] } : null;
422
+ if (typeof value !== 'object' || value === null)
423
+ return null;
424
+ const manifest = value;
425
+ if (!Array.isArray(manifest.pairs) || !manifest.pairs.every(isInstalledPair)
426
+ || !Array.isArray(manifest.wrappers) || !manifest.wrappers.every(isWrappedRootBinding))
427
+ return null;
428
+ return { pairs: manifest.pairs, wrappers: manifest.wrappers };
429
+ }
430
+ catch {
431
+ return null;
432
+ }
433
+ }
434
+ function writeManifest(manifest) {
435
+ return tmux(['set-option', '-s', TMUX_BINDING_MANIFEST, JSON.stringify(manifest)]);
436
+ }
437
+ /** Tmux parses semicolons once more even when argv already isolated them. */
438
+ function tmuxKeyArgument(key) {
439
+ return key.replace(/\\/g, '\\\\').replace(/;/g, '\\;');
440
+ }
441
+ function tmuxCommandToken(value) {
442
+ return `"${value.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/;/g, '\\;')}"`;
443
+ }
444
+ /** A top-level separator is printed as `\;` in a bind-key line, but the same
445
+ * sequence is literal after the command tail becomes one if-shell branch. */
446
+ function bindingCommandForBranch(command) {
447
+ let quote = null;
448
+ let out = '';
449
+ for (let index = 0; index < command.length; index += 1) {
450
+ const char = command[index];
451
+ if (quote === null && (char === "'" || char === '"')) {
452
+ quote = char;
453
+ out += char;
454
+ continue;
455
+ }
456
+ if (quote === char) {
457
+ quote = null;
458
+ out += char;
459
+ continue;
460
+ }
461
+ if (char === '\\' && index + 1 < command.length) {
462
+ const next = command[index + 1];
463
+ if (quote === null && next === ';') {
464
+ out += ';';
465
+ }
466
+ else {
467
+ out += char + next;
468
+ }
469
+ index += 1;
470
+ continue;
471
+ }
472
+ out += char;
473
+ }
474
+ return out;
475
+ }
476
+ function sourceBindingLine(line) {
477
+ const dir = mkdtempSync(join(tmpdir(), 'crtr-tmux-binding-'));
478
+ const file = join(dir, 'binding.conf');
479
+ try {
480
+ writeFileSync(file, `${line}\n`, 'utf8');
481
+ return tmux(['source-file', file]);
482
+ }
483
+ finally {
484
+ rmSync(dir, { recursive: true, force: true });
485
+ }
486
+ }
487
+ function restoreWrappedBinding(wrapper) {
488
+ return wrapper.original === null
489
+ ? tmux(['unbind-key', '-T', ROOT_TABLE, tmuxKeyArgument(wrapper.key)])
490
+ : sourceBindingLine(wrapper.original);
491
+ }
492
+ // --quiet keeps the background `run-shell -b` binding from printing its result JSON, which
493
+ // tmux would otherwise surface as a view-mode overlay on the active pane. The popup opening
494
+ // is the feedback; a genuine failure still prints through the CLI toggle action. This deliberately
495
+ // invokes bare `crtr` from PATH: it is installed once and must resolve to the selected generation,
496
+ // not the sealed generation that installed it. The neighboring `crtr surface node cycle` builders
497
+ // share that property.
498
+ export function inboxToggleTmuxCommand() {
499
+ return ['run-shell', '-b', 'crtr human inbox toggle --quiet --tmux-socket "#{socket_path}" --tmux-client "#{client_name}" --target-pane "#{pane_id}"'];
500
+ }
501
+ function actionCommand(id) {
502
+ switch (id) {
503
+ case 'crtr.tmux.node.next': return ['run-shell', `crtr surface node cycle --dir next --pane '#{pane_id}' >/dev/null 2>&1`];
504
+ case 'crtr.tmux.node.previous': return ['run-shell', `crtr surface node cycle --dir prev --pane '#{pane_id}' >/dev/null 2>&1`];
505
+ case 'crtr.tmux.inbox.toggle': return inboxToggleTmuxCommand();
506
+ default: throw new Error(`no tmux command for ${id}`);
507
+ }
508
+ }
509
+ /** A directory beside the server socket serializes every process driving that
510
+ * exact tmux server. Outside tmux, ask the default server for its socket first;
511
+ * an unavailable server uses one per-user fallback lock for the error path. */
512
+ function tmuxBindingLockPath() {
513
+ const envSocket = process.env['TMUX']?.split(',')[0]?.trim();
514
+ if (envSocket !== undefined && envSocket !== '')
515
+ return `${envSocket}.crtr-keybindings.lock`;
516
+ const result = tmux(['display-message', '-p', '#{socket_path}']);
517
+ if (result.ok && result.stdout !== '')
518
+ return `${result.stdout}.crtr-keybindings.lock`;
519
+ const user = typeof process.getuid === 'function' ? process.getuid() : 'user';
520
+ return join(tmpdir(), `crtr-tmux-keybindings-${user}.lock`);
521
+ }
522
+ /** Reconcile the tmux server with one immutable crouter settings snapshot.
523
+ * Passing snapshots is hermetic; the no-argument front door reads both user
524
+ * settings from the same config read. The server lock covers the entire
525
+ * manifest read, restore, install, fingerprint, and write transition. */
526
+ export function installTmuxBindings(bindingSnapshot, passthroughSnapshot = []) {
527
+ return withExclusiveDirectoryLock(tmuxBindingLockPath(), () => reconcileTmuxBindings(bindingSnapshot, passthroughSnapshot));
528
+ }
529
+ function reconcileTmuxBindings(bindingSnapshot, passthroughSnapshot = []) {
530
+ const userSettings = bindingSnapshot === undefined ? resolveUserKeybindingSettings() : undefined;
531
+ const bindings = bindingSnapshot ?? userSettings.bindings;
532
+ const passthrough = bindingSnapshot === undefined
533
+ ? userSettings.tmuxPassthrough
534
+ : normalizeTmuxPassthrough(passthroughSnapshot);
535
+ const diagnostics = [];
536
+ const installed = [];
537
+ const manifest = readManifest();
538
+ if (manifest === null) {
539
+ diagnostics.push({ code: 'tmux-error', message: `tmux is unavailable or ${TMUX_BINDING_MANIFEST} is malformed` });
540
+ return { ok: false, installed, diagnostics };
541
+ }
542
+ const desiredWrappers = new Map();
543
+ for (const bindingId of passthrough) {
544
+ const definition = BINDING_CATALOG.find((candidate) => candidate.id === bindingId);
545
+ if (definition === undefined || !isAttachPaneBinding(definition))
546
+ continue;
547
+ for (const gesture of bindings.gestures(bindingId)) {
548
+ if (gesture.includes(' > '))
549
+ continue;
550
+ const key = tmuxKey(gesture);
551
+ if (!desiredWrappers.has(key))
552
+ desiredWrappers.set(key, { bindingId, gesture });
553
+ }
554
+ }
555
+ // Restore every wrapper crouter still owns before the ordinary binding sweep.
556
+ // A live line that differs from the fingerprint is a user's later rebind: it
557
+ // is protected from this and every later reconciliation until they toggle the
558
+ // passthrough preference off and on again.
559
+ const protectedRootKeys = new Set();
560
+ const wrappers = [];
561
+ for (const prior of manifest.wrappers) {
562
+ const desired = desiredWrappers.get(prior.key);
563
+ const live = bindingAt(ROOT_TABLE, prior.key);
564
+ if (prior.state === 'relinquished' || live !== prior.wrapper) {
565
+ protectedRootKeys.add(prior.key);
566
+ if (desired !== undefined) {
567
+ wrappers.push({ ...prior, ...desired, state: 'relinquished' });
568
+ }
569
+ continue;
570
+ }
571
+ const restored = restoreWrappedBinding(prior);
572
+ if (!restored.ok) {
573
+ protectedRootKeys.add(prior.key);
574
+ wrappers.push(prior);
575
+ diagnostics.push({
576
+ code: 'tmux-error',
577
+ bindingId: prior.bindingId,
578
+ gesture: prior.gesture,
579
+ message: `could not restore tmux binding ${ROOT_TABLE}:${prior.key}: ${restored.stderr}`,
580
+ });
581
+ }
582
+ }
583
+ for (const pair of manifest.pairs) {
584
+ if (pair.table === ROOT_TABLE && protectedRootKeys.has(pair.key))
585
+ continue;
586
+ const result = tmux(['unbind-key', '-T', pair.table, tmuxKeyArgument(pair.key)]);
587
+ if (!result.ok && bindingAt(pair.table, pair.key) !== null) {
588
+ diagnostics.push({ code: 'tmux-error', message: `could not remove crouter binding ${pair.table}:${pair.key}: ${result.stderr}` });
589
+ }
590
+ }
591
+ if (diagnostics.some((diagnostic) => diagnostic.code === 'tmux-error')) {
592
+ const save = writeManifest({ pairs: manifest.pairs, wrappers });
593
+ if (!save.ok)
594
+ diagnostics.push({ code: 'tmux-error', message: `could not save crouter tmux ownership manifest: ${save.stderr}` });
595
+ return { ok: false, installed, diagnostics };
596
+ }
597
+ const install = (table, key, command, id, gesture) => {
598
+ if (bindingAt(table, key) !== null) {
599
+ diagnostics.push({ code: 'occupied', bindingId: id, gesture, message: `${table}:${key} is already bound by tmux; ${id} was not installed` });
600
+ return false;
601
+ }
602
+ const result = tmux(['bind-key', '-T', table, tmuxKeyArgument(key), ...command]);
603
+ if (!result.ok) {
604
+ diagnostics.push({ code: 'tmux-error', bindingId: id, gesture, message: `could not install ${id}: ${result.stderr}` });
605
+ return false;
606
+ }
607
+ installed.push({ table, key });
608
+ return true;
609
+ };
610
+ const menuActions = resolvedMenuActions(bindings);
611
+ const menuCommand = buildMenuArgs(' crtr ', menuItems(bindings, menuActions));
612
+ for (const gesture of bindings.gestures('crtr.tmux.menu.open')) {
613
+ install(ROOT_TABLE, tmuxKey(gesture), menuCommand, 'crtr.tmux.menu.open', gesture);
614
+ }
615
+ for (const definition of BINDING_CATALOG) {
616
+ if (definition.pair?.field !== 'menu')
617
+ continue;
618
+ const paired = BINDING_CATALOG.find((candidate) => candidate.id === definition.pair?.pairedId);
619
+ if (paired?.pair?.field !== 'global')
620
+ continue;
621
+ const menuId = definition.id;
622
+ const globalId = paired.id;
623
+ const entry = menuActions.get(menuId);
624
+ const command = entry === undefined ? null : menuActionCommand(entry.action);
625
+ if (command === null)
626
+ throw new Error(`no direct tmux action for paired menu binding ${menuId}`);
627
+ for (const gesture of bindings.gestures(globalId)) {
628
+ install(ROOT_TABLE, tmuxKey(gesture), command.argv, globalId, gesture);
629
+ }
630
+ }
631
+ for (const id of ['crtr.tmux.node.next', 'crtr.tmux.node.previous', 'crtr.tmux.inbox.toggle']) {
632
+ for (const gesture of bindings.gestures(id))
633
+ install(ROOT_TABLE, tmuxKey(gesture), actionCommand(id), id, gesture);
634
+ }
635
+ // Wrap only occupied roots. Unoccupied gestures already reach the pane and do
636
+ // not need crouter ownership. Re-read the installed line as the fingerprint;
637
+ // tmux canonicalizes quoting and braces in ways hand serialization cannot.
638
+ const newlyWrapped = [];
639
+ for (const [key, desired] of desiredWrappers) {
640
+ if (protectedRootKeys.has(key))
641
+ continue;
642
+ const original = bindingAt(ROOT_TABLE, key);
643
+ if (original === null)
644
+ continue;
645
+ const parsed = parseTmuxBinding(original);
646
+ if (parsed === null || parsed.command === '') {
647
+ diagnostics.push({ code: 'tmux-error', bindingId: desired.bindingId, gesture: desired.gesture, message: `could not parse occupied tmux binding ${ROOT_TABLE}:${key}` });
648
+ continue;
649
+ }
650
+ const result = tmux([
651
+ 'bind-key',
652
+ ...(parsed.repeat ? ['-r'] : []),
653
+ '-T', ROOT_TABLE, tmuxKeyArgument(key),
654
+ 'if-shell', '-F', '#{!=:#{@crtr_attach},}',
655
+ `send-keys ${tmuxCommandToken(key)}`,
656
+ bindingCommandForBranch(parsed.command),
657
+ ]);
658
+ if (!result.ok) {
659
+ diagnostics.push({ code: 'tmux-error', bindingId: desired.bindingId, gesture: desired.gesture, message: `could not wrap ${ROOT_TABLE}:${key}: ${result.stderr}` });
660
+ continue;
661
+ }
662
+ const wrapper = bindingAt(ROOT_TABLE, key);
663
+ if (wrapper === null || !wrapper.includes('@crtr_attach')) {
664
+ diagnostics.push({ code: 'tmux-error', bindingId: desired.bindingId, gesture: desired.gesture, message: `could not fingerprint wrapped tmux binding ${ROOT_TABLE}:${key}` });
665
+ continue;
666
+ }
667
+ const record = { ...desired, key, original, wrapper, state: 'owned' };
668
+ wrappers.push(record);
669
+ newlyWrapped.push(record);
670
+ }
671
+ const save = writeManifest({ pairs: installed, wrappers });
672
+ if (!save.ok) {
673
+ diagnostics.push({ code: 'tmux-error', message: `could not save crouter tmux ownership manifest: ${save.stderr}` });
674
+ // A wrapper without restoration data is unsafe. Put each newly wrapped key
675
+ // back immediately when manifest persistence fails.
676
+ for (const wrapper of newlyWrapped) {
677
+ if (bindingAt(ROOT_TABLE, wrapper.key) === wrapper.wrapper)
678
+ restoreWrappedBinding(wrapper);
679
+ }
680
+ }
681
+ return { ok: diagnostics.every((diagnostic) => diagnostic.code !== 'tmux-error'), installed, diagnostics };
682
+ }