@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,489 +0,0 @@
1
- // Run with: node --import tsx/esm --test src/daemon/api/__tests__/inbox.test.ts
2
- //
3
- // Integration coverage for crtrd's `/v1/human/inbox` routes
4
- // (inbox-contract.md §A, `handlers/inbox.ts`). Exercises the full leaf → typed
5
- // `CrtrClient` → in-process `createApiServer()` → handler → ticket store —
6
- // never a mock client or pre-parsed handler call. Tickets live directly under
7
- // the derived `ticketsRoot()` and use the same public store APIs as production.
8
- // A raw hand-written `deck.json` is used only for states that submission cannot
9
- // produce: an unresolved `bodyPath`, a malformed stored deck, or a raced final.
10
- import { test, describe, before, after, beforeEach } from 'node:test';
11
- import assert from 'node:assert/strict';
12
- import { spawn } from 'node:child_process';
13
- import { mkdtempSync, mkdirSync, rmSync, writeFileSync, readFileSync, existsSync, realpathSync, } from 'node:fs';
14
- import { tmpdir } from 'node:os';
15
- import { join } from 'node:path';
16
- import { createHash } from 'node:crypto';
17
- import { claimTicket, releaseClaim } from '../../../core/human/claim.js';
18
- import { deckPath, responsePath } from '../../../core/human/convention.js';
19
- import { notifyDeck } from '../../../core/human/deck-factories.js';
20
- import { ticketsRoot } from '../../../core/human/root.js';
21
- import { submitDeck, submitReview } from '../../../core/human/tickets.js';
22
- import { createApiServer } from '../server.js';
23
- import { apiSocketPath } from '../../../core/canvas/paths.js';
24
- import { CrtrClient, ApiError } from '../../../api/index.js';
25
- const TICKET_ID_PATTERN = /^[a-f0-9]{64}$/;
26
- // ---------------------------------------------------------------------------
27
- // Harness — one server for the whole file; a fresh derived tickets root per
28
- // test.
29
- // ---------------------------------------------------------------------------
30
- let crtrHome;
31
- let priorCrtrHome;
32
- let server;
33
- let client;
34
- async function waitForSocket(path) {
35
- for (let i = 0; i < 200; i++) {
36
- if (existsSync(path))
37
- return;
38
- await new Promise((r) => setTimeout(r, 25));
39
- }
40
- throw new Error(`api socket never bound at ${path}`);
41
- }
42
- before(async () => {
43
- priorCrtrHome = process.env['CRTR_HOME'];
44
- crtrHome = mkdtempSync(join(tmpdir(), 'crtr-inbox-home-'));
45
- process.env['CRTR_HOME'] = crtrHome;
46
- server = createApiServer();
47
- await waitForSocket(apiSocketPath());
48
- client = new CrtrClient({ socketPath: apiSocketPath(), autostart: false });
49
- });
50
- after(async () => {
51
- await server?.close();
52
- rmSync(crtrHome, { recursive: true, force: true });
53
- if (priorCrtrHome !== undefined)
54
- process.env['CRTR_HOME'] = priorCrtrHome;
55
- else
56
- delete process.env['CRTR_HOME'];
57
- });
58
- beforeEach(() => {
59
- rmSync(ticketsRoot(), { recursive: true, force: true });
60
- mkdirSync(ticketsRoot(), { recursive: true, mode: 0o700 });
61
- });
62
- // ---------------------------------------------------------------------------
63
- // Fixture helpers
64
- // ---------------------------------------------------------------------------
65
- function freshRoot(..._unused) {
66
- mkdirSync(ticketsRoot(), { recursive: true, mode: 0o700 });
67
- return realpathSync(ticketsRoot());
68
- }
69
- function deckJson(blockedSince, extra = {}) {
70
- return {
71
- title: 'Ship it?',
72
- source: { blockedSince },
73
- interactions: [{ id: 'q', title: 'Ship it?', subtitle: 'Approve shipping now so the release can proceed.', options: [{ id: 'yes', label: 'Yes' }, { id: 'no', label: 'No' }] }],
74
- ...extra,
75
- };
76
- }
77
- /** Create a real pending deck ticket through the public submission API — the
78
- * normal fixture path for any test that just needs a valid, answerable
79
- * ticket on disk. */
80
- function submitTestDeck(root, id, blockedSince, extra = {}) {
81
- return submitDeck({ dir: join(root, id), deck: deckJson(blockedSince, extra) }).dir;
82
- }
83
- /** Create a real pending review ticket through the public submission API. */
84
- function submitTestReview(root, id, blockedSince) {
85
- const srcDir = mkdtempSync(join(tmpdir(), 'crtr-inbox-review-src-'));
86
- const file = join(srcDir, 'plan.md');
87
- writeFileSync(file, '# Plan\n\nDo the thing.\n');
88
- return submitReview({ dir: join(root, id), review: { title: 'Review the plan', subtitle: 'Review the plan now so implementation can begin with confidence.', source: {}, file, blockedSince } }).dir;
89
- }
90
- /** RAW fixture writer — bypasses `submitDeck`'s own submit-time validation
91
- * and body-path resolution entirely. Used ONLY to construct on-disk states
92
- * a real submitter cannot produce: an unresolved `bodyPath`, a tampered
93
- * stored deck, or an adversarial root-replacement target. */
94
- function writeRawDeckTicket(root, id, deck) {
95
- const dir = join(root, id);
96
- mkdirSync(dir, { recursive: true, mode: 0o700 });
97
- writeFileSync(deckPath(dir), JSON.stringify(deck));
98
- return dir;
99
- }
100
- function ticketIdFor(root, basename) {
101
- return createHash('sha256').update(`${root}\0${basename}`, 'utf8').digest('hex');
102
- }
103
- async function expectApiError(promise, status, code) {
104
- try {
105
- await promise;
106
- }
107
- catch (err) {
108
- assert.ok(err instanceof ApiError, `expected ApiError, got ${String(err)}`);
109
- assert.equal(err.status, status, `status: ${err.message}`);
110
- assert.equal(err.code, code, `code: ${err.message}`);
111
- return err;
112
- }
113
- throw new Error('expected the promise to reject');
114
- }
115
- // ---------------------------------------------------------------------------
116
- // Wire-shape assertions — a closed allowlist per DTO plus a recursive
117
- // forbidden-content walk (host paths, claim/dir/file/output/bodyPath keys).
118
- // ---------------------------------------------------------------------------
119
- function assertKeys(obj, allowed, label) {
120
- for (const key of Object.keys(obj)) {
121
- assert.ok(allowed.includes(key), `unexpected field "${key}" in ${label}: ${JSON.stringify(obj)}`);
122
- }
123
- }
124
- function assertSourceShape(source) {
125
- assert.equal(typeof source, 'object');
126
- assertKeys(source, ['sessionName', 'askedBy', 'blockedSince', 'nodeId'], 'DeckSourceDTO');
127
- }
128
- function assertTicketSummaryShape(ticket) {
129
- assert.match(ticket.ticket_id, TICKET_ID_PATTERN);
130
- assert.ok(ticket.kind === 'deck' || ticket.kind === 'review');
131
- const allowed = ticket.kind === 'deck'
132
- ? ['ticket_id', 'kind', 'title', 'subtitle', 'blocked_since', 'source', 'interaction_kind']
133
- : ['ticket_id', 'kind', 'title', 'subtitle', 'blocked_since', 'source'];
134
- assertKeys(ticket, allowed, `InboxTicketSummaryDTO(${ticket.kind})`);
135
- assertSourceShape(ticket.source);
136
- }
137
- function assertInboxListShape(body) {
138
- assertKeys(body, ['tickets'], 'InboxListDTO');
139
- for (const ticket of body.tickets)
140
- assertTicketSummaryShape(ticket);
141
- }
142
- function assertInteractionShape(interaction) {
143
- assertKeys(interaction, ['id', 'title', 'subtitle', 'body', 'options', 'multiSelect', 'allowFreetext', 'freetextLabel', 'kind', 'preAnswered'], 'InteractionDTO');
144
- for (const option of interaction.options) {
145
- assertKeys(option, ['id', 'label', 'description'], 'InteractionOptionDTO');
146
- }
147
- if (interaction.preAnswered !== undefined) {
148
- assertKeys(interaction.preAnswered, ['selectedOptionId', 'selectedOptionIds', 'freetext', 'label'], 'InteractionPreAnswerDTO');
149
- }
150
- }
151
- function assertDeckShape(deck) {
152
- assertKeys(deck, ['title', 'source', 'interactions'], 'DeckDTO');
153
- if (deck.source !== undefined)
154
- assertSourceShape(deck.source);
155
- for (const interaction of deck.interactions)
156
- assertInteractionShape(interaction);
157
- }
158
- function assertInboxDeckShape(body) {
159
- assertKeys(body, ['ticket_id', 'kind', 'deck'], 'InboxDeckDTO');
160
- assert.equal(body.kind, 'deck');
161
- assert.match(body.ticket_id, TICKET_ID_PATTERN);
162
- assertDeckShape(body.deck);
163
- }
164
- function assertDeckResultShape(result) {
165
- assertKeys(result, ['schema', 'kind', 'responses', 'summary', 'completedAt'], 'DeckTicketResultDTO');
166
- assert.equal(result.schema, 'humanloop.response/v2');
167
- assert.equal(result.kind, 'deck');
168
- for (const response of result.responses) {
169
- assertKeys(response, ['id', 'selectedOptionId', 'selectedOptionIds', 'freetext', 'optionComments'], 'InteractionResponseDTO');
170
- }
171
- }
172
- function assertCanceledResultShape(result) {
173
- assertKeys(result, ['schema', 'kind', 'canceledAt', 'reason', 'actor'], 'CanceledTicketResultDTO');
174
- assert.equal(result.schema, 'humanloop.cancel/v1');
175
- assert.equal(result.kind, 'canceled');
176
- }
177
- const FORBIDDEN_KEYS = new Set(['dir', 'file', 'output', 'claim', 'bodyPath']);
178
- /** Recursively walk a parsed JSON value, failing on any forbidden key name or
179
- * any string value containing one of the given forbidden substrings (host
180
- * paths, in practice). Used against full success AND error bodies. */
181
- function assertNoForbiddenContent(value, forbidden, path = '$') {
182
- if (Array.isArray(value)) {
183
- value.forEach((item, i) => assertNoForbiddenContent(item, forbidden, `${path}[${i}]`));
184
- return;
185
- }
186
- if (value !== null && typeof value === 'object') {
187
- for (const [key, val] of Object.entries(value)) {
188
- assert.ok(!FORBIDDEN_KEYS.has(key), `forbidden key "${key}" present at ${path}.${key}`);
189
- assertNoForbiddenContent(val, forbidden, `${path}.${key}`);
190
- }
191
- return;
192
- }
193
- if (typeof value === 'string') {
194
- for (const needle of forbidden) {
195
- assert.ok(!value.includes(needle), `forbidden content "${needle}" leaked at ${path}: ${JSON.stringify(value)}`);
196
- }
197
- }
198
- }
199
- // ---------------------------------------------------------------------------
200
- // GET /v1/human/inbox — enumerate
201
- // ---------------------------------------------------------------------------
202
- describe('GET /v1/human/inbox — enumerate', () => {
203
- test('mixed deck + review tickets preserve canonical-root hash ids while sorting newest first', async () => {
204
- const root = freshRoot('crouter');
205
- // This is the pre-cutover opaque-id formula: canonical root + NUL + ticket
206
- // basename. The single derived root retains that canonical root, so an id
207
- // a client computed before root registration disappeared still resolves.
208
- const olderDeckId = ticketIdFor(root, 'older-deck');
209
- submitTestDeck(root, 'older-deck', '2026-01-01T00:00:00.000Z');
210
- submitTestReview(root, 'newer-review', '2026-01-02T00:00:00.000Z');
211
- const list = await client.listHumanInbox();
212
- assertInboxListShape(list);
213
- assertNoForbiddenContent(list, [root]);
214
- assert.equal(list.tickets.length, 2);
215
- assert.equal(list.tickets[0].kind, 'review', 'newer blocked_since sorts first');
216
- assert.equal(list.tickets[1].kind, 'deck');
217
- assert.equal(list.tickets[0].ticket_id, ticketIdFor(root, 'newer-review'));
218
- assert.equal(list.tickets[1].ticket_id, olderDeckId);
219
- assert.equal((await client.getHumanInboxDeck(olderDeckId)).deck.title, 'Ship it?');
220
- });
221
- test('sorts by parsed instant across differing UTC offsets, not lexical string order', async () => {
222
- const root = freshRoot('crouter');
223
- // '+14:00' is lexically GREATER than 'Z' at the date digit that differs,
224
- // but the instant it names is two hours EARLIER than the 'Z' ticket
225
- // below (2026-01-01T10:00:00Z vs. 2026-01-01T12:00:00Z). A lexical
226
- // descending sort would (wrongly) place this ticket first.
227
- submitTestDeck(root, 'lexically-later-but-earlier-instant', '2026-01-02T00:00:00+14:00');
228
- submitTestDeck(root, 'lexically-earlier-but-later-instant', '2026-01-01T12:00:00Z');
229
- const list = await client.listHumanInbox();
230
- assert.equal(list.tickets.length, 2);
231
- assert.equal(list.tickets[0].blocked_since, '2026-01-01T12:00:00Z', 'the chronologically newer instant sorts first regardless of lexical string order');
232
- assert.equal(list.tickets[0].ticket_id, ticketIdFor(root, 'lexically-earlier-but-later-instant'));
233
- assert.equal(list.tickets[1].ticket_id, ticketIdFor(root, 'lexically-later-but-earlier-instant'));
234
- });
235
- });
236
- // ---------------------------------------------------------------------------
237
- // GET /v1/human/inbox/:ticket_id — read a pending deck
238
- // ---------------------------------------------------------------------------
239
- describe('GET /v1/human/inbox/:ticket_id', () => {
240
- test('inlines bodyPath at read time; no bodyPath key on the wire', async () => {
241
- // RAW fixture: `submitDeck` resolves `bodyPath` to inline `body` at
242
- // submit time, so a ticket with a still-unresolved `bodyPath` on disk
243
- // (the state crtrd's own `parseDeck` read-time resolution exists to
244
- // handle) cannot be produced through the public submission API.
245
- const root = freshRoot('crouter');
246
- const dir = join(root, 'body-deck');
247
- mkdirSync(dir, { recursive: true, mode: 0o700 });
248
- writeFileSync(join(dir, 'body.md'), 'Full markdown body.\n');
249
- writeFileSync(deckPath(dir), JSON.stringify({
250
- title: 'Ship it?',
251
- source: { blockedSince: '2026-01-01T00:00:00.000Z' },
252
- interactions: [{ id: 'q', title: 'Ship it?', subtitle: 'Approve shipping now so the release can proceed.', bodyPath: 'body.md', options: [{ id: 'yes', label: 'Yes' }] }],
253
- }));
254
- const id = ticketIdFor(root, 'body-deck');
255
- const deckDto = await client.getHumanInboxDeck(id);
256
- assertInboxDeckShape(deckDto);
257
- assertNoForbiddenContent(deckDto, [root, dir]);
258
- assert.equal(deckDto.deck.interactions[0].body, 'Full markdown body.\n');
259
- });
260
- test('404 ticket_not_found for a syntactically valid but unknown ticket id', async () => {
261
- await expectApiError(client.getHumanInboxDeck('a'.repeat(64)), 404, 'ticket_not_found');
262
- });
263
- test('409 ticket_kind_unsupported for a review ticket', async () => {
264
- const root = freshRoot('crouter');
265
- submitTestReview(root, 'rev', '2026-01-01T00:00:00.000Z');
266
- await expectApiError(client.getHumanInboxDeck(ticketIdFor(root, 'rev')), 409, 'ticket_kind_unsupported');
267
- });
268
- test('malformed stored deck sanitizes to 500 internal: no bodyPath value or host path in error.message', async () => {
269
- // RAW fixture: simulates a ticket mutated on disk after enumeration (or a
270
- // corrupted store) — a state `submitDeck` cannot produce, since it
271
- // validates and resolves bodyPath before ever writing deck.json. This
272
- // reproduces the review's exact repro shape: a bodyPath that escapes the
273
- // ticket directory to an existing absolute host file.
274
- const root = freshRoot('crouter');
275
- const dir = writeRawDeckTicket(root, 'malformed', deckJson('2026-01-01T00:00:00.000Z', {
276
- interactions: [{ id: 'q', title: 'Ship it?', subtitle: 'Approve shipping now so the release can proceed.', bodyPath: process.execPath, options: [{ id: 'yes', label: 'Yes' }] }],
277
- }));
278
- const id = ticketIdFor(root, 'malformed');
279
- const err = await expectApiError(client.getHumanInboxDeck(id), 500, 'internal');
280
- assert.ok(!err.message.includes(process.execPath), `error.message leaked a host path: ${err.message}`);
281
- assert.ok(!err.message.includes(dir), `error.message leaked the ticket directory: ${err.message}`);
282
- assert.ok(!err.message.toLowerCase().includes('bodypath'), `error.message named bodyPath: ${err.message}`);
283
- });
284
- });
285
- // ---------------------------------------------------------------------------
286
- // POST /v1/human/inbox/:ticket_id/respond
287
- // ---------------------------------------------------------------------------
288
- describe('POST /v1/human/inbox/:ticket_id/respond', () => {
289
- test('persists the canonical humanloop.response/v2 result unchanged and matches stored response.json exactly', async () => {
290
- const root = freshRoot('crouter', true);
291
- const dir = submitTestDeck(root, 'ask', '2026-01-01T00:00:00.000Z');
292
- const id = ticketIdFor(root, 'ask');
293
- const result = await client.respondHumanInboxDeck(id, { responses: [{ id: 'q', selectedOptionId: 'yes' }] });
294
- assertDeckResultShape(result);
295
- assertNoForbiddenContent(result, [root, dir]);
296
- assert.deepEqual(result.responses, [{ id: 'q', selectedOptionId: 'yes' }]);
297
- const stored = JSON.parse(readFileSync(responsePath(dir), 'utf8'));
298
- assert.deepEqual(stored, result, 'the wire result is the stored humanloop response exactly, unreconstructed');
299
- assert.ok(existsSync(responsePath(dir)), 'the canonical response remains the only ticket receipt');
300
- });
301
- test('ordinary notify acknowledgement — no special endpoint/shape', async () => {
302
- const root = freshRoot('crouter');
303
- const id_ = 'notify';
304
- submitDeck({ dir: join(root, id_), deck: notifyDeck('Build done', { subtitle: 'The build completed successfully, so the change is ready to review.' }) });
305
- const id = ticketIdFor(root, 'notify');
306
- const result = await client.respondHumanInboxDeck(id, { responses: [{ id: 'notify', selectedOptionId: 'ok' }] });
307
- assert.equal(result.kind, 'deck');
308
- assert.deepEqual(result.responses, [{ id: 'notify', selectedOptionId: 'ok' }]);
309
- });
310
- test('409 ticket_kind_unsupported for a review ticket', async () => {
311
- const root = freshRoot('crouter');
312
- submitTestReview(root, 'rev', '2026-01-01T00:00:00.000Z');
313
- await expectApiError(client.respondHumanInboxDeck(ticketIdFor(root, 'rev'), { responses: [] }), 409, 'ticket_kind_unsupported');
314
- });
315
- test('409 ticket_already_resolved on a second respond after the first succeeds', async () => {
316
- const root = freshRoot('crouter');
317
- submitTestDeck(root, 'ask', '2026-01-01T00:00:00.000Z');
318
- const id = ticketIdFor(root, 'ask');
319
- await client.respondHumanInboxDeck(id, { responses: [{ id: 'q', selectedOptionId: 'yes' }] });
320
- await expectApiError(client.respondHumanInboxDeck(id, { responses: [{ id: 'q', selectedOptionId: 'no' }] }), 409, 'ticket_already_resolved');
321
- });
322
- test('a live foreign claim is taken over by the daemon finish path', async () => {
323
- const root = freshRoot('crouter');
324
- const dir = submitTestDeck(root, 'ask', '2026-01-01T00:00:00.000Z');
325
- const id = ticketIdFor(root, 'ask');
326
- const foreignClaim = claimTicket(dir, { host: 'someone-else' });
327
- assert.ok(foreignClaim !== null, 'foreign claim acquired');
328
- const result = await client.respondHumanInboxDeck(id, { responses: [{ id: 'q', selectedOptionId: 'yes' }] });
329
- assertDeckResultShape(result);
330
- assert.equal(releaseClaim(dir, foreignClaim.token), false, 'the takeover released the replaced claim');
331
- });
332
- test('external cancel/resolve race: a resolution that lands between the precheck and claimTicket() reports ticket_already_resolved, never ticket_unavailable', async () => {
333
- const root = freshRoot('crouter');
334
- const dir = submitTestDeck(root, 'race', '2026-01-01T00:00:00.000Z');
335
- const id = ticketIdFor(root, 'race');
336
- // A real separate OS process holds the SAME ticket lock humanloop's
337
- // `claimTicket` contends for (`<dir>/.ticket-lock`, matching the marker
338
- // scheme in humanloop's `convention.ts`). It signals once it holds the
339
- // lock, then after a short real delay writes `response.json` directly
340
- // (simulating an external actor's cancel/respond winning the race) and
341
- // releases. Because the holder grabs the lock BEFORE this test sends the
342
- // respond request, the precheck inside the handler is guaranteed to see
343
- // the ticket still pending, and `claimTicket()`'s own lock acquisition is
344
- // guaranteed to block until the holder resolves the ticket and releases
345
- // — deterministically reproducing the exact interleaving the fix must
346
- // handle, without relying on a microsecond-scale timing coincidence.
347
- const script = `
348
- const { mkdirSync, writeFileSync, rmSync } = require('node:fs');
349
- const dir = process.env.RACE_TICKET_DIR;
350
- const lockPath = dir + '/.ticket-lock';
351
- mkdirSync(lockPath, { mode: 0o700 });
352
- writeFileSync(lockPath + '/owner.race-holder', '', { flag: 'wx', mode: 0o600 });
353
- process.stdout.write('holding\\n');
354
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 300);
355
- writeFileSync(dir + '/response.json', JSON.stringify({
356
- schema: 'humanloop.cancel/v1', kind: 'canceled',
357
- canceledAt: new Date().toISOString(), reason: 'external race', actor: 'external',
358
- }) + '\\n', { mode: 0o600 });
359
- rmSync(lockPath, { recursive: true, force: true });
360
- process.stdout.write('resolved\\n');
361
- `;
362
- const holder = spawn(process.execPath, ['-e', script], {
363
- env: { ...process.env, RACE_TICKET_DIR: dir },
364
- stdio: ['ignore', 'pipe', 'pipe'],
365
- });
366
- let stdout = '';
367
- let stderr = '';
368
- holder.stdout.setEncoding('utf8');
369
- holder.stderr.setEncoding('utf8');
370
- holder.stdout.on('data', (chunk) => {
371
- stdout += chunk;
372
- });
373
- holder.stderr.on('data', (chunk) => {
374
- stderr += chunk;
375
- });
376
- const exited = new Promise((resolve) => holder.once('close', resolve));
377
- try {
378
- await new Promise((resolve, reject) => {
379
- const timer = setTimeout(() => reject(new Error(`race holder never signaled "holding": stdout=${stdout} stderr=${stderr}`)), 5000);
380
- const check = () => {
381
- if (stdout.includes('holding')) {
382
- clearTimeout(timer);
383
- resolve();
384
- }
385
- };
386
- holder.stdout.on('data', check);
387
- holder.once('error', (err) => {
388
- clearTimeout(timer);
389
- reject(err);
390
- });
391
- check();
392
- });
393
- await expectApiError(client.respondHumanInboxDeck(id, { responses: [{ id: 'q', selectedOptionId: 'yes' }] }), 409, 'ticket_already_resolved');
394
- }
395
- finally {
396
- await exited;
397
- }
398
- assert.ok(stdout.includes('resolved'), `race holder did not complete its resolve+release: stdout=${stdout} stderr=${stderr}`);
399
- });
400
- test('500 internal for a finalize failure that is not a response-shape rejection — sanitized, not misclassified as 400', async () => {
401
- const root = freshRoot('crouter');
402
- const dir = submitTestDeck(root, 'ask', '2026-01-01T00:00:00.000Z');
403
- const id = ticketIdFor(root, 'ask');
404
- // RAW tamper: rewrite the persisted deck so its own re-read inside
405
- // `finalizeDeck` fails deck-schema validation (interactions.min(1)) —
406
- // this is a storage-layer failure, not a response-shape rejection, and
407
- // `submitDeck` could never have written it in the first place.
408
- writeFileSync(deckPath(dir), JSON.stringify({ title: 'Ship it?', interactions: [] }));
409
- const err = await expectApiError(client.respondHumanInboxDeck(id, { responses: [{ id: 'q', selectedOptionId: 'yes' }] }), 500, 'internal');
410
- assert.equal(err.message, 'the ticket could not be finalized');
411
- assert.ok(!err.message.includes(dir), `error.message leaked the ticket directory: ${err.message}`);
412
- });
413
- test('400 invalid_ticket_response releases the claim so a following valid respond succeeds', async () => {
414
- const root = freshRoot('crouter');
415
- submitTestDeck(root, 'ask', '2026-01-01T00:00:00.000Z');
416
- const id = ticketIdFor(root, 'ask');
417
- const err = await expectApiError(client.respondHumanInboxDeck(id, { responses: [{ id: 'nonexistent', freetext: 'x' }] }), 400, 'invalid_ticket_response');
418
- assert.match(err.message, /response does not match a unique deck interaction: nonexistent/);
419
- const result = await client.respondHumanInboxDeck(id, { responses: [{ id: 'q', selectedOptionId: 'yes' }] });
420
- assert.equal(result.kind, 'deck', 'the claim was released, so a valid respond now succeeds');
421
- });
422
- test('400 invalid_request for a malformed body', async () => {
423
- const root = freshRoot('crouter');
424
- submitTestDeck(root, 'ask', '2026-01-01T00:00:00.000Z');
425
- const id = ticketIdFor(root, 'ask');
426
- const path = `/v1/human/inbox/${id}/respond`;
427
- await expectApiError(client.request('POST', path, { responses: [], extra: true }), 400, 'invalid_request');
428
- await expectApiError(client.request('POST', path, { responses: 'nope' }), 400, 'invalid_request');
429
- });
430
- });
431
- // ---------------------------------------------------------------------------
432
- // POST /v1/human/inbox/:ticket_id/cancel
433
- // ---------------------------------------------------------------------------
434
- describe('POST /v1/human/inbox/:ticket_id/cancel', () => {
435
- test('default reason and hardcoded human actor match stored response.json', async () => {
436
- const root = freshRoot('crouter', true);
437
- const dir = submitTestDeck(root, 'ask', '2026-01-01T00:00:00.000Z');
438
- const id = ticketIdFor(root, 'ask');
439
- const result = await client.cancelHumanInboxTicket(id);
440
- assertCanceledResultShape(result);
441
- assertNoForbiddenContent(result, [root, dir]);
442
- assert.equal(result.reason, 'Canceled from the inbox.');
443
- assert.equal(result.actor, 'human');
444
- const stored = JSON.parse(readFileSync(responsePath(dir), 'utf8'));
445
- assert.deepEqual(stored, result, 'the wire result is the stored humanloop cancellation exactly, unreconstructed');
446
- assert.ok(existsSync(responsePath(dir)), 'the canonical cancellation remains the only ticket receipt');
447
- });
448
- test('custom reason is honored; actor is always human regardless of any client-supplied field', async () => {
449
- const root = freshRoot('crouter');
450
- submitTestDeck(root, 'ask', '2026-01-01T00:00:00.000Z');
451
- const id = ticketIdFor(root, 'ask');
452
- const result = await client.cancelHumanInboxTicket(id, { reason: 'changed my mind' });
453
- assert.equal(result.reason, 'changed my mind');
454
- assert.equal(result.actor, 'human');
455
- });
456
- test('recordless review cancellation returns the stored humanloop.cancel/v1 result', async () => {
457
- const root = freshRoot('crouter');
458
- const dir = submitTestReview(root, 'rev', '2026-01-01T00:00:00.000Z');
459
- const result = await client.cancelHumanInboxTicket(ticketIdFor(root, 'rev'));
460
- assertCanceledResultShape(result);
461
- assert.deepEqual(JSON.parse(readFileSync(responsePath(dir), 'utf8')), result);
462
- });
463
- test('409 ticket_already_resolved after the ticket was already resolved via respond', async () => {
464
- const root = freshRoot('crouter');
465
- submitTestDeck(root, 'ask', '2026-01-01T00:00:00.000Z');
466
- const id = ticketIdFor(root, 'ask');
467
- await client.respondHumanInboxDeck(id, { responses: [{ id: 'q', selectedOptionId: 'yes' }] });
468
- await expectApiError(client.cancelHumanInboxTicket(id), 409, 'ticket_already_resolved');
469
- });
470
- test('400 invalid_request for an empty (post-trim) reason and for a >1000-char reason', async () => {
471
- const root = freshRoot('crouter');
472
- submitTestDeck(root, 'ask', '2026-01-01T00:00:00.000Z');
473
- const id = ticketIdFor(root, 'ask');
474
- await expectApiError(client.cancelHumanInboxTicket(id, { reason: ' ' }), 400, 'invalid_request');
475
- await expectApiError(client.cancelHumanInboxTicket(id, { reason: 'x'.repeat(1001) }), 400, 'invalid_request');
476
- });
477
- });
478
- // ---------------------------------------------------------------------------
479
- // Malformed ticket id syntax
480
- // ---------------------------------------------------------------------------
481
- describe('malformed ticket id syntax', () => {
482
- test('400 invalid_request on GET/respond/cancel for a non-hex or wrong-length id', async () => {
483
- for (const bad of ['not-hex-not-64-chars', 'a'.repeat(63), 'g'.repeat(64)]) {
484
- await expectApiError(client.request('GET', `/v1/human/inbox/${bad}`), 400, 'invalid_request');
485
- await expectApiError(client.request('POST', `/v1/human/inbox/${bad}/respond`, { responses: [] }), 400, 'invalid_request');
486
- await expectApiError(client.request('POST', `/v1/human/inbox/${bad}/cancel`, {}), 400, 'invalid_request');
487
- }
488
- });
489
- });