@north-light/crouter 0.3.170 → 0.3.172

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 (670) hide show
  1. package/dist/api/client.d.ts +37 -11
  2. package/dist/api/client.js +84 -15
  3. package/dist/api/dto/human.d.ts +53 -39
  4. package/dist/api/dto/human.js +2 -3
  5. package/dist/api/dto/inbox.d.ts +0 -1
  6. package/dist/api/dto/nodes.d.ts +12 -0
  7. package/dist/api/dto/review-comments.d.ts +137 -0
  8. package/dist/api/dto/review-comments.js +5 -0
  9. package/dist/api/dto/reviews.d.ts +109 -0
  10. package/dist/api/dto/reviews.js +5 -0
  11. package/dist/api/index.d.ts +2 -0
  12. package/dist/api/index.js +2 -0
  13. package/dist/api/routes.d.ts +17 -4
  14. package/dist/api/routes.js +21 -5
  15. package/dist/build-root.d.ts +1 -16
  16. package/dist/build-root.js +1 -25
  17. package/dist/builtin-memory/00-runtime-base.md +7 -5
  18. package/dist/builtin-memory/04-base-worker.md +1 -1
  19. package/dist/builtin-memory/04-orchestration-kernel.md +7 -7
  20. package/dist/builtin-memory/05-kinds/design/00-base.md +1 -1
  21. package/dist/builtin-memory/05-kinds/design/01-orchestrator.md +1 -1
  22. package/dist/builtin-memory/05-kinds/developer/00-base.md +1 -1
  23. package/dist/builtin-memory/05-kinds/explore/00-base.md +1 -1
  24. package/dist/builtin-memory/05-kinds/plan/00-base.md +1 -1
  25. package/dist/builtin-memory/05-kinds/plan/01-orchestrator.md +1 -1
  26. package/dist/builtin-memory/05-kinds/review/00-base.md +1 -1
  27. package/dist/builtin-memory/05-kinds/review/companion/00-base.md +20 -0
  28. package/dist/builtin-memory/05-kinds/spec/00-base.md +3 -7
  29. package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +3 -3
  30. package/dist/builtin-memory/05-kinds/spec/requirements.md +3 -3
  31. package/dist/builtin-memory/design.md +2 -2
  32. package/dist/builtin-memory/insights/capture.md +50 -0
  33. package/dist/builtin-memory/insights/init.md +45 -0
  34. package/dist/builtin-memory/insights/listen.md +9 -0
  35. package/dist/builtin-memory/internal/agent-shaping.md +2 -2
  36. package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
  37. package/dist/builtin-memory/internal/plugins.md +12 -11
  38. package/dist/builtin-memory/internal/storage-tiers.md +2 -2
  39. package/dist/builtin-memory/{planning.md → plan/roadmap.md} +3 -3
  40. package/dist/builtin-memory/plan.md +19 -0
  41. package/dist/builtin-memory/spec/guide.md +38 -0
  42. package/dist/builtin-memory/spec/requirements.md +31 -0
  43. package/dist/builtin-memory/spec/roadmap.md +35 -0
  44. package/dist/builtin-memory/spec.md +10 -86
  45. package/dist/builtin-pi-packages/pi-crtr-extensions/README.md +3 -4
  46. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/provider-rotation.test.ts +49 -5
  47. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +56 -0
  48. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +920 -0
  49. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +221 -156
  50. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/statusline.ts +4 -5
  51. package/dist/cli.js +2 -6
  52. package/dist/clients/attach/__tests__/attach-chrome-remote.test.js +7 -35
  53. package/dist/clients/attach/__tests__/attach-keybindings.test.js +32 -16
  54. package/dist/clients/attach/__tests__/context-message.test.js +142 -6
  55. package/dist/clients/attach/__tests__/crtr-output.test.js +29 -45
  56. package/dist/clients/attach/__tests__/diagram.test.js +1 -1
  57. package/dist/clients/attach/__tests__/file-review-focus.test.js +48 -0
  58. package/dist/clients/attach/__tests__/group-activity.test.js +266 -0
  59. package/dist/clients/attach/__tests__/input-controller-extension-command.test.js +32 -0
  60. package/dist/clients/attach/__tests__/session-identity-refresh.test.js +32 -0
  61. package/dist/clients/attach/__tests__/titled-editor-preview.test.js +1 -2
  62. package/dist/clients/attach/chrome/header.d.ts +10 -0
  63. package/dist/clients/attach/chrome/header.js +30 -0
  64. package/dist/clients/attach/chrome/recap.d.ts +7 -0
  65. package/dist/clients/attach/chrome/recap.js +19 -0
  66. package/dist/clients/attach/chrome/status-line.d.ts +3 -0
  67. package/dist/clients/attach/chrome/status-line.js +5 -0
  68. package/dist/clients/attach/chrome/widgets.js +11 -21
  69. package/dist/clients/attach/command.js +11 -7
  70. package/dist/clients/attach/config.d.ts +4 -0
  71. package/dist/clients/attach/config.js +3 -0
  72. package/dist/clients/attach/input/controller.d.ts +19 -0
  73. package/dist/clients/attach/input/controller.js +62 -28
  74. package/dist/clients/attach/input/titled-editor.d.ts +0 -4
  75. package/dist/clients/attach/input/titled-editor.js +2 -10
  76. package/dist/clients/attach/overlays/file-review.d.ts +9 -5
  77. package/dist/clients/attach/overlays/file-review.js +9 -70
  78. package/dist/clients/attach/overlays/help.d.ts +33 -0
  79. package/dist/clients/attach/overlays/help.js +204 -0
  80. package/dist/clients/attach/render/activity-slot.d.ts +4 -0
  81. package/dist/clients/attach/render/activity-slot.js +13 -0
  82. package/dist/clients/attach/render/chat-view.d.ts +117 -12
  83. package/dist/clients/attach/render/chat-view.js +604 -135
  84. package/dist/clients/attach/render/context-message.d.ts +2 -1
  85. package/dist/clients/attach/render/context-message.js +17 -13
  86. package/dist/clients/attach/render/crtr-output.js +1 -3
  87. package/dist/clients/attach/render/diagram.js +2 -2
  88. package/dist/clients/attach/render/edit-diff.d.ts +4 -1
  89. package/dist/clients/attach/render/edit-diff.js +7 -11
  90. package/dist/clients/attach/render/group-activity.d.ts +32 -0
  91. package/dist/clients/attach/render/group-activity.js +206 -0
  92. package/dist/clients/attach/render/group-recap.d.ts +10 -0
  93. package/dist/clients/attach/render/group-recap.js +93 -0
  94. package/dist/clients/attach/render/html-markdown.d.ts +17 -0
  95. package/dist/clients/attach/render/html-markdown.js +228 -0
  96. package/dist/clients/attach/render/measured-container.d.ts +96 -0
  97. package/dist/clients/attach/render/measured-container.js +322 -0
  98. package/dist/clients/attach/render/scroll-animation.d.ts +8 -0
  99. package/dist/clients/attach/render/scroll-animation.js +80 -0
  100. package/dist/clients/attach/render/tool-calls.js +6 -6
  101. package/dist/clients/attach/render/transcript-copy.d.ts +9 -0
  102. package/dist/clients/attach/render/transcript-copy.js +81 -0
  103. package/dist/clients/attach/render/viewport.d.ts +29 -0
  104. package/dist/clients/attach/render/viewport.js +159 -0
  105. package/dist/clients/attach/session/bindings.d.ts +10 -7
  106. package/dist/clients/attach/session/bindings.js +23 -8
  107. package/dist/clients/attach/session/connection.js +4 -5
  108. package/dist/clients/attach/session/context.d.ts +6 -4
  109. package/dist/clients/attach/session/frame.d.ts +34 -0
  110. package/dist/clients/attach/session/frame.js +176 -0
  111. package/dist/clients/attach/session/frames.d.ts +4 -1
  112. package/dist/clients/attach/session/frames.js +14 -1
  113. package/dist/clients/attach/session/identity.js +4 -3
  114. package/dist/clients/attach/session/input-wiring.d.ts +14 -4
  115. package/dist/clients/attach/session/input-wiring.js +15 -13
  116. package/dist/clients/attach/session/invariant.d.ts +9 -0
  117. package/dist/clients/attach/session/invariant.js +15 -0
  118. package/dist/clients/attach/session/keys.d.ts +10 -2
  119. package/dist/clients/attach/session/keys.js +13 -5
  120. package/dist/clients/attach/session/layout.d.ts +10 -8
  121. package/dist/clients/attach/session/layout.js +33 -34
  122. package/dist/clients/attach/session/mouse.d.ts +18 -0
  123. package/dist/clients/attach/session/mouse.js +64 -0
  124. package/dist/clients/attach/session/pane-tag.d.ts +3 -0
  125. package/dist/clients/attach/session/pane-tag.js +51 -8
  126. package/dist/clients/attach/session/reconnect.d.ts +3 -0
  127. package/dist/clients/attach/session/reconnect.js +42 -5
  128. package/dist/clients/attach/session/surface-frame.d.ts +20 -0
  129. package/dist/clients/attach/session/surface-frame.js +73 -0
  130. package/dist/clients/attach/session/surface-host.d.ts +64 -0
  131. package/dist/clients/attach/session/surface-host.js +255 -0
  132. package/dist/clients/attach/session/whip.d.ts +17 -0
  133. package/dist/clients/attach/session/whip.js +334 -0
  134. package/dist/clients/attach/slash/dispatch.d.ts +13 -1
  135. package/dist/clients/attach/slash/dispatch.js +51 -29
  136. package/dist/clients/attach/viewer.js +907 -819
  137. package/dist/clients/conversation/conversation.d.ts +65 -0
  138. package/dist/clients/conversation/conversation.js +318 -0
  139. package/dist/clients/conversation/frames.d.ts +30 -0
  140. package/dist/clients/conversation/frames.js +52 -0
  141. package/dist/clients/conversation/region.d.ts +51 -0
  142. package/dist/clients/conversation/region.js +265 -0
  143. package/dist/clients/conversation/submit.d.ts +38 -0
  144. package/dist/clients/conversation/submit.js +51 -0
  145. package/dist/clients/inbox/__tests__/inbox-controller.test.js +247 -0
  146. package/dist/clients/inbox/__tests__/mount-panel.test.js +776 -0
  147. package/dist/clients/inbox/controller.d.ts +79 -0
  148. package/dist/clients/inbox/controller.js +448 -0
  149. package/dist/clients/inbox/deck-adapter.d.ts +29 -0
  150. package/dist/clients/inbox/deck-adapter.js +62 -0
  151. package/dist/clients/inbox/layout.d.ts +8 -0
  152. package/dist/clients/inbox/layout.js +9 -0
  153. package/dist/clients/inbox/resolve.d.ts +10 -0
  154. package/dist/clients/inbox/resolve.js +34 -0
  155. package/dist/clients/inbox/review/__tests__/editor-roundtrip.test.js +29 -0
  156. package/dist/clients/inbox/review/__tests__/remap.test.js +196 -0
  157. package/dist/clients/inbox/review/__tests__/review-core.test.js +341 -0
  158. package/dist/clients/inbox/review/anchors.d.ts +41 -0
  159. package/dist/clients/inbox/review/anchors.js +89 -0
  160. package/dist/clients/inbox/review/columns.d.ts +22 -0
  161. package/dist/clients/inbox/review/columns.js +40 -0
  162. package/dist/clients/inbox/review/comments-client.d.ts +66 -0
  163. package/dist/clients/inbox/review/comments-client.js +98 -0
  164. package/dist/clients/inbox/review/composition.d.ts +60 -0
  165. package/dist/clients/inbox/review/composition.js +278 -0
  166. package/dist/clients/inbox/review/document-region.d.ts +120 -0
  167. package/dist/clients/inbox/review/document-region.js +902 -0
  168. package/dist/clients/inbox/review/frame.d.ts +45 -0
  169. package/dist/clients/inbox/review/frame.js +215 -0
  170. package/dist/clients/inbox/review/keys.d.ts +67 -0
  171. package/dist/clients/inbox/review/keys.js +130 -0
  172. package/dist/clients/inbox/review/launch.d.ts +10 -0
  173. package/dist/clients/inbox/review/launch.js +129 -0
  174. package/dist/clients/inbox/review/live-source.d.ts +24 -0
  175. package/dist/clients/inbox/review/live-source.js +160 -0
  176. package/dist/clients/inbox/review/nvim.d.ts +13 -0
  177. package/dist/clients/inbox/review/nvim.js +42 -0
  178. package/dist/clients/inbox/review/remap.d.ts +51 -0
  179. package/dist/clients/inbox/review/remap.js +157 -0
  180. package/dist/clients/inbox/review/review-client.d.ts +30 -0
  181. package/dist/clients/inbox/review/review-client.js +107 -0
  182. package/dist/clients/inbox/review/roundtrip.d.ts +5 -0
  183. package/dist/clients/inbox/review/roundtrip.js +36 -0
  184. package/dist/clients/inbox/review/state.d.ts +143 -0
  185. package/dist/clients/inbox/review/state.js +282 -0
  186. package/dist/clients/inbox/review-adapter.d.ts +29 -0
  187. package/dist/clients/inbox/review-adapter.js +92 -0
  188. package/dist/clients/inbox/review-visibility.d.ts +5 -0
  189. package/dist/clients/inbox/review-visibility.js +19 -0
  190. package/dist/clients/inbox/surface.d.ts +19 -0
  191. package/dist/clients/inbox/surface.js +128 -0
  192. package/dist/clients/inbox/tui/ansi.d.ts +66 -0
  193. package/dist/clients/inbox/tui/ansi.js +317 -0
  194. package/dist/clients/inbox/tui/clipboard.d.ts +2 -0
  195. package/dist/clients/inbox/tui/clipboard.js +26 -0
  196. package/dist/clients/inbox/tui/input.d.ts +7 -0
  197. package/dist/clients/inbox/tui/input.js +653 -0
  198. package/dist/clients/inbox/tui/keys.d.ts +28 -0
  199. package/dist/clients/inbox/tui/keys.js +111 -0
  200. package/dist/clients/inbox/tui/panel.d.ts +2 -0
  201. package/dist/clients/inbox/tui/panel.js +217 -0
  202. package/dist/clients/inbox/tui/render.d.ts +37 -0
  203. package/dist/clients/inbox/tui/render.js +476 -0
  204. package/dist/clients/inbox/tui/types.d.ts +57 -0
  205. package/dist/clients/inbox/tui/types.js +1 -0
  206. package/dist/clients/inbox/tui.d.ts +6 -0
  207. package/dist/clients/inbox/tui.js +74 -0
  208. package/dist/clients/surfaces/host.d.ts +66 -0
  209. package/dist/clients/surfaces/host.js +1 -0
  210. package/dist/clients/surfaces/region.d.ts +16 -0
  211. package/dist/clients/surfaces/region.js +1 -0
  212. package/dist/clients/web/__tests__/push-engine.test.js +14 -158
  213. package/dist/clients/web/dev-server.d.ts +3 -3
  214. package/dist/clients/web/dev-server.js +9 -23
  215. package/dist/clients/web/events.js +4 -6
  216. package/dist/clients/web/push-engine.d.ts +2 -66
  217. package/dist/clients/web/push-engine.js +30 -161
  218. package/dist/clients/web/push-registry.d.ts +0 -4
  219. package/dist/clients/web/push-registry.js +2 -7
  220. package/dist/clients/web/server.js +3 -35
  221. package/dist/clients/web/web-client/shared/protocol.d.ts +0 -108
  222. package/dist/clients/web/web-cmd.js +2 -2
  223. package/dist/commands/__tests__/human.test.js +27 -15
  224. package/dist/commands/api-client.js +3 -3
  225. package/dist/commands/canvas-browse.js +1 -1
  226. package/dist/commands/canvas-issue.js +1 -1
  227. package/dist/commands/canvas-use.js +1 -1
  228. package/dist/commands/human/doc.d.ts +2 -0
  229. package/dist/commands/human/doc.js +98 -0
  230. package/dist/commands/human/inbox.d.ts +2 -0
  231. package/dist/commands/human/inbox.js +101 -0
  232. package/dist/commands/human/prompts.d.ts +2 -3
  233. package/dist/commands/human/prompts.js +27 -180
  234. package/dist/commands/human/queue.d.ts +1 -5
  235. package/dist/commands/human/queue.js +54 -216
  236. package/dist/commands/human/review.d.ts +2 -0
  237. package/dist/commands/human/review.js +298 -0
  238. package/dist/commands/human/shared.d.ts +2 -69
  239. package/dist/commands/human/shared.js +1 -181
  240. package/dist/commands/human.js +15 -20
  241. package/dist/commands/memory/__tests__/lint.test.d.ts +1 -0
  242. package/dist/commands/memory/__tests__/lint.test.js +15 -0
  243. package/dist/commands/memory/delete.js +2 -2
  244. package/dist/commands/memory/lint.d.ts +1 -0
  245. package/dist/commands/memory/lint.js +21 -3
  246. package/dist/commands/memory/read.js +4 -4
  247. package/dist/commands/node.js +8 -7
  248. package/dist/commands/pkg/plugin-manage.js +143 -68
  249. package/dist/commands/surface-inspect.js +2 -2
  250. package/dist/commands/surface.js +6 -12
  251. package/dist/commands/sys/__tests__/setup-core.test.js +9 -5
  252. package/dist/commands/sys/__tests__/setup-front-door.test.js +7 -42
  253. package/dist/commands/sys/config.js +29 -3
  254. package/dist/commands/sys/feedback.js +1 -1
  255. package/dist/commands/sys/setup-core.d.ts +12 -11
  256. package/dist/commands/sys/setup-core.js +55 -46
  257. package/dist/commands/sys/setup-wizard.d.ts +4 -1
  258. package/dist/commands/sys/setup-wizard.js +50 -9
  259. package/dist/commands/sys/sync-deps.js +1 -1
  260. package/dist/commands/sys.js +4 -6
  261. package/dist/core/__tests__/broker-sdk-wiring.test.js +6 -1
  262. package/dist/core/__tests__/broker-snapshot-history.test.js +9 -1
  263. package/dist/core/__tests__/dead-node-policy-table.test.js +3 -4
  264. package/dist/core/__tests__/fixtures/fake-engine.d.ts +8 -5
  265. package/dist/core/__tests__/fixtures/fake-engine.js +28 -2
  266. package/dist/core/__tests__/full/broker-provider-retry.test.js +87 -2
  267. package/dist/core/__tests__/full/broker-whip-interrupt.test.d.ts +1 -0
  268. package/dist/core/__tests__/full/broker-whip-interrupt.test.js +39 -0
  269. package/dist/core/__tests__/full/detach-focus.test.js +1 -1
  270. package/dist/core/__tests__/human-deliver-e2e.test.js +64 -64
  271. package/dist/core/__tests__/human-deliver.test.js +71 -345
  272. package/dist/core/__tests__/inline-memory-refs.test.js +2 -12
  273. package/dist/core/__tests__/memory-resolver-precedence.test.js +12 -15
  274. package/dist/core/__tests__/migration.test.js +10 -0
  275. package/dist/core/__tests__/model-pin-durability.test.js +14 -0
  276. package/dist/core/__tests__/phase4-review-migration.test.d.ts +1 -0
  277. package/dist/core/__tests__/phase4-review-migration.test.js +100 -0
  278. package/dist/core/__tests__/phase4-review-store.test.d.ts +1 -0
  279. package/dist/core/__tests__/phase4-review-store.test.js +143 -0
  280. package/dist/core/__tests__/remote-canvas-target.test.js +2 -2
  281. package/dist/core/__tests__/revive.test.js +22 -53
  282. package/dist/core/__tests__/session-cycles.test.js +48 -18
  283. package/dist/core/__tests__/spawn-no-kickoff.test.js +8 -12
  284. package/dist/core/__tests__/stop-guard.test.js +16 -1
  285. package/dist/core/__tests__/tmux-surface.test.js +21 -25
  286. package/dist/core/asset-root.d.ts +7 -0
  287. package/dist/core/asset-root.js +18 -0
  288. package/dist/core/broker-client/client.d.ts +0 -7
  289. package/dist/core/broker-client/client.js +4 -10
  290. package/dist/core/broker-client/transport-relay.d.ts +3 -4
  291. package/dist/core/broker-client/transport-relay.js +3 -4
  292. package/dist/core/canvas/__tests__/attention.test.js +1 -1
  293. package/dist/core/canvas/__tests__/remote-canvas-source.test.js +1 -1
  294. package/dist/core/canvas/__tests__/remote-transport.test.d.ts +1 -0
  295. package/dist/core/{view/__tests__/transport-remote.test.js → canvas/__tests__/remote-transport.test.js} +2 -2
  296. package/dist/core/canvas/__tests__/render-remote.test.js +1 -1
  297. package/dist/core/canvas/attention.js +4 -4
  298. package/dist/core/canvas/canvas.d.ts +6 -11
  299. package/dist/core/canvas/canvas.js +11 -33
  300. package/dist/core/canvas/db.js +207 -38
  301. package/dist/core/canvas/extensions.d.ts +1 -1
  302. package/dist/core/canvas/extensions.js +8 -1
  303. package/dist/core/canvas/index.d.ts +0 -1
  304. package/dist/core/canvas/index.js +0 -1
  305. package/dist/core/canvas/nav-model.d.ts +1 -1
  306. package/dist/core/canvas/nav-model.js +1 -1
  307. package/dist/core/canvas/paths.d.ts +5 -0
  308. package/dist/core/canvas/paths.js +16 -0
  309. package/dist/core/canvas/remote-canvas-source.js +2 -2
  310. package/dist/core/canvas/remote-transport.d.ts +7 -0
  311. package/dist/core/{view/transport-remote.js → canvas/remote-transport.js} +3 -4
  312. package/dist/core/canvas/source.js +1 -1
  313. package/dist/core/canvas/status-glyph.js +4 -12
  314. package/dist/core/canvas/types.d.ts +10 -35
  315. package/dist/core/clipboard-text.d.ts +8 -0
  316. package/dist/core/clipboard-text.js +18 -0
  317. package/dist/core/command-manifests/registry.d.ts +1 -3
  318. package/dist/core/command-plugins/bundle.d.ts +29 -0
  319. package/dist/core/command-plugins/bundle.js +198 -0
  320. package/dist/core/command-plugins/discovery.d.ts +0 -8
  321. package/dist/core/command-plugins/discovery.js +2 -39
  322. package/dist/core/command-plugins/transport/http-fetch.d.ts +4 -30
  323. package/dist/core/command-plugins/transport/http-fetch.js +17 -95
  324. package/dist/core/command.d.ts +1 -13
  325. package/dist/core/command.js +1 -16
  326. package/dist/core/config.d.ts +4 -0
  327. package/dist/core/config.js +28 -3
  328. package/dist/core/document-lines.d.ts +4 -0
  329. package/dist/core/document-lines.js +6 -0
  330. package/dist/core/feed/feed.d.ts +2 -0
  331. package/dist/core/feed/feed.js +11 -7
  332. package/dist/core/human/__tests__/inbox-cancel-worker.d.ts +1 -0
  333. package/dist/core/human/__tests__/inbox-cancel-worker.js +7 -0
  334. package/dist/core/human/__tests__/inbox-claim-worker.d.ts +1 -0
  335. package/dist/core/human/__tests__/inbox-claim-worker.js +17 -0
  336. package/dist/core/human/__tests__/inbox-core.test.d.ts +1 -0
  337. package/dist/core/human/__tests__/inbox-core.test.js +144 -0
  338. package/dist/core/human/__tests__/inbox-stale-claim-worker.d.ts +1 -0
  339. package/dist/core/human/__tests__/inbox-stale-claim-worker.js +8 -0
  340. package/dist/core/human/__tests__/visible-paths.test.d.ts +1 -0
  341. package/dist/{clients/attach → core/human}/__tests__/visible-paths.test.js +9 -0
  342. package/dist/core/human/claim.d.ts +23 -0
  343. package/dist/core/human/claim.js +67 -0
  344. package/dist/core/human/convention.d.ts +30 -0
  345. package/dist/core/human/convention.js +202 -0
  346. package/dist/core/human/deck-factories.d.ts +8 -0
  347. package/dist/core/human/deck-factories.js +15 -0
  348. package/dist/core/human/deck-schema.d.ts +70 -0
  349. package/dist/core/human/deck-schema.js +92 -0
  350. package/dist/core/human/root.d.ts +7 -0
  351. package/dist/core/human/root.js +37 -0
  352. package/dist/core/human/scan.d.ts +3 -0
  353. package/dist/core/human/scan.js +76 -0
  354. package/dist/core/human/summary.d.ts +8 -0
  355. package/dist/core/human/summary.js +44 -0
  356. package/dist/core/human/tickets.d.ts +49 -0
  357. package/dist/core/human/tickets.js +190 -0
  358. package/dist/core/human/types.d.ts +136 -0
  359. package/dist/core/human/types.js +5 -0
  360. package/dist/{clients/attach → core/human}/visible-paths.d.ts +1 -1
  361. package/dist/{clients/attach → core/human}/visible-paths.js +3 -2
  362. package/dist/core/inspector/chrome.d.ts +6 -0
  363. package/dist/core/inspector/chrome.js +14 -0
  364. package/dist/core/inspector/contract.d.ts +105 -0
  365. package/dist/core/inspector/contract.js +1 -0
  366. package/dist/core/inspector/core.d.ts +4 -5
  367. package/dist/core/inspector/core.js +3 -5
  368. package/dist/core/inspector/host.d.ts +46 -0
  369. package/dist/core/{tui → inspector}/host.js +42 -208
  370. package/dist/core/inspector/text.d.ts +2 -2
  371. package/dist/core/inspector/transport.d.ts +6 -0
  372. package/dist/core/inspector/transport.js +36 -0
  373. package/dist/core/inspector/tui.d.ts +2 -2
  374. package/dist/core/inspector/tui.js +15 -15
  375. package/dist/core/keybindings/__tests__/inbox-affordance.test.js +11 -11
  376. package/dist/core/keybindings/__tests__/resolve.test.js +10 -19
  377. package/dist/core/keybindings/attach-control.d.ts +9 -3
  378. package/dist/core/keybindings/attach-control.js +3 -1
  379. package/dist/core/keybindings/catalog.d.ts +6 -5
  380. package/dist/core/keybindings/catalog.js +61 -133
  381. package/dist/core/keybindings/inbox.d.ts +5 -6
  382. package/dist/core/keybindings/inbox.js +9 -10
  383. package/dist/core/keybindings/index.d.ts +3 -3
  384. package/dist/core/keybindings/index.js +3 -3
  385. package/dist/core/keybindings/persistence.d.ts +5 -1
  386. package/dist/core/keybindings/persistence.js +24 -6
  387. package/dist/core/keybindings/resolve.d.ts +6 -0
  388. package/dist/core/keybindings/resolve.js +10 -3
  389. package/dist/core/memory/inline-ref-grammar.js +2 -3
  390. package/dist/core/memory-resolver.d.ts +27 -29
  391. package/dist/core/memory-resolver.js +45 -39
  392. package/dist/core/model-routes.d.ts +33 -0
  393. package/dist/core/model-routes.js +42 -3
  394. package/dist/core/preview-registry.js +17 -55
  395. package/dist/core/profiles/select.js +3 -3
  396. package/dist/core/{view/remote-canvas-target.d.ts → remote-canvas-target.d.ts} +2 -2
  397. package/dist/core/{view/remote-canvas-target.js → remote-canvas-target.js} +4 -4
  398. package/dist/core/review/__tests__/capture-origin.test.d.ts +1 -0
  399. package/dist/core/review/__tests__/capture-origin.test.js +139 -0
  400. package/dist/core/review/__tests__/comments.test.d.ts +1 -0
  401. package/dist/core/review/__tests__/comments.test.js +98 -0
  402. package/dist/core/review/__tests__/project.test.d.ts +1 -0
  403. package/dist/core/review/__tests__/project.test.js +71 -0
  404. package/dist/core/review/__tests__/remap.test.d.ts +1 -0
  405. package/dist/core/review/__tests__/remap.test.js +159 -0
  406. package/dist/core/review/__tests__/stage-identity.test.d.ts +1 -0
  407. package/dist/core/review/__tests__/stage-identity.test.js +140 -0
  408. package/dist/core/review/birth.d.ts +7 -0
  409. package/dist/core/review/birth.js +23 -0
  410. package/dist/core/review/comments.d.ts +69 -0
  411. package/dist/core/review/comments.js +295 -0
  412. package/dist/core/review/companion.d.ts +35 -0
  413. package/dist/core/review/companion.js +205 -0
  414. package/dist/core/review/document.d.ts +27 -0
  415. package/dist/core/review/document.js +138 -0
  416. package/dist/core/review/project.d.ts +13 -0
  417. package/dist/core/review/project.js +58 -0
  418. package/dist/core/review/realize.d.ts +19 -0
  419. package/dist/core/review/realize.js +217 -0
  420. package/dist/core/review/remap.d.ts +24 -0
  421. package/dist/core/review/remap.js +156 -0
  422. package/dist/core/review/signal.d.ts +5 -0
  423. package/dist/core/review/signal.js +31 -0
  424. package/dist/core/review/stage.d.ts +26 -0
  425. package/dist/core/review/stage.js +184 -0
  426. package/dist/core/review/store.d.ts +46 -0
  427. package/dist/core/review/store.js +163 -0
  428. package/dist/core/review/ticket-filter.d.ts +17 -0
  429. package/dist/core/review/ticket-filter.js +32 -0
  430. package/dist/core/review/types.d.ts +130 -0
  431. package/dist/core/review/types.js +23 -0
  432. package/dist/core/runtime/__tests__/session-visibility.test.d.ts +1 -0
  433. package/dist/core/runtime/__tests__/session-visibility.test.js +119 -0
  434. package/dist/core/runtime/bearings.d.ts +5 -17
  435. package/dist/core/runtime/bearings.js +88 -71
  436. package/dist/core/runtime/broker-protocol.d.ts +31 -8
  437. package/dist/core/runtime/broker.d.ts +15 -1
  438. package/dist/core/runtime/broker.js +573 -141
  439. package/dist/core/runtime/canvas-extensions.d.ts +4 -5
  440. package/dist/core/runtime/canvas-extensions.js +5 -5
  441. package/dist/core/runtime/front-door.js +4 -4
  442. package/dist/core/runtime/headless-pi.d.ts +24 -0
  443. package/dist/core/runtime/headless-pi.js +152 -0
  444. package/dist/core/runtime/kickoff.d.ts +1 -5
  445. package/dist/core/runtime/kickoff.js +1 -5
  446. package/dist/core/runtime/model-registry.d.ts +3 -0
  447. package/dist/core/runtime/model-registry.js +13 -0
  448. package/dist/core/runtime/naming-persist.d.ts +4 -0
  449. package/dist/core/runtime/naming-persist.js +27 -1
  450. package/dist/core/runtime/naming.d.ts +17 -12
  451. package/dist/core/runtime/naming.js +91 -140
  452. package/dist/core/runtime/node-read.js +19 -10
  453. package/dist/core/runtime/nodes.d.ts +9 -14
  454. package/dist/core/runtime/nodes.js +3 -53
  455. package/dist/core/runtime/package-health.d.ts +6 -21
  456. package/dist/core/runtime/package-health.js +12 -123
  457. package/dist/core/runtime/placement-tmux.d.ts +2 -1
  458. package/dist/core/runtime/placement-tmux.js +6 -4
  459. package/dist/core/runtime/placement.d.ts +1 -0
  460. package/dist/core/runtime/placement.js +4 -8
  461. package/dist/core/runtime/promote.js +3 -0
  462. package/dist/core/runtime/recap.d.ts +2 -7
  463. package/dist/core/runtime/recap.js +35 -69
  464. package/dist/core/runtime/revive.js +34 -77
  465. package/dist/core/runtime/session-cycles.d.ts +4 -0
  466. package/dist/core/runtime/session-cycles.js +14 -1
  467. package/dist/core/runtime/session-visibility.d.ts +37 -0
  468. package/dist/core/runtime/session-visibility.js +83 -0
  469. package/dist/core/runtime/spawn.js +10 -22
  470. package/dist/core/runtime/stop-guard.d.ts +1 -1
  471. package/dist/core/runtime/stop-guard.js +18 -13
  472. package/dist/core/runtime/surface-bg.js +1 -1
  473. package/dist/core/runtime/tmux-chrome.d.ts +1 -1
  474. package/dist/core/runtime/tmux-chrome.js +1 -1
  475. package/dist/core/runtime/tmux.d.ts +35 -7
  476. package/dist/core/runtime/tmux.js +439 -62
  477. package/dist/core/runtime/tool-group-summary.d.ts +19 -0
  478. package/dist/core/runtime/tool-group-summary.js +88 -0
  479. package/dist/core/scope.d.ts +2 -7
  480. package/dist/core/scope.js +9 -35
  481. package/dist/core/substrate/schema.d.ts +2 -2
  482. package/dist/core/termrender/code-doc.d.ts +12 -0
  483. package/dist/core/termrender/code-doc.js +92 -0
  484. package/dist/core/termrender/display.d.ts +12 -0
  485. package/dist/core/termrender/display.js +19 -0
  486. package/dist/core/termrender/termrender.d.ts +73 -0
  487. package/dist/core/termrender/termrender.js +795 -0
  488. package/dist/core/termrender/version.d.ts +1 -0
  489. package/dist/core/termrender/version.js +1 -0
  490. package/dist/core/tui/terminal.js +1 -2
  491. package/dist/core/user-settings.d.ts +71 -3
  492. package/dist/core/user-settings.js +83 -1
  493. package/dist/daemon/api/__tests__/inbox.test.js +44 -133
  494. package/dist/daemon/api/handlers/human.d.ts +0 -10
  495. package/dist/daemon/api/handlers/human.js +104 -702
  496. package/dist/daemon/api/handlers/inbox.js +113 -142
  497. package/dist/daemon/api/handlers/review-comments.d.ts +2 -0
  498. package/dist/daemon/api/handlers/review-comments.js +500 -0
  499. package/dist/daemon/api/handlers/reviews.d.ts +2 -0
  500. package/dist/daemon/api/handlers/reviews.js +287 -0
  501. package/dist/daemon/api/map.d.ts +22 -7
  502. package/dist/daemon/api/map.js +159 -11
  503. package/dist/daemon/api/server.js +4 -0
  504. package/dist/daemon/cron-run.js +6 -9
  505. package/dist/daemon/crtrd.js +17 -33
  506. package/dist/daemon/fleet.d.ts +1 -8
  507. package/dist/daemon/fleet.js +4 -30
  508. package/dist/daemon/human/finish.d.ts +14 -0
  509. package/dist/daemon/human/finish.js +115 -0
  510. package/dist/daemon/human/sweep.d.ts +6 -0
  511. package/dist/daemon/human/sweep.js +49 -0
  512. package/dist/daemon/messaging/node-message.d.ts +18 -0
  513. package/dist/daemon/messaging/node-message.js +70 -0
  514. package/dist/daemon/review/comment-notify.d.ts +26 -0
  515. package/dist/daemon/review/comment-notify.js +107 -0
  516. package/dist/daemon/review/deliver.d.ts +7 -0
  517. package/dist/daemon/review/deliver.js +56 -0
  518. package/dist/daemon/review/finish.d.ts +22 -0
  519. package/dist/daemon/review/finish.js +254 -0
  520. package/dist/daemon/review/sweep.d.ts +11 -0
  521. package/dist/daemon/review/sweep.js +120 -0
  522. package/dist/index.d.ts +2 -0
  523. package/dist/index.js +2 -2
  524. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +42 -64
  525. package/dist/pi-extensions/__tests__/canvas-recap.test.d.ts +1 -0
  526. package/dist/pi-extensions/__tests__/canvas-recap.test.js +159 -0
  527. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +16 -38
  528. package/dist/pi-extensions/__tests__/canvas-structured-output.test.d.ts +1 -0
  529. package/dist/pi-extensions/__tests__/canvas-structured-output.test.js +63 -0
  530. package/dist/pi-extensions/canvas-context-intro.d.ts +8 -11
  531. package/dist/pi-extensions/canvas-context-intro.js +50 -104
  532. package/dist/pi-extensions/canvas-recap.d.ts +15 -2
  533. package/dist/pi-extensions/canvas-recap.js +192 -69
  534. package/dist/pi-extensions/canvas-review-boundary.d.ts +59 -0
  535. package/dist/pi-extensions/canvas-review-boundary.js +81 -0
  536. package/dist/pi-extensions/canvas-stophook.d.ts +3 -3
  537. package/dist/pi-extensions/canvas-stophook.js +78 -128
  538. package/dist/pi-extensions/canvas-structured-output.js +52 -8
  539. package/dist/shared/generated-context.d.ts +29 -4
  540. package/dist/shared/generated-context.js +122 -7
  541. package/dist/shared/tool-groups.d.ts +23 -0
  542. package/dist/shared/tool-groups.js +60 -0
  543. package/dist/shared/working-activity.d.ts +8 -0
  544. package/dist/shared/working-activity.js +26 -0
  545. package/dist/types.d.ts +36 -2
  546. package/dist/types.js +51 -0
  547. package/dist/web-client/assets/index-CCPaLeW7.css +2 -0
  548. package/dist/web-client/assets/index-kyOWsnZK.js +86 -0
  549. package/dist/web-client/index.html +2 -2
  550. package/dist/web-client/sw.js +1 -1
  551. package/docs/compat/hearth-crtr-v4.md +2 -2
  552. package/docs/compat/hearth-crtr-v5.md +4 -2
  553. package/docs/public-api.md +3 -3
  554. package/package.json +21 -14
  555. package/runtime.lock.json +4661 -1453
  556. package/scripts/postinstall.mjs +15 -2
  557. package/dist/builtin-pi-packages/pi-mode-switch/README.md +0 -36
  558. package/dist/builtin-pi-packages/pi-mode-switch/bin/mode +0 -36
  559. package/dist/builtin-pi-packages/pi-mode-switch/extensions/index.ts +0 -449
  560. package/dist/builtin-pi-packages/pi-mode-switch/package.json +0 -14
  561. package/dist/builtin-pi-packages/pi-mode-switch/tsconfig.json +0 -9
  562. package/dist/builtin-views/_lib/states.mjs +0 -161
  563. package/dist/builtin-views/canvas/core.mjs +0 -657
  564. package/dist/builtin-views/canvas/text.mjs +0 -58
  565. package/dist/builtin-views/canvas/tui.mjs +0 -168
  566. package/dist/builtin-views/canvas/web.jsx +0 -121
  567. package/dist/builtin-views/chat/core.mjs +0 -684
  568. package/dist/builtin-views/chat/text.mjs +0 -101
  569. package/dist/builtin-views/chat/tui.mjs +0 -360
  570. package/dist/builtin-views/chat/web.jsx +0 -362
  571. package/dist/builtin-views/git-pr/core.mjs +0 -673
  572. package/dist/builtin-views/git-pr/text.mjs +0 -84
  573. package/dist/builtin-views/git-pr/tui.mjs +0 -301
  574. package/dist/builtin-views/git-pr/web.jsx +0 -216
  575. package/dist/builtin-views/inbox/_lib/render.mjs +0 -175
  576. package/dist/builtin-views/inbox/core.mjs +0 -1273
  577. package/dist/builtin-views/inbox/text.mjs +0 -73
  578. package/dist/builtin-views/inbox/tui.mjs +0 -314
  579. package/dist/builtin-views/inbox/web.jsx +0 -188
  580. package/dist/builtin-views/linkedin/core.mjs +0 -906
  581. package/dist/builtin-views/linkedin/text.mjs +0 -69
  582. package/dist/builtin-views/linkedin/tui.mjs +0 -413
  583. package/dist/builtin-views/linkedin/web.jsx +0 -206
  584. package/dist/builtin-views/prompt-review/core.mjs +0 -735
  585. package/dist/builtin-views/prompt-review/text.mjs +0 -15
  586. package/dist/builtin-views/prompt-review/tui.mjs +0 -196
  587. package/dist/builtin-views/prompt-review/web.jsx +0 -484
  588. package/dist/builtin-views/workspace-sidebar/__tests__/core.test.js +0 -50
  589. package/dist/builtin-views/workspace-sidebar/__tests__/core.test.ts +0 -53
  590. package/dist/builtin-views/workspace-sidebar/core.mjs +0 -670
  591. package/dist/builtin-views/workspace-sidebar/text.mjs +0 -53
  592. package/dist/builtin-views/workspace-sidebar/tui.mjs +0 -141
  593. package/dist/builtin-views/workspace-sidebar/web.jsx +0 -109
  594. package/dist/clients/attach/session/mode.d.ts +0 -25
  595. package/dist/clients/attach/session/mode.js +0 -97
  596. package/dist/commands/sys/promptstudio.d.ts +0 -2
  597. package/dist/commands/sys/promptstudio.js +0 -65
  598. package/dist/commands/view-cycle.d.ts +0 -2
  599. package/dist/commands/view-cycle.js +0 -130
  600. package/dist/commands/view-list.d.ts +0 -2
  601. package/dist/commands/view-list.js +0 -66
  602. package/dist/commands/view-new.d.ts +0 -2
  603. package/dist/commands/view-new.js +0 -74
  604. package/dist/commands/view-pick.d.ts +0 -6
  605. package/dist/commands/view-pick.js +0 -129
  606. package/dist/commands/view-run.d.ts +0 -2
  607. package/dist/commands/view-run.js +0 -214
  608. package/dist/commands/view.d.ts +0 -2
  609. package/dist/commands/view.js +0 -31
  610. package/dist/commands/workspace.d.ts +0 -2
  611. package/dist/commands/workspace.js +0 -165
  612. package/dist/core/__tests__/chat-view-reconnect.test.js +0 -105
  613. package/dist/core/__tests__/full/consult-startup-failure.test.js +0 -124
  614. package/dist/core/canvas/__tests__/human-work-outbox.test.js +0 -123
  615. package/dist/core/canvas/human-work-outbox.d.ts +0 -73
  616. package/dist/core/canvas/human-work-outbox.js +0 -261
  617. package/dist/core/command-plugins/store.d.ts +0 -16
  618. package/dist/core/command-plugins/store.js +0 -64
  619. package/dist/core/keybindings/__tests__/bespoke-consumers.test.js +0 -40
  620. package/dist/core/runtime/fault-recovery-nudge.d.ts +0 -3
  621. package/dist/core/runtime/fault-recovery-nudge.js +0 -3
  622. package/dist/core/tui/__tests__/host-keybindings.test.js +0 -113
  623. package/dist/core/tui/host.d.ts +0 -66
  624. package/dist/core/view/__tests__/transport-cache.test.js +0 -62
  625. package/dist/core/view/bridge.d.ts +0 -10
  626. package/dist/core/view/bridge.js +0 -31
  627. package/dist/core/view/chrome.d.ts +0 -9
  628. package/dist/core/view/chrome.js +0 -22
  629. package/dist/core/view/contract.d.ts +0 -205
  630. package/dist/core/view/contract.js +0 -23
  631. package/dist/core/view/loader.d.ts +0 -31
  632. package/dist/core/view/loader.js +0 -188
  633. package/dist/core/view/stream-local.d.ts +0 -3
  634. package/dist/core/view/stream-local.js +0 -231
  635. package/dist/core/view/transport-cache.d.ts +0 -8
  636. package/dist/core/view/transport-cache.js +0 -38
  637. package/dist/core/view/transport-local.d.ts +0 -7
  638. package/dist/core/view/transport-local.js +0 -83
  639. package/dist/core/view/transport-remote.d.ts +0 -2
  640. package/dist/core/view/transport.d.ts +0 -10
  641. package/dist/core/view/transport.js +0 -15
  642. package/dist/pi-extensions/naming-tool.d.ts +0 -24
  643. package/dist/pi-extensions/naming-tool.js +0 -67
  644. package/dist/prompts/view.d.ts +0 -7
  645. package/dist/prompts/view.js +0 -172
  646. package/dist/web/ViewChrome.d.ts +0 -7
  647. package/dist/web/ViewChrome.js +0 -28
  648. package/dist/web/ViewPane.d.ts +0 -39
  649. package/dist/web/ViewPane.js +0 -48
  650. package/dist/web/index.d.ts +0 -8
  651. package/dist/web/index.js +0 -22
  652. package/dist/web/runtime.d.ts +0 -39
  653. package/dist/web/runtime.js +0 -232
  654. package/dist/web/states.d.ts +0 -24
  655. package/dist/web/states.js +0 -24
  656. package/dist/web/transport-http.d.ts +0 -5
  657. package/dist/web/transport-http.js +0 -34
  658. package/dist/web/transport-stream.d.ts +0 -3
  659. package/dist/web/transport-stream.js +0 -204
  660. package/dist/web-client/assets/index-U_NZ66VE.js +0 -79
  661. package/dist/web-client/assets/index-aaeu4adv.css +0 -2
  662. /package/dist/{builtin-views/workspace-sidebar/__tests__/core.test.d.ts → clients/attach/__tests__/file-review-focus.test.d.ts} +0 -0
  663. /package/dist/clients/attach/__tests__/{visible-paths.test.d.ts → group-activity.test.d.ts} +0 -0
  664. /package/dist/{core/__tests__/chat-view-reconnect.test.d.ts → clients/attach/__tests__/input-controller-extension-command.test.d.ts} +0 -0
  665. /package/dist/{core/__tests__/full/consult-startup-failure.test.d.ts → clients/attach/__tests__/session-identity-refresh.test.d.ts} +0 -0
  666. /package/dist/{core/canvas/__tests__/human-work-outbox.test.d.ts → clients/inbox/__tests__/inbox-controller.test.d.ts} +0 -0
  667. /package/dist/{core/keybindings/__tests__/bespoke-consumers.test.d.ts → clients/inbox/__tests__/mount-panel.test.d.ts} +0 -0
  668. /package/dist/{core/tui/__tests__/host-keybindings.test.d.ts → clients/inbox/review/__tests__/editor-roundtrip.test.d.ts} +0 -0
  669. /package/dist/{core/view/__tests__/transport-cache.test.d.ts → clients/inbox/review/__tests__/remap.test.d.ts} +0 -0
  670. /package/dist/{core/view/__tests__/transport-remote.test.d.ts → clients/inbox/review/__tests__/review-core.test.d.ts} +0 -0
@@ -0,0 +1,59 @@
1
+ interface SessionEntryLike {
2
+ type: string;
3
+ customType?: string;
4
+ details?: {
5
+ reviewId?: string;
6
+ };
7
+ }
8
+ interface SessionStartCtxLike {
9
+ sessionManager: {
10
+ getEntries: () => SessionEntryLike[];
11
+ getBranch?: (fromId?: string) => SessionEntryLike[];
12
+ };
13
+ }
14
+ interface CustomMessageLike {
15
+ customType: string;
16
+ content: string;
17
+ display?: boolean;
18
+ details?: {
19
+ reviewId: string;
20
+ originNodeId: string;
21
+ targetFile: string;
22
+ };
23
+ }
24
+ interface RenderedMessageLike {
25
+ customType: string;
26
+ content: string | Array<{
27
+ type: string;
28
+ text?: string;
29
+ }>;
30
+ }
31
+ interface ComponentLike {
32
+ render: (width: number) => string[];
33
+ invalidate: () => void;
34
+ }
35
+ interface ThemeLike {
36
+ fg?: (color: string, text: string) => string;
37
+ }
38
+ interface PiLike {
39
+ on: (event: 'session_start', handler: (event: unknown, ctx: SessionStartCtxLike) => void | Promise<void>) => void;
40
+ sendMessage: (message: CustomMessageLike, options?: {
41
+ deliverAs?: string;
42
+ triggerTurn?: boolean;
43
+ }) => void;
44
+ registerMessageRenderer: (customType: string, renderer: (message: RenderedMessageLike, options: {
45
+ expanded?: boolean;
46
+ }, theme: ThemeLike) => ComponentLike | undefined) => void;
47
+ }
48
+ /** Render the marker as a single compact divider; its full content remains in
49
+ * the message list for the model and generated-context presenters. */
50
+ export declare function renderReviewBoundary(_message: RenderedMessageLike, _options: {
51
+ expanded?: boolean;
52
+ }, theme: ThemeLike): ComponentLike;
53
+ /**
54
+ * Register the review boundary marker. Companion nodes receive one boundary
55
+ * marker on session_start that separates inherited context from the visible
56
+ * transcript. Ordinary nodes get nothing.
57
+ */
58
+ export declare function registerCanvasReviewBoundary(pi: PiLike): void;
59
+ export default registerCanvasReviewBoundary;
@@ -0,0 +1,81 @@
1
+ // canvas-review-boundary.ts — durable visible-transcript boundary for review companions.
2
+ //
3
+ // On session_start, a review companion appends one custom_message after its
4
+ // inherited fork context and before canvas-context-intro appends fork bearings.
5
+ // The display projection starts at this marker while the model keeps the full
6
+ // inherited context.
7
+ import { getNode } from '../core/canvas/index.js';
8
+ import { isReviewBoundary, REVIEW_BOUNDARY_CUSTOM_TYPE } from '../core/runtime/session-visibility.js';
9
+ // ---------------------------------------------------------------------------
10
+ // Collapsed-by-default rendering
11
+ // ---------------------------------------------------------------------------
12
+ /** Truncate plain text to at most `width` columns, appending an ellipsis when it
13
+ * would overflow. Content here is ANSI-free plain text, so code-point count
14
+ * stands in for visible width. The renderer MUST keep every emitted line within
15
+ * the terminal width or pi's TUI aborts the whole render. */
16
+ function truncateToWidth(text, width) {
17
+ if (width <= 0)
18
+ return '';
19
+ const chars = Array.from(text);
20
+ if (chars.length <= width)
21
+ return text;
22
+ if (width === 1)
23
+ return '…';
24
+ return chars.slice(0, width - 1).join('') + '…';
25
+ }
26
+ /** Render the marker as a single compact divider; its full content remains in
27
+ * the message list for the model and generated-context presenters. */
28
+ export function renderReviewBoundary(_message, _options, theme) {
29
+ const paint = (color, text) => typeof theme?.fg === 'function' ? theme.fg(color, text) : text;
30
+ return {
31
+ render(width) {
32
+ const w = typeof width === 'number' && width > 0 ? width : 80;
33
+ return [paint('dim', truncateToWidth('[review boundary] earlier conversation is not shown', w))];
34
+ },
35
+ invalidate() {
36
+ /* stateless — nothing to clear */
37
+ },
38
+ };
39
+ }
40
+ // ---------------------------------------------------------------------------
41
+ // Extension
42
+ // ---------------------------------------------------------------------------
43
+ /**
44
+ * Register the review boundary marker. Companion nodes receive one boundary
45
+ * marker on session_start that separates inherited context from the visible
46
+ * transcript. Ordinary nodes get nothing.
47
+ */
48
+ export function registerCanvasReviewBoundary(pi) {
49
+ pi.registerMessageRenderer(REVIEW_BOUNDARY_CUSTOM_TYPE, renderReviewBoundary);
50
+ pi.on('session_start', (_event, ctx) => {
51
+ const nodeId = process.env['CRTR_NODE_ID'];
52
+ if (!nodeId || nodeId.trim() === '')
53
+ return;
54
+ const node = getNode(nodeId);
55
+ if (node?.review_binding == null)
56
+ return;
57
+ // The active branch, not the whole session file, is the context the next
58
+ // turn sees. Check for an existing boundary marker on this branch.
59
+ const scan = typeof ctx.sessionManager.getBranch === 'function'
60
+ ? ctx.sessionManager.getBranch()
61
+ : ctx.sessionManager.getEntries();
62
+ const alreadyMarked = scan.some((entry) => isReviewBoundary(entry, node.review_binding?.review_id));
63
+ if (alreadyMarked)
64
+ return;
65
+ const { review_id: reviewId, origin_node_id: originNodeId, target_file: targetFile, } = node.review_binding;
66
+ const content = [
67
+ `Reviewed file: ${targetFile}`,
68
+ `Review ID: ${reviewId}`,
69
+ `Origin node: ${originNodeId}`,
70
+ '',
71
+ "The person's visible transcript starts here. Everything above this marker is inherited context they have not seen.",
72
+ ].join('\n');
73
+ pi.sendMessage({
74
+ customType: REVIEW_BOUNDARY_CUSTOM_TYPE,
75
+ content,
76
+ display: true,
77
+ details: { reviewId, originNodeId, targetFile },
78
+ });
79
+ });
80
+ }
81
+ export default registerCanvasReviewBoundary;
@@ -26,9 +26,9 @@ interface PiLike {
26
26
  * the single "keep going past this window" verb for every persona: it refreshes
27
27
  * the node into a clean window, MODE-PRESERVING — a base node stays base,
28
28
  * continuing fresh against its goal and its note. `--promote` is a separate,
29
- * explicit opt-in (never steered here as auto-behavior) for when what remains
30
- * has genuinely grown into phases to delegate across children — so no persona
31
- * is ever steered at a bare `node promote` (which framed promotion as a heavy
29
+ * explicit opt-in (never steered here as auto-behavior) for when worthwhile
30
+ * independent work can run in parallel and coordination should become the
31
+ * node's primary job — so no persona is ever steered at a bare `node promote` (which framed promotion as a heavy
32
32
  * "become an orchestrator" step and bred yield-avoidance).
33
33
  *
34
34
  * - orchestrator (terminal OR resident): checkpoint context/roadmap.md, then
@@ -21,17 +21,16 @@
21
21
  // (c) Natural stop ('stop' | 'length') — run the stop-guard (the node is
22
22
  // NEVER auto-pushed; it reports only via its own explicit `crtr push`):
23
23
  // • 'reprompt' → pi.sendUserMessage so the node finishes or escalates.
24
- // • 'allow' (awaiting) → idle-release: free the tmux window and shut
25
- // down; the daemon watches the inbox and revives it
26
- // (resume) when a subscribed worker delivers.
24
+ // • 'allow' (awaiting) → stay dormant when focused; otherwise release
25
+ // and shut down. A subscribed node, controller, or
26
+ // background bash job delivers the inbox wake.
27
27
  // • 'allow' (attended root) → stay alive, dormant; the human wakes it.
28
28
  //
29
29
  // Plain TS-with-types — no imports from @earendil-works/* so this compiles inside
30
30
  // crouter's own tsc build without a dep on the pi packages.
31
31
  import { writeFileSync, mkdirSync, existsSync, readFileSync } from 'node:fs';
32
32
  import { join } from 'node:path';
33
- import { publishFollowUpProgress } from '@crouton-kit/humanloop';
34
- import { getNode, jobDir, updateNode, recordPid, setPresence, dispatchFollowUpWork, dispatchVisualWork, getFollowUpWorkRow, getHumanWorkRow, reconcileFollowUpWork, reconcileVisualWork } from '../core/canvas/index.js';
33
+ import { getNode, jobDir, updateNode, recordPid, setPresence } from '../core/canvas/index.js';
35
34
  import { transition } from '../core/runtime/lifecycle.js';
36
35
  import { markBusy, clearBusy, touchBusy, isBusy } from '../core/runtime/busy.js';
37
36
  import { clearFault, readFault } from '../core/runtime/fault.js';
@@ -44,7 +43,8 @@ import { clearStopSignals, consumeStopSignals } from '../core/runtime/stop-signa
44
43
  import { cliClient } from '../commands/api-client.js';
45
44
  import { focusOf, tearDownNode } from '../core/runtime/placement.js';
46
45
  import { readCursor, readInboxSince } from '../core/feed/inbox.js';
47
- import { CONTEXT_NUDGE_CUSTOM_TYPE, formatContextNudge } from '../shared/generated-context.js';
46
+ import { CONTEXT_NUDGE_CUSTOM_TYPE, formatContextNudge, formatPersonaTransition } from '../shared/generated-context.js';
47
+ import { isReviewBoundary } from '../core/runtime/session-visibility.js';
48
48
  /** Universal upper bound for an unfocused broker parked without runnable work. */
49
49
  export const UNATTENDED_PARK_MS = (() => {
50
50
  const testOverride = process.env['CRTR_TEST_UNATTENDED_PARK_MS'];
@@ -134,8 +134,8 @@ function lastAssistantMessage(messages) {
134
134
  // told to checkpoint one. `crtr node yield` is still its continue
135
135
  // verb — mode-preserving, continuing fresh against its goal and its
136
136
  // note — offered against wrap-up, since a root chat can simply end.
137
- // `--promote` is mentioned only once the chat has genuinely grown
138
- // into phases to delegate. Gentle → firm → pushy.
137
+ // `--promote` is mentioned only when worthwhile independent work
138
+ // can run in parallel and coordination should become primary. Gentle → firm → pushy.
139
139
  // terminal/base (a worker): steered to `crtr node yield` to continue in a
140
140
  // fresh window, mode-preserving, when work remains, or `push final`
141
141
  // when close. Gentle → firm → pushy.
@@ -145,7 +145,7 @@ function lastAssistantMessage(messages) {
145
145
  // bred yield-avoidance. A plain yield is always mode-preserving — a base node's
146
146
  // yield never auto-promotes, so the agent is never steered to decide about
147
147
  // promotion at all; `--promote` is a separate opt-in mentioned only for
148
- // became-multi-phase work. Only a terminal node is ever told `push final` (a
148
+ // worthwhile parallel work. Only a terminal node is ever told `push final` (a
149
149
  // resident finishes by yielding or being closed); only an orchestrator already
150
150
  // HAS a roadmap to checkpoint before it yields.
151
151
  // ---------------------------------------------------------------------------
@@ -174,9 +174,9 @@ function steerBand(tokens) {
174
174
  * the single "keep going past this window" verb for every persona: it refreshes
175
175
  * the node into a clean window, MODE-PRESERVING — a base node stays base,
176
176
  * continuing fresh against its goal and its note. `--promote` is a separate,
177
- * explicit opt-in (never steered here as auto-behavior) for when what remains
178
- * has genuinely grown into phases to delegate across children — so no persona
179
- * is ever steered at a bare `node promote` (which framed promotion as a heavy
177
+ * explicit opt-in (never steered here as auto-behavior) for when worthwhile
178
+ * independent work can run in parallel and coordination should become the
179
+ * node's primary job — so no persona is ever steered at a bare `node promote` (which framed promotion as a heavy
180
180
  * "become an orchestrator" step and bred yield-avoidance).
181
181
  *
182
182
  * - orchestrator (terminal OR resident): checkpoint context/roadmap.md, then
@@ -206,10 +206,10 @@ export function steerNote(at, lifecycle, mode) {
206
206
  // resident/base — a root conversation, mode-preserving `crtr node yield` is
207
207
  // the natural "carry this forward" verb: it refreshes into a clean window
208
208
  // and continues fresh against your goal and your note — no "become
209
- // something" decision. Only mention --promote once the chat has genuinely
210
- // grown into phases to delegate. Offer wrap-up as the alternative — a root
211
- // chat can simply end.
212
- const grow = `If this is turning into a multi-phase job, \`crtr node yield\` to continue fresh against your goal and your note — add --promote only once it has genuinely grown into phases you need to delegate across children.`;
209
+ // something" decision. Mention --promote only when worthwhile independent
210
+ // work can run in parallel and coordination should become primary. Offer
211
+ // wrap-up as the alternative — a root chat can simply end.
212
+ const grow = `If substantial work remains, \`crtr node yield\` to continue fresh against your goal and your note. Add --promote only when worthwhile independent work can run in parallel and coordinating it should become your primary job; \`crtr node yield -h\` has the boundary.`;
213
213
  if (at < 150_000) {
214
214
  return `Context ~${k}k and growing. ${grow} Otherwise no rush — wrap up when you reach a good stopping point.`;
215
215
  }
@@ -221,8 +221,7 @@ export function steerNote(at, lifecycle, mode) {
221
221
  // terminal/base — a worker. The natural "keep going past this window" verb is
222
222
  // `crtr node yield`: it refreshes into a clean window, mode-preserving, and
223
223
  // continues fresh against your goal and your note. --promote is a separate
224
- // opt-in for when what remains needs delegating across children — mentioned
225
- // only for became-multi-phase work, never steered as automatic. Steer it to
224
+ // opt-in for worthwhile parallel work, never steered as automatic. Steer it to
226
225
  // yield-or-finish, never a bare promote.
227
226
  if (at < 150_000) {
228
227
  return `Context ~${k}k and growing. If you're near done, finish with \`crtr push final\`. If real work remains, \`crtr node yield\` to continue in a fresh window against your goal and your note — no rush yet.`;
@@ -260,30 +259,13 @@ export function registerCanvasStophook(pi) {
260
259
  // a tool_execution_start flush (activity-only) preserves the latest token figure.
261
260
  let lastContext = null;
262
261
  let lastActivity = null;
263
- // If this node IS a follow-up consult fork, its ticket binding never changes,
264
- // so resolve it once and reuse it to narrate live activity back into the
265
- // waiting ticket. `undefined` = not yet looked up, `null` = not a consult.
266
- let consultTicket;
267
- function narrateToTicket(line) {
268
- if (line === null || line === '')
269
- return;
270
- if (consultTicket === undefined) {
271
- const row = getFollowUpWorkRow(String(nodeId));
272
- consultTicket = row === null ? null : { root: row.root, dir: row.dir, requestId: row.request_id };
273
- }
274
- if (consultTicket === null)
275
- return;
276
- // humanloop itself gates on the request still being the running one, so a
277
- // superseded or already-answered ticket silently ignores this.
278
- publishFollowUpProgress(consultTicket.root, consultTicket.dir, { requestId: consultTicket.requestId, line });
279
- }
280
262
  // Context-size steering. As input context grows we nudge the node once per
281
263
  // band on an escalating, persona-specific schedule (see steerBand/steerNote).
282
264
  // The node's (lifecycle, mode) persona is read at fire time, since a terminal
283
265
  // worker can promote mid-session: an orchestrator is steered to checkpoint
284
266
  // its roadmap + yield; a resident base (root chat) to yield-or-wrap-up (or
285
- // yield --promote only once it has grown into phases to delegate); a terminal
286
- // worker to yield-or-push-final.
267
+ // yield --promote only when worthwhile independent work can run in parallel);
268
+ // a terminal worker to yield-or-push-final.
287
269
  const firedBands = new Set();
288
270
  // Every broker enters this bounded-release path at session_start, including a
289
271
  // boot-revived settled node that never produces another agent_settled event.
@@ -409,6 +391,30 @@ export function registerCanvasStophook(pi) {
409
391
  // whereas a bare id is resolved cwd-relative and forks across projects.
410
392
  const filed = ctx?.sessionManager?.getSessionFile?.();
411
393
  const sessionFile = typeof filed === 'string' && filed !== '' ? filed : null;
394
+ const existing = getNode(nodeId);
395
+ const reviewId = existing?.review_binding?.review_id;
396
+ if (reviewId !== undefined) {
397
+ let hasBoundary = false;
398
+ try {
399
+ const manager = ctx?.sessionManager;
400
+ const entries = typeof manager?.getBranch === 'function'
401
+ ? manager.getBranch()
402
+ : typeof manager?.getEntries === 'function'
403
+ ? manager.getEntries()
404
+ : [];
405
+ hasBoundary = entries.some((entry) => isReviewBoundary(entry, reviewId));
406
+ }
407
+ catch {
408
+ hasBoundary = false;
409
+ }
410
+ if (!hasBoundary) {
411
+ try {
412
+ ctx?.shutdown?.();
413
+ }
414
+ catch { /* best-effort */ }
415
+ return;
416
+ }
417
+ }
412
418
  // `/new` — a brand-new conversation in the same process. The broker already
413
419
  // drove the engine-side new_session (the viewer's /new → broker
414
420
  // new_session frame); the runtime side then splits on root-ness: a ROOT
@@ -417,13 +423,12 @@ export function registerCanvasStophook(pi) {
417
423
  // its session id on the SAME node.
418
424
  if (event?.reason === 'new') {
419
425
  try {
420
- const m = getNode(nodeId);
421
426
  // A root relaunch LAUNCHES a broker, and launches are daemon-owned
422
427
  // (fleet-bound) — so the broker never runs relaunchRoot in-process.
423
428
  // It asks crtrd via POST /v1/nodes/:id/relaunch-root instead; the
424
429
  // rejection is swallowed here (the enclosing sync catch can't catch
425
430
  // an async one) to keep `/new` best-effort.
426
- if (m?.parent == null)
431
+ if (existing?.parent == null)
427
432
  void cliClient().relaunchRoot(nodeId).catch(() => { });
428
433
  else
429
434
  handleNewSession(nodeId, id, sessionFile);
@@ -446,36 +451,27 @@ export function registerCanvasStophook(pi) {
446
451
  // proof for reviveNode's cycling-attempt marker and the one-shot yield
447
452
  // note — both remain pending through any pre-session_start failure and are
448
453
  // safe to clear on any confirmed boot (cycling, resuming, or fresh).
449
- const existing = getNode(nodeId);
450
- // A pending private fork is not bound until Pi exposes BOTH the fresh child
451
- // id and its writable session file. Persist those identities and the phase
452
- // flip in one meta write: recovery sees either fork_pending with no child,
453
- // or session_started with the complete child coordinate, never a mixed
454
- // state that could fork provenance twice.
455
- if (existing?.private_fork_phase === 'fork_pending' && sessionFile === null) {
454
+ // An ordinary fork is not bound until Pi exposes BOTH the fresh child id
455
+ // and its writable session file. Recovery sees either an unbound fork or
456
+ // complete child coordinates, never a mixed state that could fork
457
+ // provenance twice.
458
+ if (existing?.fork_from != null && existing?.pi_session_id == null && sessionFile === null) {
456
459
  try {
457
460
  ctx?.shutdown?.();
458
461
  }
459
462
  catch { /* best-effort */ }
460
463
  return;
461
464
  }
462
- // Identity (session id/file/phase) → meta; runtime (pid, intent) → atomic
463
- // row setters. Any confirmed boot owns the one-shot yield note, if any;
465
+ // Identity (session id/file) → meta; runtime (pid, intent) → atomic row
466
+ // setters. Any confirmed boot owns the one-shot yield note, if any;
464
467
  // clear it once here so a pre-session_start retry preserves it, but a
465
468
  // successful revival can still only consume it once.
466
469
  clearYieldMessage(nodeId);
467
- updateNode(nodeId, existing?.private_fork_phase === 'fork_pending'
468
- ? {
469
- pi_session_id: id,
470
- pi_session_file: sessionFile,
471
- private_fork_phase: 'session_started',
472
- cycle_pending: false,
473
- }
474
- : {
475
- pi_session_id: id,
476
- pi_session_file: sessionFile,
477
- cycle_pending: false,
478
- });
470
+ updateNode(nodeId, {
471
+ pi_session_id: id,
472
+ pi_session_file: sessionFile,
473
+ cycle_pending: false,
474
+ });
479
475
  recordPid(nodeId, process.pid);
480
476
  if (existing?.intent === 'refresh')
481
477
  transition(nodeId, 'revive');
@@ -525,7 +521,6 @@ export function registerCanvasStophook(pi) {
525
521
  try {
526
522
  lastActivity = summarizeActivity(String(event?.toolName ?? ''), event?.args);
527
523
  flushTelemetry(jobDirPath, totalIn, totalOut, model, lastContext, lastActivity);
528
- narrateToTicket(lastActivity); // a consult fork streams its activity to the waiting ticket
529
524
  touchBusy(nodeId); // wedge heartbeat: a fresh tool starting is a sign of life
530
525
  clearFault(nodeId, { link: 'daemon→node' }); // a tool actually starting clears any prior wedge notice
531
526
  }
@@ -720,7 +715,7 @@ export function registerCanvasStophook(pi) {
720
715
  try {
721
716
  const drift = personaDrift(nodeId);
722
717
  if (drift !== null) {
723
- pi.sendUserMessage(drift.guidance, { deliverAs: 'steer' });
718
+ pi.sendUserMessage(formatPersonaTransition(drift.guidance), { deliverAs: 'steer' });
724
719
  commitPersonaAck(nodeId, drift.to);
725
720
  }
726
721
  }
@@ -764,59 +759,19 @@ export function registerCanvasStophook(pi) {
764
759
  const stopReason = last?.stopReason ?? '';
765
760
  // Interrupted or errored runs stay alive for re-steering. The broker
766
761
  // publishes any settled provider fault from its subscriber event stream.
767
- //
768
- // EXCEPT a follow-up consultation fork (design-followup-consult-v2.md
769
- // §B.2/§B.4; integrated-review Major-2): it is born `parent:null` with
770
- // no subscriber and nothing left to re-steer it — there is no human or
771
- // sibling that will ever send it another message. An exact-model turn
772
- // failure (the broker's `modelExact` fail-closed gates deliberately
773
- // refuse to substitute a different model/provider, so the turn just
774
- // errors) would otherwise leave it parked here forever: `armed`/`pending`
775
- // in the outbox with no future event guaranteed to reach it (the daemon
776
- // only reconciles at its own startup, and `_consult`/`_deliver` only
777
- // fire on a LATER human action on this SAME ticket). Identify it by the
778
- // presence of its own outbox row (the delivery record) and settle it
779
- // right here instead: crash the
780
- // node (frees it from the daemon's supervised LIVE set) and reconcile
781
- // its outbox immediately — `reconcileFollowUpWork`'s armed+dead branch
782
- // turns this into the ticket's `error` result, event-driven, no polling.
783
762
  if (stopReason !== 'stop' && stopReason !== 'length') {
784
- let isConsultFork = false;
785
- let isVisualFork = false;
786
- try {
787
- const work = getHumanWorkRow(nodeId);
788
- isConsultFork = work?.work_kind === 'follow_up';
789
- isVisualFork = work?.work_kind === 'visual';
790
- }
791
- catch {
792
- /* best-effort read — treat as ordinary work on storage failure */
793
- }
794
- if (isConsultFork || isVisualFork) {
795
- // Minor-6 (integrated review): shutdown must fire even when
796
- // transition/reconcile throws — sharing one try with the shutdown
797
- // call let a reconciliation exception skip it entirely, stranding
798
- // an already-crashed consult broker (settlement then waits on
799
- // NOTHING, since this fork has no subscriber to ever retry it).
800
- // `finally` guarantees the shutdown regardless of the outcome
801
- // above; the outbox row itself is unaffected either way —
802
- // `reconcileFollowUpWork` is retried at the next
803
- // daemon-crash/startup/_consult/_deliver touchpoint.
763
+ // A refresh-yield aborts its OWN turn (the tool_execution_end handler
764
+ // above calls ctx.abort() the instant `crtr node yield` returns), so a
765
+ // non-'stop' stopReason here is the deliberate refresh, never a failed
766
+ // run. Shut down and let the daemon relaunch the node fresh against
767
+ // its roadmap; classifying it below would crash the node instead and
768
+ // the daemon's exit policy would then forget an already-dead row,
769
+ // stranding the yield.
770
+ if (getNode(nodeId)?.intent === 'refresh') {
804
771
  try {
805
- const cur = getNode(nodeId);
806
- if (cur !== null && (cur.status === 'active' || cur.status === 'idle'))
807
- transition(nodeId, 'crash');
808
- reconcileFollowUpWork();
809
- reconcileVisualWork();
810
- }
811
- catch {
812
- /* best-effort — reconcileFollowUpWork is retried at the next daemon-crash/startup/_consult/_deliver touchpoint */
813
- }
814
- finally {
815
- try {
816
- ctx?.shutdown?.();
817
- }
818
- catch { /* ignore */ }
772
+ ctx?.shutdown?.();
819
773
  }
774
+ catch { /* ignore */ }
820
775
  }
821
776
  return;
822
777
  }
@@ -847,17 +802,6 @@ export function registerCanvasStophook(pi) {
847
802
  setPresence(nodeId, { pane: null, tmux_session: null, window: null });
848
803
  }
849
804
  catch { /* best-effort */ }
850
- // Consult-outbox dispatch (design-followup-consult-v2.md §B.4): if this
851
- // node is a follow-up consultation fork, its outbox row was promoted
852
- // armed→pending inside the SAME transaction that just committed this
853
- // final (feed.ts commitCanonicalFinal). Deliver it now, in-process, on
854
- // this fork's own settlement — the happy-path dispatch, event-driven,
855
- // no polling. A no-op for every non-consult node (no outbox row).
856
- try {
857
- dispatchFollowUpWork(nodeId);
858
- dispatchVisualWork(nodeId);
859
- }
860
- catch { /* best-effort — durable reconcilers retry */ }
861
805
  }
862
806
  finally {
863
807
  try {
@@ -935,6 +879,11 @@ export function registerCanvasStophook(pi) {
935
879
  }
936
880
  catch { /* best-effort */ }
937
881
  if (decision.reason === 'finished') {
882
+ // A canonical final can race the in-process watcher just like an
883
+ // awaiting stop: keep the broker alive until any non-deferred entry
884
+ // beyond the durable cursor has been delivered and committed.
885
+ if (readInboxSince(nodeId, readCursor(nodeId)).some((entry) => entry.tier !== 'deferred'))
886
+ return;
938
887
  try {
939
888
  ctx?.shutdown?.();
940
889
  }
@@ -942,11 +891,12 @@ export function registerCanvasStophook(pi) {
942
891
  return;
943
892
  }
944
893
  //
945
- // Idle-release: a node awaiting its workers (reason 'awaiting') is holding
946
- // a tmux window for nothing. Free it — mark it idle-released and shut pi
947
- // down; the daemon watches its inbox and revives it (resume) the moment a
948
- // subscribed worker delivers. An 'attended' root never releases: the human
949
- // is its wake source, so we keep its window live and dormant.
894
+ // Idle-release: an unfocused node awaiting a subscribed node, controller,
895
+ // or background bash job (reason 'awaiting') is holding a live broker for
896
+ // nothing. Mark it idle-released and shut pi down; the daemon watches its
897
+ // inbox and revives it (resume) when the awaited delivery arrives. A
898
+ // resident node never releases: the human is its wake source, so we keep
899
+ // its broker live and dormant.
950
900
  if (decision.reason === 'awaiting' || decision.reason === 'scheduled') {
951
901
  // AWAITING ≠ done (no manager-takeover). What happens next splits on
952
902
  // whether the user is WATCHING this node:
@@ -27,6 +27,50 @@ function retireTool(pi) {
27
27
  /* best-effort; the execute handler is inert when no schema file exists */
28
28
  }
29
29
  }
30
+ function strictToolSchema(schema) {
31
+ const transform = (value) => {
32
+ if (Array.isArray(value))
33
+ return value.map(transform);
34
+ if (value === null || typeof value !== 'object')
35
+ return value;
36
+ const source = value;
37
+ const transformed = {};
38
+ for (const [key, child] of Object.entries(source)) {
39
+ if (key === 'properties' && child !== null && typeof child === 'object' && !Array.isArray(child)) {
40
+ transformed[key] = Object.fromEntries(Object.entries(child).map(([name, property]) => [name, transform(property)]));
41
+ }
42
+ else {
43
+ transformed[key] = transform(child);
44
+ }
45
+ }
46
+ const properties = transformed['properties'];
47
+ if (properties === null || typeof properties !== 'object' || Array.isArray(properties))
48
+ return transformed;
49
+ const required = new Set(Array.isArray(source['required']) ? source['required'].filter((name) => typeof name === 'string') : []);
50
+ transformed['properties'] = Object.fromEntries(Object.entries(properties).map(([name, property]) => [
51
+ name,
52
+ required.has(name) ? property : { anyOf: [property, { type: 'null' }] },
53
+ ]));
54
+ transformed['required'] = Object.keys(properties);
55
+ return transformed;
56
+ };
57
+ return transform(schema);
58
+ }
59
+ function omitStrictNulls(value, schema) {
60
+ if (value === null || typeof value !== 'object' || Array.isArray(value) || schema === null || typeof schema !== 'object' || Array.isArray(schema))
61
+ return value;
62
+ const source = schema;
63
+ const properties = source['properties'];
64
+ if (properties === null || typeof properties !== 'object' || Array.isArray(properties))
65
+ return value;
66
+ const requiredNames = source['required'];
67
+ const required = new Set(Array.isArray(requiredNames) ? requiredNames.filter((name) => typeof name === 'string') : []);
68
+ return Object.fromEntries(Object.entries(value).flatMap(([name, child]) => {
69
+ if (child === null && !required.has(name) && Object.hasOwn(properties, name))
70
+ return [];
71
+ return [[name, omitStrictNulls(child, properties[name])]];
72
+ }));
73
+ }
30
74
  function toolDescription(request) {
31
75
  if (request.mode === 'terminal') {
32
76
  return 'Submit your final structured result. Calling this ends your run: the result is recorded and a final report is pushed automatically — do NOT call `crtr push final` yourself.';
@@ -66,11 +110,10 @@ export function registerCanvasStructuredOutput(pi) {
66
110
  'Use submit to answer the pending one-off structured-output request before stopping or going dormant.',
67
111
  'After one-off submit succeeds, continue with any remaining work normally.',
68
112
  ],
69
- parameters: request.schema,
70
- // pi 0.82 can ask the provider to constrain sampling to the tool's JSON schema.
71
- // `prefer` degrades silently on a model without strict tool support (`require`
72
- // would fail the whole request); crouter's server-side validation and stop-guard
73
- // stay authoritative either way — this only makes a malformed submission rarer.
113
+ // OpenAI strict tools require every property to be required. Optional fields
114
+ // become nullable in the provider-only schema and null is removed before the
115
+ // original result is persisted.
116
+ parameters: strictToolSchema(request.schema),
74
117
  constrainedSampling: { type: 'json_schema', strict: 'prefer' },
75
118
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
76
119
  const current = readOutputRequest(nodeId);
@@ -88,8 +131,9 @@ export function registerCanvasStructuredOutput(pi) {
88
131
  details: { submitted: false, reason: 'schema_replaced' },
89
132
  };
90
133
  }
134
+ const result = omitStrictNulls(params, current.schema);
91
135
  const resultPath = outputResultPath(nodeId);
92
- const json = JSON.stringify(params, null, 2);
136
+ const json = JSON.stringify(result, null, 2);
93
137
  mkdirSync(dirname(resultPath), { recursive: true });
94
138
  writeFileSync(resultPath, `${json}\n`, 'utf8');
95
139
  const body = reportBody(resultPath, json);
@@ -114,7 +158,7 @@ export function registerCanvasStructuredOutput(pi) {
114
158
  catch { /* ignore */ }
115
159
  return {
116
160
  content: [{ type: 'text', text: `Structured output submitted and finalized: ${resultPath}` }],
117
- details: { submitted: true, mode: current.mode, resultPath, result: params },
161
+ details: { submitted: true, mode: current.mode, resultPath, result },
118
162
  terminate: true,
119
163
  };
120
164
  }
@@ -124,7 +168,7 @@ export function registerCanvasStructuredOutput(pi) {
124
168
  retireTool(pi);
125
169
  return {
126
170
  content: [{ type: 'text', text: `Structured output submitted: ${resultPath}` }],
127
- details: { submitted: true, mode: current.mode, resultPath, result: params },
171
+ details: { submitted: true, mode: current.mode, resultPath, result },
128
172
  };
129
173
  },
130
174
  });