@pellux/goodvibes-tui 2.0.20 → 2.1.0

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 (388) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/README.md +16 -16
  3. package/docs/README.md +4 -4
  4. package/docs/foundation-artifacts/operator-contract.json +59 -4
  5. package/package.json +16 -6
  6. package/src/cli/management.ts +5 -2
  7. package/src/cli/tui-startup.ts +34 -39
  8. package/src/core/agent-view-render.ts +157 -0
  9. package/src/core/approval-alert.ts +49 -11
  10. package/src/core/bookmark-navigation.ts +7 -1
  11. package/src/core/budget-breach-notifier.ts +27 -8
  12. package/src/core/compaction-receipt.ts +1 -1
  13. package/src/core/context-usage.ts +1 -1
  14. package/src/core/conversation-compaction-render.ts +3 -3
  15. package/src/core/conversation-display-only.ts +86 -0
  16. package/src/core/conversation-event-navigation.ts +27 -0
  17. package/src/core/conversation-line-cache.ts +216 -447
  18. package/src/core/conversation-render-context.ts +20 -27
  19. package/src/core/conversation-rendering.ts +157 -575
  20. package/src/core/conversation-splash-state.ts +6 -1
  21. package/src/core/conversation-types.ts +35 -0
  22. package/src/core/conversation-usage.ts +12 -0
  23. package/src/core/conversation.ts +130 -131
  24. package/src/core/long-task-notifier.ts +100 -31
  25. package/src/core/notices.ts +75 -0
  26. package/src/core/pairing-tailscale-gateway.ts +1 -1
  27. package/src/core/process-output-log.ts +143 -0
  28. package/src/core/rewind-receipt.ts +1 -1
  29. package/src/core/session-focus.ts +190 -0
  30. package/src/core/session-resume-core.ts +23 -81
  31. package/src/core/stream-event-wiring.ts +31 -5
  32. package/src/core/system-message-noise.ts +2 -2
  33. package/src/core/system-message-router.ts +16 -18
  34. package/src/core/turn-event-wiring.ts +272 -33
  35. package/src/core/work-tree-focus.ts +290 -0
  36. package/src/core/work-tree-fold-store.ts +143 -0
  37. package/src/core/work-tree-model.ts +799 -0
  38. package/src/core/work-tree-render.ts +384 -0
  39. package/src/core/work-tree-sources.ts +184 -0
  40. package/src/core/work-tree-wiring.ts +176 -0
  41. package/src/core/workstream-notification.ts +36 -6
  42. package/src/core/wrfc-notice-titles.ts +37 -0
  43. package/src/input/agents-modal-text.ts +119 -0
  44. package/src/input/agents-modal.ts +699 -0
  45. package/src/input/bookmark-modal.ts +33 -9
  46. package/src/input/changes-git.ts +251 -0
  47. package/src/input/changes-modal.ts +629 -0
  48. package/src/input/changes-model.ts +125 -0
  49. package/src/input/command-palette-types.ts +41 -0
  50. package/src/input/command-palette.ts +272 -0
  51. package/src/input/command-registry.ts +77 -35
  52. package/src/input/commands/acp-runtime.ts +19 -9
  53. package/src/input/commands/channel-runtime.ts +2 -2
  54. package/src/input/commands/ci-runtime.ts +1 -1
  55. package/src/input/commands/codebase-runtime.ts +1 -1
  56. package/src/input/commands/config.ts +7 -1
  57. package/src/input/commands/context-window.ts +25 -19
  58. package/src/input/commands/control-room-runtime.ts +18 -18
  59. package/src/input/commands/conversation-runtime.ts +0 -1
  60. package/src/input/commands/cost-runtime.ts +29 -20
  61. package/src/input/commands/diff-runtime.ts +35 -181
  62. package/src/input/commands/eval.ts +1 -1
  63. package/src/input/commands/experience-runtime.ts +3 -7
  64. package/src/input/commands/fresh-conversation.ts +86 -0
  65. package/src/input/commands/git-runtime.ts +5 -22
  66. package/src/input/commands/graph-runtime.ts +1 -1
  67. package/src/input/commands/guidance-runtime.ts +1 -1
  68. package/src/input/commands/health-runtime.ts +8 -9
  69. package/src/input/commands/hooks-runtime.ts +2 -2
  70. package/src/input/commands/hosted-runtime.ts +3 -3
  71. package/src/input/commands/incident-runtime.ts +3 -3
  72. package/src/input/commands/intelligence-runtime.ts +6 -9
  73. package/src/input/commands/knowledge.ts +2 -2
  74. package/src/input/commands/legacy-panel-command.ts +57 -0
  75. package/src/input/commands/local-auth-runtime.ts +8 -9
  76. package/src/input/commands/local-provider-runtime.ts +7 -4
  77. package/src/input/commands/local-runtime.ts +12 -15
  78. package/src/input/commands/local-setup-review.ts +1 -1
  79. package/src/input/commands/local-setup.ts +13 -19
  80. package/src/input/commands/memory.ts +1 -1
  81. package/src/input/commands/notify-runtime.ts +9 -0
  82. package/src/input/commands/operator-runtime.ts +10 -12
  83. package/src/input/commands/permissions-provenance.ts +3 -3
  84. package/src/input/commands/planning-runtime.ts +7 -7
  85. package/src/input/commands/platform-sandbox-runtime.ts +2 -2
  86. package/src/input/commands/platform-services-runtime.ts +1 -1
  87. package/src/input/commands/policy-dispatch.ts +2 -2
  88. package/src/input/commands/policy.ts +3 -3
  89. package/src/input/commands/provider.ts +1 -1
  90. package/src/input/commands/remote-runtime.ts +1 -1
  91. package/src/input/commands/review-runtime.ts +39 -94
  92. package/src/input/commands/rewind-runtime.ts +81 -108
  93. package/src/input/commands/runtime-services.ts +15 -17
  94. package/src/input/commands/services-runtime.ts +2 -2
  95. package/src/input/commands/session-content.ts +21 -5
  96. package/src/input/commands/session-workflow.ts +13 -38
  97. package/src/input/commands/settings-sync-runtime.ts +2 -2
  98. package/src/input/commands/shell-core.ts +19 -4
  99. package/src/input/commands/skills-runtime.ts +2 -2
  100. package/src/input/commands/status-runtime.ts +13 -0
  101. package/src/input/commands/subscription-runtime.ts +1 -1
  102. package/src/input/commands/tasks-runtime.ts +2 -8
  103. package/src/input/commands/work-plan-runtime.ts +4 -4
  104. package/src/input/commands/workstream-attempts.ts +24 -47
  105. package/src/input/commands/workstream-runtime.ts +2 -2
  106. package/src/input/commands/worktree-runtime.ts +3 -3
  107. package/src/input/commands.ts +3 -1
  108. package/src/input/composer-editor.ts +44 -0
  109. package/src/input/concealed-input.ts +1 -1
  110. package/src/input/config-modal-types.ts +20 -8
  111. package/src/input/config-modal.ts +106 -105
  112. package/src/input/confirm-dialog-types.ts +28 -0
  113. package/src/input/confirm-dialog.ts +70 -0
  114. package/src/input/delete-key-policy.ts +3 -3
  115. package/src/input/feed-context-factory.ts +15 -16
  116. package/src/input/handler-command-route.ts +7 -42
  117. package/src/input/handler-content-actions.ts +16 -15
  118. package/src/input/handler-feed-routes.ts +26 -211
  119. package/src/input/handler-feed.ts +68 -95
  120. package/src/input/handler-interactions.ts +5 -3
  121. package/src/input/handler-modal-routes.ts +215 -216
  122. package/src/input/handler-modal-stack.ts +81 -11
  123. package/src/input/handler-modal-token-routes.ts +4 -0
  124. package/src/input/handler-onboarding.ts +0 -1
  125. package/src/input/handler-picker-routes.ts +65 -107
  126. package/src/input/handler-session-view-route.ts +149 -0
  127. package/src/input/handler-shortcuts.ts +16 -154
  128. package/src/input/handler-types.ts +4 -2
  129. package/src/input/handler-ui-state.ts +45 -15
  130. package/src/input/handler-work-tree-route.ts +123 -0
  131. package/src/input/handler.ts +25 -70
  132. package/src/input/keybindings.ts +16 -71
  133. package/src/input/masked-entry-modal.ts +117 -0
  134. package/src/input/mcp-workspace.ts +48 -17
  135. package/src/input/model-picker-filter.ts +8 -0
  136. package/src/input/model-picker-open.ts +99 -0
  137. package/src/input/model-picker-types.ts +1 -1
  138. package/src/input/model-picker.ts +92 -9
  139. package/src/input/notifications-modal.ts +123 -0
  140. package/src/input/overlay-filter.ts +26 -0
  141. package/src/input/profile-picker-modal.ts +37 -8
  142. package/src/input/search.ts +3 -3
  143. package/src/input/selection-modal-queue.ts +2 -0
  144. package/src/input/selection-modal.ts +28 -16
  145. package/src/input/session-picker-modal.ts +33 -8
  146. package/src/input/settings-modal-activation.ts +7 -2
  147. package/src/input/settings-modal-data.ts +11 -6
  148. package/src/input/settings-modal-types.ts +1 -1
  149. package/src/input/settings-modal.ts +20 -20
  150. package/src/input/submission-intent.ts +1 -1
  151. package/src/input/submission-router.ts +4 -9
  152. package/src/input/surface-modal-host.ts +110 -0
  153. package/src/input/theme-settings-actions.ts +82 -0
  154. package/src/input/usage-modal.ts +183 -0
  155. package/src/input/views.ts +97 -0
  156. package/src/main.ts +175 -165
  157. package/src/permissions/hunk-selection.ts +1 -1
  158. package/src/permissions/prompt-card.ts +511 -0
  159. package/src/permissions/prompt.ts +59 -622
  160. package/src/renderer/agents-modal.ts +310 -0
  161. package/src/renderer/autocomplete-overlay.ts +42 -220
  162. package/src/renderer/back-to-bottom.ts +80 -0
  163. package/src/renderer/block-actions-overlay.ts +30 -48
  164. package/src/renderer/bookmark-modal.ts +48 -79
  165. package/src/renderer/changes-modal.ts +325 -0
  166. package/src/renderer/code-block.ts +184 -106
  167. package/src/renderer/command-palette.ts +93 -0
  168. package/src/renderer/composer-fragments.ts +4 -4
  169. package/src/renderer/composer.ts +146 -0
  170. package/src/renderer/compositor.ts +26 -160
  171. package/src/renderer/config-modal.ts +185 -81
  172. package/src/renderer/confirm-dialog.ts +50 -0
  173. package/src/renderer/context-inspector.ts +116 -154
  174. package/src/renderer/context-status-hint.ts +4 -4
  175. package/src/renderer/conversation-layout.ts +20 -0
  176. package/src/renderer/conversation-overlays.ts +94 -84
  177. package/src/renderer/conversation-surface.ts +19 -38
  178. package/src/renderer/diff-tint.ts +98 -0
  179. package/src/renderer/file-picker-overlay.ts +63 -90
  180. package/src/renderer/footer-targets.ts +38 -0
  181. package/src/renderer/git-status.ts +3 -4
  182. package/src/renderer/header-line.ts +140 -117
  183. package/src/renderer/help-overlay.ts +133 -219
  184. package/src/renderer/history-search-overlay.ts +15 -12
  185. package/src/renderer/lane-graph/bead.ts +800 -0
  186. package/src/renderer/lane-graph/glyphs.ts +134 -0
  187. package/src/renderer/lane-graph/layout.ts +248 -0
  188. package/src/renderer/lane-graph/paint.ts +537 -0
  189. package/src/renderer/lane-graph/semantic-memo.ts +77 -0
  190. package/src/renderer/layout-engine.ts +2 -57
  191. package/src/renderer/layout.ts +7 -13
  192. package/src/renderer/markdown-inline.ts +2 -1
  193. package/src/renderer/markdown-table.ts +17 -12
  194. package/src/renderer/markdown.ts +92 -34
  195. package/src/renderer/masked-entry-modal.ts +78 -0
  196. package/src/renderer/mcp-workspace.ts +166 -203
  197. package/src/renderer/model-workspace.ts +381 -436
  198. package/src/renderer/notifications-modal.ts +116 -0
  199. package/src/renderer/onboarding/onboarding-wizard.ts +178 -588
  200. package/src/renderer/process-view.ts +192 -0
  201. package/src/renderer/profile-picker-modal.ts +58 -110
  202. package/src/renderer/search-overlay.ts +6 -3
  203. package/src/renderer/selection-modal-overlay.ts +87 -327
  204. package/src/renderer/semantic-diff.ts +2 -2
  205. package/src/renderer/session-chips.ts +102 -0
  206. package/src/renderer/session-picker-modal.ts +177 -297
  207. package/src/renderer/settings-modal-connections.ts +14 -23
  208. package/src/renderer/settings-modal-context.ts +367 -0
  209. package/src/renderer/settings-modal-helpers.ts +6 -11
  210. package/src/renderer/settings-modal.ts +322 -726
  211. package/src/renderer/shell-surface.ts +277 -175
  212. package/src/renderer/shortcuts-overlay.ts +217 -0
  213. package/src/renderer/status-line.ts +475 -0
  214. package/src/renderer/surface-compose.ts +174 -0
  215. package/src/renderer/surface-kit-extra.ts +303 -0
  216. package/src/renderer/surface-kit-list.ts +366 -0
  217. package/src/renderer/surface-kit-parts.ts +360 -0
  218. package/src/renderer/surface-kit.ts +568 -0
  219. package/src/renderer/syntax-highlighter.ts +280 -197
  220. package/src/renderer/syntax-theme.ts +51 -0
  221. package/src/renderer/system-message.ts +0 -1
  222. package/src/renderer/term-caps.ts +42 -1
  223. package/src/renderer/terminal-bg-probe.ts +116 -19
  224. package/src/renderer/terminal-palette-probe.ts +322 -0
  225. package/src/renderer/terminal-palette-reader.ts +183 -0
  226. package/src/renderer/terminal-palette.ts +58 -0
  227. package/src/renderer/theme-mode-config.ts +16 -1
  228. package/src/renderer/theme.ts +234 -207
  229. package/src/renderer/thinking.ts +0 -1
  230. package/src/renderer/throbber.ts +188 -0
  231. package/src/renderer/toast-center.ts +119 -0
  232. package/src/renderer/ui-factory.ts +39 -602
  233. package/src/renderer/ui-primitives.ts +8 -25
  234. package/src/renderer/usage-modal.ts +353 -0
  235. package/src/renderer/user-message.ts +58 -0
  236. package/src/renderer/voice-capture-chip.ts +53 -0
  237. package/src/runtime/bootstrap-command-context.ts +0 -5
  238. package/src/runtime/bootstrap-command-parts.ts +38 -89
  239. package/src/runtime/bootstrap-core.ts +13 -15
  240. package/src/runtime/bootstrap-hook-bridge.ts +12 -21
  241. package/src/runtime/bootstrap-notifier-sync.ts +17 -1
  242. package/src/runtime/bootstrap-shell.ts +16 -50
  243. package/src/runtime/bootstrap.ts +14 -14
  244. package/src/runtime/client/fleet-union.ts +5 -5
  245. package/src/runtime/client/hosted-exit.ts +2 -2
  246. package/src/runtime/client/hosted-sessions.ts +1 -1
  247. package/src/runtime/client/spine-adoption.ts +1 -1
  248. package/src/runtime/context-accounting-source.ts +5 -4
  249. package/src/runtime/index.ts +1 -0
  250. package/src/runtime/notification-dispatch.ts +102 -29
  251. package/src/runtime/recovery-offer-wiring.ts +4 -1
  252. package/src/runtime/recovery-prompt.ts +31 -15
  253. package/src/runtime/runtime-services-types.ts +10 -6
  254. package/src/runtime/services.ts +17 -12
  255. package/src/runtime/session-continuity-hints.ts +2 -5
  256. package/src/runtime/session-inbound-inputs.ts +1 -1
  257. package/src/runtime/session-resume-liveness-confirm.ts +14 -2
  258. package/src/runtime/startup-typeahead-gate.ts +103 -0
  259. package/src/runtime/store/domains/domain-read-matrix.ts +0 -1
  260. package/src/runtime/store/domains/index.ts +0 -8
  261. package/src/runtime/store/selectors/index.ts +0 -28
  262. package/src/runtime/store/state.ts +0 -8
  263. package/src/runtime/ui-services.ts +4 -6
  264. package/src/runtime/usage-tracker.ts +348 -0
  265. package/src/runtime/wrfc-persistence.ts +4 -4
  266. package/src/shell/blocking-input.ts +92 -2
  267. package/src/shell/recovery-input-helpers.ts +1 -1
  268. package/src/shell/session-views.ts +539 -0
  269. package/src/shell/status-report.ts +86 -0
  270. package/src/shell/transcript-scroll.ts +68 -0
  271. package/src/shell/ui-openers.ts +84 -172
  272. package/src/shell/view-openers.ts +205 -0
  273. package/src/tools/wrfc-agent-guard.ts +22 -2
  274. package/src/utils/format-duration.ts +4 -8
  275. package/src/utils/splash-lines.ts +9 -1
  276. package/src/utils/terminal-width.ts +56 -0
  277. package/src/verification/verification-ledger.ts +18 -16
  278. package/src/{panels → views}/agent-inspector-shared.ts +2 -2
  279. package/src/{panels → views}/builtin-modals.ts +22 -21
  280. package/src/views/builtin-views.ts +135 -0
  281. package/src/{panels → views}/confirm-state.ts +9 -9
  282. package/src/{panels → views}/diff-review-model.ts +10 -3
  283. package/src/{panels → views}/eval-registry.ts +1 -1
  284. package/src/{panels → views}/fleet-acts.ts +49 -85
  285. package/src/{panels/fleet-panel-format.ts → views/fleet-format.ts} +40 -40
  286. package/src/{panels → views}/fleet-gateway.ts +5 -5
  287. package/src/{panels → views}/fleet-observed-render.ts +16 -16
  288. package/src/{panels → views}/fleet-read-model.ts +9 -9
  289. package/src/{panels/fleet-tabs.ts → views/fleet-session-tabs.ts} +13 -13
  290. package/src/{panels → views}/fleet-spawn.ts +33 -49
  291. package/src/{panels → views}/fleet-steer.ts +12 -12
  292. package/src/{panels → views}/fleet-stop.ts +4 -4
  293. package/src/{panels → views}/fleet-transcript.ts +26 -27
  294. package/src/{panels/fleet-panel-worktree-detail.ts → views/fleet-worktree-detail.ts} +7 -7
  295. package/src/{panels → views}/hosted-session-feed.ts +6 -6
  296. package/src/views/modal-surface-registry.ts +41 -0
  297. package/src/{panels → views}/modals/devices-modal.ts +2 -2
  298. package/src/{panels → views}/modals/hooks-modal.ts +13 -13
  299. package/src/{panels → views}/modals/keybindings-modal.ts +19 -27
  300. package/src/{panels → views}/modals/knowledge-modal.ts +6 -5
  301. package/src/{panels → views}/modals/local-auth-modal.ts +22 -21
  302. package/src/{panels → views}/modals/marketplace-modal.ts +11 -11
  303. package/src/{panels → views}/modals/memory-modal.ts +8 -8
  304. package/src/{panels → views}/modals/modal-surface-helpers.ts +15 -5
  305. package/src/{panels → views}/modals/pairing-modal.ts +9 -9
  306. package/src/{panels → views}/modals/planning-modal.ts +15 -20
  307. package/src/{panels → views}/modals/plugins-modal.ts +6 -6
  308. package/src/{panels → views}/modals/policy-modal.ts +13 -5
  309. package/src/{panels → views}/modals/provider-health-modal.ts +4 -4
  310. package/src/{panels → views}/modals/remote-modal.ts +3 -3
  311. package/src/{panels → views}/modals/sandbox-modal.ts +4 -4
  312. package/src/{panels → views}/modals/security-modal.ts +22 -16
  313. package/src/{panels → views}/modals/services-modal.ts +3 -3
  314. package/src/{panels → views}/modals/settings-sync-modal.ts +4 -4
  315. package/src/{panels → views}/modals/skills-modal.ts +9 -9
  316. package/src/{panels → views}/modals/subscription-modal.ts +3 -3
  317. package/src/{panels → views}/modals/work-plan-modal.ts +10 -13
  318. package/src/views/notifications-feed.ts +314 -0
  319. package/src/{panels → views}/polish-core.ts +38 -36
  320. package/src/{panels → views}/polish-tables.ts +35 -26
  321. package/src/{panels → views}/polish.ts +101 -95
  322. package/src/{panels → views}/project-planning-answer-actions.ts +3 -3
  323. package/src/{panels → views}/provider-health-routes.ts +14 -14
  324. package/src/{panels → views}/search-focus.ts +8 -8
  325. package/src/{panels → views}/session-maintenance.ts +11 -11
  326. package/src/views/skills-discovery.ts +159 -0
  327. package/src/views/view-deps.ts +80 -0
  328. package/src/views/view-panel-adapter.ts +53 -0
  329. package/src/{panels → views}/workstream-graph-render.ts +1 -1
  330. package/src/core/conversation-fold.ts +0 -101
  331. package/src/core/conversation-turn-structure.ts +0 -464
  332. package/src/core/conversation-user-receipts.ts +0 -42
  333. package/src/input/commands/operator-panel-runtime.ts +0 -186
  334. package/src/input/panel-integration-actions.ts +0 -33
  335. package/src/input/panel-mouse-geometry.ts +0 -97
  336. package/src/input/panel-paste-flood-guard.ts +0 -86
  337. package/src/panels/base-panel.ts +0 -301
  338. package/src/panels/builtin/agent.ts +0 -27
  339. package/src/panels/builtin/development.ts +0 -92
  340. package/src/panels/builtin/knowledge.ts +0 -12
  341. package/src/panels/builtin/operations.ts +0 -177
  342. package/src/panels/builtin/session.ts +0 -81
  343. package/src/panels/builtin/shared.ts +0 -357
  344. package/src/panels/builtin-panels.ts +0 -28
  345. package/src/panels/cost-tracker-panel.ts +0 -746
  346. package/src/panels/diff-panel.ts +0 -797
  347. package/src/panels/diff-review-panel.ts +0 -395
  348. package/src/panels/expandable-list-panel.ts +0 -189
  349. package/src/panels/fleet-deep-link.ts +0 -31
  350. package/src/panels/fleet-panel.ts +0 -799
  351. package/src/panels/git-panel.ts +0 -800
  352. package/src/panels/hosted-session-panel.ts +0 -221
  353. package/src/panels/index.ts +0 -21
  354. package/src/panels/local-auth-panel.ts +0 -478
  355. package/src/panels/notifications-feed.ts +0 -127
  356. package/src/panels/notifications-panel.ts +0 -160
  357. package/src/panels/panel-confirm-overlay.ts +0 -72
  358. package/src/panels/panel-manager.ts +0 -791
  359. package/src/panels/plugins-panel.ts +0 -371
  360. package/src/panels/scrollable-list-panel.ts +0 -498
  361. package/src/panels/skills-panel.ts +0 -454
  362. package/src/panels/token-budget-panel.ts +0 -688
  363. package/src/panels/types.ts +0 -191
  364. package/src/panels/wrfc-panel-format.ts +0 -133
  365. package/src/renderer/diff-view.ts +0 -134
  366. package/src/renderer/fleet-tab-strip.ts +0 -56
  367. package/src/renderer/footer-tips.ts +0 -53
  368. package/src/renderer/fullscreen-primitives.ts +0 -146
  369. package/src/renderer/fullscreen-workspace.ts +0 -194
  370. package/src/renderer/hint-grammar.ts +0 -52
  371. package/src/renderer/modal-factory.ts +0 -480
  372. package/src/renderer/overlay-box.ts +0 -154
  373. package/src/renderer/overlay-viewport.ts +0 -104
  374. package/src/renderer/panel-composite.ts +0 -145
  375. package/src/renderer/panel-workspace-bar.ts +0 -54
  376. package/src/renderer/process-indicator.ts +0 -163
  377. package/src/renderer/tab-strip.ts +0 -222
  378. package/src/renderer/text-layout.ts +0 -31
  379. package/src/renderer/tool-call.ts +0 -276
  380. package/src/renderer/tool-result-expanded-lines.ts +0 -48
  381. package/src/renderer/tool-result-summary.ts +0 -219
  382. package/src/runtime/diagnostics/panels/index.ts +0 -21
  383. package/src/runtime/diagnostics/panels/ops.ts +0 -156
  384. package/src/runtime/perf/panel-contracts.ts +0 -32
  385. package/src/runtime/store/domains/panels.ts +0 -117
  386. /package/src/{panels → views}/memory-consolidation-gateway.ts +0 -0
  387. /package/src/{panels → views}/modals/modal-theme.ts +0 -0
  388. /package/src/{panels → views}/provider-health-domains.ts +0 -0
@@ -1,18 +1,17 @@
1
1
  // ---------------------------------------------------------------------------
2
2
  // fleet-acts.ts
3
3
  //
4
- // The Fleet panel's waiting-on-human ACTS: the flagged pick row, the flagged
5
- // conflict row, and the worktree discard all act from the panel selection with
6
- // no id ever typed. This controller owns that flow so fleet-panel.ts stays under
7
- // the 800-line architecture cap, the panel delegates the trigger keys, the
8
- // pick-mode input, and the pick-mode render here.
4
+ // The waiting-on-human ACTS in the Agents modal: the flagged pick row, the
5
+ // flagged conflict row, and the worktree discard all act from the selected row
6
+ // with no id ever typed. This controller owns that flow; the Agents modal
7
+ // delegates the trigger keys and the pick-mode input here and draws pickView().
9
8
  //
10
9
  // • Pick , the flagged workstream row (needsAttention 'pick') opens a
11
10
  // candidate picker (best-of-N held attempts, from fleet.attempts.list);
12
- // ↑↓ chooses the winner, its diff shows in the shared DiffPanel, and Enter
11
+ // ↑↓ chooses the winner, Enter shows its diff in a Changes preview and
13
12
  // drives fleet.attempts.pick preview (confirm:false) -> confirm (confirm:true)
14
- // through the DiffPanel's existing confirm overlay. No group/candidate id is
15
- // ever typed, the panel derives them from the node and the selection.
13
+ // through the question on that preview. No group/candidate id is ever
14
+ // typed; they come from the node and the selection.
16
15
  // • Conflict, the flagged work-item row (needsAttention 'conflict') runs
17
16
  // fleet.conflicts.resolve and hands the STAMPED resolution session id to the
18
17
  // shared one-key jump/attach affordance (the CI fix-session machinery). On
@@ -25,17 +24,9 @@
25
24
  import type { ProcessNode } from '@pellux/goodvibes-sdk/platform/runtime/fleet';
26
25
  import type { WorkItem } from '@pellux/goodvibes-sdk/platform/orchestration';
27
26
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
28
- import type { Line } from '@pellux/goodvibes-sdk/platform/types';
29
- import { isPanelSearchBackspace, isPanelSearchCancel, isPanelSearchCommit, isPanelSearchPrintable } from './search-focus.ts';
30
- import { appendSteerText } from './fleet-tabs.ts';
27
+ import { isViewSearchBackspace, isViewSearchCancel, isViewSearchCommit, isViewSearchPrintable } from './search-focus.ts';
28
+ import { appendSteerText } from './fleet-session-tabs.ts';
31
29
  import { isObservedExternalNode, observedKindLabel, type ObservedNode } from './fleet-observed-render.ts';
32
- import {
33
- buildKeyboardHints,
34
- buildPanelWorkspace,
35
- DEFAULT_PANEL_PALETTE,
36
- type PanelPalette,
37
- } from './polish.ts';
38
- import { buildPanelLine } from './polish.ts';
39
30
  import { formatAgentCost } from './agent-inspector-shared.ts';
40
31
  import { fleetNodeAttention } from './fleet-read-model.ts';
41
32
  import {
@@ -48,11 +39,11 @@ import {
48
39
  type FleetHeldMergeGroup,
49
40
  } from './fleet-gateway.ts';
50
41
 
51
- /** The DiffPanel-backed surface the pick act reuses: show a diff, arm its confirm overlay, close it. */
42
+ /** The Changes-preview surface the pick act reuses: show a diff, ask over it, close it. */
52
43
  export interface FleetDiffSurface {
53
- /** Open + focus the diff panel showing this unified diff (title labels the candidate). */
44
+ /** Show this unified diff in a Changes preview (title labels the candidate). */
54
45
  show(title: string, unifiedDiff: string): void;
55
- /** Arm the diff panel's existing confirm overlay (Enter/y merges, n/Esc cancels). */
46
+ /** Ask a yes/no question over the preview (or in a confirm dialog when none is open). */
56
47
  armConfirm(opts: {
57
48
  readonly id: string;
58
49
  readonly label: string;
@@ -60,14 +51,14 @@ export interface FleetDiffSurface {
60
51
  readonly onConfirm: () => void | Promise<void>;
61
52
  readonly onCancel?: () => void;
62
53
  }): void;
63
- /** Close the diff panel and return focus to the prompt. */
54
+ /** Close the preview. */
64
55
  close(): void;
65
56
  }
66
57
 
67
58
  export interface FleetActsDeps {
68
59
  /** Resolve a live gateway per act (so a daemon that comes up mid-session is seen); honest unavailable reason otherwise. */
69
60
  readonly resolveGateway: () => FleetGatewayResolution;
70
- /** The shared DiffPanel surface (reused for candidate diffs + the pick confirm). */
61
+ /** The Changes preview surface (candidate diffs + the pick confirm). */
71
62
  readonly diffSurface: FleetDiffSurface;
72
63
  /** Surface a result/receipt/error line to the operator (system message, high priority). */
73
64
  readonly notify: (message: string) => void;
@@ -85,7 +76,15 @@ interface PickMode {
85
76
  selectedHeldIndex: number;
86
77
  }
87
78
 
88
- const C = DEFAULT_PANEL_PALETTE;
79
+ /** The candidate picker, as data the Agents modal draws. */
80
+ export interface FleetPickView {
81
+ readonly title: string;
82
+ readonly candidates: ReadonlyArray<{ readonly label: string; readonly detail: string; readonly selected: boolean }>;
83
+ /** The selected candidate's unified diff, or null when it has none. */
84
+ readonly diff: string | null;
85
+ /** The model's advisory proposal, or null. */
86
+ readonly proposal: string | null;
87
+ }
89
88
 
90
89
  function shortId(id: string): string {
91
90
  return id.length > 10 ? `${id.slice(0, 10)}…` : id;
@@ -120,7 +119,7 @@ export class FleetActs {
120
119
  /**
121
120
  * Dispatch an act-trigger key pressed on the tree while `node` is selected.
122
121
  * Returns true when consumed (an act fired), false to fall through to the
123
- * panel's ordinary key handling (so Enter still attaches an agent tab, etc.).
122
+ * Agents modal's ordinary key handling (so Enter still attaches an agent tab, etc.).
124
123
  */
125
124
  public handleTreeKey(key: string, node: ProcessNode): boolean {
126
125
  if (key === 'enter' || key === 'return') {
@@ -172,10 +171,10 @@ export class FleetActs {
172
171
  /** Input while the observed-steer composer is open (mirrors the tab steer composer). */
173
172
  public handleObservedSteerInput(key: string): boolean {
174
173
  if (!this.observedSteer) return false;
175
- if (isPanelSearchCancel(key)) { this.observedSteer = null; this.deps.markDirty(); return true; }
176
- if (isPanelSearchCommit(key)) { void this.submitObservedSteer(); return true; }
177
- if (isPanelSearchBackspace(key)) { this.observedSteer.draft = this.observedSteer.draft.slice(0, -1); this.deps.markDirty(); return true; }
178
- if (key.length === 1 && (isPanelSearchPrintable(key) || key === '\r' || key === '\n')) {
174
+ if (isViewSearchCancel(key)) { this.observedSteer = null; this.deps.markDirty(); return true; }
175
+ if (isViewSearchCommit(key)) { void this.submitObservedSteer(); return true; }
176
+ if (isViewSearchBackspace(key)) { this.observedSteer.draft = this.observedSteer.draft.slice(0, -1); this.deps.markDirty(); return true; }
177
+ if (key.length === 1 && (isViewSearchPrintable(key) || key === '\r' || key === '\n')) {
179
178
  this.observedSteer.draft = appendSteerText(this.observedSteer.draft, key);
180
179
  this.deps.markDirty();
181
180
  return true;
@@ -203,11 +202,11 @@ export class FleetActs {
203
202
  }
204
203
  }
205
204
 
206
- // ── Task-graph posture (in-panel edges/pool under a workstream) ───────────
205
+ // ── Task-graph posture (in-view edges/pool under a workstream) ───────────
207
206
 
208
207
  /**
209
208
  * Lazily fetch the task graph (fleet.graph.get) for a selected workstream row
210
- * so the in-panel detail can render its edges/pool posture WITHOUT opening
209
+ * so the in-view detail can render its edges/pool posture WITHOUT opening
211
210
  * /graph. Idempotent: fetches once per node (cache + in-flight guard), quiet
212
211
  * on an unavailable daemon (caches null rather than nagging every frame). A
213
212
  * no-op for any non-workstream node.
@@ -248,7 +247,6 @@ export class FleetActs {
248
247
  }
249
248
  if (!group) { this.deps.notify('No ready best-of-N group on this workstream; every attempt must settle first.'); return; }
250
249
  this.pick = { workstreamNodeId: node.id, group, selectedHeldIndex: 0 };
251
- this.showSelectedDiff();
252
250
  this.deps.markDirty();
253
251
  }
254
252
 
@@ -259,13 +257,11 @@ export class FleetActs {
259
257
  if (key === 'escape' || key === 'esc') { this.pick = null; this.deps.markDirty(); return true; }
260
258
  if (key === 'up' || key === 'k') {
261
259
  this.pick.selectedHeldIndex = (this.pick.selectedHeldIndex - 1 + held.length) % held.length;
262
- this.showSelectedDiff();
263
260
  this.deps.markDirty();
264
261
  return true;
265
262
  }
266
263
  if (key === 'down' || key === 'j') {
267
264
  this.pick.selectedHeldIndex = (this.pick.selectedHeldIndex + 1) % held.length;
268
- this.showSelectedDiff();
269
265
  this.deps.markDirty();
270
266
  return true;
271
267
  }
@@ -273,18 +269,9 @@ export class FleetActs {
273
269
  return true; // absorb every other key while the picker owns the view
274
270
  }
275
271
 
276
- private showSelectedDiff(): void {
277
- if (!this.pick) return;
278
- const cand = heldCandidates(this.pick.group)[this.pick.selectedHeldIndex];
279
- if (!cand) return;
280
- const diff = cand.diff?.unifiedDiff?.trim();
281
- if (diff) this.deps.diffSurface.show(cand.title, cand.diff!.unifiedDiff);
282
- else this.deps.diffSurface.show(cand.title, '@@ pick @@\n (no diff to preview for this candidate)');
283
- }
284
-
285
272
  /**
286
- * Drive fleet.attempts.pick preview (confirm:false) then, behind the DiffPanel
287
- * confirm overlay, confirm (confirm:true). No id is typed, the group id and
273
+ * Drive fleet.attempts.pick preview (confirm:false) then, behind the question
274
+ * on the candidate's Changes preview, confirm (confirm:true). No id is typed, the group id and
288
275
  * the winner item id both come from the picker state.
289
276
  */
290
277
  private async confirmSelectedPick(): Promise<void> {
@@ -394,48 +381,25 @@ export class FleetActs {
394
381
  return true;
395
382
  }
396
383
 
397
- // ── Render (pick mode) ────────────────────────────────────────────────────
384
+ // ── Pick mode, as data ────────────────────────────────────────────────────
398
385
 
399
- /** The candidate picker view (replaces the tree while pick mode is active). */
400
- public renderPickMode(width: number, height: number, palette: PanelPalette = C): Line[] {
401
- const P = palette;
402
- if (!this.pick) return [];
403
- const { group } = this.pick;
386
+ /** The candidate picker while pick mode is active, else null. */
387
+ public pickView(): FleetPickView | null {
388
+ if (!this.pick) return null;
389
+ const { group, selectedHeldIndex } = this.pick;
404
390
  const held = heldCandidates(group);
405
- const lines: Line[] = [];
406
- lines.push(buildPanelLine(width, [
407
- [' Best-of-N winner pick: ', P.label],
408
- [group.sourceTitle, P.value],
409
- ]));
410
- lines.push(buildPanelLine(width, [[' Choose the winner; its diff shows in the diff panel. No id is typed.', P.dim]]));
411
- lines.push(buildPanelLine(width, [['', P.dim]]));
412
- held.forEach((cand, index) => {
413
- const selected = index === this.pick!.selectedHeldIndex;
414
- const files = cand.diff ? `${cand.diff.files.length} file(s)` : 'no diff';
415
- const cost = cand.usage.costUsd !== null && cand.usage.costState !== 'unpriced'
416
- ? formatAgentCost(cand.usage.costUsd)
417
- : 'unpriced';
418
- lines.push(buildPanelLine(width, [
419
- [selected ? ' ▸ ' : ' ', selected ? P.info : P.dim],
420
- [`${cand.attemptIndex + 1}. `, P.label],
421
- [cand.title, selected ? P.value : P.dim],
422
- [`, ${files}, ${cost}`, P.dim],
423
- ]));
424
- });
425
- if (group.judgment?.proposedWinnerItemId) {
426
- const proposed = held.find((c) => c.itemId === group.judgment!.proposedWinnerItemId);
427
- lines.push(buildPanelLine(width, [['', P.dim]]));
428
- lines.push(buildPanelLine(width, [
429
- [' judge proposal (model, advisory): ', P.label],
430
- [proposed ? `attempt ${proposed.attemptIndex + 1}` : shortId(group.judgment.proposedWinnerItemId), P.info],
431
- ]));
432
- }
433
- const footerLines = [buildKeyboardHints(width, [
434
- { keys: '↑↓', label: 'choose' },
435
- { keys: 'Enter', label: 'pick (confirm)' },
436
- { keys: 'Esc', label: 'cancel' },
437
- ], P)];
438
- return buildPanelWorkspace(width, height, { title: 'Fleet: Pick winner', sections: [{ lines }], footerLines, palette: P });
391
+ const proposedId = group.judgment?.proposedWinnerItemId;
392
+ const proposed = proposedId ? held.find((c) => c.itemId === proposedId) : undefined;
393
+ return {
394
+ title: group.sourceTitle,
395
+ candidates: held.map((cand, index) => {
396
+ const files = cand.diff ? `${cand.diff.files.length} file${cand.diff.files.length === 1 ? '' : 's'}` : 'no diff';
397
+ const cost = cand.usage.costUsd !== null && cand.usage.costState !== 'unpriced' ? formatAgentCost(cand.usage.costUsd) : 'unpriced';
398
+ return { label: `${cand.attemptIndex + 1}. ${cand.title}`, detail: `${files} · ${cost}`, selected: index === selectedHeldIndex };
399
+ }),
400
+ proposal: proposedId ? (proposed ? `attempt ${proposed.attemptIndex + 1}` : shortId(proposedId)) : null,
401
+ diff: held[selectedHeldIndex]?.diff?.unifiedDiff?.trim() ? held[selectedHeldIndex]!.diff!.unifiedDiff : null,
402
+ };
439
403
  }
440
404
 
441
405
  private requireGateway(): FleetGateway | null {
@@ -1,33 +1,33 @@
1
1
  // ---------------------------------------------------------------------------
2
- // fleet-panel-format.ts
2
+ // fleet-format.ts
3
3
  //
4
- // Pure column-layout + cell-formatting helpers for FleetPanel's tree rows.
5
- // Extracted from fleet-panel.ts (file-size hygiene) to hold that file under the
6
- // 800-line architecture cap; these are stateless functions the panel's
4
+ // Pure column-layout + cell-formatting helpers for the Agents modal's tree rows.
5
+ // Extracted from src/input/agents-modal.ts (file-size hygiene) to hold that file under the
6
+ // 800-line architecture cap; these are stateless functions the Agents modal's
7
7
  // renderItem/renderDetail call, with no `this` dependency.
8
8
  // ---------------------------------------------------------------------------
9
9
 
10
10
  import type { ProcessCostState, ProcessNode, ProcessReviewSummary, ProcessUsage } from '@pellux/goodvibes-sdk/platform/runtime/fleet';
11
11
  import type { Line } from '@pellux/goodvibes-sdk/platform/types';
12
12
  import { formatAgentCost } from './agent-inspector-shared.ts';
13
- import { buildPanelLine, DEFAULT_PANEL_PALETTE, type ColumnSpec, type PanelPalette } from './polish.ts';
13
+ import { buildViewLine, DEFAULT_VIEW_PALETTE, type ColumnSpec, type ViewPalette } from './polish.ts';
14
14
  import { fleetAttentionText, fleetNodeAttention, fleetStallMarker, fleetUsageTokens, hasFleetCost, type FleetStateTone } from './fleet-read-model.ts';
15
15
  import { fleetStateDisplay } from './fleet-stop.ts';
16
16
  import { formatElapsed } from '../utils/format-elapsed.ts';
17
17
  import { truncateDisplay } from '../utils/terminal-width.ts';
18
- import { conflictFilesFromRaw, formatWorkItemIsolationDetailFromRaw } from './fleet-panel-worktree-detail.ts';
18
+ import { conflictFilesFromRaw, formatWorkItemIsolationDetailFromRaw } from './fleet-worktree-detail.ts';
19
19
  import { wrapText } from '../utils/terminal-width.ts';
20
20
  import { buildAlignedRow } from './polish.ts';
21
21
  import { fleetKindTag } from './fleet-read-model.ts';
22
22
  import { steerBadgeGlyph, steerBadgeTone } from './fleet-steer.ts';
23
- import type { SteerBadge } from './fleet-tabs.ts';
23
+ import type { SteerBadge } from './fleet-session-tabs.ts';
24
24
  import type { FleetTreeRow } from './fleet-read-model.ts';
25
25
  import { isObservedExternalNode, renderObservedDetailLines, renderObservedRowLine } from './fleet-observed-render.ts';
26
26
  import { renderPoolSummary, type WorkstreamGraphSnapshot } from './workstream-graph-render.ts';
27
27
 
28
28
  // Column widths for the tree row layout. `label` absorbs whatever width is
29
29
  // left over after the fixed columns + gaps; on hostile (narrow) widths the
30
- // trailing columns simply clip (buildAlignedRow/buildSelectablePanelLine stop
30
+ // trailing columns simply clip (buildAlignedRow/buildSelectableViewLine stop
31
31
  // writing once a cell would overflow the row) rather than throwing or
32
32
  // wrapping, the tree stays readable, just denser.
33
33
  const KIND_W = 8;
@@ -51,12 +51,12 @@ export function planColumns(width: number): ColumnSpec[] {
51
51
  ];
52
52
  }
53
53
 
54
- export function toneColor(tone: FleetStateTone, palette: PanelPalette): string {
54
+ export function toneColor(tone: FleetStateTone, palette: ViewPalette): string {
55
55
  switch (tone) {
56
- case 'active': return palette.info ?? DEFAULT_PANEL_PALETTE.info;
57
- case 'success': return palette.good ?? DEFAULT_PANEL_PALETTE.good;
58
- case 'failure': return palette.bad ?? DEFAULT_PANEL_PALETTE.bad;
59
- case 'warn': return palette.warn ?? DEFAULT_PANEL_PALETTE.warn;
56
+ case 'active': return palette.info ?? DEFAULT_VIEW_PALETTE.info;
57
+ case 'success': return palette.good ?? DEFAULT_VIEW_PALETTE.good;
58
+ case 'failure': return palette.bad ?? DEFAULT_VIEW_PALETTE.bad;
59
+ case 'warn': return palette.warn ?? DEFAULT_VIEW_PALETTE.warn;
60
60
  case 'muted': return palette.dim;
61
61
  }
62
62
  }
@@ -75,7 +75,7 @@ export function formatFleetCost(costUsd: number | null | undefined, costState: P
75
75
  }
76
76
 
77
77
  /**
78
- * One fleet tree row. Pure (extracted from FleetPanel.renderItem for the
78
+ * One fleet tree row. Pure (extracted from the Agents modal's row renderer for the
79
79
  * 800-line cap). Two display-only overrides in priority order: an in-flight
80
80
  * `stopping` wins the glyph/label/activity, then a `blocked`-on-user node gets
81
81
  * the ⚑ badge + 'blocked on you' in the activity slot. Otherwise a queued-steer
@@ -87,7 +87,7 @@ export function renderFleetRowLine(
87
87
  stopping: boolean,
88
88
  blocked: boolean,
89
89
  badge: SteerBadge | null,
90
- palette: PanelPalette = DEFAULT_PANEL_PALETTE,
90
+ palette: ViewPalette = DEFAULT_VIEW_PALETTE,
91
91
  ): Line {
92
92
  const C = palette;
93
93
  const node = row.node;
@@ -133,7 +133,7 @@ export function renderFleetRowLine(
133
133
  : badge
134
134
  ? steerBadgeTone(badge.status, C)
135
135
  : stallMarker
136
- ? (C.warn ?? DEFAULT_PANEL_PALETTE.warn)
136
+ ? (C.warn ?? DEFAULT_VIEW_PALETTE.warn)
137
137
  : C.dim;
138
138
 
139
139
  return buildAlignedRow(
@@ -153,7 +153,7 @@ export function renderFleetRowLine(
153
153
 
154
154
  /**
155
155
  * The selected-node detail block under the fleet tree. Pure (extracted from
156
- * FleetPanel.renderDetail to hold that file under the 800-line architecture
156
+ * the Agents modal's detail renderer to hold that file under the 800-line architecture
157
157
  * cap). `stopping`/`blocked` are display-only overrides the caller derives from
158
158
  * the stop tracker + node state, mirror the tree row exactly so the literal
159
159
  * 'state' text never claims a past-tense outcome mid-write, and a
@@ -166,13 +166,13 @@ export function renderFleetRowLine(
166
166
  * whether it was verified, the evidence, and (when present) how it was
167
167
  * exercised, matching what the webui's review detail surfaces.
168
168
  */
169
- export function renderReviewLines(review: ProcessReviewSummary, width: number, palette: PanelPalette = DEFAULT_PANEL_PALETTE): Line[] {
169
+ export function renderReviewLines(review: ProcessReviewSummary, width: number, palette: ViewPalette = DEFAULT_VIEW_PALETTE): Line[] {
170
170
  const C = palette;
171
171
  const passTone = C.good ?? C.info;
172
- const failTone = C.bad ?? C.warn ?? DEFAULT_PANEL_PALETTE.warn;
172
+ const failTone = C.bad ?? C.warn ?? DEFAULT_VIEW_PALETTE.warn;
173
173
  const cyclesLabel = review.cycles === 1 ? '1 cycle' : `${review.cycles} cycles`;
174
174
  const lines: Line[] = [
175
- buildPanelLine(width, [
175
+ buildViewLine(width, [
176
176
  [' review ', C.label],
177
177
  [review.passed ? '✓ passed' : '✗ not passed', review.passed ? passTone : failTone],
178
178
  [' score ', C.label], [String(review.score), C.value],
@@ -181,25 +181,25 @@ export function renderReviewLines(review: ProcessReviewSummary, width: number, p
181
181
  ];
182
182
  if (review.checklist.length === 0) {
183
183
  // Empty checklist is itself a gate failure, say so honestly, don't hide it.
184
- lines.push(buildPanelLine(width, [[' ', C.dim], ['(the reviewer emitted no acceptance checklist; a gate failure)', failTone]]));
184
+ lines.push(buildViewLine(width, [[' ', C.dim], ['(the reviewer emitted no acceptance checklist; a gate failure)', failTone]]));
185
185
  return lines;
186
186
  }
187
187
  for (const it of review.checklist) {
188
188
  const mark = it.verified ? '[verified] ' : '[unverified]';
189
189
  const markTone = it.verified ? passTone : failTone;
190
190
  wrapText(it.item, Math.max(1, width - 16)).forEach((seg, i) => {
191
- lines.push(buildPanelLine(width, i === 0
191
+ lines.push(buildViewLine(width, i === 0
192
192
  ? [[' ', C.dim], [`${mark} `, markTone], [seg, C.value]]
193
193
  : [[' ', C.dim], [seg, C.value]]));
194
194
  });
195
195
  if (it.evidence) {
196
196
  for (const seg of wrapText(`evidence: ${it.evidence}`, Math.max(1, width - 6))) {
197
- lines.push(buildPanelLine(width, [[' ', C.dim], [seg, C.dim]]));
197
+ lines.push(buildViewLine(width, [[' ', C.dim], [seg, C.dim]]));
198
198
  }
199
199
  }
200
200
  if (it.howExercised) {
201
201
  for (const seg of wrapText(`exercised: ${it.howExercised}`, Math.max(1, width - 6))) {
202
- lines.push(buildPanelLine(width, [[' ', C.dim], [seg, C.dim]]));
202
+ lines.push(buildViewLine(width, [[' ', C.dim], [seg, C.dim]]));
203
203
  }
204
204
  }
205
205
  }
@@ -212,22 +212,22 @@ export function renderReviewLines(review: ProcessReviewSummary, width: number, p
212
212
  * only via /graph, /graph still works). Fetched lazily and cached by fleet-acts;
213
213
  * rendered only once a snapshot is in hand. An empty graph states so honestly.
214
214
  */
215
- export function renderGraphPostureLines(graph: WorkstreamGraphSnapshot, width: number, palette: PanelPalette = DEFAULT_PANEL_PALETTE): Line[] {
215
+ export function renderGraphPostureLines(graph: WorkstreamGraphSnapshot, width: number, palette: ViewPalette = DEFAULT_VIEW_PALETTE): Line[] {
216
216
  const C = palette;
217
217
  const lines: Line[] = [
218
- buildPanelLine(width, [[' graph ', C.label], [renderPoolSummary(graph.pool), C.value]]),
218
+ buildViewLine(width, [[' graph ', C.label], [renderPoolSummary(graph.pool), C.value]]),
219
219
  ];
220
220
  if (graph.edges.length === 0) {
221
- lines.push(buildPanelLine(width, [[' ', C.dim], ['no dependency edges', C.dim]]));
221
+ lines.push(buildViewLine(width, [[' ', C.dim], ['no dependency edges', C.dim]]));
222
222
  return lines;
223
223
  }
224
224
  const titleById = new Map(graph.nodes.map((n) => [n.id, n.title]));
225
- lines.push(buildPanelLine(width, [[' edges ', C.label], [`${graph.edges.length} dependency link(s)`, C.value]]));
225
+ lines.push(buildViewLine(width, [[' edges ', C.label], [`${graph.edges.length} dependency link(s)`, C.value]]));
226
226
  for (const edge of graph.edges) {
227
227
  const from = titleById.get(edge.from) ?? edge.from;
228
228
  const to = titleById.get(edge.to) ?? edge.to;
229
229
  for (const seg of wrapText(`${from} → ${to}`, Math.max(1, width - 5))) {
230
- lines.push(buildPanelLine(width, [[' ', C.dim], [seg, C.dim]]));
230
+ lines.push(buildViewLine(width, [[' ', C.dim], [seg, C.dim]]));
231
231
  }
232
232
  }
233
233
  return lines;
@@ -238,7 +238,7 @@ export function renderFleetDetailLines(
238
238
  width: number,
239
239
  stopping: boolean,
240
240
  blocked: boolean,
241
- palette: PanelPalette = DEFAULT_PANEL_PALETTE,
241
+ palette: ViewPalette = DEFAULT_VIEW_PALETTE,
242
242
  observedSteerDraft: string | null = null,
243
243
  graphSnapshot: WorkstreamGraphSnapshot | null = null,
244
244
  ): Line[] {
@@ -257,7 +257,7 @@ export function renderFleetDetailLines(
257
257
  ? fleetAttentionText(fleetNodeAttention(node) ?? { reason: 'approval' })
258
258
  : disp.label;
259
259
 
260
- const line1 = buildPanelLine(width, [
260
+ const line1 = buildViewLine(width, [
261
261
  [' ', C.dim],
262
262
  [disp.glyph, color],
263
263
  [` ${node.kind}`, C.dim],
@@ -268,7 +268,7 @@ export function renderFleetDetailLines(
268
268
  [' elapsed ', C.label],
269
269
  [formatElapsed(node.elapsedMs), C.value],
270
270
  ]);
271
- const line2 = buildPanelLine(width, [
271
+ const line2 = buildViewLine(width, [
272
272
  [' model ', C.label],
273
273
  [node.model ?? 'unknown', C.info],
274
274
  [' tokens ', C.label],
@@ -284,20 +284,20 @@ export function renderFleetDetailLines(
284
284
  ? `${node.headline.text}${stallMarker ? ` · ${stallMarker}` : ''}`
285
285
  : stallMarker;
286
286
  const headlineLine = headlineText
287
- ? [buildPanelLine(width, [
287
+ ? [buildViewLine(width, [
288
288
  [' headline ', C.label],
289
- [truncateDisplay(headlineText, Math.max(0, width - 11)), stallMarker ? (C.warn ?? DEFAULT_PANEL_PALETTE.warn) : C.value],
289
+ [truncateDisplay(headlineText, Math.max(0, width - 11)), stallMarker ? (C.warn ?? DEFAULT_VIEW_PALETTE.warn) : C.value],
290
290
  ])]
291
291
  : [];
292
292
  const activityText = node.currentActivity
293
293
  ? `${node.currentActivity.kind}: ${node.currentActivity.text}`
294
294
  : '(no recent activity)';
295
- const line3 = buildPanelLine(width, [
295
+ const line3 = buildViewLine(width, [
296
296
  [' activity ', C.label],
297
297
  [truncateDisplay(activityText, Math.max(0, width - 11)), C.dim],
298
298
  ]);
299
299
  // Approval history attaches here once session tabs land.
300
- const line4 = buildPanelLine(width, [[' approvals ', C.label], ['—', C.dim]]);
300
+ const line4 = buildViewLine(width, [[' approvals ', C.label], ['—', C.dim]]);
301
301
  const isolationDetail = node.kind === 'work-item' ? formatWorkItemIsolationDetailFromRaw(node.raw) : null;
302
302
  // A merge-conflict row shows its STRUCTURED conflicting-path list, wrapped so a
303
303
  // long path is fully readable, never clipped (STEP 4: the conflict row acts,
@@ -305,13 +305,13 @@ export function renderFleetDetailLines(
305
305
  const conflictFiles = node.kind === 'work-item' ? conflictFilesFromRaw(node.raw) : null;
306
306
  const conflictLines: Line[] = conflictFiles
307
307
  ? [
308
- buildPanelLine(width, [[' conflicts ', C.label], [`${conflictFiles.length} file(s): press Enter to resolve`, C.warn ?? DEFAULT_PANEL_PALETTE.warn]]),
308
+ buildViewLine(width, [[' conflicts ', C.label], [`${conflictFiles.length} file(s): press Enter to resolve`, C.warn ?? DEFAULT_VIEW_PALETTE.warn]]),
309
309
  // Prefix is 3 spaces of indent + a 2-col bullet/continuation marker, so
310
310
  // wrap the path at width-5 to keep the composed line within `width`
311
311
  // (a hard-wrapped long path is fully readable, never clipped).
312
312
  ...conflictFiles.flatMap((file) =>
313
313
  wrapText(file, Math.max(1, width - 5)).map((segment, i) =>
314
- buildPanelLine(width, [[' ', C.dim], [i === 0 ? `• ${segment}` : ` ${segment}`, C.value]]),
314
+ buildViewLine(width, [[' ', C.dim], [i === 0 ? `• ${segment}` : ` ${segment}`, C.value]]),
315
315
  ),
316
316
  ),
317
317
  ]
@@ -320,7 +320,7 @@ export function renderFleetDetailLines(
320
320
  // (served on node.review; absent before any review, never an empty shell).
321
321
  const reviewLines = node.review ? renderReviewLines(node.review, width, C) : [];
322
322
  // The task graph's edges/pool posture for a workstream row (fetched + cached
323
- // by fleet-acts); rendered in-panel under the chain, /graph still available.
323
+ // by fleet-acts); rendered in-view under the chain, /graph still available.
324
324
  const graphLines = graphSnapshot ? renderGraphPostureLines(graphSnapshot, width, C) : [];
325
- return [line1, line2, ...headlineLine, line3, line4, ...(isolationDetail ? [buildPanelLine(width, [[' isolation ', C.label], [isolationDetail, C.dim]])] : []), ...conflictLines, ...reviewLines, ...graphLines];
325
+ return [line1, line2, ...headlineLine, line3, line4, ...(isolationDetail ? [buildViewLine(width, [[' isolation ', C.label], [isolationDetail, C.dim]])] : []), ...conflictLines, ...reviewLines, ...graphLines];
326
326
  }
@@ -1,7 +1,7 @@
1
1
  // ---------------------------------------------------------------------------
2
2
  // fleet-gateway.ts
3
3
  //
4
- // The async, daemon-backed verb surface the Fleet panel's waiting-on-human acts
4
+ // The async, daemon-backed verb surface the Agents modal's waiting-on-human acts
5
5
  // drive, a best-of-N winner pick (fleet.attempts.list / fleet.attempts.pick),
6
6
  // a merge-conflict resolution (fleet.conflicts.resolve), and a worktree discard
7
7
  // (worktrees.discard). These are gateway verbs with no named facade on the
@@ -9,10 +9,10 @@
9
9
  // go over the generic operator invoke path (operator-rpc.ts's resolveOperatorRpc
10
10
  // -> sdk.operator.invoke), reaching the SAME daemon the command layer does.
11
11
  //
12
- // The panel never types an id: it derives the workstream/work-item id from the
12
+ // The view never types an id: it derives the workstream/work-item id from the
13
13
  // selected node's namespaced id (workstream:<id> / work-item:<id>, the SDK's own
14
14
  // fleet-adapter id scheme) and drives the verbs from there. The interface is
15
- // injectable so the panel's act flow round-trips against a mocked daemon in
15
+ // injectable so the Agents modal's act flow round-trips against a mocked daemon in
16
16
  // tests; the live builder (createFleetGateway) is wired in builtin/operations.ts.
17
17
  // ---------------------------------------------------------------------------
18
18
 
@@ -38,7 +38,7 @@ export type FleetGraphSnapshot = OperatorMethodOutput<'fleet.graph.get'>;
38
38
  export type FleetObservedSteerResult = OperatorMethodOutput<'fleet.observed.steer'>;
39
39
 
40
40
  /**
41
- * The narrow async verb surface the Fleet panel's acts drive. Every method is a
41
+ * The narrow async verb surface the Agents modal's acts drive. Every method is a
42
42
  * real daemon round-trip in production (createFleetGateway) and a mocked shape
43
43
  * in tests. `armFixSessionAttach` is the ONLY sync member, it hands a spawned
44
44
  * session id to the shared one-key jump affordance (the CI fix-session
@@ -97,7 +97,7 @@ export interface FleetGatewayDeps {
97
97
  /**
98
98
  * Build the live Fleet gateway over the generic operator invoke path, the same
99
99
  * daemon resolution the command layer uses (resolveOperatorRpc). Returns an
100
- * honest unavailable reason when no daemon is reachable, so the panel acts can
100
+ * honest unavailable reason when no daemon is reachable, so the Agents modal acts can
101
101
  * refuse cleanly instead of throwing into the render loop.
102
102
  */
103
103
  export function createFleetGateway(deps: FleetGatewayDeps): FleetGatewayResolution {
@@ -1,5 +1,5 @@
1
1
  // ---------------------------------------------------------------------------
2
- // fleet-observed-render.ts, the fleet-pane rows for observed FOREIGN coding
2
+ // fleet-observed-render.ts, the Agents modal rows for observed FOREIGN coding
3
3
  // agents (kind 'observed-external').
4
4
  //
5
5
  // goodvibes did NOT spawn these, they are externally-launched Claude Code /
@@ -7,7 +7,7 @@
7
7
  // FIRST job is visibility ("it's in claude or codex"): goodvibes never presents
8
8
  // itself as the foreign session's cockpit. So an observed row:
9
9
  // - shows its honest external kind + a liveness-derived state (active/quiet),
10
- // - is NEVER counted in any of the panel's own-fleet counts,
10
+ // - is NEVER counted in any of the Agents modal's own-fleet counts,
11
11
  // - carries NO stop affordance, ever,
12
12
  // - offers steer as a DRILL-IN only (in the detail view), and only where a
13
13
  // real channel exists; where steer.kind is 'none' the detail states why.
@@ -15,7 +15,7 @@
15
15
 
16
16
  import type { ProcessNode, ProcessObserved, ObservedAgentKind } from '@pellux/goodvibes-sdk/platform/runtime/fleet';
17
17
  import type { Line } from '@pellux/goodvibes-sdk/platform/types';
18
- import { buildPanelLine, buildSearchInputLine, DEFAULT_PANEL_PALETTE, type PanelPalette } from './polish.ts';
18
+ import { buildViewLine, buildSearchInputLine, DEFAULT_VIEW_PALETTE, type ViewPalette } from './polish.ts';
19
19
  import { truncateDisplay, wrapText } from '../utils/terminal-width.ts';
20
20
 
21
21
  /** An observed-external node carries its foreign-agent facts on `observed`. */
@@ -47,7 +47,7 @@ function livenessGlyph(state: ProcessObserved['liveness']['state']): string {
47
47
  * no stop marker, just the glyph, an "observed" tag, the session label, its
48
48
  * external kind, and its liveness state.
49
49
  */
50
- export function renderObservedRowLine(node: ObservedNode, width: number, palette: PanelPalette = DEFAULT_PANEL_PALETTE): Line {
50
+ export function renderObservedRowLine(node: ObservedNode, width: number, palette: ViewPalette = DEFAULT_VIEW_PALETTE): Line {
51
51
  const C = palette;
52
52
  const observed = node.observed;
53
53
  const glyph = livenessGlyph(observed.liveness.state);
@@ -56,9 +56,9 @@ export function renderObservedRowLine(node: ObservedNode, width: number, palette
56
56
  // overflows the row (the tell is the honesty signal, it must survive).
57
57
  const tell = `${kindLabel} · ${observed.liveness.state}`;
58
58
  const labelBudget = Math.max(4, width - tell.length - 14);
59
- return buildPanelLine(width, [
59
+ return buildViewLine(width, [
60
60
  [' ', C.dim],
61
- [glyph, observed.liveness.state === 'active' ? (C.info ?? DEFAULT_PANEL_PALETTE.info) : C.dim],
61
+ [glyph, observed.liveness.state === 'active' ? (C.info ?? DEFAULT_VIEW_PALETTE.info) : C.dim],
62
62
  [' observed ', C.dim],
63
63
  [truncateDisplay(node.label, labelBudget), C.value],
64
64
  [' ', C.dim],
@@ -79,13 +79,13 @@ export function renderObservedRowLine(node: ObservedNode, width: number, palette
79
79
  * "s: steer" hint. A channel-less row never shows an input (owner ruling), its
80
80
  * detail states the honest reason and stops there.
81
81
  */
82
- export function renderObservedDetailLines(node: ObservedNode, width: number, palette: PanelPalette = DEFAULT_PANEL_PALETTE, steerDraft: string | null = null): Line[] {
82
+ export function renderObservedDetailLines(node: ObservedNode, width: number, palette: ViewPalette = DEFAULT_VIEW_PALETTE, steerDraft: string | null = null): Line[] {
83
83
  const C = palette;
84
84
  const observed = node.observed;
85
85
  const lines: Line[] = [];
86
- lines.push(buildPanelLine(width, [
86
+ lines.push(buildViewLine(width, [
87
87
  [' ', C.dim],
88
- [livenessGlyph(observed.liveness.state), observed.liveness.state === 'active' ? (C.info ?? DEFAULT_PANEL_PALETTE.info) : C.dim],
88
+ [livenessGlyph(observed.liveness.state), observed.liveness.state === 'active' ? (C.info ?? DEFAULT_VIEW_PALETTE.info) : C.dim],
89
89
  [' observed ', C.dim],
90
90
  [observedKindLabel(observed.externalKind), C.value],
91
91
  [' pid ', C.label],
@@ -94,11 +94,11 @@ export function renderObservedDetailLines(node: ObservedNode, width: number, pal
94
94
  [observed.liveness.state, C.value],
95
95
  ]));
96
96
  if (observed.cwd) {
97
- lines.push(buildPanelLine(width, [[' cwd ', C.label], [truncateDisplay(observed.cwd, Math.max(0, width - 6)), C.dim]]));
97
+ lines.push(buildViewLine(width, [[' cwd ', C.label], [truncateDisplay(observed.cwd, Math.max(0, width - 6)), C.dim]]));
98
98
  }
99
99
  // Liveness meaning, verbatim, honest about what 'quiet' can and cannot tell.
100
100
  for (const segment of wrapText(observed.liveness.detail, Math.max(1, width - 2))) {
101
- lines.push(buildPanelLine(width, [[' ', C.dim], [segment, C.dim]]));
101
+ lines.push(buildViewLine(width, [[' ', C.dim], [segment, C.dim]]));
102
102
  }
103
103
  // Steer is a drill-in: a real channel is named here (a message sent from this
104
104
  // detail travels over it, fleet.observed.steer), and where none exists the
@@ -107,22 +107,22 @@ export function renderObservedDetailLines(node: ObservedNode, width: number, pal
107
107
  const steerText = observed.steer.kind === 'tmux'
108
108
  ? `available via tmux pane ${observed.steer.paneId} (send-keys)`
109
109
  : `unavailable: ${observed.steer.reason}`;
110
- const steerFg = observed.steer.kind === 'tmux' ? (C.info ?? DEFAULT_PANEL_PALETTE.info) : C.dim;
110
+ const steerFg = observed.steer.kind === 'tmux' ? (C.info ?? DEFAULT_VIEW_PALETTE.info) : C.dim;
111
111
  const steerSegments = wrapText(steerText, Math.max(1, width - 8));
112
112
  steerSegments.forEach((segment, i) => {
113
- lines.push(buildPanelLine(width, [[i === 0 ? ' steer ' : ' ', C.label], [segment, steerFg]]));
113
+ lines.push(buildViewLine(width, [[i === 0 ? ' steer ' : ' ', C.label], [segment, steerFg]]));
114
114
  });
115
115
  // Drill-in compose input: only where a real channel exists. An active draft
116
116
  // renders the input line + send/cancel hint; otherwise a discoverability hint.
117
117
  if (observed.steer.kind === 'tmux') {
118
118
  if (steerDraft !== null) {
119
119
  lines.push(buildSearchInputLine(width, ' send ', `${steerDraft}_`, C, { active: true, bg: C.inputBg, valueColor: C.info }));
120
- lines.push(buildPanelLine(width, [[' ', C.label], ['Enter: send Esc: cancel', C.dim]]));
120
+ lines.push(buildViewLine(width, [[' ', C.label], ['Enter: send Esc: cancel', C.dim]]));
121
121
  } else {
122
- lines.push(buildPanelLine(width, [[' ', C.label], ['s: steer this session', C.dim]]));
122
+ lines.push(buildViewLine(width, [[' ', C.label], ['s: steer this session', C.dim]]));
123
123
  }
124
124
  }
125
125
  // Visibility, not a cockpit: there is no stop here, by design.
126
- lines.push(buildPanelLine(width, [[' stop ', C.label], ['not offered: goodvibes only observes this foreign session', C.dim]]));
126
+ lines.push(buildViewLine(width, [[' stop ', C.label], ['not offered: goodvibes only observes this foreign session', C.dim]]));
127
127
  return lines;
128
128
  }