@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
@@ -3,44 +3,17 @@
3
3
  // Loaded into every canvas node's pi process via the node's launch.extensions
4
4
  // list. INERT when CRTR_NODE_ID is absent (plain pi session or legacy job agent).
5
5
  //
6
- // The bearings preamble. On `session_start` — which fires BEFORE the node's
7
- // first user message enters the session — this injects ONE <crtr-context>
8
- // message via `pi.sendMessage` (no delivery options, so at the idle start it is
9
- // pushed straight onto the message list and persisted). Because the session is
10
- // still empty at that point, the bearings land as the FIRST entry, ahead of the
11
- // node's first prompt — the orienting frame, not a trailing afterthought.
12
- // (before_agent_start / deliverAs:"nextTurn" both append AFTER the user
13
- // message — see agent-session's submit path — which is why we use
14
- // session_start instead.)
6
+ // On `session_start` — before the node's first real user message — this injects
7
+ // one persisted <crtr-context> custom message. A fresh conversation receives the
8
+ // full baseline as its first entry. A fork receives a compact update after the
9
+ // copied history and immediately before its new mandate. The prose lives in
10
+ // core/runtime/bearings.ts.
15
11
  //
16
- // The block carries: the path to the node's own context dir and the framing for
17
- // what belongs there (a shared document store for the other nodes). EVERY node
18
- // also gets a `<memory kind="knowledge">` block rendered from the document
19
- // substrate — eligible `knowledge` docs at their system-prompt visibility rung,
20
- // plus the node's own node-local substrate docs — so the bearings name what to
21
- // read on demand. (Preferences surface as their own `<memory kind="preference">`
22
- // block of the system prompt, not in this block.) An
23
- // orchestrator additionally gets the across-refresh-cycles framing (the one
24
- // thing a terminal worker's bearings drop). The prose lives in
25
- // core/runtime/bearings.ts (shared with the promotion guidance dump).
26
- //
27
- // IDEMPOTENT across resumes, but FORK-AWARE and BRANCH-AWARE: the idempotency
28
- // scan walks only the ACTIVE BRANCH (root-first from the current leaf), not
29
- // every entry in the file. A `--session` relaunch that is a true resume keeps
30
- // the same branch, so the scan finds OUR prior bearings (named by OUR node id)
31
- // and skips — it never accumulates. A post-yield CYCLE roots a fresh branch (the
32
- // `crtr-cycle` marker), so the scan correctly finds nothing on that fresh branch
33
- // and injects a new intro, even though an OLDER cycle's intro still sits
34
- // elsewhere in the same `.jsonl`. A `--fork-from` boot COPIES the source node's
35
- // whole conversation onto ITS OWN branch (bearings naming the SOURCE's node id,
36
- // not ours), so the handler must NOT treat that inherited block as ours; it only
37
- // skips when a bearings block belonging to OUR node is already present on the
38
- // active branch (exact `details.nodeId` stamp, content-match fallback),
39
- // otherwise it injects ours — whose identity assertion (leading the
40
- // <crtr-bearings> block) reasserts the fork's identity over the inherited
41
- // persona. This is ONE of two reinforcing channels: spawn.ts ALSO prepends the
42
- // same identity assertion to a fork's kickoff prompt (the turn-triggering
43
- // message), so the override does not rest on a single trailing custom_message.
12
+ // BRANCH-AWARE and IDEMPOTENT: the active branch receives one bearings message
13
+ // stamped for this node. A resume finds that stamp and injects nothing. A new
14
+ // cycle has no current-branch stamp and receives a fresh full baseline. A fork
15
+ // whose active branch carries another node's bearings receives only a compact
16
+ // node-scoped update; a fork of a non-crouter session receives the full baseline.
44
17
  //
45
18
  // COLLAPSED BY DEFAULT: a `registerMessageRenderer` keyed to our customType
46
19
  // renders the block as a single one-line stub; the full body only appears when
@@ -53,8 +26,8 @@
53
26
  //
54
27
  // Plain TS-with-types — no imports from @earendil-works/* so this compiles inside
55
28
  // crouter's own tsc build without a dep on the pi packages.
56
- import { buildContextBearings, CONTEXT_INTRO_CUSTOM_TYPE } from '../core/runtime/bearings.js';
57
- import { isWarmSpare } from '../core/canvas/index.js';
29
+ import { buildContextBearings, buildForkBearings, CONTEXT_INTRO_CUSTOM_TYPE } from '../core/runtime/bearings.js';
30
+ import { getNode, isWarmSpare } from '../core/canvas/index.js';
58
31
  /** The `customType` stamped on the injected session message. Used both to write
59
32
  * the entry and to detect it on resume (the idempotency guard). Defined beside
60
33
  * the block builder in `core/runtime/bearings.ts` because the warm-pool claim's
@@ -63,12 +36,16 @@ export { CONTEXT_INTRO_CUSTOM_TYPE };
63
36
  // ---------------------------------------------------------------------------
64
37
  // Block builder
65
38
  // ---------------------------------------------------------------------------
66
- /** Build the <crtr-context> bearings block for `nodeId`. Thin wrapper over the
67
- * shared builder in core/runtime/bearings.ts (the single source of truth, also
68
- * used by the promotion guidance dump). Exported for testing. */
39
+ /** Build the full bearings baseline for a conversation without inherited
40
+ * crouter context. Exported for testing. */
69
41
  export function buildContextIntro(nodeId) {
70
42
  return buildContextBearings(nodeId);
71
43
  }
44
+ /** Build the compact node-scoped update for a fork whose copied branch already
45
+ * carries a full crouter baseline. Exported for testing. */
46
+ export function buildForkContextIntro(nodeId) {
47
+ return buildForkBearings(nodeId);
48
+ }
72
49
  // ---------------------------------------------------------------------------
73
50
  // Collapsed-by-default rendering
74
51
  // ---------------------------------------------------------------------------
@@ -157,74 +134,43 @@ export function renderContextMessage(message, options, theme) {
157
134
  // ---------------------------------------------------------------------------
158
135
  // Extension
159
136
  // ---------------------------------------------------------------------------
160
- /**
161
- * Register the context-intro preamble on `pi`.
162
- *
163
- * Returns immediately (inert) when CRTR_NODE_ID is absent. On `session_start`
164
- * it injects the <crtr-context> block as the first message of a brand-new chat
165
- * — but only when the session does not already carry it, so a `--session <id>`
166
- * relaunch (which restores the conversation) never duplicates the block.
167
- */
137
+ /** Register the context-intro preamble. Fresh branches receive one full
138
+ * baseline, forked crouter branches receive one compact update, and resumes
139
+ * whose active branch already carries this node's stamp receive nothing. */
168
140
  export function registerCanvasContextIntro(pi) {
169
141
  // Collapse the block to a one-liner until the user expands tool output (Ctrl+O).
170
142
  // Harmless to register outside TUI mode (it's only consulted while rendering).
171
143
  pi.registerMessageRenderer(CONTEXT_INTRO_CUSTOM_TYPE, renderContextMessage);
172
144
  pi.on('session_start', (_event, ctx) => {
173
- try {
174
- const nodeId = process.env['CRTR_NODE_ID'];
175
- if (nodeId === undefined || nodeId.trim() === '')
176
- return; // not a canvas node
177
- // An UNCLAIMED warm spare gets no bearings. Nobody owns this conversation
178
- // yet, so a block built now would assert the spare's placeholder persona
179
- // (always `general`/`base`) and snapshot the repo as it looks at MINT
180
- // time. The claim builds and delivers the real one over the broker once
181
- // the row wears its claimant's kind/mode/name (`deliver-live.ts`), which
182
- // still lands first in this session because nobody has spoken in it. A
183
- // later revive of the claimed node re-injects nothing: the delivered block
184
- // carries the same `details.nodeId` stamp the guard below matches on.
185
- if (isWarmSpare(nodeId))
186
- return;
187
- // Branch-aware idempotency: scan only the ACTIVE branch (root-first from
188
- // the current leaf), not every entry in the file. A post-yield cycle roots a
189
- // FRESH branch (the crtr-cycle marker), so scanning the whole file would
190
- // find a PRIOR cycle's intro and wrongly skip injecting this cycle's own —
191
- // the node's first turn would lack its crtr-context bearings entirely.
192
- // Falls back to a whole-file scan only if the engine doesn't expose
193
- // getBranch (older/degraded engine). Not fooled by a FORK either way: a
194
- // `--fork-from` boot copies the source's whole conversation onto ITS OWN
195
- // branch (bearings naming the SOURCE's node id, not ours), so a naive
196
- // "any crtr-context present?" check would suppress our own intro and let
197
- // the fork inherit — and impersonate — the source. So we only skip when a
198
- // bearings block belonging to OUR node is already present on the scanned
199
- // branch. Primary discriminator: the EXACT `details.nodeId` stamp (machine-
200
- // readable, copied on fork, never sent to the LLM). Fallback: a substring
201
- // match on the block text (our id appears in the identity line AND the
202
- // context-dir path `…/nodes/<nodeId>/context`) — covers legacy blocks
203
- // persisted before the stamp existed. Either match ⇒ this is our own
204
- // resume, not an inherited fork block, so skip.
205
- const scan = typeof ctx.sessionManager.getBranch === 'function'
206
- ? ctx.sessionManager.getBranch()
207
- : ctx.sessionManager.getEntries();
208
- const ours = scan.some((e) => e.type === 'custom_message' &&
209
- e.customType === CONTEXT_INTRO_CUSTOM_TYPE &&
210
- (e.details?.nodeId === nodeId || entryText(e).includes(nodeId)));
211
- if (ours)
212
- return;
213
- // No delivery options: at the idle start of a session this is pushed onto
214
- // the (still empty) message list and persisted immediately, so it precedes
215
- // the node's first prompt. The `details.nodeId` stamp rides along as the
216
- // exact resume discriminator (not shown to the LLM).
217
- pi.sendMessage({
218
- customType: CONTEXT_INTRO_CUSTOM_TYPE,
219
- content: buildContextIntro(nodeId),
220
- display: true,
221
- details: { nodeId },
222
- });
223
- }
224
- catch {
225
- // Best-effort: a failure here must never break session startup.
145
+ const nodeId = process.env['CRTR_NODE_ID'];
146
+ if (nodeId === undefined || nodeId.trim() === '')
147
+ return;
148
+ // Warm spares have no claimant yet. Their claim path delivers the full
149
+ // baseline after assigning the real persona, profile, and working directory.
150
+ if (isWarmSpare(nodeId))
151
+ return;
152
+ // The active branch, rather than the whole session file, is the context the
153
+ // next turn sees. A new cycle therefore receives its own current baseline.
154
+ const scan = typeof ctx.sessionManager.getBranch === 'function'
155
+ ? ctx.sessionManager.getBranch()
156
+ : ctx.sessionManager.getEntries();
157
+ const contextEntries = scan.filter((e) => e.type === 'custom_message' && e.customType === CONTEXT_INTRO_CUSTOM_TYPE);
158
+ const ours = contextEntries.some((e) => e.details?.nodeId === nodeId || entryText(e).includes(nodeId));
159
+ if (ours)
226
160
  return;
227
- }
161
+ // A copied crouter branch already carries the shared baseline. Append only
162
+ // this fork's new node-scoped facts. A non-crouter branch has no such entry.
163
+ const inherited = contextEntries.length > 0;
164
+ const forked = getNode(nodeId)?.fork_from != null;
165
+ const content = inherited && forked
166
+ ? buildForkContextIntro(nodeId)
167
+ : buildContextIntro(nodeId);
168
+ pi.sendMessage({
169
+ customType: CONTEXT_INTRO_CUSTOM_TYPE,
170
+ content,
171
+ display: true,
172
+ details: { nodeId },
173
+ });
228
174
  });
229
175
  }
230
176
  export default registerCanvasContextIntro;
@@ -1,3 +1,5 @@
1
+ import { regenerateAndPersistName } from '../core/runtime/naming-persist.js';
2
+ import { generateRecap } from '../core/runtime/recap.js';
1
3
  interface TextContentLike {
2
4
  type: string;
3
5
  text?: string;
@@ -9,6 +11,10 @@ interface MessageLike {
9
11
  interface SessionEntryLike {
10
12
  type: string;
11
13
  message?: MessageLike;
14
+ customType?: string;
15
+ details?: {
16
+ reviewId?: string;
17
+ };
12
18
  }
13
19
  interface SessionManagerLike {
14
20
  getEntries(): SessionEntryLike[];
@@ -17,6 +23,7 @@ interface UIContextLike {
17
23
  setWidget(key: string, content: string[] | undefined, options?: {
18
24
  placement?: 'aboveEditor' | 'belowEditor';
19
25
  }): void;
26
+ notify?(message: string, type?: 'info' | 'warn' | 'warning' | 'error'): void;
20
27
  }
21
28
  interface ExtensionCtxLike {
22
29
  ui?: UIContextLike;
@@ -27,9 +34,15 @@ interface ExtensionCtxLike {
27
34
  id?: string;
28
35
  };
29
36
  }
30
- type PiEvents = 'session_start' | 'input' | 'turn_end' | 'session_shutdown';
37
+ type PiEvents = 'session_start' | 'input' | 'message_update' | 'turn_end' | 'session_shutdown';
31
38
  interface PiLike {
32
39
  on(event: PiEvents, handler: (event: any, ctx: ExtensionCtxLike) => void): void;
40
+ registerCommand?(name: string, options: {
41
+ description: string;
42
+ handler: (args: string, ctx: ExtensionCtxLike) => Promise<void> | void;
43
+ }): void;
44
+ getSessionName?(): string | undefined;
45
+ setSessionName?(name: string): void;
33
46
  }
34
47
  /**
35
48
  * Register the inactivity-recap chrome on `pi`.
@@ -37,5 +50,5 @@ interface PiLike {
37
50
  * Returns immediately (inert) when CRTR_NODE_ID is absent — a plain pi session
38
51
  * or legacy job agent loads it as a no-op.
39
52
  */
40
- export declare function registerCanvasRecap(pi: PiLike): void;
53
+ export declare function registerCanvasRecap(pi: PiLike, recapGenerator?: typeof generateRecap, nameRegenerator?: typeof regenerateAndPersistName): void;
41
54
  export default registerCanvasRecap;
@@ -1,26 +1,29 @@
1
1
  // canvas-recap.ts — pi extension for pi-native canvas agent nodes.
2
2
  //
3
- // A per-node INACTIVITY BRIEF, drawn faintly immediately above the editor border.
4
- // When a node has had NO new message (user or assistant) for IDLE_MS (60s by
5
- // default), it runs a stripped-down headless call on the conversation's current
6
- // working model and pins one concise, wrapped briefing above the editor, so a
7
- // developer returning to the conversation sees where it left off at a glance.
8
- // The card disappears the instant the next message arrives, and the idle clock
9
- // restarts.
3
+ // A per-node recap, drawn faintly immediately above the editor border. When a
4
+ // node has had NO new message (user or assistant) for IDLE_MS (60s by default),
5
+ // it runs a stripped-down headless call on the conversation's current working
6
+ // model and pins one concise, wrapped briefing above the editor, so a developer
7
+ // returning to the conversation sees where it left off at a glance. `/recap`
8
+ // generates that briefing immediately and refreshes the original generated
9
+ // editor title from a conversation-wide sample. A shown card remains pinned as
10
+ // the conversation advances and is replaced only when a newer recap succeeds.
10
11
  //
11
- // trigger/clear are keyed off MESSAGES, not turns-of-work:
12
- // • a user `input` event OR an assistant `turn_end` resets the idle clock
13
- // and clears any shown recap.
12
+ // generation is keyed off MESSAGES, not turns-of-work:
13
+ // • user `input`, assistant `message_update`, and assistant `turn_end` events
14
+ // reset the idle clock and mark any shown recap stale.
14
15
  // • a single low-rate timer (no busy-loop) checks elapsed-since-last-message
15
- // and, on crossing IDLE_MS, generates + shows the recap once.
16
+ // and, on crossing IDLE_MS, replaces a missing or stale recap once.
16
17
  //
17
- // Brief input = the FIRST 5 and MOST RECENT 5 user/assistant messages (literal
18
- // text only — the first messages carry the original request, the last carry
19
- // where it left off), plus the node's roadmap file when one exists. Tool calls,
18
+ // Brief input = the FIRST 5 and MOST RECENT 5 visible user/assistant messages
19
+ // (literal text only — for review companions, only messages after their durable
20
+ // boundary are visible), plus the node's roadmap file when one exists. Tool calls,
20
21
  // tool results, thinking blocks, and extension-injected custom messages are
21
22
  // excluded (only `message` entries with role user/assistant, and only their
22
- // `text` content blocks). Long messages are truncated per-message so the
23
- // opening request is never crowded out by a recent wall of text.
23
+ // `text` content blocks). While an assistant response is streaming, its latest
24
+ // `message_update` snapshot is appended because it is not yet in the persisted
25
+ // entries. Long messages are truncated per-message so the opening request is
26
+ // never crowded out by a recent wall of text.
24
27
  //
25
28
  // Placement: key `crtr-recap`, placement `aboveEditor`.
26
29
  //
@@ -35,8 +38,11 @@
35
38
  //
36
39
  // Plain TS-with-types — no imports from @earendil-works/* so this compiles
37
40
  // inside crouter's own tsc build without a dep on the pi packages.
41
+ import { getNode, editorLabel } from '../core/canvas/index.js';
42
+ import { regenerateAndPersistName } from '../core/runtime/naming-persist.js';
38
43
  import { generateRecap } from '../core/runtime/recap.js';
39
44
  import { readRoadmap } from '../core/runtime/roadmap.js';
45
+ import { isReviewBoundary } from '../core/runtime/session-visibility.js';
40
46
  // ---------------------------------------------------------------------------
41
47
  // Tuning constants
42
48
  // ---------------------------------------------------------------------------
@@ -79,36 +85,56 @@ function messageText(msg) {
79
85
  .join('\n')
80
86
  .trim();
81
87
  }
82
- /** Concatenate the FIRST and MOST-RECENT CONVO_EDGE_MESSAGES user/assistant
83
- * messages into a single `User:`/`Agent:` transcript (each message capped at
84
- * MESSAGE_CHAR_BUDGET chars), with an omission marker where the middle was
85
- * dropped — the opening messages carry the original request the brief exists
86
- * to surface. Excludes tool calls/results (role toolResult, plus toolCall/
87
- * thinking content blocks dropped by messageText) and extension-injected
88
- * custom messages (entry.type !== 'message'). Returns '' when there is nothing
89
- * to summarize. */
90
- function buildConversation(sm) {
88
+ /** Return the full conversation for ordinary nodes, or only messages after this
89
+ * review's first durable boundary. A missing review marker intentionally has no
90
+ * recap input: inherited context must never become widget or naming text. */
91
+ function recapEntries(sm, reviewId) {
91
92
  let entries;
92
93
  try {
93
94
  entries = sm.getEntries();
94
95
  }
95
96
  catch {
96
- return '';
97
+ return { entries: [], boundaryPresent: reviewId === undefined };
97
98
  }
99
+ if (reviewId === undefined)
100
+ return { entries, boundaryPresent: true };
101
+ const markerIndex = entries.findIndex((entry) => isReviewBoundary(entry, reviewId));
102
+ return markerIndex === -1
103
+ ? { entries: [], boundaryPresent: false }
104
+ : { entries: entries.slice(markerIndex + 1), boundaryPresent: true };
105
+ }
106
+ /** Extract every literal user/assistant message in chronological order. */
107
+ function conversationParts(sm, messageCharBudget, assistantPartial, reviewId) {
108
+ const { entries, boundaryPresent } = recapEntries(sm, reviewId);
98
109
  const parts = [];
99
- for (const e of entries) {
100
- if (e.type !== 'message' || e.message === undefined)
101
- continue;
102
- const role = e.message.role;
110
+ const append = (message) => {
111
+ const role = message.role;
103
112
  if (role !== 'user' && role !== 'assistant')
104
- continue; // drop toolResult etc.
105
- let text = messageText(e.message);
113
+ return; // drop toolResult etc.
114
+ let text = messageText(message);
106
115
  if (text === '')
116
+ return;
117
+ if (text.length > messageCharBudget)
118
+ text = `${text.slice(0, messageCharBudget)} …[truncated]`;
119
+ const part = `${role === 'user' ? 'User' : 'Agent'}: ${text}`;
120
+ // Some pi versions expose the in-progress assistant message through the
121
+ // session manager as well as message_update. Keep one latest snapshot.
122
+ if (parts.at(-1) !== part)
123
+ parts.push(part);
124
+ };
125
+ for (const e of entries) {
126
+ if (e.type !== 'message' || e.message === undefined)
107
127
  continue;
108
- if (text.length > MESSAGE_CHAR_BUDGET)
109
- text = `${text.slice(0, MESSAGE_CHAR_BUDGET)} …[truncated]`;
110
- parts.push(`${role === 'user' ? 'User' : 'Agent'}: ${text}`);
128
+ append(e.message);
111
129
  }
130
+ if (boundaryPresent && assistantPartial?.role === 'assistant')
131
+ append(assistantPartial);
132
+ return parts;
133
+ }
134
+ /** Concatenate the first and most-recent messages for the compact inactivity
135
+ * briefing. The opening request and current state are the useful recap inputs. */
136
+ function buildConversation(sm, assistantPartial, reviewId) {
137
+ const parts = conversationParts(sm, MESSAGE_CHAR_BUDGET, assistantPartial, reviewId);
112
138
  if (parts.length === 0)
113
139
  return '';
114
140
  if (parts.length <= CONVO_EDGE_MESSAGES * 2)
@@ -120,6 +146,22 @@ function buildConversation(sm) {
120
146
  ...parts.slice(parts.length - CONVO_EDGE_MESSAGES),
121
147
  ].join('\n\n');
122
148
  }
149
+ /** A bounded chronological sample spanning the whole conversation for title
150
+ * regeneration. It keeps the one-shot title request practical while giving new
151
+ * information from the middle and end equal weight with the opening request. */
152
+ function buildNamingConversation(sm, assistantPartial, reviewId) {
153
+ const parts = conversationParts(sm, 600, assistantPartial, reviewId);
154
+ if (parts.length === 0)
155
+ return '';
156
+ const maxParts = 48;
157
+ if (parts.length <= maxParts)
158
+ return parts.join('\n\n');
159
+ const sampled = Array.from({ length: maxParts }, (_, index) => {
160
+ const sourceIndex = Math.round(index * (parts.length - 1) / (maxParts - 1));
161
+ return parts[sourceIndex];
162
+ });
163
+ return sampled.join('\n\n');
164
+ }
123
165
  // ---------------------------------------------------------------------------
124
166
  // Extension
125
167
  // ---------------------------------------------------------------------------
@@ -129,7 +171,7 @@ function buildConversation(sm) {
129
171
  * Returns immediately (inert) when CRTR_NODE_ID is absent — a plain pi session
130
172
  * or legacy job agent loads it as a no-op.
131
173
  */
132
- export function registerCanvasRecap(pi) {
174
+ export function registerCanvasRecap(pi, recapGenerator = generateRecap, nameRegenerator = regenerateAndPersistName) {
133
175
  const nodeId = process.env['CRTR_NODE_ID'];
134
176
  if (nodeId === undefined || nodeId.trim() === '')
135
177
  return; // not a canvas node
@@ -148,12 +190,28 @@ export function registerCanvasRecap(pi) {
148
190
  };
149
191
  /** Wall-clock of the most recent user/assistant message. The idle clock. */
150
192
  let lastMessageAt = Date.now();
151
- /** True while a recap is currently shown (so we generate at most once per
152
- * idle window, and know whether a clear is needed on the next message). */
193
+ /** Monotonic conversation activity version used to judge generation results. */
194
+ let activityVersion = 0;
195
+ /** Latest in-progress assistant message, which is absent from persisted entries. */
196
+ let liveAssistantPartial;
197
+ /** Whether a recap is currently shown and whether conversation activity has
198
+ * made that recap eligible for replacement in the next idle window. */
153
199
  let recapShown = false;
200
+ let recapStale = false;
201
+ /** A markerless review has no safe recap input until new activity occurs. */
202
+ let recapInputUnavailable = false;
154
203
  /** True while a briefing generation is in flight (so we don't fire a second). */
155
204
  let generating = false;
156
205
  const canPaint = () => ui !== undefined && typeof ui.setWidget === 'function';
206
+ /** A manual recap is a model call that can take tens of seconds. Confirm its
207
+ * start immediately so selecting it from Alt+C is never mistaken for a dead
208
+ * menu action. The finished widget remains the durable completion signal. */
209
+ const notify = (message) => {
210
+ try {
211
+ ui?.notify?.(message, 'info');
212
+ }
213
+ catch { /* best-effort */ }
214
+ };
157
215
  const clearRecap = () => {
158
216
  if (!canPaint())
159
217
  return;
@@ -176,15 +234,93 @@ export function registerCanvasRecap(pi) {
176
234
  }
177
235
  catch { /* best-effort */ }
178
236
  };
179
- /** A user or assistant message landed: reset the idle clock and clear any
180
- * shown recap (the conversation has moved on). */
237
+ /** Conversation activity resets the idle clock. A shown recap remains useful
238
+ * context while stale and stays pinned until a replacement succeeds. */
181
239
  const onMessage = () => {
182
240
  lastMessageAt = Date.now();
183
- if (recapShown) {
241
+ activityVersion += 1;
242
+ recapInputUnavailable = false;
243
+ if (recapShown)
244
+ recapStale = true;
245
+ };
246
+ /** Re-name only when the live title is still crouter's generated node label.
247
+ * A different title came from a person and is left intact. */
248
+ const refreshAutomaticName = (conversation) => {
249
+ if (pi.getSessionName === undefined || pi.setSessionName === undefined)
250
+ return;
251
+ const meta = getNode(nodeId);
252
+ if (meta === null)
253
+ return;
254
+ // `/rename` persists a person's explicit handle on the node as well as in
255
+ // the pi session. Such a handle remains authoritative even when its live
256
+ // session text exactly matches editorLabel(meta).
257
+ if (meta.name.trim() !== '' && meta.name !== meta.kind)
258
+ return;
259
+ const original = editorLabel(meta);
260
+ if (pi.getSessionName() !== original)
261
+ return;
262
+ nameRegenerator(nodeId, conversation, () => pi.getSessionName?.() === original, (named) => {
263
+ try {
264
+ pi.setSessionName?.(editorLabel(named));
265
+ }
266
+ catch { /* best-effort */ }
267
+ });
268
+ };
269
+ /** Start one briefing generation. A manual request refreshes an untouched
270
+ * generated title as a separate best-effort task from the broader conversation. */
271
+ const requestRecap = (manual) => {
272
+ if (!canPaint() || sessionManager === undefined || generating)
273
+ return;
274
+ const assistantPartial = liveAssistantPartial;
275
+ const reviewId = getNode(nodeId)?.review_binding?.review_id;
276
+ const conversation = buildConversation(sessionManager, assistantPartial, reviewId);
277
+ if (conversation === '') {
278
+ recapInputUnavailable = true;
184
279
  recapShown = false;
280
+ recapStale = false;
185
281
  clearRecap();
282
+ return;
283
+ }
284
+ recapInputUnavailable = false;
285
+ const namingConversation = manual ? buildNamingConversation(sessionManager, assistantPartial, reviewId) : '';
286
+ const snapshotVersion = activityVersion;
287
+ generating = true;
288
+ if (manual) {
289
+ notify('Generating recap…');
290
+ refreshAutomaticName(namingConversation);
186
291
  }
292
+ let roadmap;
293
+ try {
294
+ roadmap = readRoadmap(nodeId) ?? undefined;
295
+ }
296
+ catch { /* best-effort */ }
297
+ recapGenerator(conversation, (briefing) => {
298
+ generating = false;
299
+ // A manual recap belongs to its click-time snapshot and always paints.
300
+ // Automatic work paints only while its idle snapshot remains current.
301
+ if ((!manual && activityVersion !== snapshotVersion) || !canPaint())
302
+ return;
303
+ recapShown = true;
304
+ recapStale = activityVersion !== snapshotVersion;
305
+ showRecap(briefing);
306
+ if (manual)
307
+ notify('Recap ready');
308
+ }, liveModel, roadmap);
309
+ // generateRecap is silent on failure (never calls back), so clear the
310
+ // in-flight flag after the timeout window even if no callback fires.
311
+ setTimeout(() => { generating = false; }, 30_000).unref?.();
187
312
  };
313
+ // The prefix menu sends `/recap` into the focused viewer. As an extension
314
+ // command it never becomes a user message or starts an agent turn.
315
+ pi.registerCommand?.('recap', {
316
+ description: 'Generate a Goal/State recap and refresh the original generated session title',
317
+ handler: (_args, ctx) => {
318
+ ui = ctx.ui;
319
+ sessionManager = ctx.sessionManager;
320
+ captureLiveModel(ctx);
321
+ requestRecap(true);
322
+ },
323
+ });
188
324
  // -------------------------------------------------------------------------
189
325
  // Events
190
326
  // -------------------------------------------------------------------------
@@ -195,17 +331,27 @@ export function registerCanvasRecap(pi) {
195
331
  // Fresh session / hot-swap: start the idle clock now and drop any stale
196
332
  // recap that bled through a /reload.
197
333
  lastMessageAt = Date.now();
334
+ activityVersion = 0;
335
+ liveAssistantPartial = undefined;
198
336
  recapShown = false;
337
+ recapStale = false;
338
+ recapInputUnavailable = false;
199
339
  generating = false;
200
340
  clearRecap();
201
341
  });
202
342
  pi.on('input', (_event, _ctx) => {
203
- // Every user message (any source) is activity — reset + clear.
343
+ // Every user message (any source) is activity.
344
+ onMessage();
345
+ });
346
+ pi.on('message_update', (event, _ctx) => {
347
+ const message = event?.message;
348
+ if (message?.role === 'assistant')
349
+ liveAssistantPartial = message;
204
350
  onMessage();
205
351
  });
206
352
  pi.on('turn_end', (_event, ctx) => {
207
- // A completed assistant turn is activity — reset + clear, and remember the
208
- // exact model/provider that successfully produced it for the later recap.
353
+ // The completed assistant message now lives in the session manager.
354
+ liveAssistantPartial = undefined;
209
355
  captureLiveModel(ctx);
210
356
  onMessage();
211
357
  });
@@ -218,34 +364,11 @@ export function registerCanvasRecap(pi) {
218
364
  try {
219
365
  if (!canPaint() || sessionManager === undefined)
220
366
  return;
221
- if (recapShown || generating)
367
+ if (recapInputUnavailable || (recapShown && !recapStale) || generating)
222
368
  return;
223
369
  if (Date.now() - lastMessageAt < idleMs())
224
370
  return;
225
- const convo = buildConversation(sessionManager);
226
- if (convo === '')
227
- return; // nothing to summarize yet
228
- // Snapshot the clock: if a message arrives while generation runs, discard the
229
- // (now-stale) result instead of painting over the live conversation.
230
- const startedAt = lastMessageAt;
231
- generating = true;
232
- let roadmap;
233
- try {
234
- roadmap = readRoadmap(nodeId) ?? undefined;
235
- }
236
- catch { /* best-effort */ }
237
- generateRecap(convo, (briefing) => {
238
- generating = false;
239
- if (lastMessageAt !== startedAt)
240
- return; // a message landed mid-flight
241
- if (!canPaint())
242
- return;
243
- recapShown = true;
244
- showRecap(briefing);
245
- }, liveModel, roadmap);
246
- // generateRecap is silent on failure (never calls back), so clear the
247
- // in-flight flag after the timeout window even if no callback fires.
248
- setTimeout(() => { generating = false; }, 30_000).unref?.();
371
+ requestRecap(false);
249
372
  }
250
373
  catch {
251
374
  /* timer is best-effort */