@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
@@ -0,0 +1,192 @@
1
+ /**
2
+ * process-view.ts, a background process opened full screen: its live output.
3
+ *
4
+ * row 0 blank
5
+ * rows HH:MM:SS at column 3 (faint), the line from column 13,
6
+ * wrapped to width-4 with continuations at column 13; a
7
+ * line that reads as an error in the error color
8
+ * second-last blank
9
+ * last the follow state: "▾ following · new output scrolls in",
10
+ * or how far up you are, or how the process ended; while
11
+ * searching, the search line in its place
12
+ *
13
+ * Follow mode is on by default: the newest output stays in view. Scrolling
14
+ * up leaves it; End (or scrolling back to the bottom) returns to it. A search
15
+ * leaves follow mode and jumps between matching lines.
16
+ */
17
+
18
+ import { createEmptyLine, type Line } from '@pellux/goodvibes-sdk/platform/types';
19
+ import { getDisplayWidth, truncateDisplay, wrapText } from '../utils/terminal-width.ts';
20
+ import { activeTokens } from './theme.ts';
21
+ import { keycapHintsWidth, paintKeycapHints } from './surface-kit-parts.ts';
22
+ import type { ProcessLine } from '../core/process-output-log.ts';
23
+
24
+ const TIME_X = 3;
25
+ const TEXT_X = 13;
26
+
27
+ /** One screen row of output. */
28
+ export interface ProcessRow {
29
+ /** The source line's index in the log. */
30
+ readonly source: number;
31
+ /** Set on the first row of a line. */
32
+ readonly time?: string;
33
+ readonly text: string;
34
+ readonly error: boolean;
35
+ }
36
+
37
+ export interface ProcessSearchState {
38
+ readonly query: string;
39
+ /** Typing the query (the search line takes the keys). */
40
+ readonly editing: boolean;
41
+ /** The log line of the current match (-1 when nothing matches). */
42
+ readonly current: number;
43
+ }
44
+
45
+ export interface ProcessViewInput {
46
+ readonly width: number;
47
+ /** Rows the view may use. */
48
+ readonly height: number;
49
+ readonly rows: readonly ProcessRow[];
50
+ /** Rows scrolled up from the newest; 0 follows the output. */
51
+ readonly scrollFromBottom: number;
52
+ readonly color: string;
53
+ /** How the process ended, once it has ("exited with code 0 · 12m 04s"). */
54
+ readonly ended?: { readonly text: string; readonly ok: boolean } | null;
55
+ readonly search?: ProcessSearchState | null;
56
+ /** Lines the log dropped off the front (its bound). */
57
+ readonly dropped?: number;
58
+ }
59
+
60
+ function twoDigits(n: number): string {
61
+ return n < 10 ? `0${n}` : String(n);
62
+ }
63
+
64
+ /** HH:MM:SS in local time. */
65
+ function clockTime(at: number): string {
66
+ const d = new Date(at);
67
+ return `${twoDigits(d.getHours())}:${twoDigits(d.getMinutes())}:${twoDigits(d.getSeconds())}`;
68
+ }
69
+
70
+ /** Wrap log lines into screen rows (the caller caches this per width and line count). */
71
+ export function processRows(lines: readonly ProcessLine[], width: number, formatTime: (at: number) => string = clockTime): ProcessRow[] {
72
+ const room = Math.max(10, width - 4 - TEXT_X);
73
+ const rows: ProcessRow[] = [];
74
+ lines.forEach((line, source) => {
75
+ const parts = line.text.length === 0 ? [''] : wrapText(line.text, room);
76
+ parts.forEach((text, k) => rows.push({ source, time: k === 0 ? formatTime(line.at) : undefined, text, error: line.error }));
77
+ });
78
+ return rows;
79
+ }
80
+
81
+ /** Source indexes of lines containing the query (case-insensitive). */
82
+ export function processMatches(lines: readonly ProcessLine[], query: string): number[] {
83
+ const q = query.toLowerCase();
84
+ if (!q) return [];
85
+ const out: number[] = [];
86
+ lines.forEach((line, i) => { if (line.text.toLowerCase().includes(q)) out.push(i); });
87
+ return out;
88
+ }
89
+
90
+ function put(line: Line, x: number, endX: number, text: string, style: { fg: string; bg?: string; bold?: boolean }): number {
91
+ let cx = x;
92
+ for (const ch of text) {
93
+ const w = getDisplayWidth(ch);
94
+ if (w <= 0) continue;
95
+ if (cx + w > endX || cx >= line.length) break;
96
+ line[cx] = { char: ch, fg: style.fg, bg: style.bg ?? '', bold: style.bold ?? false, dim: false, underline: false, italic: false, strikethrough: false };
97
+ if (w === 2 && cx + 1 < line.length) line[cx + 1] = { ...line[cx]!, char: '' };
98
+ cx += w;
99
+ }
100
+ return cx;
101
+ }
102
+
103
+ function blank(width: number): Line {
104
+ const line = createEmptyLine(width);
105
+ for (const cell of line) cell.bg = '';
106
+ return line;
107
+ }
108
+
109
+ /** Tint every occurrence of the query on a drawn row. */
110
+ function markMatches(line: Line, text: string, query: string, bg: string): void {
111
+ if (!query) return;
112
+ const lower = text.toLowerCase();
113
+ const q = query.toLowerCase();
114
+ let from = 0;
115
+ for (;;) {
116
+ const at = lower.indexOf(q, from);
117
+ if (at < 0) return;
118
+ const x0 = TEXT_X + getDisplayWidth(text.slice(0, at));
119
+ const w = getDisplayWidth(text.slice(at, at + q.length));
120
+ for (let x = x0; x < x0 + w && x < line.length; x++) line[x] = { ...line[x]!, bg };
121
+ from = at + q.length;
122
+ }
123
+ }
124
+
125
+ /** The largest scrollFromBottom that still shows rows. */
126
+ export function processMaxScroll(rowCount: number, height: number): number {
127
+ return Math.max(0, rowCount - Math.max(1, height - 3));
128
+ }
129
+
130
+ export function renderProcessView(input: ProcessViewInput): Line[] {
131
+ const t = activeTokens();
132
+ const { width } = input;
133
+ const logRows = Math.max(1, input.height - 3);
134
+ const end = width - 3;
135
+ const scroll = Math.max(0, Math.min(input.scrollFromBottom, processMaxScroll(input.rows.length, input.height)));
136
+ const last = input.rows.length - scroll;
137
+ const first = Math.max(0, last - logRows);
138
+ const search = input.search ?? null;
139
+
140
+ const out: Line[] = [blank(width)];
141
+ if (input.rows.length === 0) {
142
+ const line = blank(width);
143
+ put(line, TIME_X, end, input.ended ? 'The process printed nothing.' : 'No output yet.', { fg: t.textFaint });
144
+ out.push(line);
145
+ }
146
+ if (first === 0 && (input.dropped ?? 0) > 0 && input.rows.length > 0) {
147
+ const line = blank(width);
148
+ put(line, TIME_X, end, `… ${input.dropped} earlier lines are no longer kept`, { fg: t.textFaint });
149
+ out.push(line);
150
+ }
151
+ for (let r = first; r < last; r++) {
152
+ const row = input.rows[r]!;
153
+ const line = blank(width);
154
+ if (row.time) put(line, TIME_X, TEXT_X - 1, row.time, { fg: t.textFaint });
155
+ put(line, TEXT_X, end, row.text, { fg: row.error ? t.error : t.text });
156
+ if (search && search.query) markMatches(line, row.text, search.query, row.source === search.current ? t.searchCurrentBg : t.searchMatchBg);
157
+ out.push(line);
158
+ }
159
+ while (out.length < input.height - 2) out.push(blank(width));
160
+ out.length = Math.min(out.length, Math.max(0, input.height - 2));
161
+ out.push(blank(width));
162
+ out.push(statusRow(input, scroll, end));
163
+ return out;
164
+ }
165
+
166
+ function statusRow(input: ProcessViewInput, scroll: number, end: number): Line {
167
+ const t = activeTokens();
168
+ const line = blank(input.width);
169
+ const search = input.search ?? null;
170
+ if (search && (search.editing || search.query)) {
171
+ let x = put(line, TIME_X, end, '/', { fg: input.color, bold: true });
172
+ x = put(line, x + 1, end, search.query, { fg: t.text });
173
+ if (search.editing) x = put(line, x, end, '▏', { fg: input.color });
174
+ const hints: Array<[string, string]> = search.editing ? [['⏎', 'next'], ['esc', 'close']] : [['n', 'next'], ['/', 'edit'], ['esc', 'close']];
175
+ const hintsW = keycapHintsWidth(hints);
176
+ if (x + 3 + hintsW <= end) paintKeycapHints(line, x + 3, end, hints, { fg: t.textFaint });
177
+ return line;
178
+ }
179
+ if (scroll > 0) {
180
+ const x = put(line, TIME_X, end, '▴', { fg: input.color, bold: true });
181
+ put(line, x + 1, end, truncateDisplay(`paused · ${scroll} newer row${scroll === 1 ? '' : 's'} below · end follows again`, Math.max(0, end - x - 1)), { fg: t.textFaint });
182
+ return line;
183
+ }
184
+ if (input.ended) {
185
+ const x = put(line, TIME_X, end, '■', { fg: input.ended.ok ? t.success : t.error, bold: true });
186
+ put(line, x + 1, end, truncateDisplay(input.ended.text, Math.max(0, end - x - 1)), { fg: input.ended.ok ? t.textFaint : t.error });
187
+ return line;
188
+ }
189
+ const x = put(line, TIME_X, end, '▾', { fg: input.color, bold: true });
190
+ put(line, x + 1, end, 'following · new output scrolls in', { fg: t.textFaint });
191
+ return line;
192
+ }
@@ -1,128 +1,76 @@
1
1
  /**
2
- * renderProfilePickerModal, renders the /profiles picker modal as Line[]
3
- * using ModalFactory.
4
- *
5
- * Shows a list of saved profiles with:
6
- * - name, timestamp (formatted)
7
- * Footer hints: [Up/Down] Navigate [Enter] Load [d] Arm/Delete [s] Save current [Esc] Close
2
+ * renderProfilePickerModal, the /profiles picker drawn with the modal surface
3
+ * kit: the always-live search row (filters by name), one kit row per saved
4
+ * profile (name, saved time right-aligned), an armed delete shown in the
5
+ * error color with its "press d again" prompt, the status line, and keycap
6
+ * hints: ↑↓ move · ⏎ load · d delete · s save current.
8
7
  */
9
8
 
10
- import type { Line } from '@pellux/goodvibes-sdk/platform/types';
11
- import { ModalFactory } from './modal-factory.ts';
12
9
  import type { ProfilePickerModal } from '../input/profile-picker-modal.ts';
13
10
  import { formatTimestamp } from './modal-utils.ts';
14
- import { fitDisplay } from '../utils/terminal-width.ts';
15
- import { getOverlaySurfaceMetrics, getStableOverlayContentRows } from './overlay-viewport.ts';
11
+ import { activeTokens } from './theme.ts';
12
+ import {
13
+ beginModal,
14
+ finishModal,
15
+ searchRow,
16
+ scrollCountText,
17
+ type KitHint,
18
+ type SurfaceLayer,
19
+ } from './surface-kit.ts';
20
+ import { drawList, type KitRow } from './surface-kit-list.ts';
21
+ import { drawTextBlock, listHeight, modalHeightFor, modalTextWidth, textBlockHeight, type TextLine } from './surface-kit-extra.ts';
16
22
 
17
- // ---------------------------------------------------------------------------
18
- // Renderer
19
- // ---------------------------------------------------------------------------
23
+ const HINTS: readonly KitHint[] = [['↑↓', 'move'], ['⏎', 'load'], ['d', 'delete'], ['s', 'save current']];
20
24
 
21
25
  /**
22
- * Render the profile picker modal as Line[] for overlay in the viewport.
23
- *
24
- * @param modal ProfilePickerModal state object.
25
- * @param width Terminal width.
26
+ * Render the profile picker modal as a SurfaceLayer in screen coordinates.
26
27
  */
27
28
  export function renderProfilePickerModal(
28
29
  modal: ProfilePickerModal,
29
- width: number,
30
- viewportHeight = 24,
31
- ): Line[] {
32
- const metrics = getOverlaySurfaceMetrics(width, viewportHeight, {
33
- chromeRows: 6,
34
- minContentRows: 5,
35
- maxContentRows: 9,
36
- });
37
- const boxMargin = metrics.margin;
38
- const boxW = metrics.boxWidth;
39
- const contentW = metrics.contentWidth;
40
- const visibleRows = metrics.contentRows;
41
- const targetContentRows = getStableOverlayContentRows(metrics.contentRows, 8);
42
- modal.setVisibleRows(visibleRows);
30
+ screenWidth: number,
31
+ screenHeight = 24,
32
+ ): SurfaceLayer {
33
+ const t = activeTokens();
34
+ const visible = modal.visibleProfiles;
35
+ const armed = modal.deleteConfirmationTarget;
36
+ const rows: KitRow[] = visible.map((profile, i) => ({
37
+ label: profile.name,
38
+ right: formatTimestamp(profile.timestamp),
39
+ selected: i === modal.selectedIndex,
40
+ danger: armed === profile.name,
41
+ mark: armed === profile.name ? '✕' : undefined,
42
+ markFg: t.error,
43
+ }));
43
44
 
44
- const sections: import('./modal-factory.ts').ModalSection[] = [];
45
+ const notes: TextLine[] = [];
46
+ if (armed) notes.push({ text: `Press d again to permanently delete ${armed}.`, style: { fg: t.warning, bold: true } });
47
+ else if (modal.statusMessage) notes.push({ text: modal.statusMessage, style: { fg: t.accent } });
45
48
 
46
- if (modal.profiles.length === 0) {
47
- sections.push({
48
- type: 'text',
49
- content: 'No saved profiles.',
50
- style: { fg: '244', dim: true },
51
- });
52
- sections.push({
53
- type: 'text',
54
- content: 'Press [s] to save the current settings as a profile.',
55
- style: { fg: '240', dim: true },
56
- });
57
- } else {
58
- // Proportional column widths that adapt to the modal's content width:
59
- // timestamp ~22% (clamped 10..16); the name column absorbs the remainder
60
- // (ported from session-picker-modal.ts). Reserves 4 cols, 2 for the
61
- // name/timestamp separator and 2 for the list row's selection indicator
62
- // ("▸ ") that ModalFactory prepends outside the wrapped label, so the
63
- // row never spills the timestamp's embedded space onto a wrapped line.
64
- const tsW = Math.min(16, Math.max(10, Math.floor(contentW * 0.22)));
65
- const nameW = Math.max(8, contentW - tsW - 4);
66
-
67
- // Column header
68
- const nameHdr = fitDisplay('Name', nameW);
69
- const tsHdr = fitDisplay('Saved', tsW);
70
- sections.push({
71
- type: 'text',
72
- content: `${nameHdr} ${tsHdr}`,
73
- style: { fg: '240', dim: true },
74
- });
75
- sections.push({ type: 'separator' });
76
-
77
- const visibleProfiles = modal.profiles.slice(modal.scrollOffset, modal.scrollOffset + visibleRows);
78
- const listItems: import('./modal-factory.ts').ModalListItem[] = visibleProfiles.map((prof, idx) => {
79
- const isSelected = modal.scrollOffset + idx === modal.selectedIndex;
49
+ const width = modalTextWidth(screenWidth, screenHeight);
50
+ const allRows = modal.profiles.map((profile): KitRow => ({ label: profile.name, right: formatTimestamp(profile.timestamp) }));
51
+ const emptyLines: TextLine[] = [
52
+ { text: 'No saved profiles.', style: { fg: t.textMuted } },
53
+ { text: 'Press s to save the current settings as a profile.', style: { fg: t.textFaint } },
54
+ ];
55
+ const listRows = allRows.length > 0 ? listHeight(allRows, 0, width - 1) : textBlockHeight(emptyLines, width);
56
+ const noteRows = notes.length > 0 ? textBlockHeight(notes, width) + 1 : 0;
57
+ const height = modalHeightFor(screenWidth, screenHeight, { hints: HINTS }, 2 + listRows + noteRows);
80
58
 
81
- const nameStr = fitDisplay(prof.name, nameW);
59
+ const f = beginModal(screenWidth, screenHeight, { title: 'Profiles', hints: HINTS, height });
60
+ const total = modal.profiles.length;
61
+ searchRow(f, f.top, modal.query, 'Filter profiles', modal.query ? `${visible.length} of ${total}` : `${total} saved`);
82
62
 
83
- const tsStr = fitDisplay(formatTimestamp(prof.timestamp), tsW);
63
+ const top = f.top + 2;
64
+ const listBottom = f.bottom - noteRows;
65
+ if (notes.length > 0) drawTextBlock(f.canvas, f.l, listBottom + 2, f.r - f.l + 1, notes, f.bottom);
84
66
 
85
- const label = `${nameStr} ${tsStr}`;
86
- return { label, selected: isSelected };
87
- });
88
-
89
- sections.push({ type: 'list', items: listItems });
90
- if (modal.profiles.length > visibleRows) {
91
- sections.push({ type: 'separator' });
92
- sections.push({
93
- type: 'text',
94
- content: `[${modal.scrollOffset + 1}-${Math.min(modal.profiles.length, modal.scrollOffset + visibleRows)} of ${modal.profiles.length}]`,
95
- style: { fg: '244', dim: true },
96
- });
97
- }
98
- }
99
-
100
- // Status message if present
101
- if (modal.statusMessage) {
102
- sections.push({ type: 'separator' });
103
- sections.push({
104
- type: 'text',
105
- content: modal.statusMessage,
106
- style: { fg: '#00ffcc' },
107
- });
108
- }
109
- if (modal.deleteConfirmationTarget) {
110
- sections.push({
111
- type: 'text',
112
- content: `Press [d] again to permanently delete ${modal.deleteConfirmationTarget}.`,
113
- style: { fg: '#f59e0b', dim: true },
114
- });
67
+ if (total === 0) {
68
+ drawTextBlock(f.canvas, f.l, top, f.r - f.l + 1, emptyLines, listBottom);
69
+ } else if (rows.length === 0) {
70
+ drawTextBlock(f.canvas, f.l, top, f.r - f.l + 1, [{ text: `No profiles match "${modal.query}".`, style: { fg: t.textMuted } }], listBottom);
71
+ } else {
72
+ const res = drawList(f.canvas, { rows, top, bottom: listBottom, x0: f.l, x1: f.r });
73
+ f.hintRight = scrollCountText(res.above, res.below);
115
74
  }
116
-
117
- return ModalFactory.createModal(
118
- {
119
- title: 'Profiles',
120
- width: boxW,
121
- margin: boxMargin,
122
- targetContentRows,
123
- sections,
124
- hints: ['[Up/Down] Navigate', '[Enter] Load', '[d] Arm/Delete', '[s] Save current', '[Esc] Close'],
125
- },
126
- width,
127
- );
75
+ return finishModal(f);
128
76
  }
@@ -2,6 +2,7 @@ import type { Line } from '@pellux/goodvibes-sdk/platform/types';
2
2
  import { fitDisplay, getDisplayWidth, truncateDisplay } from '../utils/terminal-width.ts';
3
3
  import type { SearchManager } from '../input/search.ts';
4
4
  import { createBottomBarLine, writeBottomBarText } from '@pellux/goodvibes-terminal-shell';
5
+ import { activeTokens } from './theme.ts';
5
6
 
6
7
  /**
7
8
  * Render the search bar as a single Line[] overlay at the bottom of the viewport.
@@ -65,13 +66,15 @@ export function renderSearchOverlay(
65
66
 
66
67
  // Build the full line text (match count embedded for positional tracking)
67
68
  const fullLine = truncatedLeft + matchStr + hints + ' ';
68
- const line = createBottomBarLine(width, { fg: '#000000', bg: '#00ffcc' });
69
- writeBottomBarText(line, 0, width, fitDisplay(truncateDisplay(fullLine, width), width), { fg: '#000000', bg: '#00ffcc' });
69
+ const p = activeTokens();
70
+ const line = createBottomBarLine(width, { fg: p.selectedListItemText, bg: p.accent });
71
+ writeBottomBarText(line, 0, width, fitDisplay(truncateDisplay(fullLine, width), width), { fg: p.selectedListItemText, bg: p.accent });
70
72
 
71
73
  // Overwrite match count segment with dim grey styling
72
74
  if (matchStr.length > 0) {
73
75
  const matchStart = getDisplayWidth(truncatedLeft);
74
- writeBottomBarText(line, matchStart, matchStrW, matchStr, { fg: '#888888', bg: '#00ffcc', dim: true });
76
+ // dim kept: de-emphasis on the accent bar, where a faint grey would not read.
77
+ writeBottomBarText(line, matchStart, matchStrW, matchStr, { fg: p.selectedListItemText, bg: p.accent, dim: true });
75
78
  }
76
79
 
77
80
  return [line];