@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,188 @@
1
+ /**
2
+ * throbber.ts, the one row above the input area that says what the main
3
+ * session is doing right now. It shows only while main is working (a turn
4
+ * runs, or the conversation is being compacted) and is gone at rest.
5
+ *
6
+ * col 3 the spinner (brand gradient on the glyph only)
7
+ * col 5..w-4 what is happening, then its elapsed time
8
+ *
9
+ * It is its own surface: never inside the input area, and never on the
10
+ * status line, which keeps session state (mode, cost, context bar) and the
11
+ * keys (esc interrupt).
12
+ *
13
+ * What it names, first match wins:
14
+ * - a permission prompt waiting on you: Waiting for your approval · bash · npm test · 12s
15
+ * - a compaction: Compacting the conversation · 4s
16
+ * - a running tool: Running bash · npm test · 3s
17
+ * - the model (the honest waiting phrase from the SDK): Thinking... · 12s · first token 1.2s · 40 tok/s
18
+ *
19
+ * Inside an agent or process view the row keeps main in sight the same way,
20
+ * led by "main ·" so it is never read as the view's own activity.
21
+ */
22
+
23
+ import { type Line, createEmptyLine } from '@pellux/goodvibes-sdk/platform/types';
24
+ import type { ToolCall } from '@pellux/goodvibes-sdk/platform/types';
25
+ import { getDisplayWidth, interpolateColor, truncateDisplay } from '../utils/terminal-width.ts';
26
+ import { formatElapsed } from '../utils/format-elapsed.ts';
27
+ import { beadArgument, beadName } from './lane-graph/bead.ts';
28
+ import { activeTokens } from './theme.ts';
29
+
30
+ /** Column of the spinner (the input area's first fill column). */
31
+ const THROBBER_SPINNER_X = 3;
32
+ /** First text column (the input area's text column). */
33
+ const THROBBER_TEXT_X = 5;
34
+ /** The most a tool's argument takes before it is cut, so the elapsed time stays on the row. */
35
+ const ARGUMENT_MAX = 60;
36
+ const SEP = ' · ';
37
+
38
+ /** What the main session is doing, as the throbber names it. */
39
+ export type ThrobberActivity =
40
+ | { readonly kind: 'approval'; readonly tool: string; readonly argument: string; readonly elapsedMs?: number }
41
+ | { readonly kind: 'compacting'; readonly elapsedMs?: number }
42
+ | { readonly kind: 'tool'; readonly tool: string; readonly argument: string; readonly elapsedMs?: number }
43
+ | { readonly kind: 'model'; readonly phrase: string; readonly elapsedMs?: number; readonly ttftMs?: number; readonly tokenSpeed?: number };
44
+
45
+ /** One frame of the throbber. */
46
+ export interface ThrobberState {
47
+ /** The spinner glyph for this frame. */
48
+ readonly spinner: string;
49
+ /** Animation frame, used for the spinner's gradient position. */
50
+ readonly frame: number;
51
+ readonly activity: ThrobberActivity;
52
+ /** Set inside an agent or process view: whose activity this is ("main"). */
53
+ readonly owner?: string;
54
+ }
55
+
56
+ /** A tool call as the throbber needs it: its name and arguments. */
57
+ export interface ThrobberToolCall {
58
+ readonly name: string;
59
+ readonly args?: Record<string, unknown>;
60
+ }
61
+
62
+ export interface ThrobberActivityInput {
63
+ /** A main turn is running. */
64
+ readonly turnActive: boolean;
65
+ /** A compaction of the main conversation is running (inside a turn or not). */
66
+ readonly compacting: boolean;
67
+ /** When the running compaction started (epoch ms), once known. */
68
+ readonly compactingSinceMs?: number;
69
+ /** The permission prompt the turn is blocked on. */
70
+ readonly pendingApproval?: ThrobberToolCall | null;
71
+ /** The tool the turn is executing now, and when it started (epoch ms). */
72
+ readonly activeTool?: (ThrobberToolCall & { readonly startedAtMs?: number }) | null;
73
+ /** The model's honest waiting phrase (UIFactory.busyPhrase). */
74
+ readonly modelPhrase: string;
75
+ /** When the turn's current stream started (epoch ms); 0 or undefined when unknown. */
76
+ readonly turnStartMs?: number;
77
+ readonly ttftMs?: number;
78
+ readonly tokenSpeed?: number;
79
+ readonly now: number;
80
+ }
81
+
82
+ /** "bash", "npm test": a call's short name and key argument, the way its bead names it. */
83
+ function describeToolCall(call: ThrobberToolCall): { tool: string; argument: string } {
84
+ const asCall = { id: '', name: call.name, arguments: call.args ?? {} } as ToolCall;
85
+ let argument = '';
86
+ try { argument = beadArgument(asCall); } catch { argument = ''; }
87
+ return { tool: beadName(asCall), argument: truncateDisplay(argument, ARGUMENT_MAX) };
88
+ }
89
+
90
+ /** What main is doing now, or null at rest (the throbber is not drawn). */
91
+ export function resolveThrobberActivity(input: ThrobberActivityInput): ThrobberActivity | null {
92
+ if (!input.turnActive && !input.compacting) return null;
93
+ const since = (start: number | undefined): number | undefined => (start !== undefined && start > 0 ? Math.max(0, input.now - start) : undefined);
94
+ const turnElapsed = since(input.turnStartMs);
95
+ if (input.turnActive && input.pendingApproval) {
96
+ return { kind: 'approval', ...describeToolCall(input.pendingApproval), elapsedMs: turnElapsed };
97
+ }
98
+ if (input.compacting) return { kind: 'compacting', elapsedMs: since(input.compactingSinceMs) };
99
+ if (input.activeTool) {
100
+ return { kind: 'tool', ...describeToolCall(input.activeTool), elapsedMs: since(input.activeTool.startedAtMs) ?? turnElapsed };
101
+ }
102
+ return {
103
+ kind: 'model',
104
+ phrase: input.modelPhrase,
105
+ elapsedMs: turnElapsed,
106
+ ttftMs: input.ttftMs !== undefined && input.ttftMs > 0 ? input.ttftMs : undefined,
107
+ tokenSpeed: input.tokenSpeed !== undefined && input.tokenSpeed > 0 ? input.tokenSpeed : undefined,
108
+ };
109
+ }
110
+
111
+ interface ThrobberText {
112
+ readonly label: string;
113
+ readonly subject: string;
114
+ readonly tail: readonly string[];
115
+ }
116
+
117
+ function textOf(activity: ThrobberActivity): ThrobberText {
118
+ const elapsed = activity.elapsedMs !== undefined ? [formatElapsed(activity.elapsedMs)] : [];
119
+ switch (activity.kind) {
120
+ case 'approval':
121
+ return { label: 'Waiting for your approval', subject: [activity.tool, activity.argument].filter(Boolean).join(SEP), tail: elapsed };
122
+ case 'compacting':
123
+ return { label: 'Compacting the conversation', subject: '', tail: elapsed };
124
+ case 'tool':
125
+ return { label: `Running ${activity.tool}`, subject: activity.argument, tail: elapsed };
126
+ case 'model': {
127
+ const tail = [...elapsed];
128
+ if (activity.ttftMs !== undefined) tail.push(`first token ${formatElapsed(activity.ttftMs)}`);
129
+ if (activity.tokenSpeed !== undefined) tail.push(`${Math.round(activity.tokenSpeed)} tok/s`);
130
+ return { label: activity.phrase, subject: '', tail };
131
+ }
132
+ }
133
+ }
134
+
135
+ function put(line: Line, x: number, endX: number, text: string, fg: string, bold = false): number {
136
+ let cx = x;
137
+ for (const ch of text) {
138
+ const w = getDisplayWidth(ch);
139
+ if (w <= 0) continue;
140
+ if (cx + w > endX) break;
141
+ line[cx] = { char: ch, fg, bg: '', bold, dim: false, underline: false, italic: false, strikethrough: false };
142
+ if (w === 2 && cx + 1 < line.length) line[cx + 1] = { ...line[cx]!, char: '' };
143
+ cx += w;
144
+ }
145
+ return cx;
146
+ }
147
+
148
+ /**
149
+ * Draw the throbber row. The text ends at width-4 or earlier. When the row is
150
+ * short the elapsed pieces go first, then the subject is cut, then the label.
151
+ */
152
+ export function renderThrobberLine(width: number, state: ThrobberState): Line {
153
+ const t = activeTokens();
154
+ const line = createEmptyLine(width);
155
+ for (const cell of line) cell.bg = '';
156
+ const endX = Math.max(THROBBER_TEXT_X, width - 3); // exclusive: the last text column is width-4
157
+ if (width <= THROBBER_TEXT_X) return line;
158
+ const glyphFg = interpolateColor(t.brand, t.brandEnd, (Math.sin(state.frame / 6) + 1) / 2);
159
+ put(line, THROBBER_SPINNER_X, endX, state.spinner, glyphFg, true);
160
+
161
+ const { label, subject, tail } = textOf(state.activity);
162
+ const room = endX - THROBBER_TEXT_X;
163
+ const owner = state.owner ? `${state.owner}${SEP}` : '';
164
+ const head = owner + label;
165
+ const tailText = tail.length > 0 ? SEP + tail.join(SEP) : '';
166
+ const subjectText = subject ? SEP + subject : '';
167
+ let x = THROBBER_TEXT_X;
168
+ const fits = (w: number): boolean => w <= room;
169
+ const headW = getDisplayWidth(head);
170
+ const subjectW = getDisplayWidth(subjectText);
171
+ const tailW = getDisplayWidth(tailText);
172
+ // The label stays whole as long as it can; its trailing dots go before a letter does.
173
+ const bare = head.replace(/(\.\.\.|…)$/, '');
174
+ const headShown = fits(headW) ? head : fits(getDisplayWidth(bare)) ? bare : truncateDisplay(head, room);
175
+ if (owner && headShown.startsWith(owner)) {
176
+ x = put(line, x, endX, owner, t.textFaint);
177
+ x = put(line, x, endX, headShown.slice(owner.length), t.textMuted);
178
+ } else {
179
+ x = put(line, x, endX, headShown, t.textMuted);
180
+ }
181
+ const showTail = fits(headW + subjectW + tailW) || (subject === '' && fits(headW + tailW));
182
+ const subjectRoom = endX - x - (showTail ? tailW : 0);
183
+ if (subjectText && subjectRoom > getDisplayWidth(SEP) + 1) {
184
+ x = put(line, x, endX, truncateDisplay(subjectText, subjectRoom), t.text);
185
+ }
186
+ if (showTail && x + tailW <= endX) put(line, x, endX, tailText, t.textFaint);
187
+ return line;
188
+ }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * toast-center.ts, the toast primitive's state.
3
+ *
4
+ * A toast appears in the top right corner (drawn by renderToasts in
5
+ * surface-kit-parts.ts: a colored ┃ on both sides, the title bold, the body
6
+ * wrapped in full) and disappears after five seconds. Newest first; at most
7
+ * three are kept, older ones leave early rather than stacking down the screen.
8
+ *
9
+ * Producers: commandContext.showToast (any command), and the shared
10
+ * notification feed (bridgeNotificationFeedToToasts): every conversation
11
+ * system notice toasts ([WRFC] …, [Agents] …, compaction receipts; see
12
+ * core/notices.ts), and of the routed notifications only warning and critical
13
+ * ones do. Everything that toasts stays in the feed, which /notifications
14
+ * shows in full.
15
+ */
16
+
17
+ import type { NotificationFeedEntry, NotificationFeed } from '../views/notifications-feed.ts';
18
+ import type { ToastSpec, ToastTone } from './surface-kit-parts.ts';
19
+
20
+ /** How long a toast stays up. */
21
+ const TOAST_DURATION_MS = 5_000;
22
+ /** How many toasts are shown at once. */
23
+ const MAX_TOASTS = 3;
24
+
25
+ interface LiveToast {
26
+ readonly id: number;
27
+ readonly spec: ToastSpec;
28
+ readonly expiresAt: number;
29
+ }
30
+
31
+ export type ToastScheduler = (run: () => void, delayMs: number) => void;
32
+
33
+ const defaultScheduler: ToastScheduler = (run, delayMs) => {
34
+ const timer = setTimeout(run, delayMs);
35
+ // A pending toast expiry must never keep the process alive on exit.
36
+ (timer as { unref?: () => void }).unref?.();
37
+ };
38
+
39
+ export class ToastCenter {
40
+ private toasts: LiveToast[] = [];
41
+ private nextId = 1;
42
+
43
+ /** Called whenever the visible set changes (wired to the render request). */
44
+ onChange: (() => void) | null = null;
45
+
46
+ constructor(
47
+ private readonly clock: () => number = Date.now,
48
+ private readonly schedule: ToastScheduler = defaultScheduler,
49
+ ) {}
50
+
51
+ show(spec: ToastSpec, durationMs: number = TOAST_DURATION_MS): void {
52
+ const toast: LiveToast = { id: this.nextId++, spec, expiresAt: this.clock() + durationMs };
53
+ this.toasts = [toast, ...this.toasts].slice(0, MAX_TOASTS);
54
+ this.schedule(() => this.expire(toast.id), durationMs);
55
+ this.onChange?.();
56
+ }
57
+
58
+ /** The toasts to draw now, newest first. */
59
+ visible(): ToastSpec[] {
60
+ const now = this.clock();
61
+ return this.toasts.filter((t) => t.expiresAt > now).map((t) => t.spec);
62
+ }
63
+
64
+ clear(): void {
65
+ if (this.toasts.length === 0) return;
66
+ this.toasts = [];
67
+ this.onChange?.();
68
+ }
69
+
70
+ private expire(id: number): void {
71
+ const before = this.toasts.length;
72
+ this.toasts = this.toasts.filter((t) => t.id !== id);
73
+ if (this.toasts.length !== before) this.onChange?.();
74
+ }
75
+ }
76
+
77
+ let shared: ToastCenter | null = null;
78
+
79
+ /** The process-wide toast center (lazily created). */
80
+ export function getSharedToastCenter(): ToastCenter {
81
+ shared ??= new ToastCenter();
82
+ return shared;
83
+ }
84
+
85
+ function toneForLevel(level: NotificationFeedEntry['level']): ToastTone | null {
86
+ if (level === 'critical') return 'error';
87
+ if (level === 'warning') return 'warning';
88
+ return null;
89
+ }
90
+
91
+ /** A system notice always toasts; its level picks the bar color. */
92
+ function toneForNotice(level: NotificationFeedEntry['level']): ToastTone {
93
+ return toneForLevel(level) ?? 'info';
94
+ }
95
+
96
+ /**
97
+ * Toast every new warning or critical entry of the notification feed. A
98
+ * collapsed burst toasts once per growth of its running count, with the count
99
+ * in the title. Returns an unsubscribe function.
100
+ */
101
+ export function bridgeNotificationFeedToToasts(feed: NotificationFeed, toasts: ToastCenter): () => void {
102
+ // Per entry: the count last toasted for, and whether it has toasted at that
103
+ // count. An entry toasts when its count grows, or once when a second arrival
104
+ // of the same event (feed eventKey folding) makes a quiet entry one that
105
+ // toasts; a fold never toasts an entry twice.
106
+ const seen = new Map<string, { readonly count: number; readonly toasted: boolean }>();
107
+ for (const entry of feed.list()) seen.set(entry.key, { count: entry.collapsedCount, toasted: true });
108
+ return feed.subscribe(() => {
109
+ for (const entry of feed.list()) {
110
+ const previous = seen.get(entry.key);
111
+ const tone = entry.toast === 'never' ? null : entry.toast === 'always' ? toneForNotice(entry.level) : toneForLevel(entry.level);
112
+ if (previous && previous.count === entry.collapsedCount && (previous.toasted || !tone)) continue;
113
+ seen.set(entry.key, { count: entry.collapsedCount, toasted: Boolean(tone) });
114
+ if (!tone) continue;
115
+ const title = entry.collapsedCount > 1 ? `${entry.title} (${entry.collapsedCount} times)` : entry.title;
116
+ toasts.show({ title, body: entry.body, tone });
117
+ }
118
+ });
119
+ }