@crouton-kit/crouter 0.3.28 → 0.3.30

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 (324) hide show
  1. package/dist/build-root.d.ts +15 -7
  2. package/dist/build-root.js +48 -34
  3. package/dist/builtin-memory/crouter-development/marketplaces.md +7 -6
  4. package/dist/builtin-memory/crouter-development/personas/base-prompt.md +1 -1
  5. package/dist/builtin-memory/crouter-development/personas/orchestrator-prompt.md +1 -1
  6. package/dist/builtin-memory/crouter-development/personas.md +1 -1
  7. package/dist/builtin-memory/crouter-development/plugins.md +20 -18
  8. package/dist/builtin-memory/design.md +1 -1
  9. package/dist/builtin-memory/development.md +1 -1
  10. package/dist/builtin-memory/internal/INDEX.md +1 -1
  11. package/dist/builtin-memory/internal/examples/INDEX.md +1 -1
  12. package/dist/builtin-memory/internal/examples/imessage-assistant.md +2 -2
  13. package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
  14. package/dist/builtin-memory/internal/storage-tiers.md +1 -1
  15. package/dist/builtin-memory/planning.md +1 -1
  16. package/dist/builtin-memory/spec.md +6 -4
  17. package/dist/builtin-personas/orchestration-kernel.md +4 -5
  18. package/dist/builtin-personas/runtime-base.md +5 -4
  19. package/dist/builtin-personas/spec/PERSONA.md +8 -4
  20. package/dist/builtin-personas/spec/orchestrator.md +5 -3
  21. package/dist/builtin-personas/spec/requirements/PERSONA.md +10 -0
  22. package/dist/builtin-views/canvas/core.mjs +586 -0
  23. package/dist/builtin-views/canvas/text.mjs +58 -0
  24. package/dist/builtin-views/canvas/tui.mjs +165 -0
  25. package/dist/builtin-views/canvas/web.jsx +120 -0
  26. package/dist/builtin-views/git-pr/core.mjs +673 -0
  27. package/dist/builtin-views/git-pr/text.mjs +84 -0
  28. package/dist/builtin-views/git-pr/tui.mjs +302 -0
  29. package/dist/builtin-views/git-pr/web.jsx +216 -0
  30. package/dist/builtin-views/inbox/_lib/render.mjs +1 -3
  31. package/dist/builtin-views/inbox/core.mjs +1273 -0
  32. package/dist/builtin-views/inbox/text.mjs +73 -0
  33. package/dist/builtin-views/inbox/tui.mjs +312 -0
  34. package/dist/builtin-views/inbox/web.jsx +188 -0
  35. package/dist/builtin-views/linkedin/core.mjs +906 -0
  36. package/dist/builtin-views/linkedin/text.mjs +69 -0
  37. package/dist/builtin-views/linkedin/tui.mjs +427 -0
  38. package/dist/builtin-views/linkedin/web.jsx +206 -0
  39. package/dist/builtin-views/workspace-sidebar/core.mjs +621 -0
  40. package/dist/builtin-views/workspace-sidebar/text.mjs +53 -0
  41. package/dist/builtin-views/workspace-sidebar/tui.mjs +142 -0
  42. package/dist/builtin-views/workspace-sidebar/web.jsx +109 -0
  43. package/dist/cli.js +22 -17
  44. package/dist/clients/attach/__tests__/action-parity.test.js +48 -0
  45. package/dist/clients/attach/__tests__/clipboard-image.test.js +76 -0
  46. package/dist/clients/attach/__tests__/editor-newline.test.js +57 -0
  47. package/dist/clients/attach/__tests__/git-info.test.js +31 -0
  48. package/dist/clients/attach/__tests__/onrequest-wired.test.js +20 -0
  49. package/dist/clients/attach/__tests__/slash-quit-copy.test.js +42 -0
  50. package/dist/clients/attach/__tests__/titled-editor.test.js +39 -0
  51. package/dist/clients/attach/attach-cmd.js +282 -46
  52. package/dist/clients/attach/auth-pickers.d.ts +9 -0
  53. package/dist/clients/attach/auth-pickers.js +194 -0
  54. package/dist/clients/attach/canvas-panels.d.ts +4 -2
  55. package/dist/clients/attach/canvas-panels.js +45 -17
  56. package/dist/clients/attach/chat-view.d.ts +27 -2
  57. package/dist/clients/attach/chat-view.js +98 -9
  58. package/dist/clients/attach/clipboard-image.d.ts +47 -8
  59. package/dist/clients/attach/clipboard-image.js +150 -26
  60. package/dist/clients/attach/clipboard-text.d.ts +3 -0
  61. package/dist/clients/attach/clipboard-text.js +39 -0
  62. package/dist/clients/attach/config-load.d.ts +54 -7
  63. package/dist/clients/attach/config-load.js +99 -3
  64. package/dist/clients/attach/context-message.d.ts +12 -0
  65. package/dist/clients/attach/context-message.js +72 -0
  66. package/dist/clients/attach/git-info.d.ts +20 -0
  67. package/dist/clients/attach/git-info.js +44 -0
  68. package/dist/clients/attach/graph-overlay.d.ts +13 -4
  69. package/dist/clients/attach/graph-overlay.js +59 -19
  70. package/dist/clients/attach/input-controller.d.ts +75 -13
  71. package/dist/clients/attach/input-controller.js +305 -67
  72. package/dist/clients/attach/pickers.d.ts +58 -0
  73. package/dist/clients/attach/pickers.js +171 -0
  74. package/dist/clients/attach/slash-commands.d.ts +22 -0
  75. package/dist/clients/attach/slash-commands.js +91 -25
  76. package/dist/clients/attach/titled-editor.d.ts +33 -0
  77. package/dist/clients/attach/titled-editor.js +84 -0
  78. package/dist/clients/attach/view-socket.d.ts +18 -1
  79. package/dist/clients/attach/view-socket.js +70 -1
  80. package/dist/clients/web/dev-server.d.ts +7 -0
  81. package/dist/clients/web/dev-server.js +59 -0
  82. package/dist/clients/web/events.d.ts +14 -0
  83. package/dist/clients/web/events.js +151 -0
  84. package/dist/clients/web/server.d.ts +18 -0
  85. package/dist/clients/web/server.js +450 -0
  86. package/dist/clients/web/web-cmd.d.ts +2 -0
  87. package/dist/clients/web/web-cmd.js +120 -0
  88. package/dist/commands/canvas.js +1 -2
  89. package/dist/commands/chord.js +4 -25
  90. package/dist/commands/dashboard.js +5 -1
  91. package/dist/commands/memory/__tests__/lint-schema.test.js +6 -6
  92. package/dist/commands/memory/lint.js +14 -2
  93. package/dist/commands/memory/read.js +2 -2
  94. package/dist/commands/memory/shared.d.ts +7 -1
  95. package/dist/commands/memory/shared.js +18 -3
  96. package/dist/commands/memory/write.js +8 -4
  97. package/dist/commands/memory.js +4 -4
  98. package/dist/commands/node.d.ts +1 -1
  99. package/dist/commands/node.js +64 -65
  100. package/dist/commands/pkg.js +1 -2
  101. package/dist/commands/revive.js +11 -3
  102. package/dist/commands/sys/sync.d.ts +1 -0
  103. package/dist/commands/sys/sync.js +187 -0
  104. package/dist/commands/sys.js +3 -2
  105. package/dist/commands/view-cycle.js +2 -2
  106. package/dist/commands/view-list.js +8 -8
  107. package/dist/commands/view-new.js +21 -17
  108. package/dist/commands/view-pick.js +1 -1
  109. package/dist/commands/view-run.js +35 -14
  110. package/dist/commands/view.js +8 -6
  111. package/dist/commands/workspace.d.ts +2 -0
  112. package/dist/commands/workspace.js +161 -0
  113. package/dist/core/__tests__/broker-double-spawn.test.d.ts +1 -0
  114. package/dist/core/__tests__/broker-double-spawn.test.js +143 -0
  115. package/dist/core/__tests__/broker-fork-seam.test.d.ts +1 -0
  116. package/dist/core/__tests__/broker-fork-seam.test.js +102 -0
  117. package/dist/core/__tests__/broker-sdk-wiring.test.js +2 -0
  118. package/dist/core/__tests__/child-death-wake.test.js +56 -111
  119. package/dist/core/__tests__/close.test.js +14 -20
  120. package/dist/core/__tests__/context-intro.test.js +19 -19
  121. package/dist/core/__tests__/daemon-boot.test.js +30 -23
  122. package/dist/core/__tests__/draw-style.test.js +1 -1
  123. package/dist/core/__tests__/error-stall-recycle.test.d.ts +1 -0
  124. package/dist/core/__tests__/error-stall-recycle.test.js +141 -0
  125. package/dist/core/__tests__/fixtures/fake-engine.d.ts +17 -1
  126. package/dist/core/__tests__/fixtures/fake-engine.js +22 -2
  127. package/dist/core/__tests__/fixtures/fake-pi-host.js +2 -2
  128. package/dist/core/__tests__/focuses.test.js +25 -13
  129. package/dist/core/__tests__/fork.test.js +22 -5
  130. package/dist/core/__tests__/full/broker-control-preempt.test.d.ts +1 -0
  131. package/dist/core/__tests__/full/broker-control-preempt.test.js +61 -0
  132. package/dist/core/__tests__/full/broker-model-changed-broadcast.test.d.ts +1 -0
  133. package/dist/core/__tests__/full/broker-model-changed-broadcast.test.js +57 -0
  134. package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.d.ts +1 -0
  135. package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.js +80 -0
  136. package/dist/core/__tests__/full/broker-pane-resolution.test.js +90 -0
  137. package/dist/core/__tests__/full/cascade-close.test.js +22 -8
  138. package/dist/core/__tests__/full/detach-focus.test.js +66 -169
  139. package/dist/core/__tests__/helpers/harness.d.ts +6 -9
  140. package/dist/core/__tests__/helpers/harness.js +19 -36
  141. package/dist/core/__tests__/human-node-not-supervised.test.d.ts +1 -0
  142. package/dist/core/__tests__/human-node-not-supervised.test.js +83 -0
  143. package/dist/core/__tests__/lifecycle.test.js +1 -19
  144. package/dist/core/__tests__/listing-completeness.test.js +2 -2
  145. package/dist/core/__tests__/live-mutation-verbs.test.js +5 -5
  146. package/dist/core/__tests__/memory-resolver.test.js +1 -1
  147. package/dist/core/__tests__/on-read-dedup-resume.test.js +2 -2
  148. package/dist/core/__tests__/refresh-stall-recycle.test.d.ts +1 -0
  149. package/dist/core/__tests__/refresh-stall-recycle.test.js +88 -0
  150. package/dist/core/__tests__/relaunch-root.test.d.ts +1 -0
  151. package/dist/core/__tests__/relaunch-root.test.js +114 -0
  152. package/dist/core/__tests__/reset.test.js +19 -79
  153. package/dist/core/__tests__/steer-note.test.js +9 -7
  154. package/dist/core/__tests__/tmux-surface.test.js +13 -7
  155. package/dist/core/bootstrap.d.ts +0 -3
  156. package/dist/core/bootstrap.js +1 -143
  157. package/dist/core/canvas/browse/__tests__/model.test.js +86 -1
  158. package/dist/core/canvas/browse/__tests__/render.test.js +2 -1
  159. package/dist/core/canvas/browse/app.js +131 -8
  160. package/dist/core/canvas/browse/model.d.ts +23 -5
  161. package/dist/core/canvas/browse/model.js +68 -13
  162. package/dist/core/canvas/browse/render.d.ts +7 -1
  163. package/dist/core/canvas/browse/render.js +178 -47
  164. package/dist/core/canvas/canvas.js +1 -1
  165. package/dist/core/canvas/focuses.d.ts +4 -4
  166. package/dist/core/canvas/focuses.js +7 -7
  167. package/dist/core/canvas/nav-model.js +8 -7
  168. package/dist/core/canvas/render.d.ts +68 -9
  169. package/dist/core/canvas/render.js +195 -61
  170. package/dist/core/canvas/types.d.ts +16 -23
  171. package/dist/core/config.js +1 -4
  172. package/dist/core/memory-resolver.js +43 -5
  173. package/dist/core/runtime/bearings.d.ts +1 -1
  174. package/dist/core/runtime/bearings.js +8 -8
  175. package/dist/core/runtime/branded-host.d.ts +16 -0
  176. package/dist/core/runtime/branded-host.js +127 -0
  177. package/dist/core/runtime/broker-protocol.d.ts +212 -6
  178. package/dist/core/runtime/broker.d.ts +4 -1
  179. package/dist/core/runtime/broker.js +494 -58
  180. package/dist/core/runtime/close.d.ts +12 -2
  181. package/dist/core/runtime/close.js +37 -16
  182. package/dist/core/runtime/front-door.js +6 -14
  183. package/dist/core/runtime/host.d.ts +14 -34
  184. package/dist/core/runtime/host.js +14 -50
  185. package/dist/core/runtime/launch.d.ts +12 -9
  186. package/dist/core/runtime/launch.js +27 -15
  187. package/dist/core/runtime/lifecycle.d.ts +1 -1
  188. package/dist/core/runtime/lifecycle.js +15 -19
  189. package/dist/core/runtime/nodes.d.ts +0 -55
  190. package/dist/core/runtime/nodes.js +6 -74
  191. package/dist/core/runtime/placement.d.ts +91 -335
  192. package/dist/core/runtime/placement.js +291 -858
  193. package/dist/core/runtime/promote.d.ts +2 -0
  194. package/dist/core/runtime/promote.js +24 -6
  195. package/dist/core/runtime/recap.d.ts +8 -0
  196. package/dist/core/runtime/recap.js +107 -0
  197. package/dist/core/runtime/recycle.js +25 -61
  198. package/dist/core/runtime/reset.d.ts +43 -37
  199. package/dist/core/runtime/reset.js +131 -218
  200. package/dist/core/runtime/revive.d.ts +9 -29
  201. package/dist/core/runtime/revive.js +40 -139
  202. package/dist/core/runtime/spawn.d.ts +15 -16
  203. package/dist/core/runtime/spawn.js +165 -194
  204. package/dist/core/runtime/surface-bg.d.ts +11 -0
  205. package/dist/core/runtime/surface-bg.js +68 -0
  206. package/dist/core/runtime/tmux.d.ts +15 -52
  207. package/dist/core/runtime/tmux.js +35 -99
  208. package/dist/core/scope.d.ts +1 -2
  209. package/dist/core/scope.js +1 -5
  210. package/dist/core/skill-sync/__tests__/dry-run-wrote-count.test.d.ts +1 -0
  211. package/dist/core/skill-sync/__tests__/dry-run-wrote-count.test.js +57 -0
  212. package/dist/core/skill-sync/builtins.d.ts +42 -0
  213. package/dist/core/skill-sync/builtins.js +112 -0
  214. package/dist/core/skill-sync/claude-plugins.d.ts +23 -0
  215. package/dist/core/skill-sync/claude-plugins.js +71 -0
  216. package/dist/core/skill-sync/engine.d.ts +42 -0
  217. package/dist/core/skill-sync/engine.js +633 -0
  218. package/dist/core/skill-sync/export.d.ts +23 -0
  219. package/dist/core/skill-sync/export.js +86 -0
  220. package/dist/core/skill-sync/manifest.d.ts +64 -0
  221. package/dist/core/skill-sync/manifest.js +181 -0
  222. package/dist/core/skill-sync/profile.d.ts +76 -0
  223. package/dist/core/skill-sync/profile.js +173 -0
  224. package/dist/core/skill-sync/snapshot.d.ts +57 -0
  225. package/dist/core/skill-sync/snapshot.js +120 -0
  226. package/dist/core/substrate/index.d.ts +1 -1
  227. package/dist/core/substrate/index.js +1 -1
  228. package/dist/core/substrate/injected-store.js +3 -3
  229. package/dist/core/substrate/on-read.js +68 -6
  230. package/dist/core/substrate/render.d.ts +8 -11
  231. package/dist/core/substrate/render.js +29 -43
  232. package/dist/core/substrate/schema.d.ts +10 -3
  233. package/dist/core/substrate/schema.js +6 -3
  234. package/dist/core/tui/host.d.ts +12 -4
  235. package/dist/core/tui/host.js +280 -149
  236. package/dist/core/view/bridge.d.ts +10 -0
  237. package/dist/core/view/bridge.js +31 -0
  238. package/dist/core/view/chrome.d.ts +9 -0
  239. package/dist/core/view/chrome.js +22 -0
  240. package/dist/core/view/contract.d.ts +171 -0
  241. package/dist/core/view/contract.js +23 -0
  242. package/dist/core/view/loader.d.ts +31 -0
  243. package/dist/core/view/loader.js +188 -0
  244. package/dist/core/view/transport-local.d.ts +7 -0
  245. package/dist/core/view/transport-local.js +70 -0
  246. package/dist/core/view/transport.d.ts +4 -0
  247. package/dist/core/view/transport.js +15 -0
  248. package/dist/daemon/crtrd.d.ts +38 -27
  249. package/dist/daemon/crtrd.js +303 -376
  250. package/dist/daemon/manage.js +6 -1
  251. package/dist/index.js +1 -1
  252. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +28 -20
  253. package/dist/pi-extensions/canvas-context-intro.js +4 -4
  254. package/dist/pi-extensions/canvas-doc-substrate.js +16 -16
  255. package/dist/pi-extensions/canvas-nav.js +5 -0
  256. package/dist/pi-extensions/canvas-recap.d.ts +37 -0
  257. package/dist/pi-extensions/canvas-recap.js +236 -0
  258. package/dist/pi-extensions/canvas-resume.js +2 -1
  259. package/dist/pi-extensions/canvas-stophook.d.ts +14 -12
  260. package/dist/pi-extensions/canvas-stophook.js +87 -101
  261. package/dist/pi-extensions/canvas-view.js +2 -1
  262. package/dist/pi-extensions/widget-order-bus.d.ts +6 -0
  263. package/dist/pi-extensions/widget-order-bus.js +34 -0
  264. package/dist/prompts/view.d.ts +2 -2
  265. package/dist/prompts/view.js +145 -73
  266. package/dist/types.d.ts +1 -6
  267. package/dist/types.js +1 -3
  268. package/dist/web/ViewChrome.d.ts +7 -0
  269. package/dist/web/ViewChrome.js +28 -0
  270. package/dist/web/ViewPane.d.ts +39 -0
  271. package/dist/web/ViewPane.js +48 -0
  272. package/dist/web/index.d.ts +6 -0
  273. package/dist/web/index.js +16 -0
  274. package/dist/web/runtime.d.ts +39 -0
  275. package/dist/web/runtime.js +133 -0
  276. package/dist/web/states.d.ts +24 -0
  277. package/dist/web/states.js +24 -0
  278. package/dist/web/transport-http.d.ts +5 -0
  279. package/dist/web/transport-http.js +28 -0
  280. package/dist/web-client/assets/index-BUvQb4hR.css +2 -0
  281. package/dist/web-client/assets/index-ClLQXYAE.js +10 -0
  282. package/dist/web-client/index.html +13 -0
  283. package/package.json +20 -6
  284. package/dist/builtin-views/canvas/client.mjs +0 -303
  285. package/dist/builtin-views/canvas/view.mjs +0 -576
  286. package/dist/builtin-views/git-pr/client.mjs +0 -440
  287. package/dist/builtin-views/git-pr/view.mjs +0 -675
  288. package/dist/builtin-views/inbox/sources/gmail.mjs +0 -965
  289. package/dist/builtin-views/inbox/sources/linkedin.mjs +0 -427
  290. package/dist/builtin-views/inbox/view.mjs +0 -889
  291. package/dist/builtin-views/linkedin/client.mjs +0 -610
  292. package/dist/builtin-views/linkedin/view.mjs +0 -1171
  293. package/dist/commands/pkg/bridge.d.ts +0 -1
  294. package/dist/commands/pkg/bridge.js +0 -137
  295. package/dist/commands/skill/author.d.ts +0 -3
  296. package/dist/commands/skill/author.js +0 -140
  297. package/dist/commands/skill/shared.d.ts +0 -3
  298. package/dist/commands/skill/shared.js +0 -19
  299. package/dist/commands/skill.d.ts +0 -2
  300. package/dist/commands/skill.js +0 -21
  301. package/dist/commands/tmux-spread.d.ts +0 -2
  302. package/dist/commands/tmux-spread.js +0 -144
  303. package/dist/core/__tests__/full/daemon-liveness-pane.full.test.js +0 -292
  304. package/dist/core/__tests__/full/placement-focus.test.js +0 -309
  305. package/dist/core/__tests__/full/placement-reconcile.test.js +0 -212
  306. package/dist/core/__tests__/full/placement-revive.test.js +0 -238
  307. package/dist/core/__tests__/full/placement-teardown.test.js +0 -297
  308. package/dist/core/__tests__/home-session.test.js +0 -186
  309. package/dist/core/__tests__/relaunch.test.js +0 -335
  310. package/dist/core/bridge-map.d.ts +0 -19
  311. package/dist/core/bridge-map.js +0 -73
  312. package/dist/core/tui/contract.d.ts +0 -83
  313. package/dist/core/tui/contract.js +0 -8
  314. package/dist/core/tui/loader.d.ts +0 -16
  315. package/dist/core/tui/loader.js +0 -94
  316. package/dist/prompts/skill.d.ts +0 -2
  317. package/dist/prompts/skill.js +0 -650
  318. /package/dist/{core/__tests__/full/daemon-liveness-pane.full.test.d.ts → clients/attach/__tests__/action-parity.test.d.ts} +0 -0
  319. /package/dist/{core/__tests__/full/placement-focus.test.d.ts → clients/attach/__tests__/clipboard-image.test.d.ts} +0 -0
  320. /package/dist/{core/__tests__/full/placement-reconcile.test.d.ts → clients/attach/__tests__/editor-newline.test.d.ts} +0 -0
  321. /package/dist/{core/__tests__/full/placement-revive.test.d.ts → clients/attach/__tests__/git-info.test.d.ts} +0 -0
  322. /package/dist/{core/__tests__/full/placement-teardown.test.d.ts → clients/attach/__tests__/onrequest-wired.test.d.ts} +0 -0
  323. /package/dist/{core/__tests__/home-session.test.d.ts → clients/attach/__tests__/slash-quit-copy.test.d.ts} +0 -0
  324. /package/dist/{core/__tests__/relaunch.test.d.ts → clients/attach/__tests__/titled-editor.test.d.ts} +0 -0
@@ -1,8 +1,10 @@
1
1
  import { type Component, type TUI } from '@earendil-works/pi-tui';
2
+ import type { AttachPalette } from './config-load.js';
2
3
  export declare class GraphOverlay implements Component {
3
4
  private readonly tui;
4
5
  private readonly self;
5
6
  private readonly getAsks;
7
+ private readonly palette;
6
8
  private handle;
7
9
  /** Manual fold OVERRIDES (h collapses → userCollapsed, l expands → userExpanded);
8
10
  * both override the default activity-driven policy and survive open/close. */
@@ -15,7 +17,7 @@ export declare class GraphOverlay implements Component {
15
17
  private scrollTop;
16
18
  /** Transient y/n confirm gate (kill). */
17
19
  private pendingConfirm;
18
- constructor(tui: TUI, self: string, getAsks: () => Record<string, number>);
20
+ constructor(tui: TUI, self: string, getAsks: () => Record<string, number>, palette: AttachPalette);
19
21
  isOpen(): boolean;
20
22
  open(): void;
21
23
  close(): void;
@@ -24,11 +26,18 @@ export declare class GraphOverlay implements Component {
24
26
  refresh(): void;
25
27
  invalidate(): void;
26
28
  render(width: number): string[];
29
+ /** A top/bottom border row: `<lc>─ <label> ────<rc>`, frame in the theme border
30
+ * color, the label keeping its own styling. The label is visible-truncated to
31
+ * the available span so a long label (a narrow pane, or a long `kill <name>?`
32
+ * confirm) never spills past the corner. */
33
+ private borderRow;
27
34
  handleInput(data: string): void;
28
35
  private dispatch;
29
- /** Swap `id` into THIS viewer's tmux pane (mirrors canvas browse's return-pane
30
- * shell). Default --pane is the caller TMUX_PANE; we pass it explicitly when
31
- * set so the focus lands here even if env resolution differs. */
36
+ /** Focus node `id` from the overlay by shelling `crtr node focus <id> --pane <here>`.
37
+ * Under the one-viewer-per-node model `--pane` is the ANCHOR to open beside: if
38
+ * `id` has no viewer yet a fresh one splits beside this pane; if it already has
39
+ * one, that viewer is navigated in place (this pane is left as-is). We pass
40
+ * TMUX_PANE explicitly so the anchor is THIS pane even if env resolution differs. */
32
41
  private focusTarget;
33
42
  private shellCrtr;
34
43
  }
@@ -2,7 +2,8 @@
2
2
  //
3
3
  // Native reimplementation of canvas-nav.ts's GRAPH modal as a pi-tui OVERLAY
4
4
  // (the viewer has no pi extension host). `tui.showOverlay(this, …)` mounts this
5
- // Component full-screen and CAPTURES keyboard focus (mirrors extension-dialogs.ts);
5
+ // Component as a BOUNDED, centered modal (~72% of the terminal, themed frame) and
6
+ // CAPTURES keyboard focus (mirrors extension-dialogs.ts);
6
7
  // `OverlayHandle.hide()` tears it down and restores focus to the editor. While
7
8
  // shown, every key routes to handleInput() — a fold-aware NERDTree of the local
8
9
  // subscription graph with the canvas-nav keymap:
@@ -13,28 +14,30 @@
13
14
  // decoded with pi-tui's canonical matchesKey (kitty/CSI-u aware).
14
15
  //
15
16
  // Enter/m/x SHELL `crtr` out-of-process (node focus / node close) — the viewer
16
- // itself never spawns pi or opens a session (the §0 one-writer invariant); it
17
- // runs inside a tmux pane, so `crtr node focus --pane` swaps the chosen node in.
17
+ // itself never spawns pi or opens a session (the §0 one-writer invariant). It
18
+ // passes its own pane as `crtr node focus --pane <anchor>`: under the
19
+ // one-viewer-per-node model the target's existing viewer is navigated in place,
20
+ // or a fresh viewer opens BESIDE this pane — never a second pane for the same node.
18
21
  import { execFile } from 'node:child_process';
19
- import { matchesKey } from '@earendil-works/pi-tui';
22
+ import { matchesKey, truncateToWidth } from '@earendil-works/pi-tui';
20
23
  import { fullName } from '../../core/canvas/index.js';
21
24
  import { beginFrame, cNode, managerOf, sortedChildIds, climbRoot, computeSubtreeActivity, buildGraphModel, renderGraphRow, focusedNodeIds, shortId, visibleWidth, VIEWPORT_FALLBACK_ROWS, DIM, RESET, BOLD, YELLOW, } from '../../core/canvas/nav-model.js';
22
- const OVERLAY_OPTIONS = { anchor: 'top-left', width: '100%', maxHeight: '100%' };
25
+ // A BOUNDED, centered modal (CTO ruling: not full-bleed). Width/height are capped
26
+ // at ~72% of the terminal; the overlay clips our lines to maxHeight, and render()
27
+ // budgets the panel to the SAME fraction (HEIGHT_PCT) so the framed box is never
28
+ // clipped. margin keeps it off the screen edges.
29
+ const HEIGHT_PCT = 0.72;
30
+ const OVERLAY_OPTIONS = { anchor: 'center', width: '72%', minWidth: 48, maxHeight: '72%', margin: 1 };
23
31
  // Viewer-specific hint: nav-model's shared GRAPH_HINT advertises "e expand",
24
32
  // but that key is the tmux pane-expand prefix-bind canvas-nav installs in its
25
33
  // host pane — the attach overlay has no such bind and swallows `e`, so the key
26
34
  // would do nothing here. Drop it.
27
35
  const GRAPH_HINT = `${DIM}jk move · hl fold · ↵ focus · x kill · m mgr · esc${RESET}`;
28
- /** Pad `s` out to `width` VISIBLE columns so the overlay line is opaque (no base
29
- * content bleeds through the right edge). Lines already wider are left as-is. */
30
- function padTo(s, width) {
31
- const pad = width - visibleWidth(s);
32
- return pad > 0 ? s + ' '.repeat(pad) : s;
33
- }
34
36
  export class GraphOverlay {
35
37
  tui;
36
38
  self;
37
39
  getAsks;
40
+ palette;
38
41
  handle;
39
42
  /** Manual fold OVERRIDES (h collapses → userCollapsed, l expands → userExpanded);
40
43
  * both override the default activity-driven policy and survive open/close. */
@@ -47,10 +50,11 @@ export class GraphOverlay {
47
50
  scrollTop = 0;
48
51
  /** Transient y/n confirm gate (kill). */
49
52
  pendingConfirm;
50
- constructor(tui, self, getAsks) {
53
+ constructor(tui, self, getAsks, palette) {
51
54
  this.tui = tui;
52
55
  this.self = self;
53
56
  this.getAsks = getAsks;
57
+ this.palette = palette;
54
58
  }
55
59
  isOpen() {
56
60
  return this.handle !== undefined;
@@ -102,9 +106,15 @@ export class GraphOverlay {
102
106
  cursorIdx = 0;
103
107
  }
104
108
  this.cursorId = rows[cursorIdx]?.id ?? this.self;
105
- // Full-screen budget: 1 title line + 1 footer hint, the rest for tree rows.
106
- const totalH = Math.max(6, process.stdout.rows ?? VIEWPORT_FALLBACK_ROWS);
107
- const treeArea = Math.max(2, totalH - 2);
109
+ // Bounded panel budget (centered modal, not full-bleed): the box height
110
+ // shrinks to content but is capped at HEIGHT_PCT of the terminal — matching
111
+ // the overlay's maxHeight so our framed lines are never clipped. 2 rows go to
112
+ // the top/bottom border, the rest to tree rows.
113
+ const term = process.stdout.rows ?? VIEWPORT_FALLBACK_ROWS;
114
+ // Never exceed the overlay's own maxHeight (term-2 after the margin), so the
115
+ // bottom border is never slice-clipped even on a very short terminal.
116
+ const maxPanelH = Math.max(3, Math.min(Math.floor(term * HEIGHT_PCT), term - 2));
117
+ const treeArea = Math.max(2, Math.min(rows.length, maxPanelH - 2));
108
118
  // Track the cursor within treeArea, reserving ↑/↓ "more" indicators. Up to
109
119
  // 4 passes converge the mutual dependency between window size and indicators
110
120
  // (an indicator steals a tree row → can re-home scrollTop → toggles the other
@@ -137,7 +147,35 @@ export class GraphOverlay {
137
147
  const hint = this.pendingConfirm !== undefined
138
148
  ? `${YELLOW}${this.pendingConfirm.label} ${BOLD}y/n${RESET}`
139
149
  : GRAPH_HINT;
140
- return [title, ...body, hint].map((line) => padTo(line, width));
150
+ // Frame the panel: title in the top border, hint in the bottom border, tree
151
+ // rows boxed with themed side bars (truncate/pad to the inner width so the
152
+ // right edge stays flush and opaque).
153
+ const B = this.palette.border;
154
+ const innerW = Math.max(1, width - 4); // "│ " + content + " │"
155
+ // Hard-cut (empty ellipsis) + pad to innerW: ANSI-aware, so the cursor fill
156
+ // bar reaches the right border flush with no stray "…" and the box edge is
157
+ // opaque.
158
+ const boxed = body.map((line) => `${B('│')} ${truncateToWidth(line, innerW, '', true)} ${B('│')}`);
159
+ // Paint the WHOLE modal — border rows + boxed body + opaque space-fill — on
160
+ // the theme's distinct-surface background (selectedBg) so the float reads as
161
+ // a separate surface, not a hole in the viewer behind it (CTO ruling).
162
+ const S = this.palette.surface;
163
+ return [
164
+ this.borderRow('╭', '╮', title, width),
165
+ ...boxed,
166
+ this.borderRow('╰', '╯', hint, width),
167
+ ].map(S);
168
+ }
169
+ /** A top/bottom border row: `<lc>─ <label> ────<rc>`, frame in the theme border
170
+ * color, the label keeping its own styling. The label is visible-truncated to
171
+ * the available span so a long label (a narrow pane, or a long `kill <name>?`
172
+ * confirm) never spills past the corner. */
173
+ borderRow(lc, rc, label, width) {
174
+ const B = this.palette.border;
175
+ const span = Math.max(1, width - 5); // lc ─ _ <span> _ ─… rc
176
+ const lbl = truncateToWidth(label, span, '…');
177
+ const fill = Math.max(0, width - 5 - visibleWidth(lbl));
178
+ return `${B(`${lc}─`)} ${lbl} ${B('─'.repeat(fill) + rc)}`;
141
179
  }
142
180
  // -------------------------------------------------------------------------
143
181
  handleInput(data) {
@@ -245,9 +283,11 @@ export class GraphOverlay {
245
283
  // key never reaches the editor underneath.
246
284
  }
247
285
  // -------------------------------------------------------------------------
248
- /** Swap `id` into THIS viewer's tmux pane (mirrors canvas browse's return-pane
249
- * shell). Default --pane is the caller TMUX_PANE; we pass it explicitly when
250
- * set so the focus lands here even if env resolution differs. */
286
+ /** Focus node `id` from the overlay by shelling `crtr node focus <id> --pane <here>`.
287
+ * Under the one-viewer-per-node model `--pane` is the ANCHOR to open beside: if
288
+ * `id` has no viewer yet a fresh one splits beside this pane; if it already has
289
+ * one, that viewer is navigated in place (this pane is left as-is). We pass
290
+ * TMUX_PANE explicitly so the anchor is THIS pane even if env resolution differs. */
251
291
  focusTarget(id) {
252
292
  const argv = ['node', 'focus', id];
253
293
  const pane = process.env['TMUX_PANE'];
@@ -1,6 +1,8 @@
1
1
  import type { CustomEditor } from '@earendil-works/pi-coding-agent';
2
- import type { KeybindingsManager, TUI } from '@earendil-works/pi-tui';
3
- import { type BrokerSnapshot, type ClientToBroker, type RpcExtensionUIRequest, type RpcExtensionUIResponse } from '../../core/runtime/broker-protocol.js';
2
+ import type { Component, KeybindingsManager, TUI } from '@earendil-works/pi-tui';
3
+ import { type BrokerDataFrame, type BrokerSnapshot, type ClientToBroker, type RpcExtensionUIRequest, type RpcExtensionUIResponse } from '../../core/runtime/broker-protocol.js';
4
+ import type { ReadOpRequest } from './view-socket.js';
5
+ import { type Picker, type PickerControls } from './pickers.js';
4
6
  export interface InputControllerHooks {
5
7
  /** Send a command frame to the broker. */
6
8
  onCommand: (frame: ClientToBroker) => void;
@@ -17,20 +19,50 @@ export interface InputControllerHooks {
17
19
  /** OPTIONAL: toggle the GRAPH overlay — forwarded to the slash context so
18
20
  * `/graph` opens/closes it (Unit Q wires it from runAttach). */
19
21
  onGraph?: () => void;
22
+ /** OPTIONAL: detach the viewer — forwarded to the slash context so `/quit`
23
+ * tears down the TUI/socket (the engine keeps running). Wired by attach-cmd. */
24
+ onQuit?: () => void;
25
+ /** OPTIONAL: copy the last assistant message to the clipboard — forwarded to
26
+ * the slash context so `/copy` works. Wired by attach-cmd (it owns ChatView). */
27
+ onCopy?: () => void;
28
+ /** OPTIONAL: Ctrl+O / app.tools.expand — flip global tool-output expansion in
29
+ * the render layer (ChatView owns the components). Absent → the key no-ops. */
30
+ onToggleToolsExpand?: () => void;
31
+ /** OPTIONAL: Ctrl+T / app.thinking.toggle — flip thinking-block visibility in
32
+ * the render layer. Absent → the key no-ops. */
33
+ onToggleThinking?: () => void;
34
+ /** OPTIONAL: issue a correlated read-op and resolve with the broker's `data`
35
+ * reply. MUST be wired by attach-cmd (`onRequest: (f) => socket.request(f)`)
36
+ * for the native pickers to work; when absent every picker degrades to a
37
+ * text-arg notice. */
38
+ onRequest?: (frame: ReadOpRequest) => Promise<BrokerDataFrame>;
39
+ /** OPTIONAL pair: mount/unmount a native picker INLINE in the viewer's layout
40
+ * (attach-cmd slots it directly under the editor). When BOTH are wired,
41
+ * showPicker uses them instead of a centered overlay; absent → overlay
42
+ * fallback. The controller stays layout-agnostic either way (T5/T7 own it). */
43
+ onMountPicker?: (component: Component) => void;
44
+ onUnmountPicker?: () => void;
45
+ /** OPTIONAL: open the native /login provider picker (viewer-local auth flow). */
46
+ openLoginPicker?: () => void;
47
+ /** OPTIONAL: open the native /logout provider picker (viewer-local auth flow). */
48
+ openLogoutPicker?: () => void;
20
49
  }
21
50
  export declare class InputController {
22
51
  private readonly tui;
23
52
  private readonly editor;
24
53
  private readonly keybindings;
25
54
  private readonly hooks;
26
- /** Images pasted since the last send, attached to the next prompt/follow-up. */
27
- private pendingImages;
28
- /** Running base64-byte total of `pendingImages` (review M2 aggregate budget). */
29
- private pendingImageBytes;
30
55
  /** The currently-rendered blocking dialog, if any (for supersede/dismiss). */
31
56
  private dialog;
57
+ /** The currently-open native picker overlay, if any (for supersede/dismiss). */
58
+ private picker;
59
+ /** Monotonic open counter — a slow read-op reply whose `seq` is no longer the
60
+ * latest is dropped, so an earlier picker never pops over a later request. */
61
+ private openSeq;
32
62
  /** Latest engine state from `welcome`/`session_info_changed` (for `/session`). */
33
63
  private state;
64
+ /** Timestamp of the last lone Esc, for double-tap → tree detection (0 = none). */
65
+ private lastEscapeAt;
34
66
  constructor(tui: TUI, editor: CustomEditor, keybindings: KeybindingsManager, hooks: InputControllerHooks);
35
67
  /** Render a blocking extension dialog and route its answer to the broker.
36
68
  * Supersedes any dialog already on screen (e.g. a re-route on control
@@ -41,20 +73,50 @@ export declare class InputController {
41
73
  setState(state: BrokerSnapshot['state']): void;
42
74
  private wire;
43
75
  private slashContext;
76
+ /** Send a command frame to the broker (picker selection sink). */
77
+ private send;
78
+ /** Fetch a picker payload (narrowed on `kind`), then build + show its overlay
79
+ * iff this open is still the latest (m4: a stale slow reply is dropped). Any
80
+ * failure — unwired channel, wrong kind, request error, or a throwing builder
81
+ * — surfaces a notice instead of an unhandled rejection (m5). */
82
+ private openPicker;
83
+ /** Show a picker built by `build` (given a `close` that tears it down).
84
+ * Mounted INLINE under the editor when attach-cmd wires onMountPicker/
85
+ * onUnmountPicker (the integrated chrome path); otherwise falls back to a
86
+ * centered overlay. Supersedes any picker already on screen. Routes focus to
87
+ * the builder's declared focus target (an inner list for fork/settings) and
88
+ * ALWAYS restores editor focus on close — `OverlayHandle.hide()` only
89
+ * auto-restores when the OUTER component held focus, which is not the case
90
+ * once we focus an inner child. A throwing builder is caught into a notice (m5). */
91
+ private showPicker;
92
+ private openModelPicker;
93
+ private openSessionPicker;
94
+ private openTreePicker;
95
+ private openForkPicker;
96
+ private openSettingsPicker;
97
+ private openScopedModelsPicker;
98
+ /** Open a viewer-local auth picker (login/logout) — uses the same showPicker
99
+ * machinery as read-op pickers, but with a locally-built component (no read-op
100
+ * request; auth operations are viewer-local in tmux-local attach). */
101
+ openAuthPicker(build: (controls: PickerControls) => Picker): void;
44
102
  private handleSubmit;
45
103
  private handleFollowUp;
104
+ /** Ctrl+G / app.editor.external — open the current editor text in $VISUAL/$EDITOR
105
+ * and load the saved result back. Ported from pi's `openExternalEditor`: stop
106
+ * the TUI to release the terminal, run the editor with inherited stdio, and on
107
+ * a clean exit (status 0) replace the editor text; the socket keeps running in
108
+ * the background throughout. */
109
+ private openExternalEditor;
110
+ /** Alt+Up / app.message.dequeue — clear the broker's queued steering + follow-up
111
+ * messages and restore them to the editor, prepended to any in-progress text
112
+ * (pi's `restoreQueuedMessagesToEditor`: queued text first, joined by blank
113
+ * lines). A read-AND-mutate op over the correlated request channel. */
114
+ private handleDequeue;
46
115
  /** Send a drive frame iff the WHOLE encoded frame fits under MAX_FRAME_BYTES
47
116
  * (the broker destroys the socket on any line over its 24 MiB read cap). Over
48
117
  * the ceiling → notify + refuse so the caller leaves the editor + pending
49
118
  * images intact for the user to trim, never a socket-destroying overflow. */
50
119
  private emitDrive;
51
120
  private handlePaste;
52
- /** Snapshot the pending images as an `images?` payload (undefined when none)
53
- * WITHOUT clearing — so a frame refused by `emitDrive` (too large) keeps them
54
- * for the user to trim. The caller clears via `clearPendingImages` only after a
55
- * successful send. */
56
- private pendingImagesPayload;
57
- /** Drop all pending images + reset the aggregate byte counter (after a send). */
58
- private clearPendingImages;
59
121
  private notify;
60
122
  }