@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
@@ -4,41 +4,41 @@
4
4
  * The canonical evaluator is the SDK version exported from @/runtime/index.ts
5
5
  * (via operations.evaluateSessionMaintenance), which reads from configManager.
6
6
  * Import the evaluator from there, this module provides only the shared
7
- * Panel* type surface used across TUI panels and tests; it intentionally does
7
+ * View* type surface used across TUI views and tests; it intentionally does
8
8
  * not re-implement the evaluator.
9
9
  */
10
10
  import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
11
11
 
12
- export type PanelGuidanceMode = 'off' | 'minimal' | 'guided';
13
- export type PanelSessionMaintenanceLevel = 'stable' | 'watch' | 'suggest-compact' | 'compacting' | 'needs-repair' | 'unknown';
12
+ export type ViewGuidanceMode = 'off' | 'minimal' | 'guided';
13
+ export type ViewSessionMaintenanceLevel = 'stable' | 'watch' | 'suggest-compact' | 'compacting' | 'needs-repair' | 'unknown';
14
14
 
15
- export interface PanelSessionMaintenanceLineageEntry {
15
+ export interface ViewSessionMaintenanceLineageEntry {
16
16
  readonly branchReason?: string;
17
17
  }
18
18
 
19
- export interface PanelSessionMaintenanceSession {
20
- readonly lineage?: readonly PanelSessionMaintenanceLineageEntry[];
19
+ export interface ViewSessionMaintenanceSession {
20
+ readonly lineage?: readonly ViewSessionMaintenanceLineageEntry[];
21
21
  readonly lastCompactedAt?: number;
22
22
  readonly compactionMessageCount?: number;
23
23
  readonly compactionState?: string;
24
24
  }
25
25
 
26
- export interface PanelSessionMaintenanceInput {
26
+ export interface ViewSessionMaintenanceInput {
27
27
  /** ConfigManager used to read behavior.autoCompactThreshold and related keys. */
28
28
  readonly configManager: Pick<ConfigManager, 'get'>;
29
29
  readonly currentTokens: number;
30
30
  readonly contextWindow: number;
31
31
  readonly messageCount?: number;
32
32
  readonly sessionMemoryCount?: number;
33
- readonly session?: PanelSessionMaintenanceSession | null;
33
+ readonly session?: ViewSessionMaintenanceSession | null;
34
34
  }
35
35
 
36
- export interface PanelSessionMaintenanceStatus {
37
- readonly level: PanelSessionMaintenanceLevel;
36
+ export interface ViewSessionMaintenanceStatus {
37
+ readonly level: ViewSessionMaintenanceLevel;
38
38
  readonly summary: string;
39
39
  readonly reasons: readonly string[];
40
40
  readonly nextSteps: readonly string[];
41
- readonly guidanceMode: PanelGuidanceMode;
41
+ readonly guidanceMode: ViewGuidanceMode;
42
42
  readonly usagePct: number;
43
43
  readonly remainingTokens: number;
44
44
  /**
@@ -0,0 +1,159 @@
1
+ /**
2
+ * skills-discovery.ts, finding the skills on disk: project-local
3
+ * (.goodvibes/skills), global (~/.goodvibes/skills) and custom directories,
4
+ * each SKILL.md parsed for its frontmatter, marketplace-installed ones tagged
5
+ * with their provenance. Used by /skills, /local review and the Skills modal.
6
+ */
7
+
8
+ import { promises as fsPromises } from 'node:fs';
9
+ import { join, sep } from 'node:path';
10
+ import { listInstalledEcosystemEntries, type EcosystemCatalogPathOptions, type ShellPathService } from '@/runtime/index.ts';
11
+ import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
12
+
13
+ export type SkillOrigin = 'project-local' | 'global' | 'custom';
14
+
15
+ export interface SkillRecord {
16
+ name: string;
17
+ description: string;
18
+ path: string;
19
+ origin: SkillOrigin;
20
+ dependencies: string[];
21
+ includes: string[];
22
+ frontmatter: Record<string, string>;
23
+ /**
24
+ * Set when this skill's file lives under an installed ecosystem-marketplace
25
+ * receipt's targetPath, the receipt's provenance summary (e.g. curated
26
+ * source / signature info), so marketplace-installed skills read as such
27
+ * instead of looking identical to hand-authored ones.
28
+ */
29
+ marketplaceProvenance?: string;
30
+ }
31
+
32
+ function parseFrontmatter(content: string): Record<string, string> {
33
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
34
+ if (!match) return {};
35
+ const result: Record<string, string> = {};
36
+ for (const line of match[1].split('\n')) {
37
+ const [key, ...rest] = line.split(':');
38
+ if (key && rest.length > 0) {
39
+ result[key.trim()] = rest.join(':').trim();
40
+ }
41
+ }
42
+ return result;
43
+ }
44
+
45
+ function getSkillDirectories(cwd: string, homeDir: string): Array<{ root: string; origin: SkillOrigin }> {
46
+ return [
47
+ { root: join(cwd, '.goodvibes', 'skills'), origin: 'project-local' },
48
+ { root: join(cwd, '.goodvibes', 'tui', 'skills'), origin: 'project-local' },
49
+ { root: join(homeDir, '.goodvibes', 'skills'), origin: 'global' },
50
+ { root: join(homeDir, '.goodvibes', 'tui', 'skills'), origin: 'global' },
51
+ ];
52
+ }
53
+
54
+ async function readSkillFile(path: string, origin: SkillOrigin): Promise<SkillRecord | null> {
55
+ let content = '';
56
+ try {
57
+ content = await fsPromises.readFile(path, 'utf-8');
58
+ } catch {
59
+ return null;
60
+ }
61
+
62
+ const frontmatter = parseFrontmatter(content);
63
+ const body = content.replace(/^---\n[\s\S]*?\n---\n?/, '');
64
+ const name = frontmatter.name ?? path.split(/[\\/]/).pop()?.replace(/\.md$/, '') ?? 'skill';
65
+ const description = frontmatter.description ?? frontmatter.summary ?? '';
66
+ const dependencies = frontmatter.depends_on
67
+ ? frontmatter.depends_on.split(',').map((item) => item.trim()).filter(Boolean)
68
+ : [];
69
+ const includes: string[] = [];
70
+ const includeRegex = /^@([\w/-]+)/gm;
71
+ let match: RegExpExecArray | null;
72
+ while ((match = includeRegex.exec(body)) !== null) {
73
+ includes.push(match[1]);
74
+ }
75
+
76
+ return {
77
+ name,
78
+ description,
79
+ path,
80
+ origin,
81
+ dependencies,
82
+ includes,
83
+ frontmatter,
84
+ };
85
+ }
86
+
87
+ async function scanSkillDirectory(root: string, origin: SkillOrigin): Promise<SkillRecord[]> {
88
+ let entries: string[] = [];
89
+ try {
90
+ entries = await fsPromises.readdir(root);
91
+ } catch {
92
+ return [];
93
+ }
94
+
95
+ const records: SkillRecord[] = [];
96
+ for (const entry of entries.sort((a, b) => a.localeCompare(b))) {
97
+ if (entry.endsWith('.md')) {
98
+ const record = await readSkillFile(join(root, entry), origin);
99
+ if (record) records.push(record);
100
+ continue;
101
+ }
102
+
103
+ const markerPath = join(root, entry, 'SKILL.md');
104
+ const record = await readSkillFile(markerPath, origin);
105
+ if (record) records.push(record);
106
+ }
107
+
108
+ return records;
109
+ }
110
+
111
+ /**
112
+ * Tags records whose file lives under an installed ecosystem-marketplace
113
+ * receipt's targetPath with that receipt's provenance summary. Best-effort:
114
+ * a lookup failure (e.g. no ecosystem catalogs configured) leaves records
115
+ * untagged rather than failing skill discovery.
116
+ */
117
+ function applyMarketplaceProvenance(records: SkillRecord[], ecosystemPaths: EcosystemCatalogPathOptions): SkillRecord[] {
118
+ let receipts: ReturnType<typeof listInstalledEcosystemEntries>;
119
+ try {
120
+ receipts = listInstalledEcosystemEntries('skill', ecosystemPaths);
121
+ } catch {
122
+ return records;
123
+ }
124
+ if (receipts.length === 0) return records;
125
+ return records.map((record) => {
126
+ const receipt = receipts.find((candidate) => record.path === candidate.targetPath || record.path.startsWith(`${candidate.targetPath}${sep}`));
127
+ if (!receipt) return record;
128
+ return { ...record, marketplaceProvenance: receipt.provenanceSummary };
129
+ });
130
+ }
131
+
132
+ export async function discoverSkills(
133
+ shellPaths: Pick<ShellPathService, 'workingDirectory' | 'homeDirectory'>,
134
+ ecosystemPaths?: EcosystemCatalogPathOptions,
135
+ ): Promise<SkillRecord[]> {
136
+ const cwd = shellPaths.workingDirectory;
137
+ const homeDir = shellPaths.homeDirectory;
138
+ const seen = new Set<string>();
139
+ const records: SkillRecord[] = [];
140
+
141
+ for (const { root, origin } of getSkillDirectories(cwd, homeDir)) {
142
+ for (const record of await scanSkillDirectory(root, origin)) {
143
+ if (seen.has(record.name.toLowerCase())) continue;
144
+ seen.add(record.name.toLowerCase());
145
+ records.push(record);
146
+ }
147
+ }
148
+
149
+ const tagged = ecosystemPaths ? applyMarketplaceProvenance(records, ecosystemPaths) : records;
150
+
151
+ return tagged.sort((a, b) => {
152
+ const originRank = a.origin === b.origin
153
+ ? 0
154
+ : a.origin === 'project-local'
155
+ ? -1
156
+ : 1;
157
+ return originRank || a.name.localeCompare(b.name);
158
+ });
159
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * view-deps.ts, what the built-in modals and views are built from.
3
+ *
4
+ * Composed once at startup (runtime/bootstrap-shell.ts) and handed to
5
+ * createShellViews (builtin-views.ts), which builds the always-on read models
6
+ * (usage, fleet acts and spawn) and registers every config-modal surface.
7
+ */
8
+
9
+ import type { ConfigManager, ServiceRegistry, SubscriptionManager } from '@pellux/goodvibes-sdk/platform/config';
10
+ import type { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
11
+ import type { ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers';
12
+ import type { Orchestrator, SessionMemoryStore } from '@pellux/goodvibes-sdk/platform/core';
13
+ import type { MemoryAccess } from '@pellux/goodvibes-sdk/platform/runtime/memory-spine';
14
+ import type { HookActivityTracker, HookDispatcher, HookWorkbench } from '@pellux/goodvibes-sdk/platform/hooks';
15
+ import type { UserAuthManager } from '@pellux/goodvibes-sdk/platform/security';
16
+ import type { ProjectPlanningService, KnowledgeApi } from '@pellux/goodvibes-sdk/platform/knowledge';
17
+ import type { SessionChangeTracker } from '@pellux/goodvibes-sdk/platform/sessions';
18
+ import type { WorkPlanStore } from '@pellux/goodvibes-sdk/platform/workflow';
19
+ import type { PolicyRuntimeState, SandboxSessionRegistry } from '@/runtime/index.ts';
20
+ import type { UiRuntimeServices } from '../runtime/ui-services.ts';
21
+ import type { PluginsModalManager } from './modals/plugins-modal.ts';
22
+
23
+ export interface BuiltinViewDeps {
24
+ readonly providerRegistry: ProviderRegistry;
25
+ readonly uiServices: UiRuntimeServices;
26
+ readonly toolRegistry?: ToolRegistry;
27
+ /** The main orchestrator (session usage and context size). */
28
+ readonly orchestrator?: Orchestrator;
29
+ /** The current model's context window in tokens. */
30
+ readonly getCtxWindow?: () => number;
31
+ readonly requestRender?: () => void;
32
+ readonly sandboxSessionRegistry: SandboxSessionRegistry;
33
+ /** Memory access for the Memory modal (the spine client, which routes to an adopted daemon). */
34
+ readonly memoryRegistry?: MemoryAccess;
35
+ readonly pluginManager?: PluginsModalManager;
36
+ readonly hookDispatcher?: Pick<HookDispatcher, 'listHooks' | 'getChains'>;
37
+ readonly hookWorkbench?: HookWorkbench;
38
+ readonly hookActivityTracker?: Pick<HookActivityTracker, 'listRecent'>;
39
+ readonly knowledgeApi?: KnowledgeApi;
40
+ /** The files this session edited (the Changes modal's default view). */
41
+ readonly sessionChangeTracker?: Pick<SessionChangeTracker, 'getChangedFiles'>;
42
+ /** Report a fleet act's result (late-bound to the command context's print). */
43
+ readonly fleetActsNotify?: (message: string) => void;
44
+ /** Hand a spawned session id to the one-key jump affordance (late-bound). */
45
+ readonly armFixSessionAttach?: (sessionId: string) => void;
46
+ }
47
+
48
+ /** The deps with everything the modals require resolved from the UI services. */
49
+ export type ResolvedBuiltinViewDeps = BuiltinViewDeps & {
50
+ readonly configManager: ConfigManager;
51
+ readonly localUserAuthManager: UserAuthManager;
52
+ readonly subscriptionManager: SubscriptionManager;
53
+ readonly serviceRegistry: ServiceRegistry;
54
+ readonly sessionMemoryStore: SessionMemoryStore;
55
+ readonly projectPlanningService: ProjectPlanningService;
56
+ readonly projectPlanningProjectId: string;
57
+ readonly workPlanStore: WorkPlanStore;
58
+ readonly policyRuntimeState: PolicyRuntimeState;
59
+ };
60
+
61
+ function required<T>(value: T | undefined, what: string): T {
62
+ if (value === undefined) throw new Error(`${what} must be wired at bootstrap for the built-in modals.`);
63
+ return value;
64
+ }
65
+
66
+ export function resolveBuiltinViewDeps(deps: BuiltinViewDeps): ResolvedBuiltinViewDeps {
67
+ const ui = deps.uiServices;
68
+ return {
69
+ ...deps,
70
+ configManager: required(ui.platform.configManager, 'Config manager'),
71
+ localUserAuthManager: required(ui.platform.localUserAuthManager, 'Local auth manager'),
72
+ subscriptionManager: required(ui.platform.subscriptionManager, 'Subscription manager'),
73
+ serviceRegistry: required(ui.platform.serviceRegistry, 'Service registry'),
74
+ sessionMemoryStore: required(ui.sessions.sessionMemoryStore, 'Session memory store'),
75
+ projectPlanningService: required(ui.planning.projectPlanningService, 'Project planning service'),
76
+ projectPlanningProjectId: required(ui.planning.projectPlanningProjectId, 'Project planning project id'),
77
+ workPlanStore: required(ui.planning.workPlanStore, 'Work plan store'),
78
+ policyRuntimeState: required(ui.platform.policyRuntimeState, 'Policy runtime state'),
79
+ };
80
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * view-panel-adapter.ts, the operator API's panels.list / panels.open, answered
3
+ * by the modal views.
4
+ *
5
+ * THE ONLY PLACE PANE VOCABULARY IS KEPT IN THE TUI. The terminal has no panes:
6
+ * every view opens as a modal. The names here (ViewPanelAdapter, PanelManagerLike,
7
+ * getTopPane/getBottomPane, NO_PANES, the `panels` field) are kept on purpose
8
+ * because they are the SDK's contract, not TUI design:
9
+ * - the SDK's IntegrationHelperService serves the operator API verbs
10
+ * panels.list and panels.open (and the /api/panels/* HTTP routes) from the
11
+ * `panelManager` option, typed PanelManagerLike;
12
+ * - remote clients, the web UI and the daemon already speak those verb names.
13
+ * Renaming them is an SDK and wire change, so the TUI keeps one adapter that
14
+ * satisfies the contract and translates it: panels.list lists the views a
15
+ * remote client can open (Agents, Usage, Changes, Notifications, Sessions),
16
+ * panels.open opens one as its modal, and both pane lists are always empty
17
+ * because nothing is ever open in a pane. The opener is set by the shell once
18
+ * the modal host exists. See docs/architecture.md ("The operator API bridge").
19
+ */
20
+
21
+ import type { IntegrationHelperService } from '@/runtime/index.ts';
22
+
23
+ /** The SDK's panel-manager contract, as IntegrationHelperService takes it. */
24
+ type PanelManagerLike = ConstructorParameters<typeof IntegrationHelperService>[0]['panelManager'];
25
+ type PanelPaneLike = ReturnType<PanelManagerLike['getTopPane']>;
26
+ type PanelRegistrationLike = ReturnType<PanelManagerLike['getRegisteredTypes']>[number];
27
+
28
+ const VIEWS: readonly PanelRegistrationLike[] = [
29
+ { id: 'agents', name: 'Agents', category: 'views', description: 'Running and finished agents, chains, workflows and hosted sessions; steer, stop, open a transcript' },
30
+ { id: 'usage', name: 'Usage', category: 'views', description: 'Context pressure, session tokens and cost, per-turn history, per-agent costs, budget alert' },
31
+ { id: 'changes', name: 'Changes', category: 'views', description: 'Changed files with a tinted diff, semantic summary, hunk staging, review comments and recent commits' },
32
+ { id: 'notifications', name: 'Notifications', category: 'views', description: 'Everything the notification feed collected, newest first' },
33
+ { id: 'sessions', name: 'Sessions', category: 'views', description: 'Saved, hosted and cross-surface sessions' },
34
+ ];
35
+
36
+ const NO_PANES: PanelPaneLike = { panels: [], activeIndex: 0 };
37
+
38
+ export interface ViewPanelAdapter extends PanelManagerLike {
39
+ /** Set how a view name is opened (returns false when nothing holds it). */
40
+ setOpener(open: (id: string) => boolean): void;
41
+ }
42
+
43
+ export function createViewPanelAdapter(): ViewPanelAdapter {
44
+ let opener: ((id: string) => boolean) | null = null;
45
+ return {
46
+ getTopPane: () => NO_PANES,
47
+ getBottomPane: () => NO_PANES,
48
+ getRegisteredTypes: () => VIEWS,
49
+ open: (id: string) => opener?.(id) ?? false,
50
+ show: () => {},
51
+ setOpener: (open) => { opener = open; },
52
+ };
53
+ }
@@ -7,7 +7,7 @@
7
7
  // blockedReason, orphaned, stalled, agentId), edges (from → to dependency
8
8
  // links), and the elastic-pool state (ready/running/atCap/maxSize). This module
9
9
  // is a pure string renderer; every line is fit to the given width (no clipping,
10
- // no horizontal overflow), so the same output drives a panel or a command.
10
+ // no horizontal overflow), so the same output drives a view or a command.
11
11
  // ---------------------------------------------------------------------------
12
12
 
13
13
  import type { OperatorMethodOutput } from '@pellux/goodvibes-sdk';
@@ -1,101 +0,0 @@
1
- /**
2
- * conversation-fold.ts, which transcript rows render FOLDED, and what spacing
3
- * that earns them.
4
- *
5
- * A folded tool result is exactly ONE row: its header, with the preview riding
6
- * on the same line after the `▸ N lines` badge. It used to be four rows, a
7
- * `▄▄▄` cap, an interior preview line carrying a second `[▸ N hidden]` count, a
8
- * `▀▀▀` cap, and a blank after all of it, for one line of text the header had
9
- * already sized.
10
- *
11
- * These predicates live in their own leaf module because TWO callers must agree
12
- * on them and neither may depend on the other: the row renderer
13
- * (conversation-rendering.ts) decides how to draw the row, and the line cache
14
- * (conversation-line-cache.ts) decides the blank separator that follows it. If
15
- * those two ever disagreed about which rows are folded, a warm cache and a cold
16
- * rebuild would space the transcript differently, the exact class of bug the
17
- * cache's byte-identical contract exists to rule out.
18
- *
19
- * Everything here is PURE: collapse state is read, never written, so a row can
20
- * be asked about before it has rendered.
21
- */
22
-
23
- import { foldedToolResult, trailingBlankAfterRow } from '@pellux/goodvibes-terminal-shell';
24
- import { summarizeToolResult } from '../renderer/tool-result-summary.ts';
25
- import { isTurnCollapsed, type ConversationRenderContext } from './conversation-render-context.ts';
26
- import { collapseKeyForNode, type RenderNode } from './conversation-turn-structure.ts';
27
- import type { ConversationMessageSnapshot } from '@pellux/goodvibes-sdk/platform/core';
28
-
29
- /** The subset of a render context these predicates read. */
30
- type FoldContext = Pick<ConversationRenderContext, 'assistantTurns' | 'collapseState'>;
31
-
32
- /**
33
- * Does a tool-result row render FOLDED, one compact header row with its preview
34
- * on it, rather than header-plus-expanded-body?
35
- *
36
- * An unset collapse key answers the same as the default the row itself will
37
- * store (collapsed), so asking before and asking after the row renders give the
38
- * same answer.
39
- */
40
- export function isToolResultFolded(
41
- message: Extract<ConversationMessageSnapshot, { role: 'tool' }>,
42
- collapseState: ReadonlyMap<string, boolean>,
43
- collapseKey: string,
44
- ): boolean {
45
- // Threading only, the decision, the short-content threshold and the
46
- // unset-key default all belong to foldedToolResult(). summarizeToolResult is
47
- // this product's own renderer concern, so resolving it stays here: a
48
- // summarizable result stays folded even when short, because the one-line
49
- // summary is the better row and the raw payload belongs behind the toggle.
50
- return foldedToolResult({
51
- contentLength: message.content.length,
52
- hasSummary: summarizeToolResult(message.toolName, message.content) !== null,
53
- storedCollapsed: collapseState.get(collapseKey),
54
- });
55
- }
56
-
57
- /** A row that belongs to a tool run: the call itself, or the result under it. */
58
- function isToolRunNode(node: RenderNode): boolean {
59
- return node.kind === 'toolcall' || node.message.role === 'tool';
60
- }
61
-
62
- /**
63
- * Does this planned row emit exactly one folded tool-result line?
64
- *
65
- * A collapsed turn hides the row entirely, so there is no folded row to butt up
66
- * against the next one.
67
- */
68
- function rendersFoldedToolRow(node: RenderNode, context: FoldContext): boolean {
69
- if (node.kind === 'toolcall') return false;
70
- const message = node.message;
71
- if (message.role !== 'tool') return false;
72
- if (isTurnCollapsed(context.assistantTurns?.get(node.absIdx), context.collapseState)) return false;
73
- return isToolResultFolded(message, context.collapseState, collapseKeyForNode(node));
74
- }
75
-
76
- /**
77
- * The blank separator that follows a planned row.
78
- *
79
- * Branch rows sit tight under their parent, so the blank lands only after the
80
- * last row of a top-level unit, that is what keeps a turn's whole subtree
81
- * reading as one block. On top of that, a folded row followed by more tool
82
- * machinery gets NO blank at all: N consecutive folded results stack as N
83
- * adjacent single rows. A folded row followed by anything that is not tool
84
- * machinery keeps its blank, so the run still separates from the prose around
85
- * it.
86
- */
87
- export function trailingBlankAfter(
88
- node: RenderNode,
89
- next: RenderNode | undefined,
90
- context: FoldContext,
91
- ): boolean {
92
- // Adaptation only, RenderNode is this product's shape, so reading depth and
93
- // node kind off it stays here; the rule those facts feed belongs to
94
- // trailingBlankAfterRow(). No `next` at all means end of transcript: neither
95
- // a branch row nor tool machinery follows, which is the plain-blank case.
96
- return trailingBlankAfterRow({
97
- nextIsBranchRow: next !== undefined && next.depth !== 0,
98
- nextIsToolMachinery: next !== undefined && isToolRunNode(next),
99
- rowRendersFolded: rendersFoldedToolRow(node, context),
100
- });
101
- }