@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,41 +1,65 @@
1
1
  /**
2
- * theme.ts, Semantic colour token layer.
2
+ * theme.ts, the TUI's theme runtime.
3
3
  *
4
- * Defines named tokens for every colour decision in the markdown/compositor/
5
- * conversation-rendering pipeline, resolved to concrete hex or ANSI-256 values
6
- * per background mode.
4
+ * Every colour the TUI paints comes from ONE resolved token table: the active
5
+ * theme (config `display.theme`) resolved for the active mode (config
6
+ * `display.themeMode`, or the terminal-background probe under `auto`). The
7
+ * theme data itself (bundled themes, the `system` theme generated from the
8
+ * terminal palette, the resolver and its derived fallbacks) lives in the SDK
9
+ * presentation contract; this module only holds the session state and the
10
+ * read paths the renderer uses:
7
11
  *
8
- * Dark mode values are the historically used colours. Light mode values are
9
- * consumed when the terminal-background probe (terminal-bg-probe.ts) resolves a
10
- * light background under `display.themeMode: auto`, or when the owner forces
11
- * light. A caller with no mode of its own passes 'dark', the safe default for a
12
- * terminal whose background is unknown.
12
+ * activeTokens() the full resolved table (SDK ThemeTokens shape)
13
+ * activeTheme() transcript tokens (markdown / conversation rendering)
14
+ * activeUiTones() chrome tokens in the legacy TONE_TOKENS shape
15
+ * activeDiffTones() diff add/del/hunk in the legacy DIFF_TONES shape
13
16
  *
14
- * IMPORTANT: inline code has NO background token. The bg:#1a1a1a hardcode
15
- * that previously existed caused a near-black box on light terminals.
16
- * Differentiate inline code via inlineCodeFg + bold only; bg inherits terminal.
17
+ * Theme names: every bundled theme, 'system', and the legacy 'vaporwave'
18
+ * (an alias of 'goodvibes-neon', the pre-2026-09 look). Unknown names fall
19
+ * back to the default theme. 'system' falls back to the default theme until a
20
+ * terminal palette has been read (and stays there when the terminal answered
21
+ * nothing).
17
22
  *
18
- * resolveUiTones(mode) is the sibling read path for CHROME tokens (UI_TONES
19
- * in ui-primitives.ts, panel/modal/overlay/fullscreen backgrounds, borders,
20
- * status colours). It composes the same ThemeMode dimension so that
21
- * DEFAULT_PANEL_PALETTE, DEFAULT_STYLE, FULLSCREEN_PALETTE and
22
- * DEFAULT_OVERLAY_PALETTE all read through ONE mode-resolved path instead of
23
- * importing the static UI_TONES constant directly, so one mode flip reaches
24
- * every one of them.
23
+ * IMPORTANT: inline code has NO background token. Differentiate inline code
24
+ * via inlineCodeFg + bold only; the background inherits the terminal.
25
+ *
26
+ * The protected splash gradient does NOT come from here; see splash-lines.ts.
25
27
  */
26
28
 
27
- import { UI_TONES } from './ui-primitives.ts';
29
+ import {
30
+ DEFAULT_THEME_NAME,
31
+ SYSTEM_THEME_NAME,
32
+ generateSystemTheme,
33
+ getBundledTheme,
34
+ listBundledThemes,
35
+ resolveTheme as resolveThemeFile,
36
+ themeToDiffTones,
37
+ themeToTones,
38
+ type DiffToneTokens,
39
+ type ThemeTokens as PaletteTokens,
40
+ type ToneTokens,
41
+ } from '@pellux/goodvibes-sdk/platform/presentation';
42
+ import { getTerminalPalette, type TerminalPalette } from './terminal-palette.ts';
43
+
44
+ export type { PaletteTokens, DiffToneTokens };
28
45
 
29
46
  /** Background mode, dark is the safe default for an unprobed terminal. */
30
47
  export type ThemeMode = 'dark' | 'light';
31
48
 
32
- /** Resolved semantic colour tokens (concrete hex strings or ANSI-256 indices). */
49
+ /** User-facing appearance preference: auto probes the terminal; dark/light force. */
50
+ export type ThemeModeSetting = 'auto' | 'dark' | 'light';
51
+
52
+ /** Legacy config value kept working: the old name of goodvibes-neon. */
53
+ const LEGACY_VAPORWAVE_THEME_NAME = 'vaporwave';
54
+ const NEON_THEME_NAME = 'goodvibes-neon';
55
+
56
+ /** Transcript tokens (markdown / conversation rendering), one mode. */
33
57
  export interface ThemeTokens {
34
58
  /** H1 heading foreground + table header accent */
35
59
  heading1: string;
36
60
  /** H2 heading foreground */
37
61
  heading2: string;
38
- /** H3 heading foreground (ANSI-256, falls back to nearest on ansi256 terminals) */
62
+ /** H3 heading foreground */
39
63
  heading3: string;
40
64
  /** Inline code foreground (bold is applied separately by caller) */
41
65
  inlineCodeFg: string;
@@ -51,7 +75,7 @@ export interface ThemeTokens {
51
75
  searchCurrentFg: string;
52
76
  /** Strikethrough / muted text foreground */
53
77
  strikethrough: string;
54
- /** Blockquote / dim text foreground */
78
+ /** Blockquote text foreground */
55
79
  blockquote: string;
56
80
  /** Assistant event-line marker + label accent */
57
81
  assistantHeader: string;
@@ -61,7 +85,7 @@ export interface ThemeTokens {
61
85
  toolAccent: string;
62
86
  /** Collapsed-fragment body background (tool result preview bg) */
63
87
  collapsedBodyBg: string;
64
- /** Checked task-list checkbox foreground (✓ in green) */
88
+ /** Checked task-list checkbox foreground */
65
89
  checkboxChecked: string;
66
90
  /** Error / cancelled message bar background */
67
91
  errorBarBg: string;
@@ -73,232 +97,235 @@ export interface ThemeTokens {
73
97
  diffAccent: string;
74
98
  }
75
99
 
76
- // ---------------------------------------------------------------------------
77
- // Dark palette
78
- // ---------------------------------------------------------------------------
79
- const DARK: ThemeTokens = {
80
- heading1: '#00ffff',
81
- heading2: '#00ffff',
82
- heading3: '111',
83
- inlineCodeFg: '#ffcc00',
84
- link: '#00aaff',
85
- searchMatchBg: '#806600',
86
- searchMatchFg: '#ffffff',
87
- searchCurrentBg: '#ffff00',
88
- searchCurrentFg: '#000000',
89
- strikethrough: '244',
90
- blockquote: '244',
91
- assistantHeader: UI_TONES.accent.control,
92
- reasoningAccent: UI_TONES.state.reasoning,
93
- toolAccent: UI_TONES.state.info,
94
- collapsedBodyBg: '#1a1a1a',
95
- checkboxChecked: '#22c55e',
96
- errorBarBg: '#3a1a1a',
97
- modelNameDim: '#94a3b8',
98
- toolNameFg: '#e2e8f0',
99
- diffAccent: '#f59e0b',
100
- };
100
+ /** Chrome tokens in the legacy TONE_TOKENS shape. */
101
+ export type UiToneTokens = ToneTokens;
102
+
103
+ /** One row of the theme picker: 'system' plus every bundled theme. */
104
+ export interface ThemeChoice {
105
+ readonly name: string;
106
+ readonly label: string;
107
+ readonly variants: readonly ThemeMode[];
108
+ }
101
109
 
102
110
  // ---------------------------------------------------------------------------
103
- // Light palette
104
- //
105
- // Rationale per token:
106
- // heading1/2: Deep teal (#0077aa), readable on white/cream terminals
107
- // heading3: ANSI-256 #244 equivalent on light bg → use 24 (dark cyan)
108
- // inlineCodeFg: Dark orange (#b45309), distinguishable without a box bg
109
- // link: Standard blue (#0055cc), matches browser convention
110
- // searchMatchBg: Muted yellow (#ffe066), visible on light bg
111
- // searchMatchFg: Black (#000000)
112
- // searchCurrentBg: Strong amber (#f59e0b), current match is more vivid
113
- // searchCurrentFg: Black (#000000)
114
- // strikethrough: Medium gray (ANSI-256 244 stays; light terminals map it fine)
115
- // blockquote: Dim blue-gray (ANSI-256 67)
116
- // assistantHeader: Dark cyan (#0e7490)
117
- // reasoningAccent: Dark purple (#7c3aed)
118
- // toolAccent: Dark sky (#0369a1)
119
- // collapsedBodyBg: Very light gray (#f3f4f6)
120
- // checkboxChecked: Forest green (#15803d), AA on white (contrast ~5.2:1 on #fff)
121
- // errorBarBg: Soft rose (#fee2e2), light error bar bg, legible text on top
122
- // modelNameDim: Slate-500 (#64748b), dim label; contrast ~4.6:1 on #fff
123
- // toolNameFg: Slate-800 (#334155), strong enough for tool names
124
- // diffAccent: Amber-700 (#b45309), darker amber, contrast ~4.7:1 on #fff
111
+ // Theme names
125
112
  // ---------------------------------------------------------------------------
126
- const LIGHT: ThemeTokens = {
127
- heading1: '#0077aa',
128
- heading2: '#0077aa',
129
- heading3: '24',
130
- inlineCodeFg: '#b45309',
131
- link: '#0055cc',
132
- searchMatchBg: '#ffe066',
133
- searchMatchFg: '#000000',
134
- searchCurrentBg: '#f59e0b',
135
- searchCurrentFg: '#000000',
136
- strikethrough: '244',
137
- blockquote: '67',
138
- assistantHeader: '#0e7490',
139
- reasoningAccent: '#7c3aed',
140
- toolAccent: '#0369a1',
141
- collapsedBodyBg: '#f3f4f6',
142
- checkboxChecked: '#15803d',
143
- errorBarBg: '#fee2e2',
144
- modelNameDim: '#64748b',
145
- toolNameFg: '#334155',
146
- diffAccent: '#b45309',
147
- };
148
113
 
149
- /**
150
- * resolveTheme, Return the semantic token set for the given background mode.
151
- *
152
- * Call with the session's resolved mode; 'dark' is the safe default for a
153
- * caller that has none. The returned object is frozen, do not mutate it.
154
- */
155
- export function resolveTheme(mode: ThemeMode): Readonly<ThemeTokens> {
156
- return mode === 'light' ? LIGHT : DARK;
114
+ /** Every selectable theme: 'system' first, then the bundled catalog (default first). */
115
+ export function listThemeChoices(): ThemeChoice[] {
116
+ return [
117
+ { name: SYSTEM_THEME_NAME, label: 'System (terminal colors)', variants: ['dark', 'light'] },
118
+ ...listBundledThemes().map(({ name, label, variants }) => ({ name, label, variants })),
119
+ ];
157
120
  }
158
121
 
159
- // Freeze both palette objects so they are truly immutable at runtime,
160
- // matching the Readonly<ThemeTokens> return type in the doc comment above.
161
- Object.freeze(DARK);
162
- Object.freeze(LIGHT);
163
-
164
122
  /**
165
- * Default dark-mode token set, exported for convenience.
166
- * Frozen, do not mutate.
123
+ * Turn a configured `display.theme` value into a theme name this runtime can
124
+ * resolve: 'vaporwave' maps to 'goodvibes-neon', unknown or non-string values
125
+ * map to the default theme.
167
126
  */
168
- export const DARK_THEME: Readonly<ThemeTokens> = DARK;
127
+ export function normalizeThemeName(raw: unknown): string {
128
+ if (typeof raw !== 'string') return DEFAULT_THEME_NAME;
129
+ const name = raw.trim().toLowerCase();
130
+ if (name === LEGACY_VAPORWAVE_THEME_NAME) return NEON_THEME_NAME;
131
+ if (name === SYSTEM_THEME_NAME) return SYSTEM_THEME_NAME;
132
+ return getBundledTheme(name) !== undefined ? name : DEFAULT_THEME_NAME;
133
+ }
169
134
 
170
135
  // ---------------------------------------------------------------------------
171
- // Chrome tokens (UI_TONES), mode-resolved sibling to resolveTheme().
172
- //
173
- // UI_TONES (ui-primitives.ts) is the dark entry. The light entry mirrors
174
- // dark for every role that has no light-appropriate equivalent yet, the
175
- // deliverable is the mode dimension and single read path, not a
176
- // shipped light chrome theme (see module doc comment above).
136
+ // Resolution (cached per theme + mode; the system entry per probed palette)
177
137
  // ---------------------------------------------------------------------------
178
138
 
179
- /** Recursively widen the `as const` literal leaves of UI_TONES to `string`
180
- * so mode variants (e.g. UI_TONES_LIGHT) can assign different colour
181
- * values without fighting TypeScript's literal-type inference. */
182
- type DeepWidenToString<T> = T extends string ? string : { [K in keyof T]: DeepWidenToString<T[K]> };
139
+ interface ResolvedEntry {
140
+ readonly palette: PaletteTokens;
141
+ transcript?: Readonly<ThemeTokens>;
142
+ tones?: Readonly<UiToneTokens>;
143
+ diff?: Readonly<DiffToneTokens>;
144
+ }
145
+
146
+ const resolvedCache = new Map<string, ResolvedEntry>();
147
+ let systemCachePalette: TerminalPalette | null = null;
183
148
 
184
- export type UiToneTokens = DeepWidenToString<typeof UI_TONES>;
149
+ /** True when the probe returned at least one usable colour. */
150
+ function paletteHasColours(palette: TerminalPalette): boolean {
151
+ return palette.background !== undefined
152
+ || palette.foreground !== undefined
153
+ || palette.ansi.some((slot) => slot !== undefined);
154
+ }
185
155
 
186
- //
187
- // chrome.*, persistent header/footer/thinking foregrounds that paint on the
188
- // TRANSPARENT terminal background (see the chrome group's doc in
189
- // ui-primitives.ts). Unlike fg.muted/fg.dim (which stay light for the opaque
190
- // dark modal/panel boxes), these invert toward dark so they read on a light
191
- // terminal. Contrast ratios below are against a white terminal (#ffffff),
192
- // matching the discipline of the LIGHT ThemeTokens above:
193
- // label: Slate-500 (#64748b), header title; ~4.9:1 on #fff (matches modelNameDim)
194
- // faint: Slate-400 (#94a3b8), version/rule/clean-git; ~2.7:1 on #fff, deliberately
195
- // faint (mirrors the low-contrast intent of the dark fg.dim role)
196
- // warn: Amber-700 (#b45309), dirty git / pending risk; ~5.0:1 on #fff (matches diffAccent)
197
- // bad: Red-600 (#dc2626), DANGER banner / shell risk (bold); ~5.3:1 on #fff
198
- // good: Forest-700 (#15803d), tool-call ✓ status; ~5.02:1 on #fff (matches checkboxChecked)
199
- // remote: Violet-700 (#6d28d9), risk:remote marker / plain status; ~7.10:1 on #fff,
200
- // deliberately distinct from reasoningAccent (#7c3aed) so the remote-risk cue
201
- // never reads as a reasoning accent on a light terminal
202
- const UI_TONES_LIGHT: UiToneTokens = {
203
- ...UI_TONES,
204
- state: {
205
- ...UI_TONES.state,
206
- info: LIGHT.toolAccent,
207
- reasoning: LIGHT.reasoningAccent,
208
- },
209
- accent: {
210
- ...UI_TONES.accent,
211
- brand: LIGHT.heading1,
212
- gradientStart: LIGHT.heading1,
213
- gradientEnd: LIGHT.reasoningAccent,
214
- },
215
- chrome: {
216
- ...UI_TONES.chrome,
217
- label: '#64748b',
218
- faint: '#94a3b8',
219
- warn: '#b45309',
220
- bad: '#dc2626',
221
- good: '#15803d',
222
- remote: '#6d28d9',
223
- },
224
- };
225
-
226
- Object.freeze(UI_TONES_LIGHT.state);
227
- Object.freeze(UI_TONES_LIGHT.accent);
228
- Object.freeze(UI_TONES_LIGHT.chrome);
229
- Object.freeze(UI_TONES_LIGHT);
156
+ function resolveEntry(name: string, mode: ThemeMode): ResolvedEntry {
157
+ if (name === SYSTEM_THEME_NAME) {
158
+ const probed = getTerminalPalette();
159
+ if (probed !== systemCachePalette) {
160
+ for (const key of [...resolvedCache.keys()]) {
161
+ if (key.startsWith(`${SYSTEM_THEME_NAME}:`)) resolvedCache.delete(key);
162
+ }
163
+ systemCachePalette = probed;
164
+ }
165
+ if (probed === null || !paletteHasColours(probed)) return resolveEntry(DEFAULT_THEME_NAME, mode);
166
+ }
167
+ const key = `${name}:${mode}`;
168
+ const cached = resolvedCache.get(key);
169
+ if (cached !== undefined) return cached;
170
+ const json = name === SYSTEM_THEME_NAME
171
+ ? generateSystemTheme(systemCachePalette!, mode)
172
+ : (getBundledTheme(name) ?? getBundledTheme(DEFAULT_THEME_NAME)!).json;
173
+ const entry: ResolvedEntry = { palette: Object.freeze(resolveThemeFile(json, mode)) };
174
+ resolvedCache.set(key, entry);
175
+ return entry;
176
+ }
177
+
178
+ function transcriptFrom(p: PaletteTokens): ThemeTokens {
179
+ return {
180
+ heading1: p.markdownHeading,
181
+ heading2: p.markdownHeading,
182
+ heading3: p.markdownHeading,
183
+ inlineCodeFg: p.markdownCode,
184
+ link: p.markdownLink,
185
+ searchMatchBg: p.searchMatchBg,
186
+ searchMatchFg: p.text,
187
+ searchCurrentBg: p.searchCurrentBg,
188
+ searchCurrentFg: p.selectedListItemText,
189
+ strikethrough: p.textMuted,
190
+ blockquote: p.markdownBlockQuote,
191
+ assistantHeader: p.panelControl,
192
+ reasoningAccent: p.reasoning,
193
+ toolAccent: p.info,
194
+ collapsedBodyBg: p.backgroundPanel,
195
+ checkboxChecked: p.success,
196
+ errorBarBg: p.backgroundError,
197
+ modelNameDim: p.textMuted,
198
+ toolNameFg: p.text,
199
+ diffAccent: p.warning,
200
+ };
201
+ }
230
202
 
231
203
  /**
232
- * resolveUiTones, Return the chrome (panel/modal/overlay/fullscreen) token
233
- * set for the given background mode. Single read path for UI_TONES; the
234
- * 'dark' resolution is byte-identical to the UI_TONES constant.
235
- *
236
- * Prefer activeUiTones() at call sites, resolveUiTones is the pure per-mode
237
- * resolver underneath it.
204
+ * Transcript tokens of the active theme for `mode`. The returned object is
205
+ * frozen and stable per (theme, mode), do not mutate it.
206
+ */
207
+ export function resolveTheme(mode: ThemeMode): Readonly<ThemeTokens> {
208
+ const entry = resolveEntry(activeThemeName, mode);
209
+ entry.transcript ??= Object.freeze(transcriptFrom(entry.palette));
210
+ return entry.transcript;
211
+ }
212
+
213
+ /**
214
+ * Chrome tokens (legacy TONE_TOKENS shape) of the active theme for `mode`.
215
+ * Prefer activeUiTones() at call sites.
238
216
  */
239
217
  export function resolveUiTones(mode: ThemeMode): Readonly<UiToneTokens> {
240
- return mode === 'light' ? UI_TONES_LIGHT : UI_TONES;
218
+ const entry = resolveEntry(activeThemeName, mode);
219
+ entry.tones ??= Object.freeze(themeToTones(entry.palette));
220
+ return entry.tones;
241
221
  }
242
222
 
243
223
  // ===========================================================================
244
- // Active-mode runtime.
245
- //
246
- // The mode is decided ONCE at startup, from appearance config (display.themeMode
247
- // forced dark/light) or the terminal-background probe (auto), and is then stable
248
- // for the session. Two read shapes exist because the two token layers are
249
- // consumed differently:
224
+ // Active theme runtime.
250
225
  //
251
- // - Transcript tokens (ThemeTokens): read live per render via activeTheme(),
252
- // so a dark→light repaint (auto mode, light wins within the probe window)
253
- // re-resolves without any module reload.
254
- //
255
- // - Chrome tokens (UiToneTokens): baked into module-level palette CONSTANTS
256
- // (DEFAULT_PANEL_PALETTE, DEFAULT_OVERLAY_PALETTE, FULLSCREEN_PALETTE,
257
- // DEFAULT_STYLE) that hundreds of call sites read by reference. Those
258
- // constants cannot be re-resolved per call without a rewrite, so each owner
259
- // registers an in-place rebuild via registerThemeRefresh(); setActiveThemeMode
260
- // runs every rebuild in registration order (base palettes before the
261
- // extendPalette-derived panel palettes) so a single mode flip updates them
262
- // all. The rebuild is fully reversible: light→dark restores byte-identical
263
- // dark values (tests rely on this to keep the shared test process's default
264
- // at dark).
226
+ // Theme name and mode are session state. Transcript tokens are read live per
227
+ // render (activeTheme()). Chrome palettes (DEFAULT_VIEW_PALETTE,
228
+ // DEFAULT_OVERLAY_PALETTE, FULLSCREEN_PALETTE, DEFAULT_STYLE, MODAL_TONES and
229
+ // every extendPalette result) are module-level objects read by reference at
230
+ // hundreds of call sites, so each owner registers an in-place rebuild via
231
+ // registerThemeRefresh(); every theme or mode change runs all rebuilds in
232
+ // registration order (base palettes before the extendPalette-derived ones).
233
+ // Callers that change the theme at runtime also request a full repaint.
265
234
  // ===========================================================================
266
235
 
267
- /** User-facing appearance preference: auto probes the terminal; dark/light force. */
268
- export type ThemeModeSetting = 'auto' | 'dark' | 'light';
269
-
270
236
  /** The resolved mode in effect for the current session. Dark is the safe default. */
271
237
  let activeMode: ThemeMode = 'dark';
272
238
 
273
- /** In-place palette rebuilders, run (in registration order) on every mode flip. */
239
+ /** The theme in effect (already normalized). */
240
+ let activeThemeName: string = DEFAULT_THEME_NAME;
241
+
242
+ /** In-place palette rebuilders, run (in registration order) on every change. */
274
243
  const themeRefreshers: Array<() => void> = [];
275
244
 
276
245
  /**
277
- * Register an in-place palette rebuild to run whenever the active mode changes.
278
- * Base-palette owners register at their own module-eval time (before any
279
- * extendPalette-derived palette, which depends on the base), so refreshers run
280
- * base-first, the ordering the extended palettes require to re-merge correctly.
246
+ * Register an in-place palette rebuild to run whenever the active theme or
247
+ * mode changes. Base-palette owners register at their own module-eval time,
248
+ * before any extendPalette-derived palette (which depends on the base).
281
249
  */
282
250
  export function registerThemeRefresh(rebuild: () => void): void {
283
251
  themeRefreshers.push(rebuild);
284
252
  }
285
253
 
254
+ /** The entry for the active (theme, mode); cleared on every change. */
255
+ let activeEntry: ResolvedEntry | null = null;
256
+
257
+ function currentEntry(): ResolvedEntry {
258
+ activeEntry ??= resolveEntry(activeThemeName, activeMode);
259
+ return activeEntry;
260
+ }
261
+
262
+ function runRefreshers(): void {
263
+ activeEntry = null;
264
+ for (const rebuild of themeRefreshers) rebuild();
265
+ }
266
+
286
267
  /**
287
- * Set the active background mode and rebuild every registered chrome palette
288
- * in place. Idempotent and reversible. Callers: startup (forced mode or probe
289
- * result) and the settings-modal change hook for forced modes.
268
+ * Set the active background mode and rebuild every registered palette in
269
+ * place. Idempotent and reversible.
290
270
  */
291
271
  export function setActiveThemeMode(mode: ThemeMode): void {
292
272
  activeMode = mode;
293
- for (const rebuild of themeRefreshers) rebuild();
273
+ runRefreshers();
274
+ }
275
+
276
+ /**
277
+ * Set the active theme by (configured) name and rebuild every registered
278
+ * palette in place. Accepts any config value; see normalizeThemeName.
279
+ * Returns the normalized name now in effect.
280
+ */
281
+ export function setActiveThemeName(name: unknown): string {
282
+ activeThemeName = normalizeThemeName(name);
283
+ runRefreshers();
284
+ return activeThemeName;
285
+ }
286
+
287
+ /**
288
+ * Re-resolve after the terminal palette arrived or changed. Only the system
289
+ * theme depends on it; for any other theme this is a no-op returning false.
290
+ */
291
+ export function refreshForTerminalPalette(): boolean {
292
+ if (activeThemeName !== SYSTEM_THEME_NAME) return false;
293
+ runRefreshers();
294
+ return true;
294
295
  }
295
296
 
296
- /** Transcript tokens for the active mode, read live, per render. */
297
+ /** The resolved background mode in effect (dark or light). */
298
+ export function activeThemeMode(): ThemeMode {
299
+ return activeMode;
300
+ }
301
+
302
+ /** The normalized name of the active theme ('system' stays 'system'). */
303
+ export function getActiveThemeName(): string {
304
+ return activeThemeName;
305
+ }
306
+
307
+ /** Full token table for the active theme and mode, read live. */
308
+ export function activeTokens(): Readonly<PaletteTokens> {
309
+ return currentEntry().palette;
310
+ }
311
+
312
+ /** Transcript tokens for the active theme and mode, read live, per render. */
297
313
  export function activeTheme(): Readonly<ThemeTokens> {
298
- return resolveTheme(activeMode);
314
+ const entry = currentEntry();
315
+ entry.transcript ??= Object.freeze(transcriptFrom(entry.palette));
316
+ return entry.transcript;
299
317
  }
300
318
 
301
- /** Chrome tokens for the active mode, used to build (and rebuild) palettes. */
319
+ /** Chrome tokens for the active theme and mode, used to build (and rebuild) palettes. */
302
320
  export function activeUiTones(): Readonly<UiToneTokens> {
303
- return resolveUiTones(activeMode);
321
+ const entry = currentEntry();
322
+ entry.tones ??= Object.freeze(themeToTones(entry.palette));
323
+ return entry.tones;
324
+ }
325
+
326
+ /** Diff add/del/hunk tones for the active theme and mode. */
327
+ export function activeDiffTones(): Readonly<DiffToneTokens> {
328
+ const entry = currentEntry();
329
+ entry.diff ??= Object.freeze(themeToDiffTones(entry.palette));
330
+ return entry.diff;
304
331
  }
@@ -17,7 +17,6 @@ export function renderThinkingBlock(text: string, width: number): Line[] {
17
17
  {
18
18
  accent: t.state.reasoning,
19
19
  text: t.chrome.faint,
20
- dim: true,
21
20
  italic: true,
22
21
  },
23
22
  BORDERS.THINKING.char,