@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,48 @@
1
+ import { fileURLToPath } from 'node:url';
2
+ import { test } from 'node:test';
3
+ import assert from 'node:assert/strict';
4
+ import { initTheme } from '@earendil-works/pi-coding-agent';
5
+ import { InputController } from '../input/controller.js';
6
+ initTheme(undefined, false);
7
+ function fakeEditor() {
8
+ const obj = {
9
+ onSubmit: undefined,
10
+ onEscape: undefined,
11
+ onPasteImage: undefined,
12
+ onAction: () => { },
13
+ getText: () => '',
14
+ setText: () => { },
15
+ addToHistory: () => { },
16
+ insertTextAtCursor: () => { },
17
+ };
18
+ return obj;
19
+ }
20
+ test('choosing a review file closes the inline picker before the review surface takes focus', () => {
21
+ const editor = fakeEditor();
22
+ let focused = null;
23
+ let mountedPicker;
24
+ const tui = {
25
+ requestRender: () => { },
26
+ setFocus: (component) => { focused = component; },
27
+ showOverlay: () => ({ hide: () => { } }),
28
+ start: () => { },
29
+ stop: () => { },
30
+ };
31
+ const reviewSurface = {
32
+ render: () => [],
33
+ invalidate: () => { },
34
+ handleInput: () => { },
35
+ };
36
+ const controller = new InputController(tui, editor, {}, {
37
+ onCommand: () => { },
38
+ onDialogResponse: () => { },
39
+ onMountPicker: (component) => { mountedPicker = component; },
40
+ onUnmountPicker: () => { },
41
+ });
42
+ controller.openFileReviewPicker([fileURLToPath(import.meta.url)], process.cwd(), () => {
43
+ tui.setFocus(reviewSurface);
44
+ });
45
+ assert.ok(mountedPicker?.handleInput);
46
+ mountedPicker.handleInput('\n');
47
+ assert.equal(focused, reviewSurface, 'picker close must not restore editor focus over the review surface');
48
+ });
@@ -0,0 +1,266 @@
1
+ import assert from 'node:assert/strict';
2
+ import { homedir } from 'node:os';
3
+ import { resolve } from 'node:path';
4
+ import test from 'node:test';
5
+ import { Container, TUI, getCapabilities, setCapabilities } from '@earendil-works/pi-tui';
6
+ import { initTheme } from '@earendil-works/pi-coding-agent';
7
+ import { AUTH_FAULT_RECOVERY_BODY, RUNTIME_RESTART_CONTINUATION, isRuntimeRestartContinuation } from '../../../shared/generated-context.js';
8
+ import { ChatView } from '../render/chat-view.js';
9
+ import { GroupActivityRecorder } from '../render/group-activity.js';
10
+ import { GroupRecapComponent } from '../render/group-recap.js';
11
+ import { TOOL_ICON } from '../../../core/preview-registry.js';
12
+ function memoryRead(name, pathStyle = 'section') {
13
+ const path = pathStyle === 'field'
14
+ ? `- path: /tmp/memories/${name}.md`
15
+ : `**path:** /tmp/memories/${name}.md`;
16
+ return `- name: ${name}\n- kind: knowledge\n- scope: project\n${pathStyle === 'section' ? '\n' : ''}${path}`;
17
+ }
18
+ function fakeTerminal() {
19
+ return {
20
+ start() { }, stop() { }, async drainInput() { }, write() { },
21
+ get columns() { return 80; }, get rows() { return 24; }, get kittyProtocolActive() { return false; },
22
+ moveBy() { }, hideCursor() { }, showCursor() { }, clearLine() { }, clearFromCursor() { }, clearScreen() { }, setTitle() { }, setProgress() { },
23
+ };
24
+ }
25
+ function snapshotWithContinuation(body) {
26
+ return {
27
+ messages: [
28
+ { role: 'assistant', content: [{ type: 'toolCall', id: 'before', name: 'bash', arguments: { command: 'true' } }] },
29
+ { role: 'toolResult', toolCallId: 'before', toolName: 'bash', content: [{ type: 'text', text: '' }], isError: false },
30
+ { role: 'user', content: body },
31
+ { role: 'assistant', content: [{ type: 'toolCall', id: 'after', name: 'bash', arguments: { command: 'true' } }] },
32
+ { role: 'toolResult', toolCallId: 'after', toolName: 'bash', content: [{ type: 'text', text: '' }], isError: false },
33
+ ],
34
+ stats: {},
35
+ state: { isStreaming: false },
36
+ };
37
+ }
38
+ initTheme(undefined, false);
39
+ test('group activity aggregates successful file changes and resolved memory reads', () => {
40
+ const cwd = '/tmp/activity';
41
+ const recorder = new GroupActivityRecorder(cwd);
42
+ recorder.noteCall('edit-1', 'edit', { path: 'same.ts' });
43
+ recorder.settle('edit-1', { details: { diff: '-1 old\n+1 new' } }, false);
44
+ recorder.noteCall('write', 'write', { path: 'other.ts', content: 'one\ntwo\n' });
45
+ recorder.settle('write', {}, false);
46
+ recorder.noteCall('edit-2', 'edit', { path: resolve(cwd, 'same.ts') });
47
+ recorder.settle('edit-2', { details: { diff: '+2 later' } }, false);
48
+ recorder.noteCall('home-edit', 'edit', { path: '~/same-home.ts' });
49
+ recorder.settle('home-edit', { details: { diff: '+1 home' } }, false);
50
+ recorder.noteCall('home-write', 'write', { path: resolve(homedir(), 'same-home.ts'), content: 'replacement' });
51
+ recorder.settle('home-write', {}, false);
52
+ recorder.noteCall('failed', 'edit', { path: 'failed.ts' });
53
+ recorder.settle('failed', { details: { diff: '+1 never' } }, true);
54
+ recorder.noteCall('memory', 'bash', { command: 'crtr memory read alpha && crtr memory read beta' });
55
+ recorder.settle('memory', { content: [{ type: 'text', text: `${memoryRead('alpha')}\n\n${memoryRead('beta', 'field')}` }] }, false);
56
+ recorder.noteCall('repeat', 'bash', { command: 'crtr memory read alpha' });
57
+ recorder.settle('repeat', { content: [{ type: 'text', text: memoryRead('alpha') }] }, false);
58
+ recorder.noteCall('not-a-read', 'bash', { command: 'crtr memory list' });
59
+ recorder.settle('not-a-read', { content: [{ type: 'text', text: memoryRead('ignored') }] }, false);
60
+ recorder.noteCall('quoted-not-a-read', 'bash', { command: 'echo "not a command; crtr memory read fabricated"' });
61
+ recorder.settle('quoted-not-a-read', { content: [{ type: 'text', text: memoryRead('fabricated') }] }, false);
62
+ const activity = recorder.activity();
63
+ assert.deepEqual(activity.memories, [
64
+ { name: 'alpha', path: '/tmp/memories/alpha.md' },
65
+ { name: 'beta', path: '/tmp/memories/beta.md' },
66
+ ]);
67
+ assert.deepEqual(activity.files.map((file) => [file.kind, file.displayPath]), [
68
+ ['edit', 'same.ts'],
69
+ ['write', 'other.ts'],
70
+ ['edit', '~/same-home.ts'],
71
+ ['write', resolve(homedir(), 'same-home.ts')],
72
+ ]);
73
+ assert.deepEqual(activity.files[0], {
74
+ key: resolve(cwd, 'same.ts'),
75
+ displayPath: 'same.ts',
76
+ kind: 'edit',
77
+ added: 2,
78
+ removed: 1,
79
+ hasKnownCounts: true,
80
+ countsIncomplete: false,
81
+ });
82
+ assert.deepEqual(activity.files[1], {
83
+ key: resolve(cwd, 'other.ts'),
84
+ displayPath: 'other.ts',
85
+ kind: 'write',
86
+ added: 2,
87
+ removed: 0,
88
+ hasKnownCounts: true,
89
+ countsIncomplete: false,
90
+ });
91
+ assert.equal(activity.files[2]?.added, 1, 'edits retain their own aggregate');
92
+ assert.equal(activity.files[3]?.added, 1, 'writes retain their own aggregate');
93
+ });
94
+ test('the detailed folded recap retains paths and counts without diff or payload bodies', () => {
95
+ const recorder = new GroupActivityRecorder('/tmp/activity');
96
+ recorder.noteCall('edit', 'edit', { path: 'overwritten.ts' });
97
+ const addedDiff = Array.from({ length: 11 }, (_, index) => `+${index + 1} sensitive-new-diff`).join('\n');
98
+ recorder.settle('edit', { details: { diff: `-1 sensitive-old-diff\n${addedDiff}` } }, false);
99
+ recorder.noteCall('write', 'write', {
100
+ path: 'overwritten.ts',
101
+ content: Array.from({ length: 8 }, () => 'sensitive-write-payload').join('\n'),
102
+ });
103
+ recorder.settle('write', {}, false);
104
+ recorder.noteCall('zero', 'edit', { path: 'overwritten.ts' });
105
+ recorder.settle('zero', { details: { diff: '' } }, false);
106
+ recorder.noteCall('unavailable', 'edit', { path: 'overwritten.ts' });
107
+ recorder.settle('unavailable', {}, false);
108
+ const tone = (key) => (text) => `[${key}]${text}`;
109
+ const palette = {
110
+ accent: tone('accent'), active: tone('active'), info: tone('info'), muted: tone('muted'),
111
+ faint: tone('faint'), border: tone('border'), surface: tone('surface'), bold: tone('bold'),
112
+ error: tone('error'), warning: tone('warning'), diffAdded: tone('diffAdded'), diffRemoved: tone('diffRemoved'),
113
+ bashMode: tone('bashMode'), bashModeAlt: tone('bashModeAlt'),
114
+ };
115
+ const recap = new GroupRecapComponent();
116
+ const originalCapabilities = getCapabilities();
117
+ let lines;
118
+ try {
119
+ setCapabilities({ ...originalCapabilities, hyperlinks: true });
120
+ recap.setRecap({ bullets: ['finished'], nodesSpawned: 1, filesEdited: 3 }, 2, {
121
+ memories: [
122
+ { name: 'alpha', path: '/tmp/memories/alpha.md' },
123
+ { name: 'beta', path: '/tmp/memories/beta.md' },
124
+ ],
125
+ files: recorder.activity().files,
126
+ }, true, palette);
127
+ lines = recap.render(120);
128
+ }
129
+ finally {
130
+ setCapabilities(originalCapabilities);
131
+ }
132
+ const text = lines.join('\n');
133
+ assert.equal(lines[0], '');
134
+ assert.equal(lines.at(-1), '');
135
+ assert.match(text, /2 tool calls/, 'tool-call count remains visible in every recap mode');
136
+ assert.doesNotMatch(text, /✦/, 'the tool-call count has no decorative prefix');
137
+ assert.doesNotMatch(text, /files?\s+edited|memory\s+reads/, 'detailed recaps do not duplicate their itemized activity with count chrome');
138
+ assert.equal(lines.filter((line) => line.includes('[muted]alpha')).length, 1, 'each memory renders on one line');
139
+ assert.equal(lines.filter((line) => line.includes('[muted]beta')).length, 1, 'each memory renders on one line');
140
+ assert.match(text, /file:\/\/\/tmp\/memories\/alpha\.md/);
141
+ assert.match(text, /file:\/\/\/tmp\/memories\/beta\.md/);
142
+ assert.doesNotMatch(text, /alpha · beta/);
143
+ const fileLines = lines.filter((line) => line.includes('overwritten.ts'));
144
+ assert.equal(fileLines.length, 2, 'edits and writes remain independently visible');
145
+ const editLine = fileLines.find((line) => line.includes(`[warning]${TOOL_ICON.edit}`));
146
+ const writeLine = fileLines.find((line) => line.includes(`[warning]${TOOL_ICON.write}`));
147
+ assert.ok(editLine.indexOf(TOOL_ICON.edit) < editLine.indexOf('overwritten.ts'), 'the edit path stays inline with its glyph');
148
+ assert.ok(writeLine.indexOf(TOOL_ICON.write) < writeLine.indexOf('overwritten.ts'), 'the write path stays inline with its glyph');
149
+ assert.ok(editLine.endsWith('[diffAdded]+11 [diffRemoved]-1[muted] · counts incomplete'), 'edit counts stay with the edit');
150
+ assert.ok(writeLine.endsWith('[diffAdded]+8'), 'write counts stay with the write');
151
+ assert.equal(lines.filter((line) => line.includes('[diffAdded]')).length, 2, 'each action has one count row');
152
+ const toolCallIndex = lines.findIndex((line) => line.includes('2 tool calls'));
153
+ const bulletIndex = lines.findIndex((line) => line.includes('finished'));
154
+ assert.ok(lines.findIndex((line) => line.includes('[muted]alpha')) < toolCallIndex, 'memory reads precede the tool-call count');
155
+ assert.ok(lines.findIndex((line) => line.includes(`[warning]${TOOL_ICON.edit}`)) < toolCallIndex, 'file actions precede the tool-call count');
156
+ assert.ok(toolCallIndex < bulletIndex, 'the tool-call count precedes recap bullets');
157
+ assert.ok(!text.includes('sensitive-old-diff'));
158
+ assert.ok(!text.includes('sensitive-new-diff'));
159
+ assert.ok(!text.includes('sensitive-write-payload'));
160
+ });
161
+ async function summarizedGroup(messages, key) {
162
+ const view = new ChatView(new TUI(fakeTerminal()), new Container());
163
+ const internals = view;
164
+ internals.foldSettledTools = true;
165
+ internals.showGroupSummaries = true;
166
+ await view.applySnapshot({
167
+ messages,
168
+ stats: {},
169
+ state: { isStreaming: false },
170
+ toolGroupSummaries: {
171
+ [key]: { bullets: ['broker recap'], nodesSpawned: 0, filesEdited: 0 },
172
+ },
173
+ });
174
+ const group = internals.groups.find((candidate) => candidate.key === key);
175
+ assert.ok(group, `missing ${key} group`);
176
+ return {
177
+ group,
178
+ children: internals.historyContainer.children,
179
+ hidden: internals.historyContainer.hiddenChildren,
180
+ };
181
+ }
182
+ test('broker summaries hide every settled call while aborted/error assistant endings remain visible boundaries', async () => {
183
+ const successful = await summarizedGroup([
184
+ { role: 'assistant', content: [{ type: 'toolCall', id: 'successful', name: 'bash', arguments: { command: 'true' } }] },
185
+ { role: 'toolResult', toolCallId: 'successful', toolName: 'bash', content: [{ type: 'text', text: 'ok' }], isError: false },
186
+ ], 'successful');
187
+ assert.equal(successful.hidden.has(successful.group.recap), false, 'a settled successful group still folds to its recap');
188
+ assert.ok(successful.group.members.every((member) => successful.hidden.has(member)), 'successful group members hide behind the recap');
189
+ const mixed = await summarizedGroup([
190
+ {
191
+ role: 'assistant',
192
+ content: [
193
+ { type: 'toolCall', id: 'mixed-success', name: 'bash', arguments: { command: 'true' } },
194
+ { type: 'toolCall', id: 'mixed-failure', name: 'bash', arguments: { command: 'false' } },
195
+ ],
196
+ },
197
+ { role: 'toolResult', toolCallId: 'mixed-success', toolName: 'bash', content: [{ type: 'text', text: 'ok' }], isError: false },
198
+ { role: 'toolResult', toolCallId: 'mixed-failure', toolName: 'bash', content: [{ type: 'text', text: 'failed' }], isError: true },
199
+ ], 'mixed-success');
200
+ assert.equal(mixed.hidden.has(mixed.group.recap), false, 'a failed call does not suppress the valid group recap');
201
+ assert.ok(mixed.group.members.every((member) => mixed.hidden.has(member)), 'successful and failed calls all hide behind the recap');
202
+ for (const stopReason of ['aborted', 'error']) {
203
+ const key = `terminal-${stopReason}`;
204
+ const terminalMessage = stopReason === 'aborted'
205
+ ? { role: 'assistant', content: [], stopReason }
206
+ : { role: 'assistant', content: [{ type: 'text', text: 'partial reply' }], stopReason, errorMessage: 'provider failed' };
207
+ const terminalMessages = [
208
+ { role: 'assistant', content: [{ type: 'toolCall', id: key, name: 'bash', arguments: { command: 'true' } }] },
209
+ ];
210
+ if (stopReason === 'error') {
211
+ terminalMessages.push({ role: 'toolResult', toolCallId: key, toolName: 'bash', content: [{ type: 'text', text: 'ok' }], isError: false });
212
+ }
213
+ terminalMessages.push(terminalMessage);
214
+ const terminal = await summarizedGroup(terminalMessages, key);
215
+ assert.equal(terminal.hidden.has(terminal.group.recap), false, `${stopReason} does not suppress the preceding valid recap`);
216
+ assert.ok(terminal.group.members.every((member) => terminal.hidden.has(member)), `${stopReason} leaves preceding tool rows folded`);
217
+ const visibleBoundary = terminal.children
218
+ .filter((component) => component !== terminal.group.recap && !terminal.hidden.has(component))
219
+ .flatMap((component) => component.render(80))
220
+ .join('\n');
221
+ assert.match(visibleBoundary, stopReason === 'aborted' ? /Operation aborted|Interrupted/ : /partial reply|provider failed/, `${stopReason} assistant ending remains visible outside the folded group`);
222
+ }
223
+ });
224
+ test('streamed aborted/error endings stay visible while the preceding summarized tools remain folded', () => {
225
+ for (const stopReason of ['aborted', 'error']) {
226
+ const view = new ChatView(new TUI(fakeTerminal()), new Container());
227
+ const internals = view;
228
+ internals.foldSettledTools = true;
229
+ internals.showGroupSummaries = true;
230
+ const key = `live-${stopReason}`;
231
+ view.handleEvent({ type: 'message_start', message: { role: 'assistant', content: [] } });
232
+ view.handleEvent({ type: 'tool_execution_start', toolCallId: key, toolName: 'bash', args: { command: 'true' } });
233
+ if (stopReason === 'error') {
234
+ view.handleEvent({ type: 'tool_execution_end', toolCallId: key, result: { content: [{ type: 'text', text: 'ok' }] }, isError: false });
235
+ }
236
+ view.applyToolGroupSummary(key, { bullets: ['broker recap'], nodesSpawned: 0, filesEdited: 0 });
237
+ const group = internals.groups.find((candidate) => candidate.key === key);
238
+ assert.ok(group, `missing ${stopReason} live group`);
239
+ assert.equal(internals.historyContainer.hiddenChildren.has(group.recap), stopReason === 'aborted', 'only an in-flight call holds back an early recap');
240
+ const content = stopReason === 'aborted' ? [] : [{ type: 'text', text: 'partial reply' }];
241
+ if (content.length > 0) {
242
+ view.handleEvent({ type: 'message_update', message: { role: 'assistant', content } });
243
+ }
244
+ view.handleEvent({ type: 'message_end', message: { role: 'assistant', content, stopReason, errorMessage: 'provider failed' } });
245
+ view.applyToolGroupSummary(key, { bullets: ['broker recap'], nodesSpawned: 0, filesEdited: 0 });
246
+ assert.equal(internals.historyContainer.hiddenChildren.has(group.recap), false, `${stopReason} does not suppress the preceding streamed recap`);
247
+ assert.ok(group.members.every((member) => internals.historyContainer.hiddenChildren.has(member)), `${stopReason} leaves preceding streamed tool rows folded`);
248
+ const visibleBoundary = internals.historyContainer.children
249
+ .filter((component) => component !== group.recap && !internals.historyContainer.hiddenChildren.has(component))
250
+ .flatMap((component) => component.render(80))
251
+ .join('\n');
252
+ assert.match(visibleBoundary, stopReason === 'aborted' ? /Interrupted/ : /partial reply|provider failed/, `${stopReason} streamed assistant ending remains visible outside the folded group`);
253
+ }
254
+ });
255
+ test('only the exact runtime-restart continuation closes an attach tool group', async () => {
256
+ assert.equal(isRuntimeRestartContinuation({ role: 'user', content: RUNTIME_RESTART_CONTINUATION }), true);
257
+ assert.equal(isRuntimeRestartContinuation({ role: 'user', content: AUTH_FAULT_RECOVERY_BODY }), false);
258
+ const runtimeView = new ChatView(new TUI(fakeTerminal()), new Container());
259
+ await runtimeView.applySnapshot(snapshotWithContinuation(RUNTIME_RESTART_CONTINUATION));
260
+ const runtimeGroups = runtimeView.groups;
261
+ assert.deepEqual(runtimeGroups.map((group) => group.key), ['before', 'after']);
262
+ const recoveryView = new ChatView(new TUI(fakeTerminal()), new Container());
263
+ await recoveryView.applySnapshot(snapshotWithContinuation(AUTH_FAULT_RECOVERY_BODY));
264
+ const recoveryGroups = recoveryView.groups;
265
+ assert.deepEqual(recoveryGroups.map((group) => group.key), ['before']);
266
+ });
@@ -0,0 +1,32 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+ import { InputController } from '../input/controller.js';
4
+ function controller(sent) {
5
+ const editor = {
6
+ onSubmit: undefined,
7
+ onEscape: undefined,
8
+ onPasteImage: undefined,
9
+ onPasteImagePath: undefined,
10
+ onAction: () => { },
11
+ addToHistory: () => { },
12
+ setText: () => { },
13
+ getText: () => '',
14
+ insertTextAtCursor: () => { },
15
+ };
16
+ const input = new InputController({}, editor, { matches: () => false }, { onCommand: (frame) => sent.push(frame), onDialogResponse: () => { } });
17
+ return {
18
+ submit: (text) => editor.onSubmit(text),
19
+ setStreaming: (streaming) => input.setState({ isStreaming: streaming }),
20
+ };
21
+ }
22
+ test('an unrecognized slash command reaches the broker for extension dispatch', () => {
23
+ const sent = [];
24
+ const input = controller(sent);
25
+ input.submit('/recap');
26
+ input.setStreaming(true);
27
+ input.submit('/recap refresh');
28
+ assert.deepEqual(sent, [
29
+ { type: 'prompt', text: '/recap' },
30
+ { type: 'steer', text: '/recap refresh' },
31
+ ]);
32
+ });
@@ -0,0 +1,32 @@
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { createFrameHandler } from '../session/frames.js';
4
+ test('a regenerated session title refreshes the cached canvas icon', () => {
5
+ let identityRefreshes = 0;
6
+ const noop = () => { };
7
+ const effects = {
8
+ foldState: noop,
9
+ chat: {
10
+ applySnapshot: noop,
11
+ handleEvent: noop,
12
+ setWorkingActivity: noop,
13
+ bashStart: noop,
14
+ bashOutput: noop,
15
+ bashEnd: noop,
16
+ applyToolGroupSummary: noop,
17
+ },
18
+ setNotice: noop,
19
+ renderFooter: noop,
20
+ setEditorText: noop,
21
+ attachDialog: noop,
22
+ dismissDialog: noop,
23
+ setCommands: noop,
24
+ resetMemoryRefs: noop,
25
+ refreshNodeIdentity: () => { identityRefreshes += 1; },
26
+ reloadBindings: noop,
27
+ modelThinkingLabel: () => undefined,
28
+ };
29
+ const handler = createFrameHandler({ socket: { send: noop } }, effects);
30
+ handler({ type: 'session_info_changed', name: '\uf14e compass-recap' });
31
+ assert.equal(identityRefreshes, 1);
32
+ });
@@ -134,13 +134,12 @@ test('cursor sweep across a resolved ref decorates outside the cursor cell and s
134
134
  }
135
135
  }
136
136
  });
137
- test('chrome (loaded-command disclosure, title/info border, mode/context badge) never carries ref decoration', () => {
137
+ test('chrome (loaded-command disclosure, title/info border, context badge) never carries ref decoration', () => {
138
138
  const editorA = makeEditor();
139
139
  const editorB = makeEditor();
140
140
  for (const editor of [editorA, editorB]) {
141
141
  editor.title = 'session';
142
142
  editor.info = 'cwd-info';
143
- editor.mode = 'plan';
144
143
  editor.contextBadge = 'node-1';
145
144
  editor.loadedCommand = { name: 'dev', content: 'do the thing', inspectHint: 'ctrl+i' };
146
145
  editor.setText('please use /dev to continue');
@@ -0,0 +1,10 @@
1
+ import { Container } from '@earendil-works/pi-tui';
2
+ import type { SessionState } from '../../../core/session-model/session-state.js';
3
+ import type { AttachSession } from '../session/context.js';
4
+ export interface RecapHeader {
5
+ /** The component ViewerFrame renders as its header region. */
6
+ readonly component: Container;
7
+ /** Repaint from the live `crtr-recap` widget state. Empty widget → 0 rows. */
8
+ render(): void;
9
+ }
10
+ export declare function createRecapHeader(ctx: Pick<AttachSession, 'tui' | 'pal'>, state: () => SessionState): RecapHeader;
@@ -0,0 +1,30 @@
1
+ // chrome/header.ts — the pinned recap header above the transcript.
2
+ //
3
+ // Only the GOAL line of the broker's retained `crtr-recap` widget is painted
4
+ // here, label stripped, so it stays visible while the transcript scrolls. The
5
+ // state line rides the widget's own cockpit slot (chrome/widgets.ts).
6
+ import { Container, Text, wrapTextWithAnsi } from '@earendil-works/pi-tui';
7
+ import { DynamicBorder } from '@earendil-works/pi-coding-agent';
8
+ import { splitRecapLines } from './recap.js';
9
+ export function createRecapHeader(ctx, state) {
10
+ const { tui, pal } = ctx;
11
+ const component = new Container();
12
+ const render = () => {
13
+ component.clear();
14
+ const widget = state().display.widgets['crtr-recap'];
15
+ const goal = widget === undefined ? [] : splitRecapLines(widget.lines).goal;
16
+ if (goal.length > 0) {
17
+ const span = Math.max(1, (process.stdout.columns ?? 80) - 2);
18
+ for (const line of goal) {
19
+ // Styled BEFORE wrapping (wrapTextWithAnsi carries SGR state across
20
+ // wraps), so a wrapped continuation stays faint.
21
+ for (const wrapped of wrapTextWithAnsi(pal.faint(line), span)) {
22
+ component.addChild(new Text(wrapped, 1, 0));
23
+ }
24
+ }
25
+ component.addChild(new DynamicBorder(pal.border));
26
+ }
27
+ tui.requestRender();
28
+ };
29
+ return { component, render };
30
+ }
@@ -0,0 +1,7 @@
1
+ export interface RecapSplit {
2
+ /** `Goal:` lines, label stripped — the pinned header's content. */
3
+ goal: string[];
4
+ /** The remaining lines, `State:` label stripped — cockpit content. */
5
+ state: string[];
6
+ }
7
+ export declare function splitRecapLines(lines: readonly string[]): RecapSplit;
@@ -0,0 +1,19 @@
1
+ // chrome/recap.ts — how the broker's `crtr-recap` widget divides between the
2
+ // two chrome surfaces: the goal pins to the header above the transcript, and
3
+ // everything else (the state line) rides the widget's own cockpit slot above
4
+ // the editor. The `Goal:`/`State:` prefixes are the widget's transport format,
5
+ // not chrome — both surfaces strip them before painting.
6
+ export function splitRecapLines(lines) {
7
+ const goal = [];
8
+ const state = [];
9
+ for (const line of lines) {
10
+ const goalMatch = /^Goal:\s*/.exec(line);
11
+ if (goalMatch !== null) {
12
+ goal.push(line.slice(goalMatch[0].length));
13
+ continue;
14
+ }
15
+ const stateMatch = /^State:\s*/.exec(line);
16
+ state.push(stateMatch === null ? line : line.slice(stateMatch[0].length));
17
+ }
18
+ return { goal, state };
19
+ }
@@ -20,6 +20,9 @@ export interface StatusLineHooks {
20
20
  * a LOCAL in-tmux attach: a remote attach's local inbox registry cannot open
21
21
  * the remote canvas's filesystem tickets. */
22
22
  inboxAffordance: boolean;
23
+ /** Whether mouse reporting is currently enabled. When false, displays a
24
+ * low-priority 'mouse off' indicator in the status bar. */
25
+ mouseEnabled: () => boolean;
23
26
  }
24
27
  export interface AttachStatusLine {
25
28
  /** Repaint the bar from current state. */
@@ -76,6 +76,11 @@ export function createStatusLine(s, hooks) {
76
76
  segs.push(pal.muted(`⚑ ${total} · ${inboxOpenHint(bindings)}`));
77
77
  }
78
78
  }
79
+ // Mouse reporting state: show "mouse off" when reporting is disabled, so
80
+ // users are aware that tmux drag-select and copy-mode mouse work again.
81
+ if (!hooks.mouseEnabled()) {
82
+ segs.push(pal.muted('mouse off'));
83
+ }
79
84
  // Lowest-priority segment (R4): the Alt+C -> b hint, shown only once the
80
85
  // oldest still-foreground bash job has crossed the threshold. Read straight
81
86
  // off this node's job files rather than tracked from relayed tool-execution
@@ -3,36 +3,26 @@
3
3
  // the editor. Both read the folded `SessionState` the orchestrator owns, so it
4
4
  // arrives as a getter rather than a captured value.
5
5
  import { Text, truncateToWidth, wrapTextWithAnsi } from '@earendil-works/pi-tui';
6
- import { DynamicBorder } from '@earendil-works/pi-coding-agent';
6
+ import { splitRecapLines } from './recap.js';
7
7
  export function createChromeWidgets(ctx, state) {
8
8
  const { tui, pal } = ctx;
9
- const { chrome, aboveWidgets, belowWidgets, queued } = ctx.containers;
10
- /** A recap line is `Goal:`/`State:` + body — bold the label, faint the body.
11
- * Styled BEFORE wrapping (wrapTextWithAnsi carries SGR state across wraps),
12
- * so a wrapped continuation stays faint. Unlabeled lines are all-faint. */
13
- const styleRecapLine = (line) => {
14
- const m = /^(Goal|State):\s*/.exec(line);
15
- if (m === null)
16
- return pal.faint(line);
17
- return `${pal.bold(m[1] + ':')} ${pal.faint(line.slice(m[0].length))}`;
18
- };
19
- /** Paint serializable extension widgets into their fixed cockpit slots. The
20
- * recap sits immediately above the editor border and uses the faint palette:
21
- * persistent orientation, but visually a side note rather than primary UI. */
9
+ const { aboveWidgets, belowWidgets, queued } = ctx.containers;
10
+ /** Paint serializable extension widgets into their fixed cockpit slots. */
22
11
  const renderExtensionWidgets = () => {
23
12
  const session = state();
24
13
  aboveWidgets.clear();
25
14
  belowWidgets.clear();
26
- // The brief is an inline annotation, so do not give it the chat/chrome divider
27
- // that would make it read as a separate panel.
28
- chrome.clear();
29
- if (session.display.widgets['crtr-recap'] === undefined)
30
- chrome.addChild(new DynamicBorder(pal.border));
15
+ // The recap widget is split: its goal line is painted by the pinned
16
+ // header, while its state line lands here in the widget's own cockpit
17
+ // slot, label stripped and faint.
31
18
  const span = Math.max(1, (process.stdout.columns ?? 80) - 2);
32
19
  for (const [key, widget] of Object.entries(session.display.widgets)) {
20
+ const recap = key === 'crtr-recap';
21
+ const lines = recap ? splitRecapLines(widget.lines).state : widget.lines;
33
22
  const target = widget.placement === 'belowEditor' ? belowWidgets : aboveWidgets;
34
- for (const line of widget.lines) {
35
- const styled = key === 'crtr-recap' ? styleRecapLine(line) : line;
23
+ for (const line of lines) {
24
+ // Styled before wrapping so a wrapped continuation stays faint.
25
+ const styled = recap ? pal.faint(line) : line;
36
26
  for (const wrapped of wrapTextWithAnsi(styled, span)) {
37
27
  target.addChild(new Text(wrapped, 1, 0));
38
28
  }
@@ -2,12 +2,11 @@
2
2
  //
3
3
  // This module holds only the command metadata (help schema, flags) and the
4
4
  // thin `run` entry. It is deliberately kept OFF the heavy pi-coding-agent module
5
- // graph so that registering the `surface` subtree — for `surface view`,
6
- // `surface web`, `surface workspace`, `surface tmux-spread`, and every
7
- // `surface -h` render — costs a cheap command-framework load, not the ~363ms
8
- // ESM load of the esbuild-bundled attach viewer (`viewer.ts`, which pulls
9
- // pi-coding-agent's babel/highlight.js). The viewer runtime is dynamically
10
- // imported inside `run`, so the bundle loads ONLY when a viewer actually opens.
5
+ // graph so registering the `surface` subtree costs a cheap command-framework
6
+ // load, not the ~363ms ESM load of the esbuild-bundled attach viewer (`viewer.ts`,
7
+ // which pulls pi-coding-agent's babel/highlight.js). The viewer runtime is
8
+ // dynamically imported inside `run`, so the bundle loads ONLY when a viewer
9
+ // actually opens.
11
10
  import { defineBranch, defineLeaf } from '../../core/command.js';
12
11
  import { mark } from '../../core/timing.js';
13
12
  const attachToLeaf = defineLeaf({
@@ -74,7 +73,12 @@ const attachToLeaf = defineLeaf({
74
73
  const { runAttach } = await import('./viewer.js');
75
74
  mark('viewer.bundle_loaded');
76
75
  await runAttach(nodeId, observer, canvasName);
77
- return;
76
+ // The session has sent its final broker frame and restored the terminal.
77
+ // Force this one-shot viewer process out now: pi's bundled UI dependencies
78
+ // can retain libuv handles after their visible work is finished. The exit
79
+ // handler registered by teardown still runs, so terminal restoration remains
80
+ // safe if the normal path raced a signal.
81
+ process.exit(0);
78
82
  },
79
83
  render: (result) => (result['note'] !== undefined ? String(result['note']) : ''),
80
84
  });
@@ -63,6 +63,10 @@ export interface AttachPalette {
63
63
  error: (s: string) => string;
64
64
  /** Warning / transient notices. Same constraint as `error` → ANSI yellow. */
65
65
  warning: (s: string) => string;
66
+ /** Added display-diff prefixes/line numbers. pi exposes no foreground role here. */
67
+ diffAdded: (s: string) => string;
68
+ /** Removed display-diff prefixes/line numbers. pi exposes no foreground role here. */
69
+ diffRemoved: (s: string) => string;
66
70
  /** Editor border for a SINGLE-`!` bash command (output IS added to the agent's
67
71
  * context). Dull/normal ANSI green — pi paints shell mode from its `bashMode`
68
72
  * theme color (default `green`), which pi does NOT re-export through its public
@@ -207,6 +207,7 @@ const RED = (s) => `\x1b[31m${s}\x1b[39m`;
207
207
  const YELLOW = (s) => `\x1b[33m${s}\x1b[39m`;
208
208
  const GREEN = (s) => `\x1b[32m${s}\x1b[39m`;
209
209
  const BRIGHT_GREEN = (s) => `\x1b[92m${s}\x1b[39m`;
210
+ const DIFF_REMOVED = (s) => `\x1b[91m${s}\x1b[39m`;
210
211
  // Terminals do not support alpha. This neutral charcoal is the dark-theme
211
212
  // equivalent of a low-opacity gray overlay, without borrowing the purple
212
213
  // selection surface used by interactive chrome.
@@ -264,6 +265,8 @@ export function attachPalette() {
264
265
  bold: md.bold,
265
266
  error: RED,
266
267
  warning: YELLOW,
268
+ diffAdded: GREEN,
269
+ diffRemoved: DIFF_REMOVED,
267
270
  bashMode: GREEN,
268
271
  bashModeAlt: BRIGHT_GREEN,
269
272
  surface: (line) => `${bgOn}${line.replace(/\x1b\[0m/g, `\x1b[0m${bgOn}`)}\x1b[49m`,