@pellux/goodvibes-tui 2.0.21 → 2.1.1

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 (391) hide show
  1. package/CHANGELOG.md +65 -1
  2. package/README.md +30 -29
  3. package/docs/README.md +8 -5
  4. package/docs/foundation-artifacts/operator-contract.json +1 -1
  5. package/package.json +28 -19
  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-reference.ts +2 -2
  52. package/src/input/command-registry.ts +77 -35
  53. package/src/input/commands/acp-runtime.ts +19 -9
  54. package/src/input/commands/channel-runtime.ts +2 -2
  55. package/src/input/commands/ci-runtime.ts +1 -1
  56. package/src/input/commands/codebase-runtime.ts +1 -1
  57. package/src/input/commands/config.ts +7 -1
  58. package/src/input/commands/context-window.ts +25 -19
  59. package/src/input/commands/control-room-runtime.ts +18 -18
  60. package/src/input/commands/conversation-runtime.ts +0 -1
  61. package/src/input/commands/cost-runtime.ts +29 -20
  62. package/src/input/commands/diff-runtime.ts +35 -181
  63. package/src/input/commands/eval.ts +1 -1
  64. package/src/input/commands/experience-runtime.ts +3 -7
  65. package/src/input/commands/fresh-conversation.ts +86 -0
  66. package/src/input/commands/git-runtime.ts +5 -22
  67. package/src/input/commands/graph-runtime.ts +1 -1
  68. package/src/input/commands/guidance-runtime.ts +1 -1
  69. package/src/input/commands/health-runtime.ts +8 -9
  70. package/src/input/commands/hooks-runtime.ts +2 -2
  71. package/src/input/commands/hosted-runtime.ts +3 -3
  72. package/src/input/commands/incident-runtime.ts +3 -3
  73. package/src/input/commands/intelligence-runtime.ts +6 -9
  74. package/src/input/commands/knowledge.ts +2 -2
  75. package/src/input/commands/legacy-panel-command.ts +57 -0
  76. package/src/input/commands/local-auth-runtime.ts +8 -9
  77. package/src/input/commands/local-provider-runtime.ts +7 -4
  78. package/src/input/commands/local-runtime.ts +12 -15
  79. package/src/input/commands/local-setup-review.ts +1 -1
  80. package/src/input/commands/local-setup.ts +13 -19
  81. package/src/input/commands/memory.ts +1 -1
  82. package/src/input/commands/notify-runtime.ts +9 -0
  83. package/src/input/commands/operator-runtime.ts +10 -12
  84. package/src/input/commands/permissions-provenance.ts +3 -3
  85. package/src/input/commands/planning-runtime.ts +7 -7
  86. package/src/input/commands/platform-sandbox-runtime.ts +2 -2
  87. package/src/input/commands/platform-services-runtime.ts +1 -1
  88. package/src/input/commands/policy-dispatch.ts +2 -2
  89. package/src/input/commands/policy.ts +3 -3
  90. package/src/input/commands/provider.ts +1 -1
  91. package/src/input/commands/remote-runtime.ts +1 -1
  92. package/src/input/commands/review-runtime.ts +39 -94
  93. package/src/input/commands/rewind-runtime.ts +81 -108
  94. package/src/input/commands/runtime-services.ts +15 -17
  95. package/src/input/commands/services-runtime.ts +2 -2
  96. package/src/input/commands/session-content.ts +21 -5
  97. package/src/input/commands/session-workflow.ts +13 -38
  98. package/src/input/commands/settings-sync-runtime.ts +2 -2
  99. package/src/input/commands/shell-core.ts +19 -4
  100. package/src/input/commands/skills-runtime.ts +2 -2
  101. package/src/input/commands/status-runtime.ts +13 -0
  102. package/src/input/commands/subscription-runtime.ts +1 -1
  103. package/src/input/commands/tasks-runtime.ts +2 -8
  104. package/src/input/commands/work-plan-runtime.ts +4 -4
  105. package/src/input/commands/workstream-attempts.ts +24 -47
  106. package/src/input/commands/workstream-runtime.ts +2 -2
  107. package/src/input/commands/worktree-runtime.ts +3 -3
  108. package/src/input/commands.ts +3 -1
  109. package/src/input/composer-editor.ts +44 -0
  110. package/src/input/concealed-input.ts +1 -1
  111. package/src/input/config-modal-types.ts +20 -8
  112. package/src/input/config-modal.ts +106 -105
  113. package/src/input/confirm-dialog-types.ts +28 -0
  114. package/src/input/confirm-dialog.ts +70 -0
  115. package/src/input/delete-key-policy.ts +3 -3
  116. package/src/input/feed-context-factory.ts +15 -16
  117. package/src/input/handler-command-route.ts +7 -42
  118. package/src/input/handler-content-actions.ts +16 -15
  119. package/src/input/handler-feed-routes.ts +26 -211
  120. package/src/input/handler-feed.ts +68 -95
  121. package/src/input/handler-interactions.ts +5 -3
  122. package/src/input/handler-modal-routes.ts +215 -216
  123. package/src/input/handler-modal-stack.ts +81 -11
  124. package/src/input/handler-modal-token-routes.ts +4 -0
  125. package/src/input/handler-onboarding.ts +0 -1
  126. package/src/input/handler-picker-routes.ts +65 -107
  127. package/src/input/handler-session-view-route.ts +149 -0
  128. package/src/input/handler-shortcuts.ts +16 -154
  129. package/src/input/handler-types.ts +4 -2
  130. package/src/input/handler-ui-state.ts +45 -15
  131. package/src/input/handler-work-tree-route.ts +123 -0
  132. package/src/input/handler.ts +25 -70
  133. package/src/input/keybindings.ts +16 -71
  134. package/src/input/masked-entry-modal.ts +117 -0
  135. package/src/input/mcp-workspace.ts +48 -17
  136. package/src/input/model-picker-filter.ts +8 -0
  137. package/src/input/model-picker-open.ts +99 -0
  138. package/src/input/model-picker-types.ts +1 -1
  139. package/src/input/model-picker.ts +92 -9
  140. package/src/input/notifications-modal.ts +123 -0
  141. package/src/input/overlay-filter.ts +26 -0
  142. package/src/input/profile-picker-modal.ts +37 -8
  143. package/src/input/search.ts +3 -3
  144. package/src/input/selection-modal-queue.ts +2 -0
  145. package/src/input/selection-modal.ts +28 -16
  146. package/src/input/session-picker-modal.ts +33 -8
  147. package/src/input/settings-modal-activation.ts +7 -2
  148. package/src/input/settings-modal-data.ts +11 -6
  149. package/src/input/settings-modal-types.ts +1 -1
  150. package/src/input/settings-modal.ts +20 -20
  151. package/src/input/submission-intent.ts +1 -1
  152. package/src/input/submission-router.ts +4 -9
  153. package/src/input/surface-modal-host.ts +110 -0
  154. package/src/input/theme-settings-actions.ts +82 -0
  155. package/src/input/usage-modal.ts +183 -0
  156. package/src/input/views.ts +97 -0
  157. package/src/main.ts +175 -165
  158. package/src/permissions/hunk-selection.ts +1 -1
  159. package/src/permissions/prompt-card.ts +511 -0
  160. package/src/permissions/prompt.ts +59 -622
  161. package/src/renderer/agents-modal.ts +310 -0
  162. package/src/renderer/autocomplete-overlay.ts +42 -220
  163. package/src/renderer/back-to-bottom.ts +80 -0
  164. package/src/renderer/block-actions-overlay.ts +30 -48
  165. package/src/renderer/bookmark-modal.ts +48 -79
  166. package/src/renderer/changes-modal.ts +325 -0
  167. package/src/renderer/code-block.ts +184 -106
  168. package/src/renderer/command-palette.ts +93 -0
  169. package/src/renderer/composer-fragments.ts +4 -4
  170. package/src/renderer/composer.ts +146 -0
  171. package/src/renderer/compositor.ts +26 -160
  172. package/src/renderer/config-modal.ts +185 -81
  173. package/src/renderer/confirm-dialog.ts +50 -0
  174. package/src/renderer/context-inspector.ts +116 -154
  175. package/src/renderer/context-status-hint.ts +4 -4
  176. package/src/renderer/conversation-layout.ts +20 -0
  177. package/src/renderer/conversation-overlays.ts +94 -84
  178. package/src/renderer/conversation-surface.ts +19 -38
  179. package/src/renderer/diff-tint.ts +98 -0
  180. package/src/renderer/file-picker-overlay.ts +63 -90
  181. package/src/renderer/footer-targets.ts +38 -0
  182. package/src/renderer/git-status.ts +3 -4
  183. package/src/renderer/header-line.ts +140 -117
  184. package/src/renderer/help-overlay.ts +133 -219
  185. package/src/renderer/history-search-overlay.ts +15 -12
  186. package/src/renderer/lane-graph/bead.ts +800 -0
  187. package/src/renderer/lane-graph/glyphs.ts +134 -0
  188. package/src/renderer/lane-graph/layout.ts +248 -0
  189. package/src/renderer/lane-graph/paint.ts +537 -0
  190. package/src/renderer/lane-graph/semantic-memo.ts +77 -0
  191. package/src/renderer/layout-engine.ts +2 -57
  192. package/src/renderer/layout.ts +7 -13
  193. package/src/renderer/markdown-inline.ts +2 -1
  194. package/src/renderer/markdown-table.ts +17 -12
  195. package/src/renderer/markdown.ts +92 -34
  196. package/src/renderer/masked-entry-modal.ts +78 -0
  197. package/src/renderer/mcp-workspace.ts +166 -203
  198. package/src/renderer/model-workspace.ts +381 -436
  199. package/src/renderer/notifications-modal.ts +116 -0
  200. package/src/renderer/onboarding/onboarding-wizard.ts +178 -588
  201. package/src/renderer/process-view.ts +192 -0
  202. package/src/renderer/profile-picker-modal.ts +58 -110
  203. package/src/renderer/search-overlay.ts +6 -3
  204. package/src/renderer/selection-modal-overlay.ts +87 -327
  205. package/src/renderer/semantic-diff.ts +2 -2
  206. package/src/renderer/session-chips.ts +102 -0
  207. package/src/renderer/session-picker-modal.ts +177 -297
  208. package/src/renderer/settings-modal-connections.ts +14 -23
  209. package/src/renderer/settings-modal-context.ts +367 -0
  210. package/src/renderer/settings-modal-helpers.ts +6 -11
  211. package/src/renderer/settings-modal.ts +322 -726
  212. package/src/renderer/shell-surface.ts +277 -175
  213. package/src/renderer/shortcuts-overlay.ts +217 -0
  214. package/src/renderer/status-line.ts +475 -0
  215. package/src/renderer/surface-compose.ts +174 -0
  216. package/src/renderer/surface-kit-extra.ts +303 -0
  217. package/src/renderer/surface-kit-list.ts +366 -0
  218. package/src/renderer/surface-kit-parts.ts +360 -0
  219. package/src/renderer/surface-kit.ts +568 -0
  220. package/src/renderer/syntax-highlighter.ts +280 -197
  221. package/src/renderer/syntax-theme.ts +51 -0
  222. package/src/renderer/system-message.ts +0 -1
  223. package/src/renderer/term-caps.ts +42 -1
  224. package/src/renderer/terminal-bg-probe.ts +116 -19
  225. package/src/renderer/terminal-palette-probe.ts +322 -0
  226. package/src/renderer/terminal-palette-reader.ts +183 -0
  227. package/src/renderer/terminal-palette.ts +58 -0
  228. package/src/renderer/theme-mode-config.ts +16 -1
  229. package/src/renderer/theme.ts +234 -207
  230. package/src/renderer/thinking.ts +0 -1
  231. package/src/renderer/throbber.ts +188 -0
  232. package/src/renderer/toast-center.ts +119 -0
  233. package/src/renderer/ui-factory.ts +39 -602
  234. package/src/renderer/ui-primitives.ts +8 -25
  235. package/src/renderer/usage-modal.ts +353 -0
  236. package/src/renderer/user-message.ts +58 -0
  237. package/src/renderer/voice-capture-chip.ts +53 -0
  238. package/src/runtime/bootstrap-command-context.ts +0 -5
  239. package/src/runtime/bootstrap-command-parts.ts +38 -89
  240. package/src/runtime/bootstrap-core.ts +13 -15
  241. package/src/runtime/bootstrap-hook-bridge.ts +12 -21
  242. package/src/runtime/bootstrap-notifier-sync.ts +17 -1
  243. package/src/runtime/bootstrap-shell.ts +16 -50
  244. package/src/runtime/bootstrap.ts +14 -14
  245. package/src/runtime/client/fleet-union.ts +5 -5
  246. package/src/runtime/client/hosted-exit.ts +2 -2
  247. package/src/runtime/client/hosted-sessions.ts +1 -1
  248. package/src/runtime/client/spine-adoption.ts +1 -1
  249. package/src/runtime/context-accounting-source.ts +5 -4
  250. package/src/runtime/index.ts +1 -0
  251. package/src/runtime/notification-dispatch.ts +102 -29
  252. package/src/runtime/recovery-offer-wiring.ts +4 -1
  253. package/src/runtime/recovery-prompt.ts +31 -15
  254. package/src/runtime/runtime-services-types.ts +10 -6
  255. package/src/runtime/services.ts +17 -12
  256. package/src/runtime/session-continuity-hints.ts +2 -5
  257. package/src/runtime/session-inbound-inputs.ts +1 -1
  258. package/src/runtime/session-resume-liveness-confirm.ts +14 -2
  259. package/src/runtime/startup-typeahead-gate.ts +103 -0
  260. package/src/runtime/store/domains/domain-read-matrix.ts +0 -1
  261. package/src/runtime/store/domains/index.ts +0 -8
  262. package/src/runtime/store/selectors/index.ts +0 -28
  263. package/src/runtime/store/state.ts +0 -8
  264. package/src/runtime/ui-services.ts +4 -6
  265. package/src/runtime/usage-tracker.ts +348 -0
  266. package/src/runtime/wrfc-persistence.ts +4 -4
  267. package/src/shell/blocking-input.ts +92 -2
  268. package/src/shell/recovery-input-helpers.ts +1 -1
  269. package/src/shell/session-views.ts +539 -0
  270. package/src/shell/status-report.ts +86 -0
  271. package/src/shell/transcript-scroll.ts +68 -0
  272. package/src/shell/ui-openers.ts +84 -172
  273. package/src/shell/view-openers.ts +205 -0
  274. package/src/tools/wrfc-agent-guard.ts +22 -2
  275. package/src/utils/format-duration.ts +4 -8
  276. package/src/utils/splash-lines.ts +9 -1
  277. package/src/utils/terminal-width.ts +56 -0
  278. package/src/verification/live-verifier.ts +0 -10
  279. package/src/version.ts +1 -1
  280. package/src/{panels → views}/agent-inspector-shared.ts +2 -2
  281. package/src/{panels → views}/builtin-modals.ts +22 -21
  282. package/src/views/builtin-views.ts +135 -0
  283. package/src/{panels → views}/confirm-state.ts +9 -9
  284. package/src/{panels → views}/diff-review-model.ts +10 -3
  285. package/src/{panels → views}/eval-registry.ts +1 -1
  286. package/src/{panels → views}/fleet-acts.ts +49 -85
  287. package/src/{panels/fleet-panel-format.ts → views/fleet-format.ts} +40 -40
  288. package/src/{panels → views}/fleet-gateway.ts +5 -5
  289. package/src/{panels → views}/fleet-observed-render.ts +16 -16
  290. package/src/{panels → views}/fleet-read-model.ts +9 -9
  291. package/src/{panels/fleet-tabs.ts → views/fleet-session-tabs.ts} +13 -13
  292. package/src/{panels → views}/fleet-spawn.ts +33 -49
  293. package/src/{panels → views}/fleet-steer.ts +12 -12
  294. package/src/{panels → views}/fleet-stop.ts +4 -4
  295. package/src/{panels → views}/fleet-transcript.ts +26 -27
  296. package/src/{panels/fleet-panel-worktree-detail.ts → views/fleet-worktree-detail.ts} +7 -7
  297. package/src/{panels → views}/hosted-session-feed.ts +6 -6
  298. package/src/views/modal-surface-registry.ts +41 -0
  299. package/src/{panels → views}/modals/devices-modal.ts +2 -2
  300. package/src/{panels → views}/modals/hooks-modal.ts +13 -13
  301. package/src/{panels → views}/modals/keybindings-modal.ts +19 -27
  302. package/src/{panels → views}/modals/knowledge-modal.ts +6 -5
  303. package/src/{panels → views}/modals/local-auth-modal.ts +22 -21
  304. package/src/{panels → views}/modals/marketplace-modal.ts +11 -11
  305. package/src/{panels → views}/modals/memory-modal.ts +8 -8
  306. package/src/{panels → views}/modals/modal-surface-helpers.ts +15 -5
  307. package/src/{panels → views}/modals/pairing-modal.ts +9 -9
  308. package/src/{panels → views}/modals/planning-modal.ts +15 -20
  309. package/src/{panels → views}/modals/plugins-modal.ts +6 -6
  310. package/src/{panels → views}/modals/policy-modal.ts +13 -5
  311. package/src/{panels → views}/modals/provider-health-modal.ts +4 -4
  312. package/src/{panels → views}/modals/remote-modal.ts +3 -3
  313. package/src/{panels → views}/modals/sandbox-modal.ts +4 -4
  314. package/src/{panels → views}/modals/security-modal.ts +22 -16
  315. package/src/{panels → views}/modals/services-modal.ts +3 -3
  316. package/src/{panels → views}/modals/settings-sync-modal.ts +4 -4
  317. package/src/{panels → views}/modals/skills-modal.ts +9 -9
  318. package/src/{panels → views}/modals/subscription-modal.ts +3 -3
  319. package/src/{panels → views}/modals/work-plan-modal.ts +10 -13
  320. package/src/views/notifications-feed.ts +314 -0
  321. package/src/{panels → views}/polish-core.ts +38 -36
  322. package/src/{panels → views}/polish-tables.ts +35 -26
  323. package/src/{panels → views}/polish.ts +101 -95
  324. package/src/{panels → views}/project-planning-answer-actions.ts +3 -3
  325. package/src/{panels → views}/provider-health-routes.ts +14 -14
  326. package/src/{panels → views}/search-focus.ts +8 -8
  327. package/src/{panels → views}/session-maintenance.ts +11 -11
  328. package/src/views/skills-discovery.ts +159 -0
  329. package/src/views/view-deps.ts +80 -0
  330. package/src/views/view-panel-adapter.ts +53 -0
  331. package/src/{panels → views}/workstream-graph-render.ts +1 -1
  332. package/src/core/conversation-fold.ts +0 -101
  333. package/src/core/conversation-turn-structure.ts +0 -464
  334. package/src/core/conversation-user-receipts.ts +0 -42
  335. package/src/input/commands/operator-panel-runtime.ts +0 -186
  336. package/src/input/panel-integration-actions.ts +0 -33
  337. package/src/input/panel-mouse-geometry.ts +0 -97
  338. package/src/input/panel-paste-flood-guard.ts +0 -86
  339. package/src/panels/base-panel.ts +0 -301
  340. package/src/panels/builtin/agent.ts +0 -27
  341. package/src/panels/builtin/development.ts +0 -92
  342. package/src/panels/builtin/knowledge.ts +0 -12
  343. package/src/panels/builtin/operations.ts +0 -177
  344. package/src/panels/builtin/session.ts +0 -81
  345. package/src/panels/builtin/shared.ts +0 -357
  346. package/src/panels/builtin-panels.ts +0 -28
  347. package/src/panels/cost-tracker-panel.ts +0 -746
  348. package/src/panels/diff-panel.ts +0 -797
  349. package/src/panels/diff-review-panel.ts +0 -395
  350. package/src/panels/expandable-list-panel.ts +0 -189
  351. package/src/panels/fleet-deep-link.ts +0 -31
  352. package/src/panels/fleet-panel.ts +0 -799
  353. package/src/panels/git-panel.ts +0 -800
  354. package/src/panels/hosted-session-panel.ts +0 -221
  355. package/src/panels/index.ts +0 -21
  356. package/src/panels/local-auth-panel.ts +0 -478
  357. package/src/panels/notifications-feed.ts +0 -127
  358. package/src/panels/notifications-panel.ts +0 -160
  359. package/src/panels/panel-confirm-overlay.ts +0 -72
  360. package/src/panels/panel-manager.ts +0 -791
  361. package/src/panels/plugins-panel.ts +0 -371
  362. package/src/panels/scrollable-list-panel.ts +0 -498
  363. package/src/panels/skills-panel.ts +0 -454
  364. package/src/panels/token-budget-panel.ts +0 -688
  365. package/src/panels/types.ts +0 -191
  366. package/src/panels/wrfc-panel-format.ts +0 -133
  367. package/src/renderer/diff-view.ts +0 -134
  368. package/src/renderer/fleet-tab-strip.ts +0 -56
  369. package/src/renderer/footer-tips.ts +0 -53
  370. package/src/renderer/fullscreen-primitives.ts +0 -146
  371. package/src/renderer/fullscreen-workspace.ts +0 -194
  372. package/src/renderer/hint-grammar.ts +0 -52
  373. package/src/renderer/modal-factory.ts +0 -480
  374. package/src/renderer/overlay-box.ts +0 -154
  375. package/src/renderer/overlay-viewport.ts +0 -104
  376. package/src/renderer/panel-composite.ts +0 -145
  377. package/src/renderer/panel-workspace-bar.ts +0 -54
  378. package/src/renderer/process-indicator.ts +0 -163
  379. package/src/renderer/tab-strip.ts +0 -222
  380. package/src/renderer/text-layout.ts +0 -31
  381. package/src/renderer/tool-call.ts +0 -276
  382. package/src/renderer/tool-result-expanded-lines.ts +0 -48
  383. package/src/renderer/tool-result-summary.ts +0 -219
  384. package/src/runtime/diagnostics/panels/index.ts +0 -21
  385. package/src/runtime/diagnostics/panels/ops.ts +0 -156
  386. package/src/runtime/perf/panel-contracts.ts +0 -32
  387. package/src/runtime/store/domains/panels.ts +0 -117
  388. package/src/verification/verification-ledger.ts +0 -707
  389. /package/src/{panels → views}/memory-consolidation-gateway.ts +0 -0
  390. /package/src/{panels → views}/modals/modal-theme.ts +0 -0
  391. /package/src/{panels → views}/provider-health-domains.ts +0 -0
@@ -1,237 +1,200 @@
1
+ /**
2
+ * renderMcpWorkspace, the MCP server workspace as a kit modal with a list and a detail side:
3
+ * the server and action list on the left (✦ servers / actions groups, a ● or
4
+ * ○ connection marker, the selected row as the gradient) and the selected
5
+ * row's details in an element inset on the right (connection, trust, launch
6
+ * command, allowed paths and hosts, quarantine, the server's tools, and the
7
+ * status line). The add/edit form and the remove confirmation are sub-views
8
+ * of the same modal: Esc returns from them to the browser.
9
+ */
10
+
1
11
  import type { McpWorkspace, McpWorkspaceRow } from '../input/mcp-workspace.ts';
2
- import type { Line } from '@pellux/goodvibes-sdk/platform/types';
3
- import { wrapText } from '../utils/terminal-width.ts';
4
- import { GLYPHS } from './ui-primitives.ts';
12
+ import { activeTokens } from './theme.ts';
5
13
  import {
6
- getFullscreenWorkspaceMetrics,
7
- padDisplay,
8
- renderFullscreenWorkspace,
9
- stableWindow,
10
- WORKSPACE_PALETTE as PALETTE,
11
- type WorkspaceRow,
12
- } from './fullscreen-workspace.ts';
14
+ beginModal,
15
+ finishModal,
16
+ searchRow,
17
+ scrollCountText,
18
+ type KitHint,
19
+ type ModalFrame,
20
+ type SurfaceLayer,
21
+ } from './surface-kit.ts';
22
+ import { drawList, type KitRow } from './surface-kit-list.ts';
23
+ import { inset } from './surface-kit-parts.ts';
24
+ import { drawTextBlock, splitListDetail, textBlockHeight, type TextLine } from './surface-kit-extra.ts';
13
25
 
14
26
  function statusColor(text: string): string {
15
- if (text.includes('failed') || text.includes('Save failed') || text.includes('Remove failed')) return PALETTE.bad;
16
- if (text.includes('attention') || text.includes('quarantine')) return PALETTE.warn;
17
- return PALETTE.muted;
18
- }
19
-
20
- function connectedColor(connected: boolean): string {
21
- return connected ? PALETTE.good : PALETTE.warn;
27
+ const t = activeTokens();
28
+ if (text.includes('failed')) return t.error;
29
+ if (text.includes('attention') || text.includes('quarantine')) return t.warning;
30
+ return t.textMuted;
22
31
  }
23
32
 
24
- function rowLabel(row: McpWorkspaceRow): string {
25
- if (row.type === 'server') return `${row.server.name} (${row.server.source})`;
26
- return row.label;
27
- }
28
-
29
- function rowDetail(row: McpWorkspaceRow): string {
30
- if (row.type === 'server') {
31
- const server = row.server;
32
- return `${server.connected ? 'connected' : 'offline'} · ${server.role} · ${server.trustMode} · schema ${server.freshness}`;
33
+ function browseRows(workspace: McpWorkspace): KitRow[] {
34
+ const t = activeTokens();
35
+ const rows: KitRow[] = [];
36
+ const visible = workspace.visibleRows;
37
+ const servers = visible.filter((row) => row.type === 'server');
38
+ rows.push({ header: 'Servers', headerRight: `${workspace.servers.filter((s) => s.connected).length}/${workspace.servers.length} connected` });
39
+ if (servers.length === 0) {
40
+ rows.push({ label: workspace.servers.length === 0 ? 'No configured servers' : 'No servers match', muted: true });
33
41
  }
34
- return row.detail;
35
- }
36
-
37
- function buildLeftRows(workspace: McpWorkspace, height: number): WorkspaceRow[] {
38
- const rendered: WorkspaceRow[] = [];
39
- let selectedRenderedIndex = 0;
40
- let sawServerGroup = false;
41
- let sawActionGroup = false;
42
-
43
- workspace.rows.forEach((row, rowIndex) => {
44
- if (row.type === 'server' && !sawServerGroup) {
45
- rendered.push({ text: 'SERVERS', kind: 'group', bold: true });
46
- sawServerGroup = true;
42
+ let sawAction = false;
43
+ visible.forEach((row: McpWorkspaceRow, index) => {
44
+ const selected = workspace.mode === 'browse' && index === workspace.selectedIndex;
45
+ if (row.type === 'server') {
46
+ rows.push({
47
+ label: row.server.name,
48
+ desc: row.server.source,
49
+ mark: row.server.connected ? '●' : '○',
50
+ markFg: row.server.connected ? t.success : t.warning,
51
+ right: row.server.quarantineReason ? 'quarantined' : row.server.connected ? '' : 'offline',
52
+ rightFg: row.server.quarantineReason ? t.error : t.textFaint,
53
+ selected,
54
+ });
55
+ return;
47
56
  }
48
- if (row.type === 'action' && !sawActionGroup) {
49
- if (!sawServerGroup) rendered.push({ text: 'SERVERS', kind: 'group', bold: true });
50
- if (workspace.servers.length === 0) rendered.push({ text: ' No configured servers', kind: 'item', fg: PALETTE.dim, dim: true });
51
- rendered.push({ text: 'ACTIONS', kind: 'group', bold: true });
52
- sawActionGroup = true;
57
+ if (!sawAction) {
58
+ rows.push({ header: 'Actions' });
59
+ sawAction = true;
53
60
  }
54
-
55
- const selected = workspace.mode === 'browse' && rowIndex === workspace.selectedIndex;
56
- if (selected) selectedRenderedIndex = rendered.length;
57
- const marker = selected ? GLYPHS.navigation.selected : row.type === 'server' ? (row.server.connected ? '✓' : '•') : '+';
58
- rendered.push({
59
- text: ` ${marker} ${rowLabel(row)}`,
60
- selected,
61
- kind: 'item',
62
- fg: row.type === 'server' ? connectedColor(row.server.connected) : PALETTE.info,
63
- bold: selected || row.type === 'action',
64
- });
61
+ rows.push({ label: row.label, mark: '+', markFg: t.info, selected });
65
62
  });
66
-
67
- const visible = Math.max(1, height);
68
- const window = stableWindow(rendered.length, selectedRenderedIndex, visible);
69
- const rows = rendered.slice(window.start, window.end);
70
- if (window.start > 0 && rows.length > 0) {
71
- rows[0] = { text: `${GLYPHS.navigation.moreAbove} ${window.start} more row(s) above`, kind: 'more', fg: PALETTE.dim, dim: true };
72
- }
73
- if (window.end < rendered.length && rows.length > 0) {
74
- rows[rows.length - 1] = { text: `${GLYPHS.navigation.moreBelow} ${rendered.length - window.end} more row(s) below`, kind: 'more', fg: PALETTE.dim, dim: true };
75
- }
76
- while (rows.length < height) rows.push({ text: '', kind: 'empty' });
77
- return rows.slice(0, height);
63
+ return rows;
78
64
  }
79
65
 
80
- function selectedDetailLines(workspace: McpWorkspace, width: number): WorkspaceRow[] {
81
- const lines: string[] = [];
82
- if (workspace.mode === 'form') {
83
- const field = workspace.formFields[workspace.formIndex];
84
- lines.push(
85
- workspace.editingServerName ? `Editing server: ${workspace.editingServerName}` : 'Adding an MCP server',
86
- 'Write a server through the SDK MCP config manager, then reload the live runtime without restarting the TUI.',
87
- field ? `${field.label}: ${field.help}` : '',
88
- 'Project scope writes to this workspace. Global scope writes to your user MCP config. External Claude/Desktop config files are shown but not edited here.',
89
- );
90
- } else if (workspace.mode === 'delete-confirm') {
66
+ function detailLines(workspace: McpWorkspace): TextLine[] {
67
+ const t = activeTokens();
68
+ const title = (text: string): TextLine => ({ text, style: { fg: t.text, bold: true } });
69
+ const body = (text: string): TextLine => ({ text, style: { fg: t.textMuted } });
70
+ const lines: TextLine[] = [];
71
+ const selected = workspace.selectedRow;
72
+ if (!selected) {
73
+ lines.push(body(workspace.query ? `No rows match "${workspace.query}".` : 'No MCP rows available.'));
74
+ } else if (selected.type === 'action') {
75
+ lines.push(title(selected.label), body(selected.detail));
76
+ } else {
77
+ const server = selected.server;
91
78
  lines.push(
92
- `Remove configured server: ${workspace.editingServerName ?? '(unknown)'}`,
93
- 'This removes the selected writable project/global config entry and reloads MCP runtime state.',
94
- 'Press y to remove, n or Esc to cancel.',
79
+ title(server.name),
80
+ { text: `${server.connected ? 'connected' : 'offline'} · ${server.source} · schema ${server.freshness}`, style: { fg: server.connected ? t.success : t.warning } },
81
+ { text: '' },
82
+ body(`Role ${server.role} · trust ${server.trustMode}`),
83
+ body(`Command ${server.command ? `${server.command}${server.args?.length ? ` ${server.args.join(' ')}` : ''}` : '(runtime only; no launch config found)'}`),
84
+ body(`Allowed paths ${server.allowedPaths.length > 0 ? server.allowedPaths.join(', ') : '(none)'}`),
85
+ body(`Allowed hosts ${server.allowedHosts.length > 0 ? server.allowedHosts.join(', ') : '(none)'}`),
95
86
  );
96
- } else {
97
- const selected = workspace.selectedRow;
98
- if (!selected) lines.push('No MCP rows available.');
99
- else if (selected.type === 'action') lines.push(selected.label, selected.detail);
100
- else {
101
- const server = selected.server;
102
- lines.push(
103
- server.name,
104
- `Connected: ${server.connected ? 'yes' : 'no'} Source: ${server.source} Schema: ${server.freshness}`,
105
- `Role: ${server.role} Trust: ${server.trustMode}`,
106
- `Command: ${server.command ? `${server.command}${server.args?.length ? ` ${server.args.join(' ')}` : ''}` : '(runtime only; no launch config found)'}`,
107
- `Allowed paths: ${server.allowedPaths.length > 0 ? server.allowedPaths.join(', ') : '(none)'}`,
108
- `Allowed hosts: ${server.allowedHosts.length > 0 ? server.allowedHosts.join(', ') : '(none)'}`,
109
- ...(server.quarantineReason ? [`Quarantine: ${server.quarantineReason}${server.quarantineDetail ? ` - ${server.quarantineDetail}` : ''}`] : []),
110
- );
87
+ if (server.quarantineReason) {
88
+ lines.push({ text: `Quarantine: ${server.quarantineReason}${server.quarantineDetail ? ` - ${server.quarantineDetail}` : ''}`, style: { fg: t.error } });
111
89
  }
112
90
  }
113
-
114
- lines.push('', `Status: ${workspace.status}`);
115
- return lines.flatMap((text, index): WorkspaceRow[] => {
116
- if (text === '') return [{ text: '', dim: true }];
117
- return wrapText(text, Math.max(1, width)).map((wrapped, wrapIndex): WorkspaceRow => ({
118
- text: wrapped,
119
- fg: index === 0 ? PALETTE.title : text.startsWith('Status:') ? statusColor(workspace.status) : PALETTE.text,
120
- bold: index === 0 && wrapIndex === 0,
121
- dim: text.length === 0,
122
- }));
123
- });
124
- }
125
-
126
- function buildFormRows(workspace: McpWorkspace, width: number, height: number): WorkspaceRow[] {
127
- const rows: WorkspaceRow[] = [];
128
- const fields = workspace.formFields;
129
- const labelWidth = Math.min(24, Math.max(14, Math.floor(width * 0.24)));
130
- const valueWidth = Math.max(12, width - labelWidth - 20);
131
- rows.push({
132
- text: ` ${padDisplay('Field', labelWidth)} ${padDisplay('Value', valueWidth)} ${padDisplay('Edit', 10)}`,
133
- fg: PALETTE.muted,
134
- bold: true,
135
- });
136
-
137
- const visible = Math.max(1, height - 2);
138
- const window = stableWindow(fields.length, workspace.formIndex, visible);
139
- if (window.start > 0) rows.push({ text: `${GLYPHS.navigation.moreAbove} ${window.start} more field(s) above`, kind: 'more', fg: PALETTE.dim, dim: true });
140
- for (let index = window.start; index < window.end; index += 1) {
141
- const field = fields[index]!;
142
- const selected = index === workspace.formIndex;
143
- const marker = selected ? GLYPHS.navigation.selected : ' ';
144
- const value = field.id === 'save' || field.id === 'cancel'
145
- ? field.help
146
- : field.value.length > 0 ? field.value : '(empty)';
147
- rows.push({
148
- text: `${marker} ${padDisplay(field.label, labelWidth)} ${padDisplay(value, valueWidth)} ${padDisplay(field.editable ? 'text' : 'cycle/action', 12)}`,
149
- selected,
150
- fg: field.id === 'save' ? PALETTE.good : field.id === 'cancel' ? PALETTE.warn : field.editable ? PALETTE.text : PALETTE.info,
151
- bold: selected,
152
- });
153
- }
154
- if (window.end < fields.length) rows.push({ text: `${GLYPHS.navigation.moreBelow} ${fields.length - window.end} more field(s) below`, kind: 'more', fg: PALETTE.dim, dim: true });
155
- while (rows.length < height) rows.push({ text: '', kind: 'empty' });
156
- return rows.slice(0, height);
157
- }
158
-
159
- function buildToolRows(workspace: McpWorkspace, width: number, height: number): WorkspaceRow[] {
91
+ lines.push({ text: '' });
160
92
  const server = workspace.selectedServer?.name;
161
93
  const tools = server ? workspace.tools.filter((tool) => tool.serverName === server) : workspace.tools;
162
- const toolWidth = Math.min(36, Math.max(18, Math.floor(width * 0.34)));
163
- const serverWidth = Math.min(24, Math.max(12, Math.floor(width * 0.20)));
164
- const descriptionWidth = Math.max(12, width - toolWidth - serverWidth - 8);
165
- const label = workspace.loadingTools
166
- ? 'Tools: loading...'
167
- : server
168
- ? `Tools for ${server}: ${tools.length}`
169
- : `Tools: ${tools.length}`;
170
- const rows: WorkspaceRow[] = [
171
- { text: label, fg: PALETTE.subtitle, bold: true },
172
- { text: ` ${padDisplay('Tool', toolWidth)} ${padDisplay('Server', serverWidth)} ${padDisplay('Description', descriptionWidth)}`, fg: PALETTE.muted, bold: true },
173
- ];
174
-
94
+ lines.push(title(workspace.loadingTools ? 'Tools: loading' : server ? `Tools for ${server}: ${tools.length}` : `Tools: ${tools.length}`));
175
95
  if (tools.length === 0) {
176
- rows.push({
177
- text: workspace.loadingTools ? 'Loading tool list from connected MCP servers.' : 'No tools cached for the selected server. Press t to refresh.',
178
- fg: PALETTE.muted,
179
- dim: true,
180
- });
96
+ lines.push(body(workspace.loadingTools ? 'Loading the tool list from connected MCP servers.' : 'No tools cached for the selected server. Press t to refresh.'));
181
97
  } else {
182
- for (const tool of tools.slice(0, Math.max(0, height - rows.length))) {
183
- rows.push({
184
- text: ` ${padDisplay(tool.toolName, toolWidth)} ${padDisplay(tool.serverName, serverWidth)} ${padDisplay(tool.description ?? '', descriptionWidth)}`,
185
- fg: PALETTE.text,
186
- });
98
+ for (const tool of tools) {
99
+ lines.push({ text: `${tool.toolName}${server ? '' : ` (${tool.serverName})`}${tool.description ? ` ${tool.description}` : ''}`, style: { fg: t.textMuted } });
187
100
  }
188
101
  }
102
+ return lines;
103
+ }
189
104
 
190
- while (rows.length < height) rows.push({ text: '', kind: 'empty' });
191
- return rows.slice(0, height);
105
+ function formRows(workspace: McpWorkspace): KitRow[] {
106
+ const t = activeTokens();
107
+ return workspace.formFields.map((field, index) => {
108
+ const selected = index === workspace.formIndex;
109
+ const isAction = field.id === 'save' || field.id === 'cancel';
110
+ const value = isAction ? undefined : field.value.length > 0 ? field.value : '(empty)';
111
+ return {
112
+ label: field.label,
113
+ desc: value !== undefined && selected && field.editable ? `${field.value}▏` : value,
114
+ right: !isAction && !field.editable ? '←→' : undefined,
115
+ labelFg: field.id === 'save' ? t.success : field.id === 'cancel' ? t.warning : undefined,
116
+ bold: isAction,
117
+ selected,
118
+ };
119
+ });
192
120
  }
193
121
 
194
- function buildDeleteRows(workspace: McpWorkspace, height: number): WorkspaceRow[] {
195
- const rows: WorkspaceRow[] = [
196
- { text: `${GLYPHS.navigation.selected} Confirm remove ${workspace.editingServerName ?? '(unknown)'}`, selected: true, fg: PALETTE.bad, bold: true },
197
- { text: ' Cancel and return to MCP server browser', fg: PALETTE.muted },
122
+ function formLines(workspace: McpWorkspace): TextLine[] {
123
+ const t = activeTokens();
124
+ const field = workspace.formFields[workspace.formIndex];
125
+ // The selected field's help leads: it is what the user needs right now.
126
+ return [
127
+ ...(field ? [{ text: field.label, style: { fg: t.text, bold: true } }, { text: field.help, style: { fg: t.textMuted } }, { text: '' }] : []),
128
+ { text: workspace.editingServerName ? `Editing server: ${workspace.editingServerName}` : 'Adding an MCP server', style: { fg: t.text, bold: true } },
129
+ { text: 'Writes a server through the SDK MCP config manager, then reloads the live runtime without restarting the TUI.', style: { fg: t.textMuted } },
130
+ { text: '' },
131
+ { text: 'Project scope writes to this workspace. Global scope writes to your user MCP config. External Claude/Desktop config files are shown but not edited here.', style: { fg: t.textFaint } },
198
132
  ];
199
- while (rows.length < height) rows.push({ text: '', kind: 'empty' });
200
- return rows.slice(0, height);
201
133
  }
202
134
 
203
- function buildControlRows(workspace: McpWorkspace, width: number, height: number): WorkspaceRow[] {
204
- if (workspace.mode === 'form') return buildFormRows(workspace, width, height);
205
- if (workspace.mode === 'delete-confirm') return buildDeleteRows(workspace, height);
206
- return buildToolRows(workspace, width, height);
135
+ function hintsFor(workspace: McpWorkspace): KitHint[] {
136
+ if (workspace.mode === 'form') return [['↑↓', 'field'], ['←→', 'cycle'], ['type', 'edit'], ['⏎', 'save or cancel row'], ['esc', 'back']];
137
+ if (workspace.mode === 'delete-confirm') return [['y', 'remove'], ['n', 'cancel'], ['esc', 'back']];
138
+ return [['↑↓', 'move'], ['⏎', 'edit or run'], ['a', 'add'], ['d', 'remove'], ['r', 'reload'], ['t', 'tools']];
207
139
  }
208
140
 
209
- function footerText(workspace: McpWorkspace): string {
210
- if (workspace.mode === 'form') return 'Focus server form · Up/Down field · Left/Right cycle · Type edit · Enter save/cancel row · Esc back';
211
- if (workspace.mode === 'delete-confirm') return 'Focus remove confirmation · y confirm · n/Esc cancel';
212
- return 'Focus MCP workspace · Up/Down choose · Enter edit/action · a add · d remove · r reload · t tools · Esc close';
141
+ function drawDetailInset(f: ModalFrame, split: ReturnType<typeof splitListDetail>, lines: readonly TextLine[]): void {
142
+ const t = activeTokens();
143
+ const p = inset(f.canvas, split.detailX, split.detailY, split.detailW, split.detailH);
144
+ const width = p.r - p.l + 1;
145
+ const need = textBlockHeight(lines, width);
146
+ const room = p.bottom - p.top + 1;
147
+ if (need <= room) {
148
+ drawTextBlock(f.canvas, p.l, p.top, width, lines, p.bottom);
149
+ return;
150
+ }
151
+ // Keep the last inset row for an honest count of what did not fit.
152
+ drawTextBlock(f.canvas, p.l, p.top, width, lines, p.bottom - 1);
153
+ f.canvas.put(p.l, p.bottom, `${need - room + 1} more lines`, { fg: t.textFaint });
213
154
  }
214
155
 
215
- export function renderMcpWorkspace(workspace: McpWorkspace, width: number, height: number): Line[] {
216
- const metrics = getFullscreenWorkspaceMetrics({ width, height });
217
- const connected = workspace.servers.filter((server) => server.connected).length;
218
- const stateLabel = workspace.mode === 'browse' ? 'Browse' : workspace.mode === 'form' ? 'Edit Server' : 'Confirm Remove';
219
- const mainHeader = workspace.mode === 'form'
220
- ? 'MCP server form'
221
- : workspace.mode === 'delete-confirm'
222
- ? 'Remove MCP server'
223
- : `Servers ${connected}/${workspace.servers.length} connected · Tools ${workspace.tools.length}`;
156
+ export function renderMcpWorkspace(workspace: McpWorkspace, screenWidth: number, screenHeight: number): SurfaceLayer {
157
+ const t = activeTokens();
158
+ const crumbs = workspace.mode === 'form'
159
+ ? [workspace.editingServerName ? 'Edit server' : 'Add server']
160
+ : workspace.mode === 'delete-confirm' ? ['Remove server'] : [];
161
+ const f = beginModal(screenWidth, screenHeight, { title: 'MCP servers', crumbs, hints: hintsFor(workspace) });
162
+
163
+ // Status sits under both sides, wrapped in full.
164
+ const status: TextLine[] = [{ text: `Status: ${workspace.status}`, style: { fg: statusColor(workspace.status) } }];
165
+ const statusRows = textBlockHeight(status, f.r - f.l + 1);
166
+ const bodyBottom = f.bottom - statusRows - 1;
167
+ drawTextBlock(f.canvas, f.l, bodyBottom + 2, f.r - f.l + 1, status, f.bottom);
168
+
169
+ let top = f.top;
170
+ if (workspace.mode === 'browse') {
171
+ const total = workspace.rows.length;
172
+ searchRow(f, top, workspace.query, 'Filter servers and actions', workspace.query ? `${workspace.visibleRows.length} of ${total}` : `${workspace.tools.length} tools`);
173
+ top += 2;
174
+ }
224
175
 
225
- return renderFullscreenWorkspace({
226
- width,
227
- height,
228
- title: 'MCP Workspace / Servers',
229
- stateLabel,
230
- leftHeader: 'Servers',
231
- mainHeader,
232
- leftRows: buildLeftRows(workspace, metrics.bodyRows),
233
- contextRows: selectedDetailLines(workspace, metrics.contextWidth),
234
- controlRows: buildControlRows(workspace, metrics.contextWidth, metrics.controlRows),
235
- footer: footerText(workspace),
236
- });
176
+ if (workspace.mode === 'delete-confirm') {
177
+ const split = splitListDetail(f.l, f.r, top, bodyBottom, 0.45, 3);
178
+ drawList(f.canvas, {
179
+ rows: [
180
+ { label: `Remove ${workspace.editingServerName ?? '(unknown)'}`, danger: true, selected: true, mark: '✕', markFg: t.error, right: 'y' },
181
+ { label: 'Cancel and return to the server browser', right: 'n' },
182
+ ],
183
+ top: split.top, bottom: split.bottom, x0: split.x0, x1: split.x1,
184
+ });
185
+ drawDetailInset(f, split, [
186
+ { text: `Remove configured server: ${workspace.editingServerName ?? '(unknown)'}`, style: { fg: t.text, bold: true } },
187
+ { text: 'This removes the selected writable project or global config entry and reloads the MCP runtime.', style: { fg: t.textMuted } },
188
+ { text: '' },
189
+ { text: 'Press y to remove, n or Esc to cancel.', style: { fg: t.warning } },
190
+ ]);
191
+ return finishModal(f);
192
+ }
193
+
194
+ const rows = workspace.mode === 'form' ? formRows(workspace) : browseRows(workspace);
195
+ const split = splitListDetail(f.l, f.r, top, bodyBottom, 0.45);
196
+ const res = drawList(f.canvas, { rows, top: split.top, bottom: split.bottom, x0: split.x0, x1: split.x1 });
197
+ f.hintRight = scrollCountText(res.above, res.below);
198
+ drawDetailInset(f, split, workspace.mode === 'form' ? formLines(workspace) : detailLines(workspace));
199
+ return finishModal(f);
237
200
  }