@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
@@ -1,776 +0,0 @@
1
- import { mountPanel } from '../tui/panel.js';
2
- import { decodeInboxKey } from '../tui/keys.js';
3
- import assert from 'node:assert/strict';
4
- // ── helpers ───────────────────────────────────────────────────────────────────
5
- function mkKey(partial) {
6
- return {
7
- ctrl: false,
8
- meta: false,
9
- upArrow: false,
10
- downArrow: false,
11
- leftArrow: false,
12
- rightArrow: false,
13
- wordLeft: false,
14
- wordRight: false,
15
- home: false,
16
- end: false,
17
- pageUp: false,
18
- pageDown: false,
19
- del: false,
20
- return: false,
21
- newline: false,
22
- escape: false,
23
- tab: false,
24
- backspace: false,
25
- ...partial,
26
- };
27
- }
28
- const RETURN = mkKey({ return: true });
29
- const ESCAPE = mkKey({ escape: true });
30
- // ── fixtures ──────────────────────────────────────────────────────────────────
31
- const deckA = {
32
- title: 'Smoke Deck',
33
- interactions: [
34
- {
35
- id: 'q1',
36
- title: 'Use Postgres',
37
- subtitle: 'over SQLite',
38
- options: [
39
- { id: 'approve', label: 'Approve', shortcut: 'a' },
40
- { id: 'reject', label: 'Reject', shortcut: 'x' },
41
- ],
42
- allowFreetext: true,
43
- },
44
- {
45
- id: 'q2',
46
- title: 'Migration tool', subtitle: 'Migration tool requires your attention.',
47
- options: [
48
- { id: 'prisma', label: 'Prisma', shortcut: 'p' },
49
- { id: 'drizzle', label: 'Drizzle', shortcut: 'd' },
50
- { id: 'raw', label: 'raw SQL', shortcut: 's' },
51
- ],
52
- },
53
- ],
54
- };
55
- // ── Test 1: render contains deck title or first interaction title ──────────────
56
- const panel = mountPanel({ deck: deckA, cols: 80, rows: 24 });
57
- const lines = panel.render();
58
- const joined = lines.join('\n');
59
- assert.ok(joined.includes('Decisions') || joined.includes('Smoke Deck'), 'render must include deck title or header');
60
- assert.ok(joined.includes('Use Postgres'), 'render must include first interaction title');
61
- // ── Test 2: unmount does not throw; subsequent render returns empty array ──────
62
- panel.unmount();
63
- const postUnmount = panel.render();
64
- assert.deepEqual(postUnmount, [], 'render after unmount returns empty array');
65
- // ── Test 3: prevFrame isolation across two concurrent mounts ──────────────────
66
- const panelA = mountPanel({ deck: deckA, cols: 80, rows: 24 });
67
- const panelB = mountPanel({ deck: deckA, cols: 40, rows: 12 });
68
- const linesA1 = panelA.render();
69
- const linesB1 = panelB.render();
70
- panelA.handleResize(80, 24);
71
- panelB.handleResize(40, 12);
72
- const linesA2 = panelA.render();
73
- const linesB2 = panelB.render();
74
- assert.deepEqual(linesA1, linesA2, 'panel A render is stable across panel B activity');
75
- assert.deepEqual(linesB1, linesB2, 'panel B render is stable across panel A activity');
76
- assert.notDeepEqual(linesA1, linesB1, 'two panels with different geometry produce different output');
77
- panelA.unmount();
78
- panelB.unmount();
79
- // ── Test 4: question scroll survives resize ─────────────────────────────────
80
- const scrollPanel = mountPanel({
81
- deck: { title: 'Scroll positions', interactions: [{ id: 'scroll', title: 'Scrollable question', subtitle: 'Scrollable question requires your attention.', body: Array.from({ length: 40 }, (_, i) => `- question ${i}`).join('\n'), options: [] }] },
82
- cols: 50,
83
- rows: 12,
84
- });
85
- await new Promise((resolve) => setImmediate(resolve));
86
- scrollPanel.handleKey('', mkKey({ return: true }));
87
- scrollPanel.handleKey('d', mkKey({}));
88
- scrollPanel.handleKey('', mkKey({ pageDown: true }));
89
- scrollPanel.handleResize(50, 20);
90
- assert.match(scrollPanel.render().join('\n'), /more above/, 'Question scroll survives resize');
91
- scrollPanel.unmount();
92
- // ── Test 5: v2 round-trip ─────────────────────────────────────────────────────
93
- const roundTripDeck = {
94
- title: 'Test deck',
95
- interactions: [
96
- {
97
- id: 'i1', title: 'Review PR', subtitle: 'Review PR requires your attention.',
98
- options: [{ id: 'approve', label: 'Approve', shortcut: 'a' }, { id: 'reject', label: 'Reject', shortcut: 'r' }],
99
- allowFreetext: true,
100
- kind: 'decision',
101
- },
102
- {
103
- id: 'i2', title: 'Pick ORM', subtitle: 'Pick ORM requires your attention.',
104
- options: [{ id: 'opt-0', label: 'Prisma', shortcut: 'p' }, { id: 'opt-1', label: 'Drizzle', shortcut: 'z' }],
105
- allowFreetext: true,
106
- kind: 'decision',
107
- },
108
- {
109
- id: 'i3', title: 'Rate limit', subtitle: 'Rate limit requires your attention.',
110
- options: [],
111
- allowFreetext: true,
112
- kind: 'context',
113
- },
114
- ],
115
- };
116
- // ── v2 round-trip proper flow ─────────────────────────────────────────────────
117
- let capturedResponses2 = [];
118
- const rtPanel2 = mountPanel({
119
- deck: roundTripDeck,
120
- cols: 80,
121
- rows: 40,
122
- onComplete: (responses) => { capturedResponses2 = responses; },
123
- });
124
- // overview -> item-review
125
- rtPanel2.handleKey('', RETURN);
126
- // i1: cursor lands on 'approve' (selectedAction=0). Press 'c' → enters comment
127
- // mode WITH 'approve' pre-attached. Type freely (letters never trigger shortcuts).
128
- // Enter submits {selectedOptionId: 'approve', freetext: 'looks good'}.
129
- rtPanel2.handleKey('c', mkKey({})); // enter comment mode w/ 'approve' pre-attached
130
- for (const ch of 'looks good') {
131
- rtPanel2.handleKey(ch, mkKey({}));
132
- }
133
- rtPanel2.handleKey('', RETURN); // commit option + comment
134
- // Now at i2: press 'z' for Drizzle
135
- rtPanel2.handleKey('z', mkKey({}));
136
- // Now at i3 (freetext-only): press 'r' to open freetext mode
137
- rtPanel2.handleKey('r', mkKey({}));
138
- // Type response
139
- for (const ch of 'rate-limit at 5 rps') {
140
- rtPanel2.handleKey(ch, mkKey({}));
141
- }
142
- // Submit with enter
143
- rtPanel2.handleKey('', RETURN);
144
- // Now in final phase, press enter to complete
145
- rtPanel2.handleKey('', RETURN);
146
- assert.deepEqual(capturedResponses2, [
147
- { id: 'i1', selectedOptionId: 'approve', freetext: 'looks good' },
148
- { id: 'i2', selectedOptionId: 'opt-1' },
149
- { id: 'i3', freetext: 'rate-limit at 5 rps' },
150
- ], 'v2 round-trip responses must match expected');
151
- // ── Test 5: loadDeck smoke ────────────────────────────────────────────────────
152
- const deckB = {
153
- title: 'Deck B',
154
- interactions: [
155
- { id: 'b1', title: 'First B item', subtitle: 'First B item requires your attention.', options: [{ id: 'yes', label: 'Yes', shortcut: 'y' }] },
156
- { id: 'b2', title: 'Second B item', subtitle: 'Second B item requires your attention.', options: [], allowFreetext: true },
157
- ],
158
- };
159
- const loadDeckPanel = mountPanel({ deck: deckA, cols: 80, rows: 24 });
160
- const beforeLoad = loadDeckPanel.render().join('\n');
161
- assert.ok(beforeLoad.includes('Use Postgres'), 'before loadDeck: deck A title visible');
162
- loadDeckPanel.loadDeck(deckB);
163
- const afterLoad = loadDeckPanel.render().join('\n');
164
- assert.ok(!afterLoad.includes('Use Postgres'), 'after loadDeck: deck A title gone');
165
- assert.ok(afterLoad.includes('First B item'), 'after loadDeck: deck B first interaction visible');
166
- assert.ok(afterLoad.includes('1/2') || afterLoad.includes('0/2'), 'after loadDeck: position counter reflects deck B');
167
- loadDeckPanel.unmount();
168
- // ── Test 6: canAcceptHostKeys matrix ─────────────────────────────────────────
169
- const deckSingle = {
170
- title: 'Test deck',
171
- interactions: [
172
- {
173
- id: 's1', title: 'Single item', subtitle: 'Single item requires your attention.',
174
- options: [{ id: 'opt', label: 'Option', shortcut: 'o' }],
175
- allowFreetext: true,
176
- },
177
- {
178
- id: 's2', title: 'Second item', subtitle: 'Second item requires your attention.',
179
- options: [{ id: 'opt2', label: 'Option2', shortcut: 'o' }],
180
- },
181
- ],
182
- };
183
- const ckPanel = mountPanel({ deck: deckSingle, cols: 80, rows: 24 });
184
- assert.equal(ckPanel.canAcceptHostKeys(), true, 'initially (overview): canAcceptHostKeys true');
185
- // overview -> item-review
186
- ckPanel.handleKey('', RETURN);
187
- assert.equal(ckPanel.canAcceptHostKeys(), true, 'item-review without input mode: canAcceptHostKeys true');
188
- // enter comment mode
189
- ckPanel.handleKey('c', mkKey({}));
190
- assert.equal(ckPanel.canAcceptHostKeys(), false, 'in comment input mode: canAcceptHostKeys false');
191
- // cancel
192
- ckPanel.handleKey('', ESCAPE);
193
- assert.equal(ckPanel.canAcceptHostKeys(), true, 'after esc: canAcceptHostKeys true');
194
- // answer both interactions to reach final phase
195
- ckPanel.handleKey('o', mkKey({})); // selects option for s1, advances to s2
196
- ckPanel.handleKey('o', mkKey({})); // selects option for s2, advances to final
197
- // Should be in final phase now — canAcceptHostKeys still true
198
- assert.equal(ckPanel.canAcceptHostKeys(), true, 'final phase: canAcceptHostKeys true');
199
- ckPanel.unmount();
200
- assert.equal(ckPanel.canAcceptHostKeys(), false, 'after unmount: canAcceptHostKeys false');
201
- // ── Test 7: empty Enter in freetext-only mode records response and completes ────
202
- // Regression for: empty buffer caused truthy guard to skip submitOption, so
203
- // responses.size < interactions.length forever and onComplete never fired.
204
- const freetextOnlyDeck = {
205
- title: 'Test deck',
206
- interactions: [
207
- { id: 'q1', title: 'Optional notes', subtitle: 'Optional notes requires your attention.', options: [], allowFreetext: true },
208
- ],
209
- };
210
- let capturedFreetextEmpty = [];
211
- const ftPanel = mountPanel({
212
- deck: freetextOnlyDeck,
213
- cols: 80,
214
- rows: 24,
215
- onComplete: (responses) => { capturedFreetextEmpty = responses; },
216
- });
217
- // Single-item deck starts directly in item-review (no overview). 'r' opens freetext.
218
- ftPanel.handleKey('r', mkKey({}));
219
- // Submit with empty buffer (no typing)
220
- ftPanel.handleKey('', RETURN);
221
- // Final phase: press Enter to complete
222
- ftPanel.handleKey('', RETURN);
223
- assert.deepEqual(capturedFreetextEmpty, [{ id: 'q1', freetext: '' }], 'empty freetext Enter must record response and fire onComplete');
224
- ftPanel.unmount();
225
- // ── Test 8: empty Enter in comment mode (allowFreetext + options) records response ─
226
- const commentDeck = {
227
- title: 'Test deck',
228
- interactions: [
229
- {
230
- id: 'c1', title: 'Approve deploy?', subtitle: 'Approve deploy? requires your attention.',
231
- options: [{ id: 'yes', label: 'Yes', shortcut: 'y' }],
232
- allowFreetext: true,
233
- },
234
- ],
235
- };
236
- let capturedCommentEmpty = [];
237
- const cmPanel = mountPanel({
238
- deck: commentDeck,
239
- cols: 80,
240
- rows: 24,
241
- onComplete: (responses) => { capturedCommentEmpty = responses; },
242
- });
243
- // Single-item deck starts directly in item-review. Navigate to [c] row WITHOUT pre-attaching.
244
- cmPanel.handleKey('j', mkKey({}));
245
- // Enter comment mode (no option attached — cursor on [c] row)
246
- cmPanel.handleKey('c', mkKey({}));
247
- // Submit empty comment via Enter (no option selected)
248
- cmPanel.handleKey('', RETURN);
249
- // Final phase: press Enter to complete
250
- cmPanel.handleKey('', RETURN);
251
- assert.deepEqual(capturedCommentEmpty, [{ id: 'c1', freetext: '' }], 'empty Enter in comment mode must record response and fire onComplete');
252
- cmPanel.unmount();
253
- // ── Test 9: option-shortcut letters in comment mode are typed, not shortcuts ──
254
- // Regression: pressing 'y' or 'n' (or any option shortcut) while in comment mode
255
- // must append to the buffer, never submit the option.
256
- const shortcutTypingDeck = {
257
- title: 'Test deck',
258
- interactions: [
259
- {
260
- id: 'q1', title: 'Approve?', subtitle: 'Approve? requires your attention.',
261
- options: [
262
- { id: 'yes', label: 'Yes', shortcut: 'y' },
263
- { id: 'no', label: 'No', shortcut: 'n' },
264
- ],
265
- allowFreetext: true,
266
- },
267
- ],
268
- };
269
- let capturedShortcutTyping = [];
270
- const stPanel = mountPanel({
271
- deck: shortcutTypingDeck,
272
- cols: 80,
273
- rows: 24,
274
- onComplete: (responses) => { capturedShortcutTyping = responses; },
275
- });
276
- // Single-item deck starts directly in item-review. Navigate to [c] row.
277
- stPanel.handleKey('j', mkKey({}));
278
- stPanel.handleKey('j', mkKey({}));
279
- // Enter comment mode (no option attached)
280
- stPanel.handleKey('c', mkKey({}));
281
- // Type 'yes no' — both 'y' and 'n' are option shortcuts; must go to buffer.
282
- for (const ch of 'yes no') {
283
- stPanel.handleKey(ch, mkKey({}));
284
- }
285
- // Submit comment via Enter — must NOT have selectedOptionId
286
- stPanel.handleKey('', RETURN);
287
- stPanel.handleKey('', RETURN); // final → complete
288
- assert.deepEqual(capturedShortcutTyping, [{ id: 'q1', freetext: 'yes no' }], 'option-shortcut letters typed in comment mode must append to buffer, not select option');
289
- stPanel.unmount();
290
- // ── Test 10: 'c' from option row pre-attaches that option ─────────────────────
291
- const attachDeck = {
292
- title: 'Test deck',
293
- interactions: [
294
- {
295
- id: 'a1', title: 'Approve?', subtitle: 'Approve? requires your attention.',
296
- options: [
297
- { id: 'yes', label: 'Yes', shortcut: 'y' },
298
- { id: 'no', label: 'No', shortcut: 'n' },
299
- ],
300
- allowFreetext: true,
301
- },
302
- ],
303
- };
304
- let capturedAttach = [];
305
- const atPanel = mountPanel({
306
- deck: attachDeck,
307
- cols: 80,
308
- rows: 24,
309
- onComplete: (responses) => { capturedAttach = responses; },
310
- });
311
- // Single-item deck starts directly in item-review (selectedAction = 0, on 'yes' row)
312
- atPanel.handleKey('c', mkKey({})); // enter comment with 'yes' pre-attached
313
- for (const ch of 'lgtm')
314
- atPanel.handleKey(ch, mkKey({}));
315
- atPanel.handleKey('', RETURN); // submit
316
- atPanel.handleKey('', RETURN); // final → complete
317
- assert.deepEqual(capturedAttach, [{ id: 'a1', selectedOptionId: 'yes', freetext: 'lgtm' }], "'c' from option row must pre-attach that option to the comment");
318
- atPanel.unmount();
319
- // ── Test 11: Tab cycles attached option in comment mode ───────────────────────
320
- let capturedTab = [];
321
- const tabPanel = mountPanel({
322
- deck: attachDeck,
323
- cols: 80,
324
- rows: 24,
325
- onComplete: (responses) => { capturedTab = responses; },
326
- });
327
- // Single-item deck starts directly in item-review. Navigate to [c] row.
328
- // Navigate cursor to [c] row (selectedAction = 2 — past both option rows)
329
- tabPanel.handleKey('j', mkKey({}));
330
- tabPanel.handleKey('j', mkKey({}));
331
- tabPanel.handleKey('c', mkKey({})); // enter comment, no option attached
332
- for (const ch of 'meh')
333
- tabPanel.handleKey(ch, mkKey({}));
334
- // Tab once: attaches first option ('yes')
335
- tabPanel.handleKey('', mkKey({ tab: true }));
336
- // Tab again: cycles to 'no'
337
- tabPanel.handleKey('', mkKey({ tab: true }));
338
- // Tab again: cycles back to none
339
- tabPanel.handleKey('', mkKey({ tab: true }));
340
- // Tab once more: 'yes'
341
- tabPanel.handleKey('', mkKey({ tab: true }));
342
- tabPanel.handleKey('', RETURN); // submit with 'yes' attached
343
- tabPanel.handleKey('', RETURN); // final → complete
344
- assert.deepEqual(capturedTab, [{ id: 'a1', selectedOptionId: 'yes', freetext: 'meh' }], 'Tab in comment mode must cycle attached option (none → opt1 → opt2 → none)');
345
- tabPanel.unmount();
346
- // ── Test 12: multi-select — Space/shortcut toggle, Enter confirms set ─────────
347
- const multiDeck = {
348
- title: 'Test deck',
349
- interactions: [
350
- {
351
- id: 'ms1', title: 'Pick toppings', subtitle: 'Pick toppings requires your attention.', multiSelect: true,
352
- options: [
353
- { id: 'mush', label: 'Mushroom', shortcut: 'a' },
354
- { id: 'onion', label: 'Onion', shortcut: 'b' },
355
- { id: 'olive', label: 'Olive', shortcut: 'x' },
356
- ],
357
- },
358
- ],
359
- };
360
- let capturedMulti = [];
361
- const msPanel = mountPanel({
362
- deck: multiDeck,
363
- cols: 80,
364
- rows: 24,
365
- onComplete: (responses) => { capturedMulti = responses; },
366
- });
367
- // Single-item deck starts in item-review, cursor on option 0 ('mush').
368
- msPanel.handleKey(' ', mkKey({})); // toggle 'mush' on
369
- msPanel.handleKey('j', mkKey({})); // cursor → 'onion'
370
- msPanel.handleKey(' ', mkKey({})); // toggle 'onion' on
371
- msPanel.handleKey(' ', mkKey({})); // toggle 'onion' back off
372
- const midRender = msPanel.render().join('\n');
373
- assert.ok(midRender.includes('[x]') && midRender.includes('[ ]'), 'multi-select must render checked [x] and unchecked [ ] boxes');
374
- msPanel.handleKey('x', mkKey({})); // shortcut toggles 'olive' on (no advance)
375
- msPanel.handleKey('', RETURN); // confirm set + advance → final
376
- msPanel.handleKey('', RETURN); // final → complete
377
- assert.deepEqual(capturedMulti, [{ id: 'ms1', selectedOptionIds: ['mush', 'olive'] }], 'multi-select must accumulate toggled options and return them as selectedOptionIds');
378
- msPanel.unmount();
379
- // ── Test 13: preAnswered seeds responses and renders with ◆ marker ────────────
380
- const preAnsweredDeck = {
381
- title: 'Test deck',
382
- interactions: [
383
- {
384
- id: 'r1', title: 'Carry-over requirement', subtitle: 'Carry-over requirement requires your attention.',
385
- options: [
386
- { id: 'approve', label: 'Approve', shortcut: 'a' },
387
- { id: 'reject', label: 'Reject', shortcut: 'r' },
388
- ],
389
- allowFreetext: true,
390
- preAnswered: { selectedOptionId: 'approve', label: 'Previously approved' },
391
- },
392
- {
393
- id: 'r2', title: 'Fresh requirement', subtitle: 'Fresh requirement requires your attention.',
394
- options: [
395
- { id: 'approve', label: 'Approve', shortcut: 'a' },
396
- { id: 'reject', label: 'Reject', shortcut: 'r' },
397
- ],
398
- },
399
- ],
400
- };
401
- const paPanel = mountPanel({ deck: preAnsweredDeck, cols: 80, rows: 24 });
402
- const paOverview = paPanel.render().join('\n');
403
- assert.ok(paOverview.includes('◆'), 'overview must render ◆ marker for preAnswered interaction');
404
- assert.ok(paOverview.includes('1/2'), 'overview must count preAnswered as answered (1/2)');
405
- paPanel.unmount();
406
- // ── Test 14: currentIndex starts on first unanswered ──────────────────────────
407
- const skipStartDeck = {
408
- title: 'Test deck',
409
- interactions: [
410
- {
411
- id: 's1', title: 'Carried-1', subtitle: 'Carried-1 requires your attention.',
412
- options: [{ id: 'approve', label: 'Approve', shortcut: 'a' }],
413
- preAnswered: { selectedOptionId: 'approve' },
414
- },
415
- {
416
- id: 's2', title: 'Carried-2', subtitle: 'Carried-2 requires your attention.',
417
- options: [{ id: 'approve', label: 'Approve', shortcut: 'a' }],
418
- preAnswered: { selectedOptionId: 'approve' },
419
- },
420
- {
421
- id: 's3', title: 'Needs answer', subtitle: 'Needs answer requires your attention.',
422
- options: [{ id: 'approve', label: 'Approve', shortcut: 'a' }],
423
- },
424
- ],
425
- };
426
- const startPanel = mountPanel({ deck: skipStartDeck, cols: 80, rows: 24 });
427
- // Enter overview → item-review. Cursor should already be on s3 (first unanswered).
428
- startPanel.handleKey('', RETURN);
429
- const startReview = startPanel.render().join('\n');
430
- assert.ok(startReview.includes('Needs answer'), 'cursor lands on first unanswered interaction at mount, not the first preAnswered');
431
- assert.ok(startReview.includes('3/3'), 'item-review position counter shows 3/3 — third of three');
432
- startPanel.unmount();
433
- // ── Test 15: post-answer submit skips pre-answered, lands on next unanswered ──
434
- const skipMidDeck = {
435
- title: 'Test deck',
436
- interactions: [
437
- {
438
- id: 'm1', title: 'Fresh-1', subtitle: 'Fresh-1 requires your attention.',
439
- options: [{ id: 'approve', label: 'Approve', shortcut: 'a' }],
440
- },
441
- {
442
- id: 'm2', title: 'Carried', subtitle: 'Carried requires your attention.',
443
- options: [{ id: 'approve', label: 'Approve', shortcut: 'a' }],
444
- preAnswered: { selectedOptionId: 'approve' },
445
- },
446
- {
447
- id: 'm3', title: 'Fresh-2', subtitle: 'Fresh-2 requires your attention.',
448
- options: [{ id: 'approve', label: 'Approve', shortcut: 'a' }],
449
- },
450
- ],
451
- };
452
- let capturedSkip = [];
453
- const skipMidPanel = mountPanel({
454
- deck: skipMidDeck,
455
- cols: 80,
456
- rows: 24,
457
- onComplete: (responses) => { capturedSkip = responses; },
458
- });
459
- // overview → item-review on m1 (first unanswered).
460
- skipMidPanel.handleKey('', RETURN);
461
- // Answer m1 with shortcut 'a' — post-submit advance should skip m2, land on m3.
462
- skipMidPanel.handleKey('a', mkKey({}));
463
- const afterFirst = skipMidPanel.render().join('\n');
464
- assert.ok(afterFirst.includes('Fresh-2'), 'after answering m1, post-submit advance must skip preAnswered m2 and land on m3');
465
- // Answer m3 with 'a' — should now exit to final.
466
- skipMidPanel.handleKey('a', mkKey({}));
467
- skipMidPanel.handleKey('', RETURN); // final → complete
468
- assert.deepEqual(capturedSkip, [
469
- { id: 'm1', selectedOptionId: 'approve' },
470
- { id: 'm2', selectedOptionId: 'approve' },
471
- { id: 'm3', selectedOptionId: 'approve' },
472
- ], 'preAnswered response carried through to onComplete output');
473
- skipMidPanel.unmount();
474
- // ── Test 16: n/p still steps onto pre-answered (no skip) ──────────────────────
475
- const npReachDeck = {
476
- title: 'Test deck',
477
- interactions: [
478
- {
479
- id: 'n1', title: 'Fresh', subtitle: 'Fresh requires your attention.',
480
- options: [{ id: 'approve', label: 'Approve', shortcut: 'a' }],
481
- },
482
- {
483
- id: 'n2', title: 'Carried', subtitle: 'Carried requires your attention.',
484
- options: [{ id: 'approve', label: 'Approve', shortcut: 'a' }],
485
- preAnswered: { selectedOptionId: 'approve', label: 'Previously approved' },
486
- },
487
- {
488
- id: 'n3', title: 'Also fresh', subtitle: 'Also fresh requires your attention.',
489
- options: [{ id: 'approve', label: 'Approve', shortcut: 'a' }],
490
- },
491
- ],
492
- };
493
- const npPanel = mountPanel({ deck: npReachDeck, cols: 80, rows: 24 });
494
- npPanel.handleKey('', RETURN); // overview → item-review on n1 (first unanswered)
495
- npPanel.handleKey('n', mkKey({})); // raw 'n' should step to n2 even though it's pre-answered
496
- const onPreAnswered = npPanel.render().join('\n');
497
- assert.ok(onPreAnswered.includes('Carried'), 'raw n must reach the pre-answered interaction (no skip on single-step nav)');
498
- assert.ok(onPreAnswered.includes('Previously approved'), 'item-review of pre-answered shows the preAnswered.label marker');
499
- npPanel.handleKey('p', mkKey({})); // raw 'p' steps back to n1
500
- const backToFirst = npPanel.render().join('\n');
501
- assert.ok(backToFirst.includes('Fresh') && !backToFirst.includes('Carried'), 'raw p steps back single-step');
502
- npPanel.unmount();
503
- // ── Test 17: user override clears preAnsweredIds and updates response ─────────
504
- const overrideDeck = {
505
- title: 'Test deck',
506
- interactions: [
507
- {
508
- id: 'o1', title: 'Carried, may override', subtitle: 'Carried, may override requires your attention.',
509
- options: [
510
- { id: 'approve', label: 'Approve', shortcut: 'a' },
511
- { id: 'reject', label: 'Reject', shortcut: 'r' },
512
- ],
513
- preAnswered: { selectedOptionId: 'approve', label: 'Previously approved' },
514
- },
515
- {
516
- id: 'o2', title: 'Fresh', subtitle: 'Fresh requires your attention.',
517
- options: [{ id: 'approve', label: 'Approve', shortcut: 'a' }],
518
- },
519
- ],
520
- };
521
- let capturedOverride = [];
522
- const ovPanel = mountPanel({
523
- deck: overrideDeck,
524
- cols: 80,
525
- rows: 24,
526
- onComplete: (responses) => { capturedOverride = responses; },
527
- });
528
- // Cursor lands on o2 (first unanswered). Step back to o1 with 'p'.
529
- ovPanel.handleKey('', RETURN);
530
- ovPanel.handleKey('p', mkKey({}));
531
- // Override: pick 'reject' via shortcut.
532
- ovPanel.handleKey('r', mkKey({}));
533
- // Post-submit advance lands on o2 (next unanswered).
534
- ovPanel.handleKey('a', mkKey({}));
535
- ovPanel.handleKey('', RETURN); // final → complete
536
- assert.deepEqual(capturedOverride, [
537
- { id: 'o1', selectedOptionId: 'reject' },
538
- { id: 'o2', selectedOptionId: 'approve' },
539
- ], 'user override of preAnswered must replace the seeded selectedOptionId');
540
- ovPanel.unmount();
541
- // ── Test 18: multi-select per-option comments via 'c' on focused option ──────
542
- // 'c' on a focused option enters comment mode pre-attached to that option;
543
- // Enter saves to optionComments[id], auto-checks the option, stays on the same
544
- // interaction so further options can be commented. The [c] freetext row still
545
- // produces an overall comment.
546
- const optCommentDeck = {
547
- title: 'Test deck',
548
- interactions: [
549
- {
550
- id: 'oc1', title: 'Pick toppings (with notes)', subtitle: 'Pick toppings (with notes) requires your attention.', multiSelect: true,
551
- allowFreetext: true,
552
- options: [
553
- { id: 'mush', label: 'Mushroom', shortcut: 'a' },
554
- { id: 'onion', label: 'Onion', shortcut: 'b' },
555
- { id: 'olive', label: 'Olive', shortcut: 'x' },
556
- ],
557
- },
558
- ],
559
- };
560
- let capturedOpt = [];
561
- const ocPanel = mountPanel({
562
- deck: optCommentDeck,
563
- cols: 80,
564
- rows: 24,
565
- onComplete: (responses) => { capturedOpt = responses; },
566
- });
567
- // Single-item deck starts in item-review, cursor on 'mush'.
568
- // 'c' on 'mush' → enter comment mode pre-attached.
569
- ocPanel.handleKey('c', mkKey({}));
570
- ocPanel.handleKey('y', mkKey({}));
571
- ocPanel.handleKey('u', mkKey({}));
572
- ocPanel.handleKey('m', mkKey({}));
573
- ocPanel.handleKey('', RETURN); // save per-option comment, auto-check 'mush'
574
- // Should still be on the same interaction, NOT advanced to final.
575
- const afterOptComment = ocPanel.render().join('\n');
576
- assert.ok(afterOptComment.includes('Pick toppings'), 'after submitting a per-option comment, stay on the same interaction');
577
- assert.ok(afterOptComment.includes('yum'), 'per-option comment renders inline under the option');
578
- // Move cursor to 'onion' and comment without auto-checking via different path:
579
- ocPanel.handleKey('j', mkKey({})); // cursor → 'onion'
580
- ocPanel.handleKey('c', mkKey({}));
581
- ocPanel.handleKey('m', mkKey({}));
582
- ocPanel.handleKey('e', mkKey({}));
583
- ocPanel.handleKey('h', mkKey({}));
584
- ocPanel.handleKey('', RETURN); // save + auto-check 'onion'
585
- // Now confirm the multi-select set with Enter on a checked option row.
586
- // Cursor is still on 'onion'. Enter confirms accumulated set + advances.
587
- ocPanel.handleKey('', RETURN); // commit multi → advance to final
588
- ocPanel.handleKey('', RETURN); // final → complete
589
- assert.deepEqual(capturedOpt, [{
590
- id: 'oc1',
591
- selectedOptionIds: ['mush', 'onion'],
592
- optionComments: { mush: 'yum', onion: 'meh' },
593
- }], 'per-option comments accumulate under optionComments and auto-check their options');
594
- ocPanel.unmount();
595
- // ── Test 19: multi-select requires explicit confirm (no auto-finalize on 1st Enter) ──
596
- // Regression for: a single-interaction multiSelect deck auto-finalized the
597
- // instant the set was confirmed, with no Summary/confirm pause. Now the first
598
- // Enter lands on the Summary screen; a second deliberate Enter submits.
599
- const confirmDeck = {
600
- title: 'Test deck',
601
- interactions: [
602
- {
603
- id: 'cs1', title: 'Pick toppings', subtitle: 'Pick toppings requires your attention.', multiSelect: true,
604
- options: [
605
- { id: 'mush', label: 'Mushroom', shortcut: 'a' },
606
- { id: 'onion', label: 'Onion', shortcut: 'b' },
607
- ],
608
- },
609
- ],
610
- };
611
- let confirmFired = false;
612
- let confirmResponses = [];
613
- const confirmPanel = mountPanel({
614
- deck: confirmDeck,
615
- cols: 80,
616
- rows: 24,
617
- onComplete: (responses) => { confirmFired = true; confirmResponses = responses; },
618
- });
619
- // Single-item deck starts in item-review, cursor on 'mush'.
620
- confirmPanel.handleKey(' ', mkKey({})); // toggle 'mush' on
621
- confirmPanel.handleKey('', RETURN); // confirm set → lands on Summary, must NOT finalize
622
- assert.equal(confirmFired, false, 'multi-select first Enter must NOT auto-finalize (lands on the confirm screen)');
623
- const confirmScreen = confirmPanel.render().join('\n');
624
- assert.ok(confirmScreen.includes('Summary'), 'after confirming a multi-select set, the deck shows the Summary/confirm screen');
625
- // Second deliberate Enter on the Summary screen finalizes.
626
- confirmPanel.handleKey('', RETURN);
627
- assert.equal(confirmFired, true, 'second Enter on the Summary screen finalizes the multi-select deck');
628
- assert.deepEqual(confirmResponses, [{ id: 'cs1', selectedOptionIds: ['mush'] }], 'confirmed multi-select set returned on finalize');
629
- confirmPanel.unmount();
630
- // ── Test 20: empty multi-select Enter is a no-op (does not finalize or advance) ──
631
- // Regression for: Enter with zero options toggled committed {selectedOptionIds:[]}
632
- // and finalized the deck. Now it's a no-op with an inline hint; the deck is not
633
- // stuck — picking an option and confirming still works.
634
- const emptyDeck = {
635
- title: 'Test deck',
636
- interactions: [
637
- {
638
- id: 'es1', title: 'Pick toppings', subtitle: 'Pick toppings requires your attention.', multiSelect: true,
639
- options: [
640
- { id: 'mush', label: 'Mushroom', shortcut: 'a' },
641
- { id: 'onion', label: 'Onion', shortcut: 'b' },
642
- ],
643
- },
644
- ],
645
- };
646
- let emptyFired = false;
647
- const emptyPanel = mountPanel({
648
- deck: emptyDeck,
649
- cols: 80,
650
- rows: 24,
651
- onComplete: () => { emptyFired = true; },
652
- });
653
- // Cursor on 'mush', nothing toggled. Enter must be a no-op.
654
- emptyPanel.handleKey('', RETURN);
655
- assert.equal(emptyFired, false, 'Enter with an empty multi-select set must NOT finalize');
656
- const stillReview = emptyPanel.render().join('\n');
657
- assert.ok(stillReview.includes('Pick toppings'), 'after empty Enter, still on the interaction (no advance)');
658
- assert.ok(!stillReview.includes('Summary'), 'after empty Enter, the deck did NOT advance to the Summary screen');
659
- assert.ok(stillReview.toLowerCase().includes('select at least one'), 'empty multi-select Enter surfaces an inline hint');
660
- // Prove the deck is not trapped: pick an option, then confirm.
661
- emptyPanel.handleKey('a', mkKey({})); // shortcut toggles 'mush' on
662
- emptyPanel.handleKey('', RETURN); // confirm → Summary
663
- emptyPanel.handleKey('', RETURN); // second Enter → finalize
664
- assert.equal(emptyFired, true, 'after picking an option, the multi-select deck can still be confirmed');
665
- emptyPanel.unmount();
666
- // ── Test 21: Alt+Backspace deletes the previous word in freetext input ────────
667
- // Required deliverable: Option/Alt+Backspace arrives as ESC+DEL (\x1b\x7f) /
668
- // ESC+BS (\x1b\b), parsed by parseKeypress into key.meta+key.backspace, and
669
- // deletes back over any trailing whitespace + the preceding word — matching
670
- // macOS text-input behavior. The freetext buffer is end-anchored (no mid-string
671
- // cursor), so forward word-delete (Option+Delete) and word-motion
672
- // (Option+Left/Right) are deferred: they'd require introducing a cursor index.
673
- const ALT_BACKSPACE = mkKey({ backspace: true, meta: true });
674
- function freetextAfter(typed, ops) {
675
- const deck = {
676
- title: 'Test deck',
677
- interactions: [{ id: 'w1', title: 'Notes', subtitle: 'Notes requires your attention.', options: [], allowFreetext: true }],
678
- };
679
- let captured = [];
680
- const p = mountPanel({ deck, cols: 80, rows: 24, onComplete: (r) => { captured = r; } });
681
- p.handleKey('r', mkKey({})); // single-item deck → item-review; 'r' opens freetext
682
- for (const ch of typed)
683
- p.handleKey(ch, mkKey({}));
684
- for (const op of ops)
685
- p.handleKey('', op);
686
- p.handleKey('', RETURN); // submit freetext
687
- p.handleKey('', RETURN); // final → complete
688
- p.unmount();
689
- return captured[0]?.freetext;
690
- }
691
- assert.equal(freetextAfter('hello world foo', [ALT_BACKSPACE]), 'hello world ', 'Alt+Backspace deletes the trailing word, leaving the separating space');
692
- assert.equal(freetextAfter('alpha beta ', [ALT_BACKSPACE]), 'alpha ', 'Alt+Backspace deletes trailing whitespace then the preceding word');
693
- assert.equal(freetextAfter('one two three', [ALT_BACKSPACE, ALT_BACKSPACE]), 'one ', 'repeated Alt+Backspace deletes successive words');
694
- assert.equal(freetextAfter('solo', [ALT_BACKSPACE, ALT_BACKSPACE]), '', 'Alt+Backspace at start-of-buffer is a no-op (no underflow past empty)');
695
- // ── Test 22: raw iTerm2 control bytes drive word-delete / line-clear ──────────────
696
- // iTerm2 maps Option+Backspace → bare 0x17 (Ctrl-W) and Cmd+Backspace → bare
697
- // 0x15 (Ctrl-U), with no ESC prefix. These are fed through the real
698
- // parseKeypress so the terminal-layer mapping is exercised end-to-end, not just
699
- // the synthetic meta+backspace key tested above.
700
- function freetextRaw(typed, rawOps) {
701
- const deck = {
702
- title: 'Test deck',
703
- interactions: [{ id: 'w2', title: 'Notes', subtitle: 'Notes requires your attention.', options: [], allowFreetext: true }],
704
- };
705
- let captured = [];
706
- const p = mountPanel({ deck, cols: 80, rows: 24, onComplete: (r) => { captured = r; } });
707
- p.handleKey('r', mkKey({})); // single-item deck → item-review; 'r' opens freetext
708
- for (const ch of typed)
709
- p.handleKey(ch, mkKey({}));
710
- for (const raw of rawOps) {
711
- const { input, key } = decodeInboxKey(raw);
712
- p.handleKey(input, key);
713
- }
714
- p.handleKey('', RETURN); // submit freetext
715
- p.handleKey('', RETURN); // final → complete
716
- p.unmount();
717
- return captured[0]?.freetext;
718
- }
719
- assert.equal(freetextRaw('hello world foo', ['\x17']), 'hello world ', 'bare 0x17 (Ctrl-W, iTerm2 Option+Backspace) deletes the trailing word');
720
- assert.equal(freetextRaw('alpha beta ', ['\x17']), 'alpha ', '0x17 deletes trailing whitespace then the preceding word');
721
- assert.equal(freetextRaw('one two three', ['\x17', '\x17']), 'one ', 'repeated 0x17 deletes successive words');
722
- assert.equal(freetextRaw('clear me out', ['\x15']), '', 'bare 0x15 (Ctrl-U, iTerm2 Cmd+Backspace) deletes to line start (clears buffer)');
723
- assert.equal(freetextRaw('keep', ['\x15', '\x15']), '', '0x15 on an already-empty buffer is a no-op');
724
- // ── Test 23: comment arrows navigate text; PageUp/PageDown scroll body ────────
725
- // While an attached option comment is open, arrows move through the multiline
726
- // comment buffer. PageUp/PageDown are the dedicated question-body scroll keys.
727
- const longBodyDeck = {
728
- title: 'Test deck',
729
- interactions: [{
730
- id: 'scroll-comment',
731
- title: 'Scrollable question', subtitle: 'Scrollable question requires your attention.',
732
- body: Array.from({ length: 40 }, (_, i) => `body line ${i + 1}`).join('\n'),
733
- options: [{ id: 'yes', label: 'Yes', shortcut: 'y' }],
734
- allowFreetext: true,
735
- }],
736
- };
737
- let scrollCommentResponses = [];
738
- const scrollCommentPanel = mountPanel({
739
- deck: longBodyDeck,
740
- cols: 80,
741
- rows: 20,
742
- onComplete: (r) => { scrollCommentResponses = r; },
743
- });
744
- scrollCommentPanel.handleKey('c', mkKey({})); // attached to the focused 'yes' option
745
- for (const ch of 'one')
746
- scrollCommentPanel.handleKey(ch, mkKey({}));
747
- scrollCommentPanel.handleKey('', mkKey({ newline: true }));
748
- for (const ch of 'two')
749
- scrollCommentPanel.handleKey(ch, mkKey({}));
750
- scrollCommentPanel.handleKey('', mkKey({ newline: true }));
751
- for (const ch of 'three')
752
- scrollCommentPanel.handleKey(ch, mkKey({}));
753
- assert.ok(scrollCommentPanel.render().join('\n').includes('↓'), 'long body shows below-scroll affordance while editing a comment');
754
- scrollCommentPanel.handleKey('', mkKey({ upArrow: true }));
755
- scrollCommentPanel.handleKey('!', mkKey({}));
756
- scrollCommentPanel.handleKey('', mkKey({ pageDown: true }));
757
- const scrolledComment = scrollCommentPanel.render().join('\n');
758
- assert.ok(scrolledComment.includes('↑') || scrolledComment.includes('more above'), 'PageDown scrolls the body without moving to the bottom of the comment buffer');
759
- scrollCommentPanel.handleKey('', RETURN);
760
- assert.deepEqual(scrollCommentResponses, [{ id: 'scroll-comment', selectedOptionId: 'yes', freetext: 'one\ntwo!\nthree' }], 'arrow navigation edits the multiline comment and PageDown does not alter it');
761
- scrollCommentPanel.unmount();
762
- // ── Test 24: host capability hints are truthful ───────────────────────────────
763
- const capabilityDeck = { title: 'Test deck', interactions: [{ id: 'note', title: 'Note', subtitle: 'Note requires your attention.', options: [], allowFreetext: true }] };
764
- const noCapabilityPanel = mountPanel({ deck: capabilityDeck, cols: 80, rows: 20 });
765
- assert.ok(!noCapabilityPanel.render().join('\n').includes('expand'), 'a deck does not advertise removed controls');
766
- noCapabilityPanel.handleKey('r', mkKey({}));
767
- assert.ok(!noCapabilityPanel.render().join('\n').includes('^O'), 'a host without an editor callback does not advertise Ctrl+O');
768
- noCapabilityPanel.unmount();
769
- let editorRequests = 0;
770
- const editorCapabilityPanel = mountPanel({ deck: capabilityDeck, cols: 80, rows: 20, onEditorRequest: () => { editorRequests++; } });
771
- editorCapabilityPanel.handleKey('r', mkKey({}));
772
- assert.ok(editorCapabilityPanel.render().join('\n').includes('^O'), 'an editor-capable host advertises Ctrl+O');
773
- editorCapabilityPanel.handleKey('o', mkKey({ ctrl: true }));
774
- assert.equal(editorRequests, 1, 'Ctrl+O delegates only through the host editor callback');
775
- editorCapabilityPanel.unmount();
776
- console.log('OK');