@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
@@ -21,6 +21,11 @@ export class BookmarkModal {
21
21
  public scrollOffset = 0;
22
22
  /** Max visible list rows. */
23
23
  public visibleRows = BookmarkModal.DEFAULT_VISIBLE_ROWS;
24
+ /**
25
+ * The always-live search row's query. Narrows the list by key and label;
26
+ * selectedIndex indexes the narrowed list (visibleEntries).
27
+ */
28
+ public query = '';
24
29
 
25
30
  public constructor(private readonly bookmarkManager: BookmarkManager) {}
26
31
 
@@ -29,6 +34,7 @@ export class BookmarkModal {
29
34
  */
30
35
  open(): void {
31
36
  this.entries = this.bookmarkManager.list();
37
+ this.query = '';
32
38
  this.selectedIndex = 0;
33
39
  this.scrollOffset = 0;
34
40
  this.active = true;
@@ -36,6 +42,21 @@ export class BookmarkModal {
36
42
 
37
43
  close(): void {
38
44
  this.active = false;
45
+ this.query = '';
46
+ }
47
+
48
+ /** The entries the search row lets through, in order. */
49
+ get visibleEntries(): BookmarkEntry[] {
50
+ const q = this.query.trim().toLowerCase();
51
+ if (!q) return this.entries;
52
+ return this.entries.filter((entry) => entry.key.toLowerCase().includes(q) || entry.label.toLowerCase().includes(q));
53
+ }
54
+
55
+ /** Replace the query; the selection moves to the first match. */
56
+ setQuery(query: string): void {
57
+ this.query = query;
58
+ this.selectedIndex = 0;
59
+ this.scrollOffset = 0;
39
60
  }
40
61
 
41
62
  setVisibleRows(rows: number): void {
@@ -44,19 +65,21 @@ export class BookmarkModal {
44
65
  }
45
66
 
46
67
  moveUp(): void {
47
- if (this.entries.length === 0) return;
48
- this.selectedIndex = (this.selectedIndex - 1 + this.entries.length) % this.entries.length;
68
+ const n = this.visibleEntries.length;
69
+ if (n === 0) return;
70
+ this.selectedIndex = (this.selectedIndex - 1 + n) % n;
49
71
  this._clampScroll();
50
72
  }
51
73
 
52
74
  moveDown(): void {
53
- if (this.entries.length === 0) return;
54
- this.selectedIndex = (this.selectedIndex + 1) % this.entries.length;
75
+ const n = this.visibleEntries.length;
76
+ if (n === 0) return;
77
+ this.selectedIndex = (this.selectedIndex + 1) % n;
55
78
  this._clampScroll();
56
79
  }
57
80
 
58
81
  getSelected(): BookmarkEntry | null {
59
- return this.entries[this.selectedIndex] ?? null;
82
+ return this.visibleEntries[this.selectedIndex] ?? null;
60
83
  }
61
84
 
62
85
  /**
@@ -69,10 +92,11 @@ export class BookmarkModal {
69
92
  this.bookmarkManager.toggle(entry.key); // toggle off = remove
70
93
  this.entries = this.bookmarkManager.list();
71
94
  // Clamp selectedIndex after removal
72
- if (this.entries.length === 0) {
95
+ const n = this.visibleEntries.length;
96
+ if (n === 0) {
73
97
  this.selectedIndex = 0;
74
- } else if (this.selectedIndex >= this.entries.length) {
75
- this.selectedIndex = this.entries.length - 1;
98
+ } else if (this.selectedIndex >= n) {
99
+ this.selectedIndex = n - 1;
76
100
  }
77
101
  this._clampScroll();
78
102
  return entry;
@@ -109,7 +133,7 @@ export class BookmarkModal {
109
133
  } else if (this.selectedIndex >= this.scrollOffset + visRows) {
110
134
  this.scrollOffset = this.selectedIndex - visRows + 1;
111
135
  }
112
- const maxOffset = Math.max(0, this.entries.length - visRows);
136
+ const maxOffset = Math.max(0, this.visibleEntries.length - visRows);
113
137
  this.scrollOffset = Math.max(0, Math.min(this.scrollOffset, maxOffset));
114
138
  }
115
139
  }
@@ -0,0 +1,251 @@
1
+ /**
2
+ * changes-git.ts, the git reads and writes behind the Changes modal.
3
+ *
4
+ * Every spawn captures stdout and stderr: a child left with inherited stdio
5
+ * would write straight to the TUI's terminal, outside the renderer. Nothing
6
+ * here throws into the render loop; failures come back as text to show.
7
+ */
8
+
9
+ import { isAbsolute, join, relative } from 'node:path';
10
+ import { GitService } from '@pellux/goodvibes-sdk/platform/git';
11
+ import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
12
+
13
+ /** Which diff the modal shows. */
14
+ export type ChangesSource = 'session' | 'working' | 'staged' | 'head';
15
+
16
+ export const CHANGES_SOURCES: readonly ChangesSource[] = ['session', 'working', 'staged', 'head'];
17
+
18
+ export const CHANGES_SOURCE_LABELS: Readonly<Record<ChangesSource, string>> = {
19
+ session: 'this session',
20
+ working: 'not staged',
21
+ staged: 'staged',
22
+ head: 'all changes vs HEAD',
23
+ };
24
+
25
+ interface RunResult { readonly out: string; readonly err: string; readonly ok: boolean }
26
+
27
+ /**
28
+ * Pin the a/ and b/ path prefixes: a user's diff.mnemonicPrefix or
29
+ * diff.noprefix setting would otherwise turn paths into w/src/x.ts or
30
+ * src/x.ts, which the file list, hunk staging and the semantic reader all
31
+ * misread.
32
+ */
33
+ const DIFF_PREFIX_ARGS: readonly string[] = ['--src-prefix=a/', '--dst-prefix=b/'];
34
+
35
+ async function run(args: string[], cwd: string, stdin?: string): Promise<RunResult> {
36
+ try {
37
+ const proc = Bun.spawn(['git', ...args], { cwd, stdout: 'pipe', stderr: 'pipe', stdin: stdin !== undefined ? 'pipe' : 'ignore' });
38
+ if (stdin !== undefined && proc.stdin) {
39
+ proc.stdin.write(stdin);
40
+ await proc.stdin.end();
41
+ }
42
+ const [out, err] = await Promise.all([new Response(proc.stdout).text(), new Response(proc.stderr).text()]);
43
+ const code = await proc.exited;
44
+ return { out, err: err.trim(), ok: code === 0 };
45
+ } catch (error) {
46
+ return { out: '', err: summarizeError(error), ok: false };
47
+ }
48
+ }
49
+
50
+ export function isGitRepo(cwd: string): boolean {
51
+ return GitService.isGitRepo(cwd);
52
+ }
53
+
54
+ export interface LoadedDiff {
55
+ readonly raw: string;
56
+ /** What the diff is, in words ("this session: 3 files vs HEAD"). */
57
+ readonly label: string;
58
+ readonly error: string | null;
59
+ }
60
+
61
+ /** Untracked files larger than this show as added with a note instead of every line. */
62
+ export const MAX_UNTRACKED_BYTES = 256 * 1024;
63
+ /** Untracked files with more lines than this show as added with a note instead of every line. */
64
+ export const MAX_UNTRACKED_LINES = 4000;
65
+ /** At most this many untracked files are read into one diff; the label counts the rest. */
66
+ export const MAX_UNTRACKED_FILES = 200;
67
+
68
+ /**
69
+ * A new-file chunk with no hunks and a note line in place of the content. The
70
+ * note line starts with "# ", which no git header line does; parseChanges
71
+ * reads it into ChangeFile.note.
72
+ */
73
+ function noteChunk(path: string, note: string): string {
74
+ return `diff --git a/${path} b/${path}\nnew file mode 100644\n# ${note}\n`;
75
+ }
76
+
77
+ /** One untracked file as an all-added diff chunk (paths relative to the repo root). */
78
+ async function untrackedChunk(repoRoot: string, path: string): Promise<string> {
79
+ let size = 0;
80
+ try {
81
+ size = Bun.file(join(repoRoot, path)).size;
82
+ } catch {
83
+ size = 0;
84
+ }
85
+ if (size > MAX_UNTRACKED_BYTES) return noteChunk(path, `large new file (${Math.round(size / 1024)} KB), not shown line by line`);
86
+ // --no-index against /dev/null is git's own new-file patch: binary detection,
87
+ // "new file mode", "--- /dev/null", and a hunk staging can apply as is.
88
+ const result = await run(['diff', '--no-index', '--no-color', ...DIFF_PREFIX_ARGS, '--', '/dev/null', path], repoRoot);
89
+ // --no-index exits 1 when the files differ, which is the expected case here.
90
+ if (!result.out.trim()) return result.err ? noteChunk(path, `could not read: ${result.err.split('\n')[0]}`) : noteChunk(path, 'empty new file');
91
+ const lines = result.out.split('\n').length;
92
+ if (lines > MAX_UNTRACKED_LINES) return noteChunk(path, `large new file (${lines} lines), not shown line by line`);
93
+ return result.out.endsWith('\n') ? result.out : `${result.out}\n`;
94
+ }
95
+
96
+ /**
97
+ * Untracked, non-ignored files as all-added diff chunks, one per file. With
98
+ * `only` set, just the untracked files among those paths (the session's own
99
+ * new files); otherwise every untracked file in the repository.
100
+ */
101
+ export async function loadUntrackedDiff(cwd: string, only?: readonly string[]): Promise<{ raw: string; count: number; skipped: number }> {
102
+ if (only && only.length === 0) return { raw: '', count: 0, skipped: 0 };
103
+ const top = await run(['rev-parse', '--show-toplevel'], cwd);
104
+ if (!top.ok) return { raw: '', count: 0, skipped: 0 };
105
+ const repoRoot = top.out.trim() || cwd;
106
+ // A session path outside this repository would fail the whole listing; leave it out.
107
+ const specs = only ? only.filter((path) => !isAbsolute(path) || path.startsWith(`${repoRoot}/`)) : [':/'];
108
+ if (specs.length === 0) return { raw: '', count: 0, skipped: 0 };
109
+ const listed = await run(['ls-files', '--others', '--exclude-standard', '--full-name', '-z', '--', ...specs], cwd);
110
+ if (!listed.ok) return { raw: '', count: 0, skipped: 0 };
111
+ const paths = listed.out.split('\0').filter((path) => path.length > 0).sort();
112
+ const shown = paths.slice(0, MAX_UNTRACKED_FILES);
113
+ const chunks: string[] = [];
114
+ // A few at a time: one git process per file, never hundreds at once.
115
+ for (let i = 0; i < shown.length; i += 8) {
116
+ chunks.push(...await Promise.all(shown.slice(i, i + 8).map((path) => untrackedChunk(repoRoot, path))));
117
+ }
118
+ return { raw: chunks.join(''), count: shown.length, skipped: paths.length - shown.length };
119
+ }
120
+
121
+ /**
122
+ * The diff for a source. `sessionFiles` are the files this session edited.
123
+ * Untracked files are part of every source except "staged": they show as
124
+ * added files with their whole content (the session source takes only the
125
+ * untracked files this session wrote).
126
+ */
127
+ export async function loadDiff(cwd: string, source: ChangesSource, sessionFiles: readonly string[]): Promise<LoadedDiff> {
128
+ let args: string[];
129
+ let label: string;
130
+ let untrackedOnly: readonly string[] | undefined;
131
+ if (source === 'working') {
132
+ args = ['diff', '--no-color', ...DIFF_PREFIX_ARGS];
133
+ label = 'not staged';
134
+ } else if (source === 'staged') {
135
+ args = ['diff', '--cached', '--no-color', ...DIFF_PREFIX_ARGS];
136
+ label = 'staged';
137
+ } else if (source === 'session' && sessionFiles.length > 0) {
138
+ args = ['diff', '--no-color', ...DIFF_PREFIX_ARGS, 'HEAD', '--', ...sessionFiles];
139
+ label = `this session · ${sessionFiles.length} file${sessionFiles.length === 1 ? '' : 's'} vs HEAD`;
140
+ untrackedOnly = sessionFiles;
141
+ } else {
142
+ args = ['diff', '--no-color', ...DIFF_PREFIX_ARGS, 'HEAD'];
143
+ label = source === 'session' ? 'no files tracked this session · all changes vs HEAD' : 'all changes vs HEAD';
144
+ }
145
+ const [result, untracked] = await Promise.all([
146
+ run(args, cwd),
147
+ source === 'staged' ? Promise.resolve({ raw: '', count: 0, skipped: 0 }) : loadUntrackedDiff(cwd, untrackedOnly),
148
+ ]);
149
+ if (!result.ok) return { raw: '', label, error: result.err || 'git diff failed' };
150
+ const total = untracked.count + untracked.skipped;
151
+ if (total > 0) {
152
+ label += ` · ${total} untracked`;
153
+ if (untracked.skipped > 0) label += ` (${untracked.skipped} not shown)`;
154
+ }
155
+ const tracked = result.out && !result.out.endsWith('\n') ? `${result.out}\n` : result.out;
156
+ return { raw: tracked + untracked.raw, label, error: null };
157
+ }
158
+
159
+ export interface CommitEntry {
160
+ readonly hash: string;
161
+ readonly message: string;
162
+ readonly date: string;
163
+ }
164
+
165
+ export async function loadRecentCommits(cwd: string, count = 10): Promise<CommitEntry[]> {
166
+ try {
167
+ const entries = await new GitService(cwd).log(count);
168
+ return entries.map((entry) => ({ hash: entry.hash, message: entry.message, date: entry.date }));
169
+ } catch {
170
+ return [];
171
+ }
172
+ }
173
+
174
+ /** A commit's patch (works for root commits too). */
175
+ export async function loadCommitDiff(cwd: string, hash: string): Promise<LoadedDiff> {
176
+ const result = await run(['show', '--no-color', '--format=', '--patch', ...DIFF_PREFIX_ARGS, hash], cwd);
177
+ const label = `commit ${hash.slice(0, 7)}`;
178
+ if (!result.ok) return { raw: '', label, error: result.err || 'git show failed' };
179
+ return { raw: result.out, label, error: null };
180
+ }
181
+
182
+ export interface RepoSummary {
183
+ readonly branch: string;
184
+ readonly staged: number;
185
+ readonly unstaged: number;
186
+ }
187
+
188
+ export async function loadRepoSummary(cwd: string): Promise<RepoSummary | null> {
189
+ try {
190
+ const git = new GitService(cwd);
191
+ const [status, branch] = await Promise.all([git.status(), git.branch()]);
192
+ let staged = 0;
193
+ let unstaged = 0;
194
+ for (const f of status.files) {
195
+ if (f.index === '?' && f.working_dir === '?') { unstaged++; continue; }
196
+ if (f.index !== ' ') staged++;
197
+ if (f.working_dir !== ' ') unstaged++;
198
+ }
199
+ return { branch: branch.current || (branch.detached ? 'detached' : 'no branch'), staged, unstaged };
200
+ } catch {
201
+ return null;
202
+ }
203
+ }
204
+
205
+ /** Stage (or with reverse, unstage) exactly one hunk. */
206
+ export async function applyHunkToIndex(cwd: string, patch: string, reverse: boolean): Promise<string | null> {
207
+ const args = ['apply', '--cached', '--recount', ...(reverse ? ['-R'] : []), '-'];
208
+ const result = await run(args, cwd, patch);
209
+ return result.ok ? null : (result.err || 'git apply failed');
210
+ }
211
+
212
+ /** Stage or unstage a whole file. */
213
+ export async function setFileStaged(cwd: string, path: string, staged: boolean): Promise<string | null> {
214
+ const result = staged ? await run(['add', '--', path], cwd) : await run(['reset', '-q', '--', path], cwd);
215
+ return result.ok ? null : (result.err || `git ${staged ? 'add' : 'reset'} failed`);
216
+ }
217
+
218
+ export async function commitStaged(cwd: string, message: string): Promise<{ hash: string; error: string | null }> {
219
+ try {
220
+ const result = await new GitService(cwd).commit(message);
221
+ return { hash: result.hash, error: null };
222
+ } catch (error) {
223
+ return { hash: '', error: summarizeError(error) };
224
+ }
225
+ }
226
+
227
+ export function initRepo(cwd: string): string | null {
228
+ const result = GitService.initRepo(cwd);
229
+ return result.success ? null : (result.error ?? 'git init failed');
230
+ }
231
+
232
+ /**
233
+ * The semantic changes in one file (functions, classes, imports added,
234
+ * removed or changed), comparing `ref` against the file on disk. Null when it
235
+ * cannot be computed (a new file, an unsupported language, no repo).
236
+ */
237
+ export async function loadSemanticDiff(cwd: string, filePath: string, ref: string): Promise<import('../renderer/semantic-diff.ts').SemanticDiff | null> {
238
+ try {
239
+ const top = await run(['rev-parse', '--show-toplevel'], cwd);
240
+ const repoRoot = top.ok ? top.out.trim() || cwd : cwd;
241
+ const absPath = filePath.startsWith('/') ? filePath : join(repoRoot, filePath);
242
+ const repoRel = filePath.startsWith('/') ? relative(repoRoot, filePath) : filePath;
243
+ const before = await run(['show', `${ref}:${repoRel}`], repoRoot);
244
+ if (!before.ok) return null;
245
+ const after = await Bun.file(absPath).text();
246
+ const { computeSemanticDiff } = await import('../renderer/semantic-diff.ts');
247
+ return await computeSemanticDiff(filePath, before.out, after);
248
+ } catch {
249
+ return null;
250
+ }
251
+ }