@pellux/goodvibes-tui 2.0.21 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (391) hide show
  1. package/CHANGELOG.md +65 -1
  2. package/README.md +30 -29
  3. package/docs/README.md +8 -5
  4. package/docs/foundation-artifacts/operator-contract.json +1 -1
  5. package/package.json +28 -19
  6. package/src/cli/management.ts +5 -2
  7. package/src/cli/tui-startup.ts +34 -39
  8. package/src/core/agent-view-render.ts +157 -0
  9. package/src/core/approval-alert.ts +49 -11
  10. package/src/core/bookmark-navigation.ts +7 -1
  11. package/src/core/budget-breach-notifier.ts +27 -8
  12. package/src/core/compaction-receipt.ts +1 -1
  13. package/src/core/context-usage.ts +1 -1
  14. package/src/core/conversation-compaction-render.ts +3 -3
  15. package/src/core/conversation-display-only.ts +86 -0
  16. package/src/core/conversation-event-navigation.ts +27 -0
  17. package/src/core/conversation-line-cache.ts +216 -447
  18. package/src/core/conversation-render-context.ts +20 -27
  19. package/src/core/conversation-rendering.ts +157 -575
  20. package/src/core/conversation-splash-state.ts +6 -1
  21. package/src/core/conversation-types.ts +35 -0
  22. package/src/core/conversation-usage.ts +12 -0
  23. package/src/core/conversation.ts +130 -131
  24. package/src/core/long-task-notifier.ts +100 -31
  25. package/src/core/notices.ts +75 -0
  26. package/src/core/pairing-tailscale-gateway.ts +1 -1
  27. package/src/core/process-output-log.ts +143 -0
  28. package/src/core/rewind-receipt.ts +1 -1
  29. package/src/core/session-focus.ts +190 -0
  30. package/src/core/session-resume-core.ts +23 -81
  31. package/src/core/stream-event-wiring.ts +31 -5
  32. package/src/core/system-message-noise.ts +2 -2
  33. package/src/core/system-message-router.ts +16 -18
  34. package/src/core/turn-event-wiring.ts +272 -33
  35. package/src/core/work-tree-focus.ts +290 -0
  36. package/src/core/work-tree-fold-store.ts +143 -0
  37. package/src/core/work-tree-model.ts +799 -0
  38. package/src/core/work-tree-render.ts +384 -0
  39. package/src/core/work-tree-sources.ts +184 -0
  40. package/src/core/work-tree-wiring.ts +176 -0
  41. package/src/core/workstream-notification.ts +36 -6
  42. package/src/core/wrfc-notice-titles.ts +37 -0
  43. package/src/input/agents-modal-text.ts +119 -0
  44. package/src/input/agents-modal.ts +699 -0
  45. package/src/input/bookmark-modal.ts +33 -9
  46. package/src/input/changes-git.ts +251 -0
  47. package/src/input/changes-modal.ts +629 -0
  48. package/src/input/changes-model.ts +125 -0
  49. package/src/input/command-palette-types.ts +41 -0
  50. package/src/input/command-palette.ts +272 -0
  51. package/src/input/command-reference.ts +2 -2
  52. package/src/input/command-registry.ts +77 -35
  53. package/src/input/commands/acp-runtime.ts +19 -9
  54. package/src/input/commands/channel-runtime.ts +2 -2
  55. package/src/input/commands/ci-runtime.ts +1 -1
  56. package/src/input/commands/codebase-runtime.ts +1 -1
  57. package/src/input/commands/config.ts +7 -1
  58. package/src/input/commands/context-window.ts +25 -19
  59. package/src/input/commands/control-room-runtime.ts +18 -18
  60. package/src/input/commands/conversation-runtime.ts +0 -1
  61. package/src/input/commands/cost-runtime.ts +29 -20
  62. package/src/input/commands/diff-runtime.ts +35 -181
  63. package/src/input/commands/eval.ts +1 -1
  64. package/src/input/commands/experience-runtime.ts +3 -7
  65. package/src/input/commands/fresh-conversation.ts +86 -0
  66. package/src/input/commands/git-runtime.ts +5 -22
  67. package/src/input/commands/graph-runtime.ts +1 -1
  68. package/src/input/commands/guidance-runtime.ts +1 -1
  69. package/src/input/commands/health-runtime.ts +8 -9
  70. package/src/input/commands/hooks-runtime.ts +2 -2
  71. package/src/input/commands/hosted-runtime.ts +3 -3
  72. package/src/input/commands/incident-runtime.ts +3 -3
  73. package/src/input/commands/intelligence-runtime.ts +6 -9
  74. package/src/input/commands/knowledge.ts +2 -2
  75. package/src/input/commands/legacy-panel-command.ts +57 -0
  76. package/src/input/commands/local-auth-runtime.ts +8 -9
  77. package/src/input/commands/local-provider-runtime.ts +7 -4
  78. package/src/input/commands/local-runtime.ts +12 -15
  79. package/src/input/commands/local-setup-review.ts +1 -1
  80. package/src/input/commands/local-setup.ts +13 -19
  81. package/src/input/commands/memory.ts +1 -1
  82. package/src/input/commands/notify-runtime.ts +9 -0
  83. package/src/input/commands/operator-runtime.ts +10 -12
  84. package/src/input/commands/permissions-provenance.ts +3 -3
  85. package/src/input/commands/planning-runtime.ts +7 -7
  86. package/src/input/commands/platform-sandbox-runtime.ts +2 -2
  87. package/src/input/commands/platform-services-runtime.ts +1 -1
  88. package/src/input/commands/policy-dispatch.ts +2 -2
  89. package/src/input/commands/policy.ts +3 -3
  90. package/src/input/commands/provider.ts +1 -1
  91. package/src/input/commands/remote-runtime.ts +1 -1
  92. package/src/input/commands/review-runtime.ts +39 -94
  93. package/src/input/commands/rewind-runtime.ts +81 -108
  94. package/src/input/commands/runtime-services.ts +15 -17
  95. package/src/input/commands/services-runtime.ts +2 -2
  96. package/src/input/commands/session-content.ts +21 -5
  97. package/src/input/commands/session-workflow.ts +13 -38
  98. package/src/input/commands/settings-sync-runtime.ts +2 -2
  99. package/src/input/commands/shell-core.ts +19 -4
  100. package/src/input/commands/skills-runtime.ts +2 -2
  101. package/src/input/commands/status-runtime.ts +13 -0
  102. package/src/input/commands/subscription-runtime.ts +1 -1
  103. package/src/input/commands/tasks-runtime.ts +2 -8
  104. package/src/input/commands/work-plan-runtime.ts +4 -4
  105. package/src/input/commands/workstream-attempts.ts +24 -47
  106. package/src/input/commands/workstream-runtime.ts +2 -2
  107. package/src/input/commands/worktree-runtime.ts +3 -3
  108. package/src/input/commands.ts +3 -1
  109. package/src/input/composer-editor.ts +44 -0
  110. package/src/input/concealed-input.ts +1 -1
  111. package/src/input/config-modal-types.ts +20 -8
  112. package/src/input/config-modal.ts +106 -105
  113. package/src/input/confirm-dialog-types.ts +28 -0
  114. package/src/input/confirm-dialog.ts +70 -0
  115. package/src/input/delete-key-policy.ts +3 -3
  116. package/src/input/feed-context-factory.ts +15 -16
  117. package/src/input/handler-command-route.ts +7 -42
  118. package/src/input/handler-content-actions.ts +16 -15
  119. package/src/input/handler-feed-routes.ts +26 -211
  120. package/src/input/handler-feed.ts +68 -95
  121. package/src/input/handler-interactions.ts +5 -3
  122. package/src/input/handler-modal-routes.ts +215 -216
  123. package/src/input/handler-modal-stack.ts +81 -11
  124. package/src/input/handler-modal-token-routes.ts +4 -0
  125. package/src/input/handler-onboarding.ts +0 -1
  126. package/src/input/handler-picker-routes.ts +65 -107
  127. package/src/input/handler-session-view-route.ts +149 -0
  128. package/src/input/handler-shortcuts.ts +16 -154
  129. package/src/input/handler-types.ts +4 -2
  130. package/src/input/handler-ui-state.ts +45 -15
  131. package/src/input/handler-work-tree-route.ts +123 -0
  132. package/src/input/handler.ts +25 -70
  133. package/src/input/keybindings.ts +16 -71
  134. package/src/input/masked-entry-modal.ts +117 -0
  135. package/src/input/mcp-workspace.ts +48 -17
  136. package/src/input/model-picker-filter.ts +8 -0
  137. package/src/input/model-picker-open.ts +99 -0
  138. package/src/input/model-picker-types.ts +1 -1
  139. package/src/input/model-picker.ts +92 -9
  140. package/src/input/notifications-modal.ts +123 -0
  141. package/src/input/overlay-filter.ts +26 -0
  142. package/src/input/profile-picker-modal.ts +37 -8
  143. package/src/input/search.ts +3 -3
  144. package/src/input/selection-modal-queue.ts +2 -0
  145. package/src/input/selection-modal.ts +28 -16
  146. package/src/input/session-picker-modal.ts +33 -8
  147. package/src/input/settings-modal-activation.ts +7 -2
  148. package/src/input/settings-modal-data.ts +11 -6
  149. package/src/input/settings-modal-types.ts +1 -1
  150. package/src/input/settings-modal.ts +20 -20
  151. package/src/input/submission-intent.ts +1 -1
  152. package/src/input/submission-router.ts +4 -9
  153. package/src/input/surface-modal-host.ts +110 -0
  154. package/src/input/theme-settings-actions.ts +82 -0
  155. package/src/input/usage-modal.ts +183 -0
  156. package/src/input/views.ts +97 -0
  157. package/src/main.ts +175 -165
  158. package/src/permissions/hunk-selection.ts +1 -1
  159. package/src/permissions/prompt-card.ts +511 -0
  160. package/src/permissions/prompt.ts +59 -622
  161. package/src/renderer/agents-modal.ts +310 -0
  162. package/src/renderer/autocomplete-overlay.ts +42 -220
  163. package/src/renderer/back-to-bottom.ts +80 -0
  164. package/src/renderer/block-actions-overlay.ts +30 -48
  165. package/src/renderer/bookmark-modal.ts +48 -79
  166. package/src/renderer/changes-modal.ts +325 -0
  167. package/src/renderer/code-block.ts +184 -106
  168. package/src/renderer/command-palette.ts +93 -0
  169. package/src/renderer/composer-fragments.ts +4 -4
  170. package/src/renderer/composer.ts +146 -0
  171. package/src/renderer/compositor.ts +26 -160
  172. package/src/renderer/config-modal.ts +185 -81
  173. package/src/renderer/confirm-dialog.ts +50 -0
  174. package/src/renderer/context-inspector.ts +116 -154
  175. package/src/renderer/context-status-hint.ts +4 -4
  176. package/src/renderer/conversation-layout.ts +20 -0
  177. package/src/renderer/conversation-overlays.ts +94 -84
  178. package/src/renderer/conversation-surface.ts +19 -38
  179. package/src/renderer/diff-tint.ts +98 -0
  180. package/src/renderer/file-picker-overlay.ts +63 -90
  181. package/src/renderer/footer-targets.ts +38 -0
  182. package/src/renderer/git-status.ts +3 -4
  183. package/src/renderer/header-line.ts +140 -117
  184. package/src/renderer/help-overlay.ts +133 -219
  185. package/src/renderer/history-search-overlay.ts +15 -12
  186. package/src/renderer/lane-graph/bead.ts +800 -0
  187. package/src/renderer/lane-graph/glyphs.ts +134 -0
  188. package/src/renderer/lane-graph/layout.ts +248 -0
  189. package/src/renderer/lane-graph/paint.ts +537 -0
  190. package/src/renderer/lane-graph/semantic-memo.ts +77 -0
  191. package/src/renderer/layout-engine.ts +2 -57
  192. package/src/renderer/layout.ts +7 -13
  193. package/src/renderer/markdown-inline.ts +2 -1
  194. package/src/renderer/markdown-table.ts +17 -12
  195. package/src/renderer/markdown.ts +92 -34
  196. package/src/renderer/masked-entry-modal.ts +78 -0
  197. package/src/renderer/mcp-workspace.ts +166 -203
  198. package/src/renderer/model-workspace.ts +381 -436
  199. package/src/renderer/notifications-modal.ts +116 -0
  200. package/src/renderer/onboarding/onboarding-wizard.ts +178 -588
  201. package/src/renderer/process-view.ts +192 -0
  202. package/src/renderer/profile-picker-modal.ts +58 -110
  203. package/src/renderer/search-overlay.ts +6 -3
  204. package/src/renderer/selection-modal-overlay.ts +87 -327
  205. package/src/renderer/semantic-diff.ts +2 -2
  206. package/src/renderer/session-chips.ts +102 -0
  207. package/src/renderer/session-picker-modal.ts +177 -297
  208. package/src/renderer/settings-modal-connections.ts +14 -23
  209. package/src/renderer/settings-modal-context.ts +367 -0
  210. package/src/renderer/settings-modal-helpers.ts +6 -11
  211. package/src/renderer/settings-modal.ts +322 -726
  212. package/src/renderer/shell-surface.ts +277 -175
  213. package/src/renderer/shortcuts-overlay.ts +217 -0
  214. package/src/renderer/status-line.ts +475 -0
  215. package/src/renderer/surface-compose.ts +174 -0
  216. package/src/renderer/surface-kit-extra.ts +303 -0
  217. package/src/renderer/surface-kit-list.ts +366 -0
  218. package/src/renderer/surface-kit-parts.ts +360 -0
  219. package/src/renderer/surface-kit.ts +568 -0
  220. package/src/renderer/syntax-highlighter.ts +280 -197
  221. package/src/renderer/syntax-theme.ts +51 -0
  222. package/src/renderer/system-message.ts +0 -1
  223. package/src/renderer/term-caps.ts +42 -1
  224. package/src/renderer/terminal-bg-probe.ts +116 -19
  225. package/src/renderer/terminal-palette-probe.ts +322 -0
  226. package/src/renderer/terminal-palette-reader.ts +183 -0
  227. package/src/renderer/terminal-palette.ts +58 -0
  228. package/src/renderer/theme-mode-config.ts +16 -1
  229. package/src/renderer/theme.ts +234 -207
  230. package/src/renderer/thinking.ts +0 -1
  231. package/src/renderer/throbber.ts +188 -0
  232. package/src/renderer/toast-center.ts +119 -0
  233. package/src/renderer/ui-factory.ts +39 -602
  234. package/src/renderer/ui-primitives.ts +8 -25
  235. package/src/renderer/usage-modal.ts +353 -0
  236. package/src/renderer/user-message.ts +58 -0
  237. package/src/renderer/voice-capture-chip.ts +53 -0
  238. package/src/runtime/bootstrap-command-context.ts +0 -5
  239. package/src/runtime/bootstrap-command-parts.ts +38 -89
  240. package/src/runtime/bootstrap-core.ts +13 -15
  241. package/src/runtime/bootstrap-hook-bridge.ts +12 -21
  242. package/src/runtime/bootstrap-notifier-sync.ts +17 -1
  243. package/src/runtime/bootstrap-shell.ts +16 -50
  244. package/src/runtime/bootstrap.ts +14 -14
  245. package/src/runtime/client/fleet-union.ts +5 -5
  246. package/src/runtime/client/hosted-exit.ts +2 -2
  247. package/src/runtime/client/hosted-sessions.ts +1 -1
  248. package/src/runtime/client/spine-adoption.ts +1 -1
  249. package/src/runtime/context-accounting-source.ts +5 -4
  250. package/src/runtime/index.ts +1 -0
  251. package/src/runtime/notification-dispatch.ts +102 -29
  252. package/src/runtime/recovery-offer-wiring.ts +4 -1
  253. package/src/runtime/recovery-prompt.ts +31 -15
  254. package/src/runtime/runtime-services-types.ts +10 -6
  255. package/src/runtime/services.ts +17 -12
  256. package/src/runtime/session-continuity-hints.ts +2 -5
  257. package/src/runtime/session-inbound-inputs.ts +1 -1
  258. package/src/runtime/session-resume-liveness-confirm.ts +14 -2
  259. package/src/runtime/startup-typeahead-gate.ts +103 -0
  260. package/src/runtime/store/domains/domain-read-matrix.ts +0 -1
  261. package/src/runtime/store/domains/index.ts +0 -8
  262. package/src/runtime/store/selectors/index.ts +0 -28
  263. package/src/runtime/store/state.ts +0 -8
  264. package/src/runtime/ui-services.ts +4 -6
  265. package/src/runtime/usage-tracker.ts +348 -0
  266. package/src/runtime/wrfc-persistence.ts +4 -4
  267. package/src/shell/blocking-input.ts +92 -2
  268. package/src/shell/recovery-input-helpers.ts +1 -1
  269. package/src/shell/session-views.ts +539 -0
  270. package/src/shell/status-report.ts +86 -0
  271. package/src/shell/transcript-scroll.ts +68 -0
  272. package/src/shell/ui-openers.ts +84 -172
  273. package/src/shell/view-openers.ts +205 -0
  274. package/src/tools/wrfc-agent-guard.ts +22 -2
  275. package/src/utils/format-duration.ts +4 -8
  276. package/src/utils/splash-lines.ts +9 -1
  277. package/src/utils/terminal-width.ts +56 -0
  278. package/src/verification/live-verifier.ts +0 -10
  279. package/src/version.ts +1 -1
  280. package/src/{panels → views}/agent-inspector-shared.ts +2 -2
  281. package/src/{panels → views}/builtin-modals.ts +22 -21
  282. package/src/views/builtin-views.ts +135 -0
  283. package/src/{panels → views}/confirm-state.ts +9 -9
  284. package/src/{panels → views}/diff-review-model.ts +10 -3
  285. package/src/{panels → views}/eval-registry.ts +1 -1
  286. package/src/{panels → views}/fleet-acts.ts +49 -85
  287. package/src/{panels/fleet-panel-format.ts → views/fleet-format.ts} +40 -40
  288. package/src/{panels → views}/fleet-gateway.ts +5 -5
  289. package/src/{panels → views}/fleet-observed-render.ts +16 -16
  290. package/src/{panels → views}/fleet-read-model.ts +9 -9
  291. package/src/{panels/fleet-tabs.ts → views/fleet-session-tabs.ts} +13 -13
  292. package/src/{panels → views}/fleet-spawn.ts +33 -49
  293. package/src/{panels → views}/fleet-steer.ts +12 -12
  294. package/src/{panels → views}/fleet-stop.ts +4 -4
  295. package/src/{panels → views}/fleet-transcript.ts +26 -27
  296. package/src/{panels/fleet-panel-worktree-detail.ts → views/fleet-worktree-detail.ts} +7 -7
  297. package/src/{panels → views}/hosted-session-feed.ts +6 -6
  298. package/src/views/modal-surface-registry.ts +41 -0
  299. package/src/{panels → views}/modals/devices-modal.ts +2 -2
  300. package/src/{panels → views}/modals/hooks-modal.ts +13 -13
  301. package/src/{panels → views}/modals/keybindings-modal.ts +19 -27
  302. package/src/{panels → views}/modals/knowledge-modal.ts +6 -5
  303. package/src/{panels → views}/modals/local-auth-modal.ts +22 -21
  304. package/src/{panels → views}/modals/marketplace-modal.ts +11 -11
  305. package/src/{panels → views}/modals/memory-modal.ts +8 -8
  306. package/src/{panels → views}/modals/modal-surface-helpers.ts +15 -5
  307. package/src/{panels → views}/modals/pairing-modal.ts +9 -9
  308. package/src/{panels → views}/modals/planning-modal.ts +15 -20
  309. package/src/{panels → views}/modals/plugins-modal.ts +6 -6
  310. package/src/{panels → views}/modals/policy-modal.ts +13 -5
  311. package/src/{panels → views}/modals/provider-health-modal.ts +4 -4
  312. package/src/{panels → views}/modals/remote-modal.ts +3 -3
  313. package/src/{panels → views}/modals/sandbox-modal.ts +4 -4
  314. package/src/{panels → views}/modals/security-modal.ts +22 -16
  315. package/src/{panels → views}/modals/services-modal.ts +3 -3
  316. package/src/{panels → views}/modals/settings-sync-modal.ts +4 -4
  317. package/src/{panels → views}/modals/skills-modal.ts +9 -9
  318. package/src/{panels → views}/modals/subscription-modal.ts +3 -3
  319. package/src/{panels → views}/modals/work-plan-modal.ts +10 -13
  320. package/src/views/notifications-feed.ts +314 -0
  321. package/src/{panels → views}/polish-core.ts +38 -36
  322. package/src/{panels → views}/polish-tables.ts +35 -26
  323. package/src/{panels → views}/polish.ts +101 -95
  324. package/src/{panels → views}/project-planning-answer-actions.ts +3 -3
  325. package/src/{panels → views}/provider-health-routes.ts +14 -14
  326. package/src/{panels → views}/search-focus.ts +8 -8
  327. package/src/{panels → views}/session-maintenance.ts +11 -11
  328. package/src/views/skills-discovery.ts +159 -0
  329. package/src/views/view-deps.ts +80 -0
  330. package/src/views/view-panel-adapter.ts +53 -0
  331. package/src/{panels → views}/workstream-graph-render.ts +1 -1
  332. package/src/core/conversation-fold.ts +0 -101
  333. package/src/core/conversation-turn-structure.ts +0 -464
  334. package/src/core/conversation-user-receipts.ts +0 -42
  335. package/src/input/commands/operator-panel-runtime.ts +0 -186
  336. package/src/input/panel-integration-actions.ts +0 -33
  337. package/src/input/panel-mouse-geometry.ts +0 -97
  338. package/src/input/panel-paste-flood-guard.ts +0 -86
  339. package/src/panels/base-panel.ts +0 -301
  340. package/src/panels/builtin/agent.ts +0 -27
  341. package/src/panels/builtin/development.ts +0 -92
  342. package/src/panels/builtin/knowledge.ts +0 -12
  343. package/src/panels/builtin/operations.ts +0 -177
  344. package/src/panels/builtin/session.ts +0 -81
  345. package/src/panels/builtin/shared.ts +0 -357
  346. package/src/panels/builtin-panels.ts +0 -28
  347. package/src/panels/cost-tracker-panel.ts +0 -746
  348. package/src/panels/diff-panel.ts +0 -797
  349. package/src/panels/diff-review-panel.ts +0 -395
  350. package/src/panels/expandable-list-panel.ts +0 -189
  351. package/src/panels/fleet-deep-link.ts +0 -31
  352. package/src/panels/fleet-panel.ts +0 -799
  353. package/src/panels/git-panel.ts +0 -800
  354. package/src/panels/hosted-session-panel.ts +0 -221
  355. package/src/panels/index.ts +0 -21
  356. package/src/panels/local-auth-panel.ts +0 -478
  357. package/src/panels/notifications-feed.ts +0 -127
  358. package/src/panels/notifications-panel.ts +0 -160
  359. package/src/panels/panel-confirm-overlay.ts +0 -72
  360. package/src/panels/panel-manager.ts +0 -791
  361. package/src/panels/plugins-panel.ts +0 -371
  362. package/src/panels/scrollable-list-panel.ts +0 -498
  363. package/src/panels/skills-panel.ts +0 -454
  364. package/src/panels/token-budget-panel.ts +0 -688
  365. package/src/panels/types.ts +0 -191
  366. package/src/panels/wrfc-panel-format.ts +0 -133
  367. package/src/renderer/diff-view.ts +0 -134
  368. package/src/renderer/fleet-tab-strip.ts +0 -56
  369. package/src/renderer/footer-tips.ts +0 -53
  370. package/src/renderer/fullscreen-primitives.ts +0 -146
  371. package/src/renderer/fullscreen-workspace.ts +0 -194
  372. package/src/renderer/hint-grammar.ts +0 -52
  373. package/src/renderer/modal-factory.ts +0 -480
  374. package/src/renderer/overlay-box.ts +0 -154
  375. package/src/renderer/overlay-viewport.ts +0 -104
  376. package/src/renderer/panel-composite.ts +0 -145
  377. package/src/renderer/panel-workspace-bar.ts +0 -54
  378. package/src/renderer/process-indicator.ts +0 -163
  379. package/src/renderer/tab-strip.ts +0 -222
  380. package/src/renderer/text-layout.ts +0 -31
  381. package/src/renderer/tool-call.ts +0 -276
  382. package/src/renderer/tool-result-expanded-lines.ts +0 -48
  383. package/src/renderer/tool-result-summary.ts +0 -219
  384. package/src/runtime/diagnostics/panels/index.ts +0 -21
  385. package/src/runtime/diagnostics/panels/ops.ts +0 -156
  386. package/src/runtime/perf/panel-contracts.ts +0 -32
  387. package/src/runtime/store/domains/panels.ts +0 -117
  388. package/src/verification/verification-ledger.ts +0 -707
  389. /package/src/{panels → views}/memory-consolidation-gateway.ts +0 -0
  390. /package/src/{panels → views}/modals/modal-theme.ts +0 -0
  391. /package/src/{panels → views}/provider-health-domains.ts +0 -0
@@ -1,7 +1,8 @@
1
1
  // ---------------------------------------------------------------------------
2
- // acp-runtime.ts, the scripted path for hosting third-party coding agents,
3
- // over the SAME verbs the Fleet panel's spawn affordance drives (acp.agents.list
4
- // / acp.sessions.create). `/agents list` shows what the daemon discovered
2
+ // acp-runtime.ts, `/agents`. Bare `/agents` opens the Agents modal
3
+ // (`--target <id>[:<kind>]` selects a process in it). The scripted path for
4
+ // hosting third-party coding agents drives the SAME verbs the Agents modal's
5
+ // n key does (acp.agents.list / acp.sessions.create). `/agents list` shows what the daemon discovered
5
6
  // (read-only, quiet when none); `/agents host <agentId> [dir]` spawns one as a
6
7
  // long-lived daemon session that shows up as an acp-agent fleet row. A working
7
8
  // directory defaults to the current one; a known workspace root can be named
@@ -14,17 +15,26 @@
14
15
 
15
16
  import type { CommandRegistry } from '../command-registry.ts';
16
17
  import { requireShellPaths } from './runtime-services.ts';
18
+ import { takeTargetFlag } from '../views.ts';
17
19
  import { describeOperatorRpcError, getOperatorRpc } from './operator-rpc.ts';
18
20
 
19
21
  export function registerAcpRuntimeCommands(registry: CommandRegistry): void {
20
22
  registry.register({
21
23
  name: 'agents',
22
24
  aliases: ['acp'],
23
- description: 'Host third-party coding agents (Claude Code, Codex, opencode) as fleet rows over ACP',
24
- usage: 'list | host <agentId> [directory]',
25
- argsHint: '[list|host]',
25
+ description: 'Open Agents (everything running: agents, chains, workflows, hosted sessions); list or host third-party coding agents over ACP',
26
+ usage: '[--target <id>[:<kind>]] | list | host <agentId> [directory]',
27
+ argsHint: '[list|host|--target <id>]',
26
28
  async handler(args, ctx) {
27
- const sub = (args[0] ?? 'list').toLowerCase();
29
+ const rest = [...args];
30
+ const target = takeTargetFlag(rest);
31
+ if (rest.length === 0) {
32
+ // Bare /agents (or /agents --target <id>) opens the Agents modal.
33
+ if (ctx.openAgents) ctx.openAgents({ target });
34
+ else ctx.print('The Agents view is not available in this session; /agents list prints the hostable agents.');
35
+ return;
36
+ }
37
+ const sub = (rest[0] ?? 'list').toLowerCase();
28
38
  const rpc = getOperatorRpc(ctx);
29
39
  if (!rpc.available) { ctx.print(`[agents] ${rpc.reason}`); return; }
30
40
 
@@ -46,12 +56,12 @@ export function registerAcpRuntimeCommands(registry: CommandRegistry): void {
46
56
  }
47
57
 
48
58
  if (sub === 'host') {
49
- const agentId = args[1];
59
+ const agentId = rest[1];
50
60
  if (!agentId) {
51
61
  ctx.print('Usage: /agents host <agentId> [directory] (agentId from /agents list; directory defaults to the current one)');
52
62
  return;
53
63
  }
54
- const cwd = args[2] ?? requireShellPaths(ctx).workingDirectory;
64
+ const cwd = rest[2] ?? requireShellPaths(ctx).workingDirectory;
55
65
  try {
56
66
  const { hosted, started } = await rpc.sdk.operator.invoke('acp.sessions.create', { agentId, cwd });
57
67
  if (hosted.error) {
@@ -147,7 +147,7 @@ export function registerChannelRuntimeCommands(registry: CommandRegistry): void
147
147
  const asJson = args.includes('--json');
148
148
 
149
149
  if (!sub || sub === 'open' || sub === 'panel') {
150
- if (ctx.showPanel) ctx.showPanel('routes');
150
+ ctx.openView?.('routes');
151
151
  return;
152
152
  }
153
153
 
@@ -269,7 +269,7 @@ export function registerChannelRuntimeCommands(registry: CommandRegistry): void
269
269
 
270
270
  ctx.print(
271
271
  'Usage: /channel <subcommand>\n'
272
- + ' (no args) — open the Routes panel\n'
272
+ + ' (no args) — open Agents (where routes live now)\n'
273
273
  + ' pair [surface] — guided channel pairing: list adapters, enter declared credentials, verify\n'
274
274
  + ' status — channel overview: routes, sessions, tasks, pending approvals\n'
275
275
  + ' routes — active route binding snapshot\n'
@@ -83,7 +83,7 @@ export function renderWatch(watch: CiWatchSubscription): string {
83
83
  export function registerCiRuntimeCommands(registry: CommandRegistry): void {
84
84
  registry.register({
85
85
  name: 'ci',
86
- description: 'CI-watch: one-shot per-job status and standing watches over the operator panel',
86
+ description: 'CI-watch: one-shot per-job status and standing watches, surfaced in Agents',
87
87
  usage: 'status <repo-or-pr> | watch <repo-or-pr> <deliveryChannel> [--fix-session] | watches | unwatch <id>',
88
88
  argsHint: '[status|watch|watches|unwatch]',
89
89
  async handler(args, ctx) {
@@ -201,7 +201,7 @@ export function registerCodebaseRuntimeCommands(registry: CommandRegistry): void
201
201
  return;
202
202
  }
203
203
  store.scheduleBuild();
204
- ctx.print('Build scheduled: track progress with /codebase status or the fleet panel (code-index node).');
204
+ ctx.print('Build scheduled: track progress with /codebase status or Agents (F2, the code-index row).');
205
205
  return;
206
206
  }
207
207
 
@@ -1,6 +1,6 @@
1
1
  import type { CommandContext, CommandRegistry } from '../command-registry.ts';
2
2
  import type { ConfigKey } from '@pellux/goodvibes-sdk/platform/config';
3
- import { setActiveThemeMode, type ThemeMode } from '../../renderer/theme.ts';
3
+ import { setActiveThemeMode, setActiveThemeName, type ThemeMode } from '../../renderer/theme.ts';
4
4
  import {
5
5
  buildGoodVibesSecretKey,
6
6
  defaultSecretBackedScope,
@@ -45,9 +45,15 @@ export function registerConfigCommand(registry: CommandRegistry): void {
45
45
  ctx.print(`Set ${key}: ${JSON.stringify(before)} → ${JSON.stringify(after)}`);
46
46
  // Forced theme modes apply immediately (matches the settings-modal
47
47
  // path); 'auto' re-probes on the next launch (stated honestly).
48
+ if (key === 'display.theme') {
49
+ const applied = setActiveThemeName(after);
50
+ ctx.requestFullRepaint?.();
51
+ ctx.print(`Theme applied: ${applied}.`);
52
+ }
48
53
  if (key === 'display.themeMode') {
49
54
  if (after === 'dark' || after === 'light') {
50
55
  setActiveThemeMode(after as ThemeMode);
56
+ ctx.requestFullRepaint?.();
51
57
  ctx.print('Theme applied. Note: transcript, modal, and header/footer/thinking chrome all flip; only the background colour follows your terminal.');
52
58
  } else {
53
59
  ctx.print('Theme mode "auto" probes the terminal background on the next launch.');
@@ -6,11 +6,13 @@
6
6
  * control-plane config dir with provenance 'configured_cap'), so it survives
7
7
  * restarts, applies to any model (cloud or local), and is honored by every
8
8
  * consumer of the same home. Clearing returns the model to its automatic
9
- * window (catalog / provider API / family fallback).
9
+ * window (catalog / provider API / family fallback). The source line names
10
+ * where the window came from, with the SDK's describeContextWindowSource
11
+ * ('catalog: abacus', 'consensus of 4 providers', 'family default').
10
12
  */
11
13
  import type { CommandContext } from '../command-registry.ts';
12
14
  import type { ModelDefinition } from '@pellux/goodvibes-sdk/platform/providers';
13
- import { MAX_CONTEXT_WINDOW_OVERRIDE } from '@pellux/goodvibes-sdk/platform/providers';
15
+ import { MAX_CONTEXT_WINDOW_OVERRIDE, describeContextWindowSource } from '@pellux/goodvibes-sdk/platform/providers';
14
16
 
15
17
  /**
16
18
  * Parse a user-supplied context window size. Accepts plain token counts
@@ -28,26 +30,28 @@ export function parseContextWindowSize(raw: string): number | null {
28
30
  return value;
29
31
  }
30
32
 
31
- function describeProvenance(model: ModelDefinition): string {
32
- switch (model.contextWindowProvenance) {
33
- case 'configured_cap': return 'custom override';
34
- case 'observed_limit': return 'learned from a provider rejection';
35
- case 'provider_api': return 'reported by the provider';
36
- case 'fallback': return 'family default (no catalog entry)';
37
- default: return 'model catalog';
38
- }
39
- }
40
-
41
33
  /** Status text for the current model's window + override state. */
42
34
  export function buildContextWindowStatusText(
43
35
  model: ModelDefinition,
44
- resolvedWindow: number,
36
+ /** The window a source states, or null when unknown. */
37
+ resolvedWindow: number | null,
45
38
  override: number | null,
46
39
  observed: number | null = null,
47
40
  ): string {
41
+ const resolvedText = resolvedWindow === null
42
+ ? model.contextWindowProvenance === 'accepted_floor'
43
+ ? `unknown (the provider accepted ${model.contextWindow.toLocaleString()} tokens, more than the stated window)`
44
+ : model.contextWindowOrigin?.kind === 'family_default'
45
+ ? `unknown (no catalog provider lists this model; the family default of ${model.contextWindow.toLocaleString()} tokens is a guess)`
46
+ : 'unknown (no catalog entry or provider report states it)'
47
+ : `${resolvedWindow.toLocaleString()} tokens`;
48
+ const sourceText = resolvedWindow === null && model.contextWindowProvenance === 'accepted_floor'
49
+ ? null
50
+ : describeContextWindowSource(model);
48
51
  const lines = [
49
52
  `Context window for ${model.displayName} (${model.registryKey}):`,
50
- ` resolved: ${resolvedWindow.toLocaleString()} tokens (${describeProvenance(model)})`,
53
+ ` resolved: ${resolvedText}`,
54
+ ...(sourceText === null ? [] : [` source: ${sourceText}`]),
51
55
  ` override: ${override === null ? 'none (automatic)' : `${override.toLocaleString()} tokens`}`,
52
56
  ];
53
57
  if (observed !== null) {
@@ -71,23 +75,25 @@ export function handleContextWindowSubcommand(args: readonly string[], ctx: Comm
71
75
  if (arg === '') {
72
76
  output = buildContextWindowStatusText(
73
77
  model,
74
- registry.getContextWindowForModel(model),
78
+ registry.getKnownContextWindowForModel(model),
75
79
  registry.getModelContextCap(model.registryKey),
76
80
  registry.getObservedContextWindow(model.registryKey),
77
81
  );
78
82
  } else if (arg === 'clear' || arg === 'auto' || arg === 'reset') {
79
83
  const existed = registry.clearModelContextCap(model.registryKey);
80
- const resolved = registry.getContextWindowForModel(registry.getCurrentModel());
84
+ const known = registry.getKnownContextWindowForModel(registry.getCurrentModel());
85
+ const resolved = known === null ? 'unknown' : `${known.toLocaleString()} tokens`;
81
86
  output = existed
82
- ? `Context window settings cleared for ${model.displayName} (custom override and any learned limit). Back to automatic: ${resolved.toLocaleString()} tokens.`
83
- : `${model.displayName} has no custom context window or learned limit set (automatic: ${resolved.toLocaleString()} tokens).`;
87
+ ? `Context window settings cleared for ${model.displayName} (custom override and any learned limit). Back to automatic: ${resolved}.`
88
+ : `${model.displayName} has no custom context window or learned limit set (automatic: ${resolved}).`;
84
89
  } else {
85
90
  const size = parseContextWindowSize(arg);
86
91
  if (size === null) {
87
92
  output = `Invalid size '${args[0]}'. Use a token count between 1 and ${MAX_CONTEXT_WINDOW_OVERRIDE.toLocaleString()}, e.g. 120000, 200k, 1m, or 'clear'.`;
88
93
  } else {
94
+ const was = registry.getKnownContextWindowForModel(model);
89
95
  registry.setModelContextCap(model.registryKey, size);
90
- output = `Context window for ${model.displayName} set to ${size.toLocaleString()} tokens (was ${registry.getContextWindowForModel(model).toLocaleString()}). Clear with /context window clear.`;
96
+ output = `Context window for ${model.displayName} set to ${size.toLocaleString()} tokens (was ${was === null ? 'unknown' : `${was.toLocaleString()} tokens`}). Clear with /context window clear.`;
91
97
  }
92
98
  }
93
99
 
@@ -9,13 +9,13 @@ export function registerControlRoomRuntimeCommands(registry: CommandRegistry): v
9
9
  registry.register({
10
10
  name: 'cockpit',
11
11
  aliases: [],
12
- description: 'Open the unified operator cockpit',
12
+ description: 'Open Agents (the old operator cockpit)',
13
13
  handler(_args, ctx) {
14
- if (ctx.openCockpitPanel) {
15
- ctx.openCockpitPanel();
14
+ if (ctx.openCockpitView) {
15
+ ctx.openCockpitView();
16
16
  return;
17
17
  }
18
- ctx.print('Cockpit panel is not available in this runtime.');
18
+ ctx.print('The Agents view is not available in this runtime.');
19
19
  },
20
20
  });
21
21
 
@@ -27,12 +27,12 @@ export function registerControlRoomRuntimeCommands(registry: CommandRegistry): v
27
27
  handler(args, ctx) {
28
28
  const graphs = [...requireReadModels(ctx).orchestration.getSnapshot().graphs];
29
29
  if (args.length === 0) {
30
- if (ctx.openOrchestrationPanel) {
31
- ctx.openOrchestrationPanel();
30
+ if (ctx.openOrchestrationView) {
31
+ ctx.openOrchestrationView();
32
32
  return;
33
33
  }
34
34
  if (graphs.length === 0) {
35
- ctx.print('Orchestration panel is not available in this runtime.');
35
+ ctx.print('The Agents view is not available in this runtime.');
36
36
  return;
37
37
  }
38
38
  }
@@ -103,11 +103,11 @@ export function registerControlRoomRuntimeCommands(registry: CommandRegistry): v
103
103
  aliases: ['comms'],
104
104
  description: 'Inspect structured agent communication routes and recent activity',
105
105
  handler(_args, ctx) {
106
- if (ctx.openCommunicationPanel) {
107
- ctx.openCommunicationPanel();
106
+ if (ctx.openCommunicationView) {
107
+ ctx.openCommunicationView();
108
108
  return;
109
109
  }
110
- ctx.print('Communication panel is not available in this runtime.');
110
+ ctx.print('The Agents view is not available in this runtime.');
111
111
  },
112
112
  });
113
113
 
@@ -118,11 +118,11 @@ export function registerControlRoomRuntimeCommands(registry: CommandRegistry): v
118
118
  usage: '[review | attack-paths | tokens]',
119
119
  handler(args, ctx) {
120
120
  if (args.length === 0) {
121
- if (ctx.openSecurityPanel) {
122
- ctx.openSecurityPanel();
121
+ if (ctx.openSecurityView) {
122
+ ctx.openSecurityView();
123
123
  return;
124
124
  }
125
- ctx.print('Security panel is not available in this runtime.');
125
+ ctx.print('The Security view is not available in this runtime.');
126
126
  return;
127
127
  }
128
128
 
@@ -201,11 +201,11 @@ export function registerControlRoomRuntimeCommands(registry: CommandRegistry): v
201
201
  async handler(args, ctx) {
202
202
  const subcommand = (args[0] ?? 'open').toLowerCase();
203
203
  if (subcommand === 'open') {
204
- if (ctx.openMemoryPanel) {
205
- ctx.openMemoryPanel();
204
+ if (ctx.openMemoryView) {
205
+ ctx.openMemoryView();
206
206
  return;
207
207
  }
208
- ctx.print('Memory panel is not available in this runtime.');
208
+ ctx.print('The Memory view is not available in this runtime.');
209
209
  return;
210
210
  }
211
211
  if (subcommand === 'queue') {
@@ -250,8 +250,8 @@ export function registerControlRoomRuntimeCommands(registry: CommandRegistry): v
250
250
  ctx.print(prompt ?? 'No reviewed project knowledge matched that task.');
251
251
  return;
252
252
  }
253
- if (ctx.openMemoryPanel) {
254
- ctx.openMemoryPanel();
253
+ if (ctx.openMemoryView) {
254
+ ctx.openMemoryView();
255
255
  return;
256
256
  }
257
257
  ctx.print(`Unknown project-memory subcommand: ${subcommand}`);
@@ -79,7 +79,6 @@ function buildComposerReview(ctx: CommandContext): string[] {
79
79
  const composer = deriveComposerState({
80
80
  text: '',
81
81
  commandMode: false,
82
- panelFocused: false,
83
82
  pendingApproval: session.pendingApproval,
84
83
  hasAttachments: false,
85
84
  turnState: session.turnState,
@@ -1,6 +1,5 @@
1
1
  import type { CommandRegistry } from '../command-registry.ts';
2
- import { CostTrackerPanel } from '../../panels/cost-tracker-panel.ts';
3
- import { openCommandPanel, requirePanelManager } from './runtime-services.ts';
2
+ import { BUDGET_ALERT_USD_CONFIG_KEY } from '@pellux/goodvibes-sdk/platform/providers';
4
3
  import { describeOperatorRpcError, getOperatorRpc } from './operator-rpc.ts';
5
4
  import {
6
5
  COST_ATTRIBUTION_OPTIONAL_DIMENSIONS,
@@ -11,23 +10,37 @@ import {
11
10
  } from './cost-attribution-format.ts';
12
11
 
13
12
  /**
14
- * /cost budget <usd>, makes the CostTrackerPanel's budget alert real.
15
- * Opens the cost panel (creating it via the registered factory if not already
16
- * open) and sets its budget threshold directly, so the meter+alert already
17
- * built into CostTrackerPanel.render() (:266-290) actually fires. 0 disables
18
- * the alert. Mirrors the /auth local rotate-password → panel-instance-call
19
- * pattern (local-auth-runtime.ts) rather than only printing a signpost.
13
+ * /usage and /cost. `/usage` (and `/cost` or `/cost panel`) opens the Usage
14
+ * modal. `/cost budget <usd>` sets the budget alert: it writes the
15
+ * behavior.budgetAlertUsd setting, the one the Usage modal's b key, the Usage
16
+ * modal's budget row and the background budget-breach notifier all read, so
17
+ * the alert is real wherever it shows. 0 turns it off.
20
18
  */
21
19
  export function registerCostRuntimeCommands(registry: CommandRegistry): void {
20
+ registry.register({
21
+ name: 'usage',
22
+ description: 'Context pressure, session tokens and cost, per-turn history, per-agent costs and the budget alert',
23
+ usage: '[turns|agents]',
24
+ handler(args, ctx) {
25
+ const tab = (args[0] ?? '').toLowerCase();
26
+ if (!ctx.openUsage) {
27
+ ctx.print('The Usage view is not available in this session.');
28
+ return;
29
+ }
30
+ ctx.openUsage({ tab: tab === 'turns' || tab === 'agents' ? tab : undefined });
31
+ },
32
+ });
33
+
22
34
  registry.register({
23
35
  name: 'cost',
24
- description: 'Inspect session/agent cost tracking, windowed cost attribution, and the budget alert threshold',
36
+ description: 'Open Usage, set the session budget alert, or show windowed cost attribution',
25
37
  usage: '[panel|budget <usd>|attribution [24h|7d] [--json]]',
26
38
  async handler(args, ctx) {
27
39
  const sub = (args[0] ?? 'panel').toLowerCase();
28
40
 
29
41
  if (sub === 'panel' || sub === 'open') {
30
- openCommandPanel(ctx, 'cost');
42
+ if (ctx.openUsage) ctx.openUsage();
43
+ else ctx.print('The Usage view is not available in this session.');
31
44
  return;
32
45
  }
33
46
 
@@ -38,16 +51,12 @@ export function registerCostRuntimeCommands(registry: CommandRegistry): void {
38
51
  ctx.print('Usage: /cost budget <usd> (0 disables the alert)');
39
52
  return;
40
53
  }
41
- const panelManager = requirePanelManager(ctx);
42
- const panel = panelManager.open('cost');
43
- if (panel instanceof CostTrackerPanel) {
44
- panel.setBudgetThreshold(usd);
45
- ctx.print(usd > 0
46
- ? `Cost budget alert set to $${usd.toFixed(2)}.`
47
- : 'Cost budget alert disabled.');
48
- } else {
49
- ctx.print('Cost tracking is not available in this session.');
50
- }
54
+ const config = ctx.platform.configManager;
55
+ config.set(BUDGET_ALERT_USD_CONFIG_KEY as Parameters<typeof config.set>[0], usd as never);
56
+ ctx.print(usd > 0
57
+ ? `Cost budget alert set to $${usd.toFixed(2)}.`
58
+ : 'Cost budget alert disabled.');
59
+ ctx.renderRequest();
51
60
  return;
52
61
  }
53
62
 
@@ -1,193 +1,47 @@
1
- import { join } from 'path';
2
- import { logger } from '@pellux/goodvibes-sdk/platform/utils';
3
- import { GitService } from '@pellux/goodvibes-sdk/platform/git';
4
1
  import type { CommandContext, CommandRegistry } from '../command-registry.ts';
5
- import { requirePanelManager, requireSessionChangeTracker, requireShellPaths } from './runtime-services.ts';
6
-
7
- /**
8
- * Run a git command that lists changed file names, capturing stderr instead
9
- * of letting it fall through to the process's real stderr (which, for a
10
- * spawned child with no stdio option, is inherited from the parent, i.e.
11
- * written straight to the TUI's controlling terminal, corrupting the screen
12
- * outside the renderer's front/back-buffer diffing). Mirrors the 'staged'
13
- * subcommand's existing pattern below.
14
- */
15
- async function runGitNameOnly(args: string[], cwd: string): Promise<{ files: string[]; errText: string; ok: boolean }> {
16
- const proc = Bun.spawn(args, { stdout: 'pipe', stderr: 'pipe', cwd });
17
- const [out, errRaw] = await Promise.all([
18
- new Response(proc.stdout).text(),
19
- new Response(proc.stderr).text(),
20
- ]);
21
- const exitCode = await proc.exited;
22
- return {
23
- files: out.trim().split('\n').filter(Boolean),
24
- errText: errRaw.trim(),
25
- ok: exitCode === 0,
26
- };
2
+ import type { ChangesSource } from '../changes-git.ts';
3
+
4
+ /** `session` (default), `working` (not staged), `staged`, or `head` (everything vs HEAD). */
5
+ function sourceFor(arg: string | undefined): ChangesSource {
6
+ const sub = (arg ?? 'session').toLowerCase();
7
+ if (sub === 'working' || sub === 'unstaged') return 'working';
8
+ if (sub === 'staged' || sub === 'cached') return 'staged';
9
+ if (sub === 'head' || sub === 'all') return 'head';
10
+ return 'session';
27
11
  }
28
12
 
29
- /** Report a failed name-only fetch through the normal print channel and force
30
- * a full repaint on the next frame as defense-in-depth, in case anything did
31
- * reach the real tty. */
32
- function reportGitNameOnlyFailure(ctx: CommandContext, label: string, errText: string): void {
33
- ctx.print(`${label} failed: ${errText || 'unknown error'}`);
34
- ctx.requestFullRepaint?.();
35
- }
36
-
37
- async function enrichSemanticDiff(
38
- panel: InstanceType<typeof import('../../panels/diff-panel.ts').DiffPanel>,
39
- files: string[],
40
- ref: string,
41
- renderFn: () => void,
42
- workingDirectory: string,
43
- ): Promise<void> {
44
- const { computeSemanticDiff, formatSemanticDiffSummary } = await import('../../renderer/semantic-diff.ts');
45
- const { relative: pathRelative } = await import('path');
46
- const repoRootProc = Bun.spawn(['git', 'rev-parse', '--show-toplevel'], { stdout: 'pipe', stderr: 'pipe', cwd: workingDirectory });
47
- await repoRootProc.exited;
48
- const repoRoot = (await new Response(repoRootProc.stdout).text()).trim() || workingDirectory;
49
- await Promise.allSettled(
50
- files.map(async (filePath) => {
51
- try {
52
- const absPath = filePath.startsWith('/') ? filePath : join(workingDirectory, filePath);
53
- const repoRelPath = filePath.startsWith('/') ? pathRelative(repoRoot, filePath) : filePath;
54
- const [beforeResult, afterResult] = await Promise.allSettled([
55
- (async () => {
56
- const proc = Bun.spawn(
57
- ['git', 'show', `${ref}:${repoRelPath}`],
58
- { stdout: 'pipe', stderr: 'pipe', cwd: repoRoot },
59
- );
60
- const [text, exitCode] = await Promise.all([new Response(proc.stdout).text(), proc.exited]);
61
- if (exitCode !== 0) throw new Error(`git show failed for ${repoRelPath}`);
62
- return text;
63
- })(),
64
- Bun.file(absPath).text(),
65
- ]);
66
- if (beforeResult.status !== 'fulfilled' || afterResult.status !== 'fulfilled') return;
67
- const semanticDiff = await computeSemanticDiff(filePath, beforeResult.value, afterResult.value);
68
- if (!semanticDiff) return;
69
- const summary = formatSemanticDiffSummary(semanticDiff);
70
- if (summary) {
71
- panel.setSemanticSummary(filePath, summary);
72
- renderFn();
73
- }
74
- } catch {
75
- // best-effort only
76
- }
77
- }),
78
- );
13
+ function openChanges(ctx: CommandContext, args: string[]): void {
14
+ if (!ctx.openChanges) {
15
+ ctx.print('The Changes view is not available in this session.');
16
+ return;
17
+ }
18
+ ctx.openChanges({ source: sourceFor(args[0]) });
79
19
  }
80
20
 
21
+ /**
22
+ * `/changes` and `/diff`: the Changes modal over this repository. With no
23
+ * argument it shows the files this session edited against HEAD (everything vs
24
+ * HEAD when none are tracked yet); `working`, `staged` and `head` pick the
25
+ * other views, which v also cycles inside the modal.
26
+ */
81
27
  export function registerDiffRuntimeCommands(registry: CommandRegistry): void {
28
+ registry.register({
29
+ name: 'changes',
30
+ description: 'Changed files with a tinted diff and semantic summary: stage hunks, comment for the model, mark reviewed',
31
+ usage: '[session|working|staged|head]',
32
+ argsHint: '[session|working|staged|head]',
33
+ handler(args, ctx) {
34
+ openChanges(ctx, args);
35
+ },
36
+ });
82
37
  registry.register({
83
38
  name: 'diff',
84
39
  aliases: ['d'],
85
- description: 'Show unified diff of session file changes. Uses git diff HEAD if in a git repo',
86
- usage: '[session|head|working|staged|<git-ref>]',
87
- argsHint: '[session|head|working|staged|<ref>]',
88
- async handler(args, ctx) {
89
- const shellPaths = requireShellPaths(ctx);
90
- const workingDirectory = shellPaths.workingDirectory;
91
- // Gate before any git spawn happens (same defensive check /git already
92
- // has), every subcommand below shells out to git, and without this
93
- // they each produced a differently-shaped error for the same
94
- // not-a-git-repo condition.
95
- if (!GitService.isGitRepo(workingDirectory)) {
96
- ctx.print('Not a git repository here. Run /git to initialize one.');
97
- return;
98
- }
99
- const { DiffPanel } = await import('../../panels/diff-panel.ts');
100
-
101
- const pm = requirePanelManager(ctx);
102
- let panel = pm.getAllOpen().find(p => p.id === 'diff');
103
- if (!panel) {
104
- try {
105
- panel = pm.open('diff');
106
- } catch {
107
- ctx.print('Could not open diff panel.');
108
- return;
109
- }
110
- }
111
- pm.activateById('diff');
112
- if (!pm.isVisible()) pm.show();
113
- ctx.focusPanels?.();
114
-
115
- const diffPanel = panel as InstanceType<typeof DiffPanel>;
116
- const sub = (args[0] ?? 'session').toLowerCase();
117
-
118
- switch (sub) {
119
- case 'working': {
120
- ctx.print('Loading working-tree diff...');
121
- await diffPanel.showGitDiff();
122
- ctx.print('Diff panel updated: working tree changes.');
123
- const workingChanged = await runGitNameOnly(['git', 'diff', '--name-only'], workingDirectory);
124
- if (!workingChanged.ok) {
125
- reportGitNameOnlyFailure(ctx, 'git diff --name-only', workingChanged.errText);
126
- } else if (workingChanged.files.length > 0) {
127
- enrichSemanticDiff(diffPanel, workingChanged.files, 'HEAD', () => ctx.renderRequest(), workingDirectory).catch((err) => { logger.debug('semantic diff enrichment failed', { err }); });
128
- }
129
- break;
130
- }
131
- case 'staged': {
132
- ctx.print('Loading staged diff...');
133
- const proc = Bun.spawn(['/bin/sh', '-c', 'git diff --cached'], { stdout: 'pipe', stderr: 'pipe', cwd: workingDirectory });
134
- const [raw, errText] = await Promise.all([new Response(proc.stdout).text(), new Response(proc.stderr).text()]);
135
- const exitCode = await proc.exited;
136
- if (exitCode !== 0) {
137
- ctx.print(`git diff --cached failed: ${errText.trim() || 'unknown error'}`);
138
- return;
139
- }
140
- if (!raw.trim()) {
141
- ctx.print('No staged changes.');
142
- diffPanel.showDiff('(no staged changes)', '@@ -0,0 +0,0 @@\n No staged changes.');
143
- } else {
144
- diffPanel.loadRawDiff(raw);
145
- ctx.print('Diff panel updated: staged changes.');
146
- const stagedChanged = await runGitNameOnly(['git', 'diff', '--cached', '--name-only'], workingDirectory);
147
- if (!stagedChanged.ok) {
148
- reportGitNameOnlyFailure(ctx, 'git diff --cached --name-only', stagedChanged.errText);
149
- } else if (stagedChanged.files.length > 0) {
150
- enrichSemanticDiff(diffPanel, stagedChanged.files, 'HEAD', () => ctx.renderRequest(), workingDirectory).catch((err) => { logger.debug('semantic diff enrichment failed', { err }); });
151
- }
152
- }
153
- break;
154
- }
155
- case 'head': {
156
- ctx.print('Loading diff vs HEAD...');
157
- await diffPanel.showGitDiff('HEAD');
158
- ctx.print('Diff panel updated: all changes vs HEAD.');
159
- const headChanged = await runGitNameOnly(['git', 'diff', 'HEAD', '--name-only'], workingDirectory);
160
- if (!headChanged.ok) {
161
- reportGitNameOnlyFailure(ctx, 'git diff HEAD --name-only', headChanged.errText);
162
- } else if (headChanged.files.length > 0) {
163
- enrichSemanticDiff(diffPanel, headChanged.files, 'HEAD', () => ctx.renderRequest(), workingDirectory).catch((err) => { logger.debug('semantic diff enrichment failed', { err }); });
164
- }
165
- break;
166
- }
167
- case 'session':
168
- default: {
169
- const sessionFiles = requireSessionChangeTracker(ctx).getChangedFiles();
170
- if (sessionFiles.length > 0) {
171
- ctx.print(`Loading session diff (${sessionFiles.length} file${sessionFiles.length === 1 ? '' : 's'} changed this session)...`);
172
- await diffPanel.showFileDiffs(sessionFiles, 'HEAD');
173
- ctx.print(`Diff panel updated: ${sessionFiles.length} session file${sessionFiles.length === 1 ? '' : 's'}.`);
174
- enrichSemanticDiff(diffPanel, sessionFiles, 'HEAD', () => ctx.renderRequest(), workingDirectory).catch((err) => { logger.debug('semantic diff enrichment failed', { err }); });
175
- } else {
176
- ctx.print('No session changes tracked yet. Showing diff vs HEAD...');
177
- await diffPanel.showGitDiff('HEAD');
178
- ctx.print('Diff panel updated: all changes vs HEAD.');
179
- const fallback = await runGitNameOnly(['git', 'diff', 'HEAD', '--name-only'], workingDirectory);
180
- if (!fallback.ok) {
181
- reportGitNameOnlyFailure(ctx, 'git diff HEAD --name-only', fallback.errText);
182
- } else if (fallback.files.length > 0) {
183
- enrichSemanticDiff(diffPanel, fallback.files, 'HEAD', () => ctx.renderRequest(), workingDirectory).catch((err) => { logger.debug('semantic diff enrichment failed', { err }); });
184
- }
185
- }
186
- break;
187
- }
188
- }
189
-
190
- ctx.renderRequest();
40
+ description: 'Show the diff of this session\'s file changes (or working, staged, or everything vs HEAD) in Changes',
41
+ usage: '[session|head|working|staged]',
42
+ argsHint: '[session|head|working|staged]',
43
+ handler(args, ctx) {
44
+ openChanges(ctx, args);
191
45
  },
192
46
  });
193
47
  }
@@ -14,7 +14,7 @@ import { EvalRunner } from '@/runtime/index.ts';
14
14
  import { BUILTIN_SUITES } from '@/runtime/index.ts';
15
15
  import { formatScorecard } from '@/runtime/index.ts';
16
16
  import { loadBaseline, captureBaseline, formatBaselineComparison, writeBaseline } from '@/runtime/index.ts';
17
- import type { EvalRegistry } from '../../panels/eval-registry.ts';
17
+ import type { EvalRegistry } from '../../views/eval-registry.ts';
18
18
  import { formatSuiteResult, formatGateResult } from '@/runtime/index.ts';
19
19
  import { requireShellPaths } from './runtime-services.ts';
20
20
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';