@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,11 +21,9 @@
21
21
  // The undo/redo stacks stay TUI-side: the service reports how to reverse a
22
22
  // rewind (its receipt's undo block), and this module performs the reversal.
23
23
  //
24
- // The confirm step reuses the DiffPanel confirm idiom (PanelConfirmOverlay),
25
- // exactly like the former checkpoint-id /rewind this replaces (see the
26
- // architecture note in checkpoint-runtime.ts): the handler resolves the
27
- // anchor, previews the change, and arms the panel's confirm overlay; the actual
28
- // y/n handling lives in DiffPanel.handleInput().
24
+ // The confirm step is a question on a Changes preview (ctx.previewChanges):
25
+ // the handler resolves the anchor, shows exactly what changes, and waits for
26
+ // the answer; Esc or closing the preview answers no.
29
27
  // ---------------------------------------------------------------------------
30
28
 
31
29
  import {
@@ -44,7 +42,6 @@ import type { CommandContext, CommandRegistry } from '../command-registry.ts';
44
42
  import { buildRewindReceiptBlock } from '../../core/rewind-receipt.ts';
45
43
  import { getTurnAnchors, type TurnAnchor } from '@pellux/goodvibes-sdk/platform/rewind';
46
44
  import { createConversationRewindPort, type ConversationRewindPort } from '../../runtime/conversation-rewind-port.ts';
47
- import { requirePanelManager } from './runtime-services.ts';
48
45
  import { shortId } from './checkpoint-runtime.ts';
49
46
 
50
47
  export type RewindScope = SdkRewindScope;
@@ -239,7 +236,7 @@ function parseScope(token: string | undefined): RewindScope | null {
239
236
  // dead-ending on "no completed turns" while /checkpoints and the boot notice
240
237
  // both point back here, /rewind falls back to listing and restoring
241
238
  // checkpoints directly, a FILES-ONLY restore (there is no turn anchor to
242
- // join a conversation boundary against), reusing the same diff-panel
239
+ // join a conversation boundary against), reusing the same diff
243
240
  // preview/confirm idiom as the turn-anchored path above.
244
241
  // ---------------------------------------------------------------------------
245
242
 
@@ -304,52 +301,42 @@ async function handleCheckpointOnlyRewind(args: string[], ctx: CommandContext):
304
301
  }
305
302
  const checkpoint = resolved;
306
303
 
307
- const { DiffPanel } = await import('../../panels/diff-panel.ts');
308
- const pm = requirePanelManager(ctx);
309
- let panel = pm.getAllOpen().find((p) => p.id === 'diff');
310
- if (!panel) {
311
- try { panel = pm.open('diff'); } catch { ctx.print('Could not open diff panel.'); return; }
312
- }
313
- pm.activateById('diff');
314
- if (!pm.isVisible()) pm.show();
315
- ctx.focusPanels?.();
316
- const diffPanel = panel as InstanceType<typeof DiffPanel>;
317
-
304
+ let diff: string | undefined;
305
+ let note: string | undefined;
318
306
  try {
319
- const diff = await mgr.diff(checkpoint.id);
320
- if (diff.unifiedDiff.trim()) diffPanel.loadRawDiff(diff.unifiedDiff);
321
- else diffPanel.showDiff('(no file changes)', '@@ -0,0 +0,0 @@\n Working tree already matches this checkpoint.');
307
+ const result = await mgr.diff(checkpoint.id);
308
+ if (result.unifiedDiff.trim()) diff = result.unifiedDiff;
309
+ else note = 'The working tree already matches this checkpoint.';
322
310
  } catch {
323
- diffPanel.showDiff('(preview unavailable)', '@@ -0,0 +0,0 @@\n Could not load the checkpoint diff.');
311
+ note = 'Could not load the checkpoint diff.';
312
+ }
313
+ if (!ctx.previewChanges) {
314
+ ctx.print('Previewing a restore needs the Changes view, which is not available in this session.');
315
+ return;
324
316
  }
325
317
 
326
- diffPanel.confirmOverlay.arm({
327
- id: checkpoint.id,
328
- label: `${checkpoint.label}: restore FILES ONLY (no conversation state this run)`,
329
- verb: 'Restore',
330
- onConfirm: async () => {
331
- try {
332
- await mgr.restore(checkpoint.id, { safetyCheckpoint: true });
333
- ctx.session.conversationManager.addTypedSystemMessage(
334
- `[Rewind] Restored files from checkpoint ${shortId(checkpoint.id)} ("${checkpoint.label}"). Files only: no turn anchors exist this run, so conversation state is unchanged.`,
335
- 'operational',
336
- );
337
- pm.close('diff');
338
- ctx.focusPrompt?.();
339
- ctx.renderRequest();
340
- } catch (err) {
341
- ctx.print(`Checkpoint restore failed: ${summarizeError(err)}`);
342
- }
343
- },
344
- onCancel: () => {
345
- ctx.print('Restore cancelled: nothing changed.');
346
- pm.close('diff');
347
- ctx.focusPrompt?.();
348
- ctx.renderRequest();
349
- },
318
+ ctx.print(`Previewing checkpoint restore: "${checkpoint.label}" (files only; no conversation state this run). Enter or y restores, n or Esc cancels.`);
319
+ ctx.renderRequest();
320
+ const confirmed = await ctx.previewChanges({
321
+ title: checkpoint.label,
322
+ diff,
323
+ note,
324
+ question: { text: `Restore "${checkpoint.label}"? Files only: no conversation state this run.`, confirmLabel: 'Restore', tone: 'warning' },
350
325
  });
351
-
352
- ctx.print(`Previewing checkpoint restore: "${checkpoint.label}" (FILES ONLY; no conversation state this run). Confirm in the diff panel: Enter/y to restore, n/Esc to cancel.`);
326
+ if (!confirmed) {
327
+ ctx.print('Restore cancelled: nothing changed.');
328
+ ctx.renderRequest();
329
+ return;
330
+ }
331
+ try {
332
+ await mgr.restore(checkpoint.id, { safetyCheckpoint: true });
333
+ ctx.session.conversationManager.addTypedSystemMessage(
334
+ `[Rewind] Restored files from checkpoint ${shortId(checkpoint.id)} ("${checkpoint.label}"). Files only: no turn anchors exist this run, so conversation state is unchanged.`,
335
+ 'operational',
336
+ );
337
+ } catch (err) {
338
+ ctx.print(`Checkpoint restore failed: ${summarizeError(err)}`);
339
+ }
353
340
  ctx.renderRequest();
354
341
  }
355
342
 
@@ -412,82 +399,68 @@ export function registerRewindRuntimeCommands(registry: CommandRegistry): void {
412
399
  return;
413
400
  }
414
401
 
415
- // Preview in the DiffPanel + arm its confirm overlay (same idiom the
416
- // former checkpoint-id /rewind used, see checkpoint-runtime.ts).
417
- const { DiffPanel } = await import('../../panels/diff-panel.ts');
418
- const pm = requirePanelManager(ctx);
419
- let panel = pm.getAllOpen().find((p) => p.id === 'diff');
420
- if (!panel) {
421
- try { panel = pm.open('diff'); } catch { ctx.print('Could not open diff panel.'); return; }
422
- }
423
- pm.activateById('diff');
424
- if (!pm.isVisible()) pm.show();
425
- ctx.focusPanels?.();
426
- const diffPanel = panel as InstanceType<typeof DiffPanel>;
427
-
402
+ // Preview what changes in Changes, with the question on it.
403
+ let diff: string | undefined;
404
+ let note: string | undefined;
428
405
  const checkpointId = plan.files?.checkpointId ?? null;
429
406
  if (filesAvailable && checkpointId && ctx.workspace.workspaceCheckpointManager) {
430
407
  try {
431
- const diff = await ctx.workspace.workspaceCheckpointManager.diff(checkpointId);
432
- if (diff.unifiedDiff.trim()) diffPanel.loadRawDiff(diff.unifiedDiff);
433
- else diffPanel.showDiff('(no file changes)', '@@ -0,0 +0,0 @@\n Working tree already matches this checkpoint.');
408
+ const result = await ctx.workspace.workspaceCheckpointManager.diff(checkpointId);
409
+ if (result.unifiedDiff.trim()) diff = result.unifiedDiff;
410
+ else note = 'The working tree already matches this checkpoint.';
434
411
  } catch {
435
- diffPanel.showDiff('(preview unavailable)', '@@ -0,0 +0,0 @@\n Could not load the checkpoint diff.');
412
+ note = 'Could not load the checkpoint diff.';
436
413
  }
437
414
  } else {
438
415
  const drop = plan.conversation?.messagesToDrop ?? 0;
439
416
  const remaining = plan.conversation?.messagesRemaining ?? 0;
440
- diffPanel.showDiff(
441
- `Conversation rewind: drop ${drop} message(s)`,
442
- `@@ rewind @@\n Keep ${remaining} message(s), drop ${drop} after this turn. No files change.`,
443
- );
417
+ note = `Conversation rewind: keep ${remaining} message(s), drop ${drop} after this turn. No files change.`;
444
418
  }
445
419
 
446
420
  const summaryParts: string[] = [];
447
421
  if (wants(scope, 'files')) summaryParts.push(filesAvailable ? `${plan.files?.affectedFileCount ?? 0} file(s)` : 'files: none');
448
422
  if (wants(scope, 'conversation')) summaryParts.push(conversationAvailable ? `${plan.conversation?.messagesToDrop ?? 0} message(s)` : 'conversation: unavailable');
423
+ if (!ctx.previewChanges) {
424
+ ctx.print('Previewing a rewind needs the Changes view, which is not available in this session.');
425
+ return;
426
+ }
449
427
 
450
- diffPanel.confirmOverlay.arm({
451
- id: anchor.turnId ?? sessionId,
452
- label: `${resolved.label}: rewind ${scope} (${summaryParts.join(', ')})`,
453
- verb: 'Rewind',
454
- onConfirm: async () => {
455
- try {
456
- const result = await state.service.apply(anchor, scope, { confirmToken: plan.token });
457
- const receipt = result.receipt;
458
- if (!receipt) {
459
- ctx.print(`Rewind not applied: ${result.refusal?.reason ?? 'confirmation was refused.'}`);
460
- return;
461
- }
462
- if (undoAvailable(receipt)) {
463
- state.undo.push(receipt);
464
- state.redo.length = 0; // a fresh apply invalidates the redo stack
465
- }
466
- // addTypedSystemMessage persists the receipt into real session
467
- // history (indexed by getTranscriptEventIndex + save/load), and the
468
- // [Rewind] prefix is force-surfaced inline (system-message-router.ts).
469
- ctx.session.conversationManager.addTypedSystemMessage(
470
- buildRewindReceiptBlock({ ...receipt, undoAvailable: undoAvailable(receipt) }),
471
- 'operational',
472
- );
473
- pm.close('diff');
474
- ctx.focusPrompt?.();
475
- ctx.renderRequest();
476
- } catch (err) {
477
- ctx.print(`Rewind failed: ${summarizeError(err)}`);
478
- }
479
- },
480
- onCancel: () => {
481
- ctx.print('Rewind cancelled: nothing changed.');
482
- pm.close('diff');
483
- ctx.focusPrompt?.();
484
- ctx.renderRequest();
485
- },
486
- });
487
-
488
- ctx.print(`Previewing rewind of turn "${resolved.label}" (${scope}: ${summaryParts.join(', ')}). Confirm in the diff panel: Enter/y to rewind, n/Esc to cancel.`);
428
+ ctx.print(`Previewing rewind of turn "${resolved.label}" (${scope}: ${summaryParts.join(', ')}). Enter or y rewinds, n or Esc cancels.`);
489
429
  for (const w of plan.warnings) ctx.print(` note: ${w}`);
490
430
  ctx.renderRequest();
431
+ const confirmed = await ctx.previewChanges({
432
+ title: `rewind ${resolved.label}`,
433
+ diff,
434
+ note,
435
+ question: { text: `Rewind ${scope} to "${resolved.label}"? (${summaryParts.join(', ')})`, confirmLabel: 'Rewind', tone: 'warning' },
436
+ });
437
+ if (!confirmed) {
438
+ ctx.print('Rewind cancelled: nothing changed.');
439
+ ctx.renderRequest();
440
+ return;
441
+ }
442
+ try {
443
+ const result = await state.service.apply(anchor, scope, { confirmToken: plan.token });
444
+ const receipt = result.receipt;
445
+ if (!receipt) {
446
+ ctx.print(`Rewind not applied: ${result.refusal?.reason ?? 'confirmation was refused.'}`);
447
+ return;
448
+ }
449
+ if (undoAvailable(receipt)) {
450
+ state.undo.push(receipt);
451
+ state.redo.length = 0; // a fresh apply invalidates the redo stack
452
+ }
453
+ // addTypedSystemMessage persists the receipt into real session
454
+ // history (indexed by getTranscriptEventIndex + save/load), and the
455
+ // [Rewind] prefix is force-surfaced inline (system-message-router.ts).
456
+ ctx.session.conversationManager.addTypedSystemMessage(
457
+ buildRewindReceiptBlock({ ...receipt, undoAvailable: undoAvailable(receipt) }),
458
+ 'operational',
459
+ );
460
+ ctx.renderRequest();
461
+ } catch (err) {
462
+ ctx.print(`Rewind failed: ${summarizeError(err)}`);
463
+ }
491
464
  },
492
465
  });
493
466
  }
@@ -104,21 +104,21 @@ export function requirePluginPathOptions(
104
104
  };
105
105
  }
106
106
 
107
- export function openCommandPanel(
108
- context: Pick<CommandContext, 'showPanel'>,
109
- panelId: string,
110
- pane?: 'top' | 'bottom',
107
+ /**
108
+ * Open the modal that holds a view, by its current or old name (views.ts):
109
+ * 'fleet' and 'worktrees' open Agents, 'cost' opens Usage, and so on.
110
+ */
111
+ export function openCommandView(
112
+ context: Pick<CommandContext, 'openView' | 'print'>,
113
+ name: string,
111
114
  ): void {
112
- const showPanel = requireContextValue(context.showPanel, 'showPanel');
113
- showPanel(panelId, pane);
115
+ const openView = requireContextValue(context.openView, 'openView');
116
+ if (!openView(name)) context.print(`Nothing holds "${name}" in this build.`);
114
117
  }
115
118
 
116
119
  /**
117
- * (group-B migration): open a config-modal surface by name via the
118
- * ctx.openModal seam (ui-openers wires it; the host replaces the interim
119
- * "not available yet" implementation with real dispatch). Front-doors for
120
- * panels that migrated to modals call this instead of openCommandPanel, the
121
- * modal is the surface's new home. Stubbed in tests by setting ctx.openModal.
120
+ * Open a config-modal surface by name via the ctx.openModal seam (ui-openers
121
+ * wires it). Stubbed in tests by setting ctx.openModal.
122
122
  */
123
123
  export function openModalCommand(
124
124
  context: Pick<CommandContext, 'openModal'>,
@@ -145,10 +145,6 @@ export function requireProfileManager(context: CommandContext) {
145
145
  return requireContextValue(context.workspace.profileManager, 'workspace.profileManager');
146
146
  }
147
147
 
148
- export function requirePanelManager(context: CommandContext) {
149
- return requireContextValue(context.workspace.panelManager, 'workspace.panelManager');
150
- }
151
-
152
148
  export function requireBookmarkManager(context: CommandContext) {
153
149
  return requireContextValue(context.workspace.bookmarkManager, 'workspace.bookmarkManager');
154
150
  }
@@ -283,9 +279,11 @@ export async function compactConversation(context: CommandContext): Promise<Comp
283
279
  // Resolve the live context window for the current model so manual /compact
284
280
  // matches the auto-compaction path (which scales behaviour by window size)
285
281
  // instead of passing a meaningless 0.
286
- const contextWindow = providerRegistry.getContextWindowForModel(
282
+ // 0 when the window is unknown (a guess, or disproven by a larger accepted
283
+ // request): an unknown window is never treated as a small one.
284
+ const contextWindow = providerRegistry.getKnownContextWindowForModel(
287
285
  providerRegistry.getCurrentModel(),
288
- );
286
+ ) ?? 0;
289
287
 
290
288
  // Small-window models lack room for the structured (multi-LLM) extraction
291
289
  // pipeline, so mirror the SDK auto-compaction path and degrade to the
@@ -3,7 +3,7 @@ import { dirname, join, resolve } from 'node:path';
3
3
  import { atomicWriteFileSync } from '@pellux/goodvibes-sdk/platform/config';
4
4
  import type { CommandRegistry } from '../command-registry.ts';
5
5
  import type { SelectionAction, SelectionItem } from '../selection-modal.ts';
6
- import { openCommandPanel, requireServiceRegistry, requireShellPaths } from './runtime-services.ts';
6
+ import { requireServiceRegistry, requireShellPaths } from './runtime-services.ts';
7
7
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
8
8
 
9
9
  export function registerServicesRuntimeCommands(registry: CommandRegistry): void {
@@ -16,7 +16,7 @@ export function registerServicesRuntimeCommands(registry: CommandRegistry): void
16
16
  const sub = args[0] ?? 'open';
17
17
  const shellPaths = requireShellPaths(ctx);
18
18
  if (sub === 'open' || sub === 'panel') {
19
- ctx.openModal?.('services-modal'); // services panel -> config modal
19
+ ctx.openModal?.('services-modal'); // services view -> config modal
20
20
  return;
21
21
  }
22
22
  const svcRegistry = requireServiceRegistry(ctx);
@@ -280,15 +280,31 @@ export function registerSessionContentCommands(registry: CommandRegistry): void
280
280
  ctx.openSelection('Sessions', items, { allowSearch: true, customActions: deleteAction }, (result) => {
281
281
  if (!result) return;
282
282
  if (result.action === 'delete') {
283
- try {
284
- const sessionInfo = sessions.find(s => s.name === result.item.id);
285
- if (sessionInfo) {
283
+ const sessionInfo = sessions.find(s => s.name === result.item.id);
284
+ if (!sessionInfo) return;
285
+ const remove = (): void => {
286
+ try {
286
287
  unlinkSync(sessionInfo.filePath);
287
288
  ctx.print(`Session deleted: ${result.item.id}`);
289
+ } catch (e) {
290
+ ctx.print(`Failed to delete session: ${summarizeError(e)}`);
288
291
  }
289
- } catch (e) {
290
- ctx.print(`Failed to delete session: ${summarizeError(e)}`);
292
+ ctx.renderRequest();
293
+ };
294
+ // Deleting is permanent, so it asks first where a confirm dialog exists.
295
+ if (!ctx.confirm) {
296
+ remove();
297
+ return;
291
298
  }
299
+ void ctx.confirm({
300
+ title: 'Delete session?',
301
+ body: `This removes "${sessionInfo.name}" and its ${sessionInfo.messageCount} message${sessionInfo.messageCount === 1 ? '' : 's'} from this project.\nIt cannot be undone.`,
302
+ confirmLabel: 'Delete',
303
+ tone: 'danger',
304
+ }).then((confirmed) => {
305
+ if (confirmed) remove();
306
+ else ctx.renderRequest();
307
+ });
292
308
  } else {
293
309
  try {
294
310
  const { meta, messages } = sessionManager.load(result.item.id);
@@ -5,9 +5,9 @@ import { type SessionMeta } from '@pellux/goodvibes-sdk/platform/sessions';
5
5
  import type { TranscriptEventKind } from '@pellux/goodvibes-sdk/platform/core';
6
6
  import type { ConversationTitleSource } from '../../core/conversation';
7
7
  import type { SessionReturnContextSummary } from '@/runtime/index.ts';
8
- import { formatReturnContextForDisplay, getReturnContextMode, maybeAssistReturnContextSummary } from '@/runtime/index.ts';
9
- import { requirePanelManager, requireProviderApi, requireSessionManager, requireSurface } from './runtime-services.ts';
10
- import { resumeSessionCore, reopenPanelsWithModalSkip, DEFAULT_PANEL_REOPEN_LIMIT } from '../../core/session-resume-core.ts';
8
+ import { formatReturnContextForDisplay, getReturnContextMode, loadedReturnContext, maybeAssistReturnContextSummary } from '@/runtime/index.ts';
9
+ import { requireProviderApi, requireSessionManager, requireSurface } from './runtime-services.ts';
10
+ import { resumeSessionCore } from '../../core/session-resume-core.ts';
11
11
  import { checkSessionLiveness } from '@pellux/goodvibes-sdk/platform/runtime/operations';
12
12
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
13
13
 
@@ -80,24 +80,6 @@ function buildTranscriptReviewLines(
80
80
  ];
81
81
  }
82
82
 
83
- // Exported (test-only concern) so the MIGRATE-TO-MODAL redirect-skip honesty
84
- // (W6 review, finding 3: saved-layout restore with 'sessions' must not lie)
85
- // can be unit-tested directly instead of through a full /resume harness.
86
- // Delegates to the shared reopenPanelsWithModalSkip (core/session-resume-core.ts)
87
- //, the same routine resumeSessionCore uses, so this standalone entry point
88
- // and the canonical resume sequence can never diverge on panel-reopen behavior.
89
- export function reopenPanelsFromReturnContext(ctx: CommandContext, summary: SessionReturnContextSummary | undefined): string[] {
90
- if (!summary?.openPanels || summary.openPanels.length === 0) return [];
91
- const panelManager = requirePanelManager(ctx);
92
- const { reopened, movedToModal, notReopened } = reopenPanelsWithModalSkip(panelManager, summary.openPanels, DEFAULT_PANEL_REOPEN_LIMIT);
93
- if (movedToModal.length > 0) {
94
- ctx.print(`Note: ${movedToModal.join(', ')} moved to a modal; reopen via its command instead of as a panel.`);
95
- }
96
- if (notReopened.length > 0) {
97
- ctx.print(` …and ${notReopened.length} more not reopened (/panels to open)`);
98
- }
99
- return [...reopened];
100
- }
101
83
 
102
84
  function printSessionExport(
103
85
  ctx: { print: (text: string) => void },
@@ -181,14 +163,11 @@ export async function handleSessionWorkflowCommand(args: string[], ctx: CommandC
181
163
  const model = session.model ? ` [${session.model}]` : '';
182
164
  const active = session.name === ctx.session.runtime.sessionId ? ' ●' : ' ';
183
165
  lines.push(`${active} ${session.name.padEnd(28)} ${name.slice(0, 22).padEnd(22)} ${date} ${session.messageCount} msgs${model}`);
184
- if (session.returnContext?.activeTasks || session.returnContext?.blockedTasks || session.returnContext?.pendingApprovals || session.returnContext?.openPanels?.length) {
166
+ if (session.returnContext?.activeTasks || session.returnContext?.blockedTasks || session.returnContext?.pendingApprovals) {
185
167
  const posture = [
186
168
  session.returnContext.activeTasks ? `active=${session.returnContext.activeTasks}` : null,
187
169
  session.returnContext.blockedTasks ? `blocked=${session.returnContext.blockedTasks}` : null,
188
170
  session.returnContext.pendingApprovals ? `approvals=${session.returnContext.pendingApprovals}` : null,
189
- session.returnContext.openPanels?.length
190
- ? `panels=${session.returnContext.openPanels.slice(0, 3).join(',')}${session.returnContext.openPanels.length > 3 ? ` (+${session.returnContext.openPanels.length - 3} more)` : ''}`
191
- : null,
192
171
  ].filter(Boolean).join(' ');
193
172
  if (posture) lines.push(` posture: ${posture}`);
194
173
  }
@@ -270,11 +249,10 @@ export async function handleSessionWorkflowCommand(args: string[], ctx: CommandC
270
249
  conversation: ctx.session.conversationManager,
271
250
  runtime: ctx.session.runtime,
272
251
  surface: requireSurface(ctx),
273
- panelManager: requirePanelManager(ctx),
274
252
  selectModel: (model) => providerApi.selectModel(model),
275
253
  hydrateSessionUsage: ctx.session.hydrateSessionUsage,
276
254
  });
277
- const { meta, journalReplay, restoredAnchorCount, resumedMessageCount, panels } = outcome;
255
+ const { meta, journalReplay, restoredAnchorCount, resumedMessageCount } = outcome;
278
256
 
279
257
  ctx.renderRequest();
280
258
  ctx.print(`Resumed session: ${found.name}\n Name: ${meta.title || '(untitled)'}\n Messages: ${resumedMessageCount}\n Model: ${meta.model || ctx.session.runtime.model}`);
@@ -289,20 +267,13 @@ export async function handleSessionWorkflowCommand(args: string[], ctx: CommandC
289
267
  } else if (journalReplay.hadCorruptTail) {
290
268
  ctx.print(' [Recovery] Journal tail was partially corrupt (quarantined). Replay stopped at last good record.');
291
269
  }
292
- if (panels.movedToModal.length > 0) {
293
- ctx.print(`Note: ${panels.movedToModal.join(', ')} moved to a modal; reopen via its command instead of as a panel.`);
294
- }
295
- if (panels.notReopened.length > 0) {
296
- ctx.print(` …and ${panels.notReopened.length} more not reopened (/panels to open)`);
297
- }
298
270
  const returnContextMode = getReturnContextMode(ctx.platform.configManager);
299
271
  if (returnContextMode !== 'off' && meta.returnContext) {
272
+ // The SDK's session loader already dropped any legacy open-view list from a
273
+ // session saved by an older TUI, so the loaded return context is shown as-is.
300
274
  for (const line of formatReturnContextForDisplay(meta.returnContext)) {
301
275
  ctx.print(` ${line}`);
302
276
  }
303
- if (panels.reopened.length > 0) {
304
- ctx.print(` Reopened panels: ${panels.reopened.join(', ')}`);
305
- }
306
277
  if ((meta.returnContext.remoteRunners?.length ?? 0) > 0) {
307
278
  ctx.print(` Remote re-entry: /remote recover ${meta.returnContext.remoteRunners![0]}`);
308
279
  }
@@ -336,7 +307,9 @@ export async function handleSessionWorkflowCommand(args: string[], ctx: CommandC
336
307
  provider: ctx.session.runtime.provider,
337
308
  timestamp: Date.now(),
338
309
  titleSource: exportData.titleSource,
339
- returnContext: exportData.returnContext,
310
+ // Same shape a session file is read back in: a legacy open-view list
311
+ // (from an older session file) is never written again.
312
+ returnContext: loadedReturnContext(exportData.returnContext),
340
313
  // The operator asked for this fork by name; it is not turn machinery.
341
314
  saveSource: 'user',
342
315
  };
@@ -362,7 +335,9 @@ export async function handleSessionWorkflowCommand(args: string[], ctx: CommandC
362
335
  provider: ctx.session.runtime.provider,
363
336
  timestamp: Date.now(),
364
337
  titleSource: exportData.titleSource,
365
- returnContext: exportData.returnContext,
338
+ // Same shape a session file is read back in: a legacy open-view list
339
+ // (from an older session file) is never written again.
340
+ returnContext: loadedReturnContext(exportData.returnContext),
366
341
  // The one unambiguous "keep this" act in the app. Marked so the
367
342
  // session-conversations retention sweep never expires it, unlike the
368
343
  // automatic per-turn snapshot (turn-event-wiring.ts, saveSource 'auto').
@@ -19,7 +19,7 @@ import { getProviderIdFromModel } from '@pellux/goodvibes-sdk/platform/providers
19
19
  import { type ConfigKey } from '@pellux/goodvibes-sdk/platform/config';
20
20
  import { CONFIG_KEYS } from '@pellux/goodvibes-sdk/platform/config';
21
21
  import type { CommandRegistry } from '../command-registry.ts';
22
- import { openCommandPanel, requireShellPaths } from './runtime-services.ts';
22
+ import { requireShellPaths } from './runtime-services.ts';
23
23
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
24
24
 
25
25
  export function registerSettingsSyncRuntimeCommands(registry: CommandRegistry): void {
@@ -41,7 +41,7 @@ export function registerSettingsSyncRuntimeCommands(registry: CommandRegistry):
41
41
  return;
42
42
  }
43
43
  if (sub === 'panel' || sub === 'open') {
44
- ctx.openModal?.('settings-sync-modal'); // settings-sync panel -> config modal
44
+ ctx.openModal?.('settings-sync-modal'); // settings-sync view -> config modal
45
45
  return;
46
46
  }
47
47
  if (sub === 'report' || sub === 'review') {
@@ -12,6 +12,7 @@ import {
12
12
  toEffortModel,
13
13
  } from '../../providers/reasoning-effort-surface.ts';
14
14
  import { executeWriteQuit } from './quit-shared.ts';
15
+ import { startFreshConversation, type FreshConversationResult } from './fresh-conversation.ts';
15
16
  import { compactConversation, requireKeybindingsManager, requireProviderApi, requireSessionMemoryStore } from './runtime-services.ts';
16
17
  import { buildCompactionPreview, buildCompactionAfterNotice, buildPinUsageText, buildPinSuccessText } from '../../renderer/compaction-preview.ts';
17
18
  import { buildCompactionHistoryText } from '../../renderer/compaction-history-modal.ts';
@@ -242,9 +243,22 @@ export function registerShellCoreCommands(registry: CommandRegistry): void {
242
243
  registry.register({
243
244
  name: 'clear',
244
245
  aliases: ['cls'],
245
- description: 'Clear the conversation display (keeps LLM context)',
246
+ description: 'Start a fresh conversation (the current one is saved as its own session)',
246
247
  handler(_args, ctx) {
247
- ctx.session.conversationManager.clearDisplay();
248
+ if (ctx.isGenerating?.()) {
249
+ ctx.print('A turn is still running. Stop it with Esc or let it finish, then /clear.');
250
+ return;
251
+ }
252
+ let result: FreshConversationResult;
253
+ try {
254
+ result = startFreshConversation(ctx);
255
+ } catch (e) {
256
+ ctx.print(`Could not save the current conversation, so nothing was cleared: ${summarizeError(e)}`);
257
+ return;
258
+ }
259
+ if (result.savedAs) {
260
+ ctx.showToast?.({ title: 'Fresh conversation', body: `The previous one is saved as ${result.savedAs}. /session resume ${result.savedAs} returns to it.`, tone: 'info' });
261
+ }
248
262
  ctx.renderRequest();
249
263
  },
250
264
  });
@@ -274,9 +288,10 @@ export function registerShellCoreCommands(registry: CommandRegistry): void {
274
288
  // its own behaviour by window size. Previously hardcoded to 0 here, which
275
289
  // silently suppressed buildCompactionPreview()'s capacity-% clause even
276
290
  // though the builder has always supported it.
277
- const contextWindow = ctx.provider.providerRegistry.getContextWindowForModel(
291
+ // 0 when the window is unknown: the preview then leaves out the capacity clause.
292
+ const contextWindow = ctx.provider.providerRegistry.getKnownContextWindowForModel(
278
293
  ctx.provider.providerRegistry.getCurrentModel(),
279
- );
294
+ ) ?? 0;
280
295
  const memStore = ctx.session.sessionMemoryStore;
281
296
  const pinnedMemoryCount = memStore ? memStore.list().length : 0;
282
297
  // Pre-compact preview: honest estimate, clearly labelled.
@@ -1,5 +1,5 @@
1
1
  import type { CommandRegistry } from '../command-registry.ts';
2
- import { discoverSkills } from '../../panels/skills-panel.ts';
2
+ import { discoverSkills } from '../../views/skills-discovery.ts';
3
3
  import {
4
4
  installEcosystemCatalogEntry,
5
5
  listInstalledEcosystemEntries,
@@ -169,7 +169,7 @@ export function registerSkillsRuntimeCommands(registry: CommandRegistry): void {
169
169
  ` source: ${entry.source}`,
170
170
  ` tags: ${entry.tags.join(', ') || '(none)'}`,
171
171
  ` trust notes: ${entry.trustNotes ?? '(none)'}`,
172
- ` install hint: ${entry.installHint ?? 'Place the skill pack under a configured skill directory and refresh the skills panel.'}`,
172
+ ` install hint: ${entry.installHint ?? 'Place the skill pack under a configured skill directory and refresh the skills modal.'}`,
173
173
  ].join('\n'));
174
174
  return;
175
175
  }
@@ -0,0 +1,13 @@
1
+ import type { CommandRegistry } from '../command-registry.ts';
2
+
3
+ /** /status, everything the footer used to carry, in one report (shell/status-report.ts). */
4
+ export function registerStatusRuntimeCommands(registry: CommandRegistry): void {
5
+ registry.register({
6
+ name: 'status',
7
+ aliases: [],
8
+ description: 'Show session status: model, tools, token totals and cost, context use, surfaces and safety states',
9
+ handler(_args, ctx) {
10
+ ctx.print(ctx.describeStatus ? ctx.describeStatus() : 'Status is not available in this runtime.');
11
+ },
12
+ });
13
+ }
@@ -80,7 +80,7 @@ export function registerSubscriptionRuntimeCommands(registry: CommandRegistry):
80
80
  async handler(args, ctx) {
81
81
  const shellPaths = requireShellPaths(ctx);
82
82
  if (args.length === 0 && ctx.openModal) {
83
- ctx.openModal('subscription-modal'); // subscription panel -> config modal
83
+ ctx.openModal('subscription-modal'); // subscription view -> config modal
84
84
  return;
85
85
  }
86
86
  const sub = (args[0] ?? 'review').toLowerCase();
@@ -23,7 +23,7 @@
23
23
  import type { CommandRegistry, CommandContext } from '../command-registry.ts';
24
24
  import type { RuntimeTask, TaskLifecycleState } from '@/runtime/index.ts';
25
25
  import { reviewWorktreeAttachments } from '@/runtime/index.ts';
26
- import { requireOperatorClient, requireOpsApi, requirePanelManager, requireShellPaths } from './runtime-services.ts';
26
+ import { requireOperatorClient, requireOpsApi, requireShellPaths } from './runtime-services.ts';
27
27
  import { createTasksClient, type TasksClient, type UnionTask } from '@pellux/goodvibes-sdk/platform/runtime/client';
28
28
  import { createDaemonVerbCaller } from '../../runtime/client/operator-endpoint.ts';
29
29
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
@@ -85,13 +85,7 @@ export function registerTasksRuntimeCommands(registry: CommandRegistry): void {
85
85
  usage: '[list [status|kind] | show <taskId> | output <taskId> | create <kind> <owner> <title...> | update <taskId> <title|description|result> <value...> | complete <taskId> [result] | fail <taskId> <error...> | cancel <taskId> [note] | pause <taskId> [note] | resume <taskId> [note] | retry <taskId> [note]]',
86
86
  async handler(args, ctx) {
87
87
  if (args.length === 0) {
88
- if (ctx.showPanel) ctx.showPanel('tasks');
89
- else {
90
- const panelManager = requirePanelManager(ctx);
91
- panelManager.open('tasks');
92
- panelManager.show();
93
- ctx.renderRequest();
94
- }
88
+ if (!ctx.openView?.('tasks')) ctx.print('The Agents view is not available in this session; /tasks list prints them.');
95
89
  return;
96
90
  }
97
91
 
@@ -24,7 +24,7 @@ function getStore(ctx: import('../command-registry.ts').CommandContext): WorkPla
24
24
  return ctx.workspace.workPlanStore ?? null;
25
25
  }
26
26
 
27
- function openPanel(ctx: import('../command-registry.ts').CommandContext): void {
27
+ function openWorkPlanModal(ctx: import('../command-registry.ts').CommandContext): void {
28
28
  // work-plan migrated to the 'work-plan' modal, open it via the seam.
29
29
  openModalCommand(ctx, 'work-plan-modal');
30
30
  }
@@ -86,8 +86,8 @@ export function registerWorkPlanRuntimeCommands(registry: CommandRegistry): void
86
86
  const subcommand = (args[0] ?? 'panel').toLowerCase();
87
87
  try {
88
88
  if (subcommand === 'panel' || subcommand === 'open') {
89
- openPanel(ctx);
90
- ctx.print('Opened work plan panel.');
89
+ openWorkPlanModal(ctx);
90
+ ctx.print('Opened the work plan.');
91
91
  return;
92
92
  }
93
93
  if (subcommand === 'list') {
@@ -118,7 +118,7 @@ export function registerWorkPlanRuntimeCommands(registry: CommandRegistry): void
118
118
  ...(parsed.notes ? { notes: parsed.notes } : {}),
119
119
  };
120
120
  const item = store.addItem(parsed.title, addOptions);
121
- openPanel(ctx);
121
+ openWorkPlanModal(ctx);
122
122
  ctx.print(`Added work plan item ${item.id}.`);
123
123
  return;
124
124
  }