@pellux/goodvibes-tui 2.0.20 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (388) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/README.md +16 -16
  3. package/docs/README.md +4 -4
  4. package/docs/foundation-artifacts/operator-contract.json +59 -4
  5. package/package.json +16 -6
  6. package/src/cli/management.ts +5 -2
  7. package/src/cli/tui-startup.ts +34 -39
  8. package/src/core/agent-view-render.ts +157 -0
  9. package/src/core/approval-alert.ts +49 -11
  10. package/src/core/bookmark-navigation.ts +7 -1
  11. package/src/core/budget-breach-notifier.ts +27 -8
  12. package/src/core/compaction-receipt.ts +1 -1
  13. package/src/core/context-usage.ts +1 -1
  14. package/src/core/conversation-compaction-render.ts +3 -3
  15. package/src/core/conversation-display-only.ts +86 -0
  16. package/src/core/conversation-event-navigation.ts +27 -0
  17. package/src/core/conversation-line-cache.ts +216 -447
  18. package/src/core/conversation-render-context.ts +20 -27
  19. package/src/core/conversation-rendering.ts +157 -575
  20. package/src/core/conversation-splash-state.ts +6 -1
  21. package/src/core/conversation-types.ts +35 -0
  22. package/src/core/conversation-usage.ts +12 -0
  23. package/src/core/conversation.ts +130 -131
  24. package/src/core/long-task-notifier.ts +100 -31
  25. package/src/core/notices.ts +75 -0
  26. package/src/core/pairing-tailscale-gateway.ts +1 -1
  27. package/src/core/process-output-log.ts +143 -0
  28. package/src/core/rewind-receipt.ts +1 -1
  29. package/src/core/session-focus.ts +190 -0
  30. package/src/core/session-resume-core.ts +23 -81
  31. package/src/core/stream-event-wiring.ts +31 -5
  32. package/src/core/system-message-noise.ts +2 -2
  33. package/src/core/system-message-router.ts +16 -18
  34. package/src/core/turn-event-wiring.ts +272 -33
  35. package/src/core/work-tree-focus.ts +290 -0
  36. package/src/core/work-tree-fold-store.ts +143 -0
  37. package/src/core/work-tree-model.ts +799 -0
  38. package/src/core/work-tree-render.ts +384 -0
  39. package/src/core/work-tree-sources.ts +184 -0
  40. package/src/core/work-tree-wiring.ts +176 -0
  41. package/src/core/workstream-notification.ts +36 -6
  42. package/src/core/wrfc-notice-titles.ts +37 -0
  43. package/src/input/agents-modal-text.ts +119 -0
  44. package/src/input/agents-modal.ts +699 -0
  45. package/src/input/bookmark-modal.ts +33 -9
  46. package/src/input/changes-git.ts +251 -0
  47. package/src/input/changes-modal.ts +629 -0
  48. package/src/input/changes-model.ts +125 -0
  49. package/src/input/command-palette-types.ts +41 -0
  50. package/src/input/command-palette.ts +272 -0
  51. package/src/input/command-registry.ts +77 -35
  52. package/src/input/commands/acp-runtime.ts +19 -9
  53. package/src/input/commands/channel-runtime.ts +2 -2
  54. package/src/input/commands/ci-runtime.ts +1 -1
  55. package/src/input/commands/codebase-runtime.ts +1 -1
  56. package/src/input/commands/config.ts +7 -1
  57. package/src/input/commands/context-window.ts +25 -19
  58. package/src/input/commands/control-room-runtime.ts +18 -18
  59. package/src/input/commands/conversation-runtime.ts +0 -1
  60. package/src/input/commands/cost-runtime.ts +29 -20
  61. package/src/input/commands/diff-runtime.ts +35 -181
  62. package/src/input/commands/eval.ts +1 -1
  63. package/src/input/commands/experience-runtime.ts +3 -7
  64. package/src/input/commands/fresh-conversation.ts +86 -0
  65. package/src/input/commands/git-runtime.ts +5 -22
  66. package/src/input/commands/graph-runtime.ts +1 -1
  67. package/src/input/commands/guidance-runtime.ts +1 -1
  68. package/src/input/commands/health-runtime.ts +8 -9
  69. package/src/input/commands/hooks-runtime.ts +2 -2
  70. package/src/input/commands/hosted-runtime.ts +3 -3
  71. package/src/input/commands/incident-runtime.ts +3 -3
  72. package/src/input/commands/intelligence-runtime.ts +6 -9
  73. package/src/input/commands/knowledge.ts +2 -2
  74. package/src/input/commands/legacy-panel-command.ts +57 -0
  75. package/src/input/commands/local-auth-runtime.ts +8 -9
  76. package/src/input/commands/local-provider-runtime.ts +7 -4
  77. package/src/input/commands/local-runtime.ts +12 -15
  78. package/src/input/commands/local-setup-review.ts +1 -1
  79. package/src/input/commands/local-setup.ts +13 -19
  80. package/src/input/commands/memory.ts +1 -1
  81. package/src/input/commands/notify-runtime.ts +9 -0
  82. package/src/input/commands/operator-runtime.ts +10 -12
  83. package/src/input/commands/permissions-provenance.ts +3 -3
  84. package/src/input/commands/planning-runtime.ts +7 -7
  85. package/src/input/commands/platform-sandbox-runtime.ts +2 -2
  86. package/src/input/commands/platform-services-runtime.ts +1 -1
  87. package/src/input/commands/policy-dispatch.ts +2 -2
  88. package/src/input/commands/policy.ts +3 -3
  89. package/src/input/commands/provider.ts +1 -1
  90. package/src/input/commands/remote-runtime.ts +1 -1
  91. package/src/input/commands/review-runtime.ts +39 -94
  92. package/src/input/commands/rewind-runtime.ts +81 -108
  93. package/src/input/commands/runtime-services.ts +15 -17
  94. package/src/input/commands/services-runtime.ts +2 -2
  95. package/src/input/commands/session-content.ts +21 -5
  96. package/src/input/commands/session-workflow.ts +13 -38
  97. package/src/input/commands/settings-sync-runtime.ts +2 -2
  98. package/src/input/commands/shell-core.ts +19 -4
  99. package/src/input/commands/skills-runtime.ts +2 -2
  100. package/src/input/commands/status-runtime.ts +13 -0
  101. package/src/input/commands/subscription-runtime.ts +1 -1
  102. package/src/input/commands/tasks-runtime.ts +2 -8
  103. package/src/input/commands/work-plan-runtime.ts +4 -4
  104. package/src/input/commands/workstream-attempts.ts +24 -47
  105. package/src/input/commands/workstream-runtime.ts +2 -2
  106. package/src/input/commands/worktree-runtime.ts +3 -3
  107. package/src/input/commands.ts +3 -1
  108. package/src/input/composer-editor.ts +44 -0
  109. package/src/input/concealed-input.ts +1 -1
  110. package/src/input/config-modal-types.ts +20 -8
  111. package/src/input/config-modal.ts +106 -105
  112. package/src/input/confirm-dialog-types.ts +28 -0
  113. package/src/input/confirm-dialog.ts +70 -0
  114. package/src/input/delete-key-policy.ts +3 -3
  115. package/src/input/feed-context-factory.ts +15 -16
  116. package/src/input/handler-command-route.ts +7 -42
  117. package/src/input/handler-content-actions.ts +16 -15
  118. package/src/input/handler-feed-routes.ts +26 -211
  119. package/src/input/handler-feed.ts +68 -95
  120. package/src/input/handler-interactions.ts +5 -3
  121. package/src/input/handler-modal-routes.ts +215 -216
  122. package/src/input/handler-modal-stack.ts +81 -11
  123. package/src/input/handler-modal-token-routes.ts +4 -0
  124. package/src/input/handler-onboarding.ts +0 -1
  125. package/src/input/handler-picker-routes.ts +65 -107
  126. package/src/input/handler-session-view-route.ts +149 -0
  127. package/src/input/handler-shortcuts.ts +16 -154
  128. package/src/input/handler-types.ts +4 -2
  129. package/src/input/handler-ui-state.ts +45 -15
  130. package/src/input/handler-work-tree-route.ts +123 -0
  131. package/src/input/handler.ts +25 -70
  132. package/src/input/keybindings.ts +16 -71
  133. package/src/input/masked-entry-modal.ts +117 -0
  134. package/src/input/mcp-workspace.ts +48 -17
  135. package/src/input/model-picker-filter.ts +8 -0
  136. package/src/input/model-picker-open.ts +99 -0
  137. package/src/input/model-picker-types.ts +1 -1
  138. package/src/input/model-picker.ts +92 -9
  139. package/src/input/notifications-modal.ts +123 -0
  140. package/src/input/overlay-filter.ts +26 -0
  141. package/src/input/profile-picker-modal.ts +37 -8
  142. package/src/input/search.ts +3 -3
  143. package/src/input/selection-modal-queue.ts +2 -0
  144. package/src/input/selection-modal.ts +28 -16
  145. package/src/input/session-picker-modal.ts +33 -8
  146. package/src/input/settings-modal-activation.ts +7 -2
  147. package/src/input/settings-modal-data.ts +11 -6
  148. package/src/input/settings-modal-types.ts +1 -1
  149. package/src/input/settings-modal.ts +20 -20
  150. package/src/input/submission-intent.ts +1 -1
  151. package/src/input/submission-router.ts +4 -9
  152. package/src/input/surface-modal-host.ts +110 -0
  153. package/src/input/theme-settings-actions.ts +82 -0
  154. package/src/input/usage-modal.ts +183 -0
  155. package/src/input/views.ts +97 -0
  156. package/src/main.ts +175 -165
  157. package/src/permissions/hunk-selection.ts +1 -1
  158. package/src/permissions/prompt-card.ts +511 -0
  159. package/src/permissions/prompt.ts +59 -622
  160. package/src/renderer/agents-modal.ts +310 -0
  161. package/src/renderer/autocomplete-overlay.ts +42 -220
  162. package/src/renderer/back-to-bottom.ts +80 -0
  163. package/src/renderer/block-actions-overlay.ts +30 -48
  164. package/src/renderer/bookmark-modal.ts +48 -79
  165. package/src/renderer/changes-modal.ts +325 -0
  166. package/src/renderer/code-block.ts +184 -106
  167. package/src/renderer/command-palette.ts +93 -0
  168. package/src/renderer/composer-fragments.ts +4 -4
  169. package/src/renderer/composer.ts +146 -0
  170. package/src/renderer/compositor.ts +26 -160
  171. package/src/renderer/config-modal.ts +185 -81
  172. package/src/renderer/confirm-dialog.ts +50 -0
  173. package/src/renderer/context-inspector.ts +116 -154
  174. package/src/renderer/context-status-hint.ts +4 -4
  175. package/src/renderer/conversation-layout.ts +20 -0
  176. package/src/renderer/conversation-overlays.ts +94 -84
  177. package/src/renderer/conversation-surface.ts +19 -38
  178. package/src/renderer/diff-tint.ts +98 -0
  179. package/src/renderer/file-picker-overlay.ts +63 -90
  180. package/src/renderer/footer-targets.ts +38 -0
  181. package/src/renderer/git-status.ts +3 -4
  182. package/src/renderer/header-line.ts +140 -117
  183. package/src/renderer/help-overlay.ts +133 -219
  184. package/src/renderer/history-search-overlay.ts +15 -12
  185. package/src/renderer/lane-graph/bead.ts +800 -0
  186. package/src/renderer/lane-graph/glyphs.ts +134 -0
  187. package/src/renderer/lane-graph/layout.ts +248 -0
  188. package/src/renderer/lane-graph/paint.ts +537 -0
  189. package/src/renderer/lane-graph/semantic-memo.ts +77 -0
  190. package/src/renderer/layout-engine.ts +2 -57
  191. package/src/renderer/layout.ts +7 -13
  192. package/src/renderer/markdown-inline.ts +2 -1
  193. package/src/renderer/markdown-table.ts +17 -12
  194. package/src/renderer/markdown.ts +92 -34
  195. package/src/renderer/masked-entry-modal.ts +78 -0
  196. package/src/renderer/mcp-workspace.ts +166 -203
  197. package/src/renderer/model-workspace.ts +381 -436
  198. package/src/renderer/notifications-modal.ts +116 -0
  199. package/src/renderer/onboarding/onboarding-wizard.ts +178 -588
  200. package/src/renderer/process-view.ts +192 -0
  201. package/src/renderer/profile-picker-modal.ts +58 -110
  202. package/src/renderer/search-overlay.ts +6 -3
  203. package/src/renderer/selection-modal-overlay.ts +87 -327
  204. package/src/renderer/semantic-diff.ts +2 -2
  205. package/src/renderer/session-chips.ts +102 -0
  206. package/src/renderer/session-picker-modal.ts +177 -297
  207. package/src/renderer/settings-modal-connections.ts +14 -23
  208. package/src/renderer/settings-modal-context.ts +367 -0
  209. package/src/renderer/settings-modal-helpers.ts +6 -11
  210. package/src/renderer/settings-modal.ts +322 -726
  211. package/src/renderer/shell-surface.ts +277 -175
  212. package/src/renderer/shortcuts-overlay.ts +217 -0
  213. package/src/renderer/status-line.ts +475 -0
  214. package/src/renderer/surface-compose.ts +174 -0
  215. package/src/renderer/surface-kit-extra.ts +303 -0
  216. package/src/renderer/surface-kit-list.ts +366 -0
  217. package/src/renderer/surface-kit-parts.ts +360 -0
  218. package/src/renderer/surface-kit.ts +568 -0
  219. package/src/renderer/syntax-highlighter.ts +280 -197
  220. package/src/renderer/syntax-theme.ts +51 -0
  221. package/src/renderer/system-message.ts +0 -1
  222. package/src/renderer/term-caps.ts +42 -1
  223. package/src/renderer/terminal-bg-probe.ts +116 -19
  224. package/src/renderer/terminal-palette-probe.ts +322 -0
  225. package/src/renderer/terminal-palette-reader.ts +183 -0
  226. package/src/renderer/terminal-palette.ts +58 -0
  227. package/src/renderer/theme-mode-config.ts +16 -1
  228. package/src/renderer/theme.ts +234 -207
  229. package/src/renderer/thinking.ts +0 -1
  230. package/src/renderer/throbber.ts +188 -0
  231. package/src/renderer/toast-center.ts +119 -0
  232. package/src/renderer/ui-factory.ts +39 -602
  233. package/src/renderer/ui-primitives.ts +8 -25
  234. package/src/renderer/usage-modal.ts +353 -0
  235. package/src/renderer/user-message.ts +58 -0
  236. package/src/renderer/voice-capture-chip.ts +53 -0
  237. package/src/runtime/bootstrap-command-context.ts +0 -5
  238. package/src/runtime/bootstrap-command-parts.ts +38 -89
  239. package/src/runtime/bootstrap-core.ts +13 -15
  240. package/src/runtime/bootstrap-hook-bridge.ts +12 -21
  241. package/src/runtime/bootstrap-notifier-sync.ts +17 -1
  242. package/src/runtime/bootstrap-shell.ts +16 -50
  243. package/src/runtime/bootstrap.ts +14 -14
  244. package/src/runtime/client/fleet-union.ts +5 -5
  245. package/src/runtime/client/hosted-exit.ts +2 -2
  246. package/src/runtime/client/hosted-sessions.ts +1 -1
  247. package/src/runtime/client/spine-adoption.ts +1 -1
  248. package/src/runtime/context-accounting-source.ts +5 -4
  249. package/src/runtime/index.ts +1 -0
  250. package/src/runtime/notification-dispatch.ts +102 -29
  251. package/src/runtime/recovery-offer-wiring.ts +4 -1
  252. package/src/runtime/recovery-prompt.ts +31 -15
  253. package/src/runtime/runtime-services-types.ts +10 -6
  254. package/src/runtime/services.ts +17 -12
  255. package/src/runtime/session-continuity-hints.ts +2 -5
  256. package/src/runtime/session-inbound-inputs.ts +1 -1
  257. package/src/runtime/session-resume-liveness-confirm.ts +14 -2
  258. package/src/runtime/startup-typeahead-gate.ts +103 -0
  259. package/src/runtime/store/domains/domain-read-matrix.ts +0 -1
  260. package/src/runtime/store/domains/index.ts +0 -8
  261. package/src/runtime/store/selectors/index.ts +0 -28
  262. package/src/runtime/store/state.ts +0 -8
  263. package/src/runtime/ui-services.ts +4 -6
  264. package/src/runtime/usage-tracker.ts +348 -0
  265. package/src/runtime/wrfc-persistence.ts +4 -4
  266. package/src/shell/blocking-input.ts +92 -2
  267. package/src/shell/recovery-input-helpers.ts +1 -1
  268. package/src/shell/session-views.ts +539 -0
  269. package/src/shell/status-report.ts +86 -0
  270. package/src/shell/transcript-scroll.ts +68 -0
  271. package/src/shell/ui-openers.ts +84 -172
  272. package/src/shell/view-openers.ts +205 -0
  273. package/src/tools/wrfc-agent-guard.ts +22 -2
  274. package/src/utils/format-duration.ts +4 -8
  275. package/src/utils/splash-lines.ts +9 -1
  276. package/src/utils/terminal-width.ts +56 -0
  277. package/src/verification/verification-ledger.ts +18 -16
  278. package/src/{panels → views}/agent-inspector-shared.ts +2 -2
  279. package/src/{panels → views}/builtin-modals.ts +22 -21
  280. package/src/views/builtin-views.ts +135 -0
  281. package/src/{panels → views}/confirm-state.ts +9 -9
  282. package/src/{panels → views}/diff-review-model.ts +10 -3
  283. package/src/{panels → views}/eval-registry.ts +1 -1
  284. package/src/{panels → views}/fleet-acts.ts +49 -85
  285. package/src/{panels/fleet-panel-format.ts → views/fleet-format.ts} +40 -40
  286. package/src/{panels → views}/fleet-gateway.ts +5 -5
  287. package/src/{panels → views}/fleet-observed-render.ts +16 -16
  288. package/src/{panels → views}/fleet-read-model.ts +9 -9
  289. package/src/{panels/fleet-tabs.ts → views/fleet-session-tabs.ts} +13 -13
  290. package/src/{panels → views}/fleet-spawn.ts +33 -49
  291. package/src/{panels → views}/fleet-steer.ts +12 -12
  292. package/src/{panels → views}/fleet-stop.ts +4 -4
  293. package/src/{panels → views}/fleet-transcript.ts +26 -27
  294. package/src/{panels/fleet-panel-worktree-detail.ts → views/fleet-worktree-detail.ts} +7 -7
  295. package/src/{panels → views}/hosted-session-feed.ts +6 -6
  296. package/src/views/modal-surface-registry.ts +41 -0
  297. package/src/{panels → views}/modals/devices-modal.ts +2 -2
  298. package/src/{panels → views}/modals/hooks-modal.ts +13 -13
  299. package/src/{panels → views}/modals/keybindings-modal.ts +19 -27
  300. package/src/{panels → views}/modals/knowledge-modal.ts +6 -5
  301. package/src/{panels → views}/modals/local-auth-modal.ts +22 -21
  302. package/src/{panels → views}/modals/marketplace-modal.ts +11 -11
  303. package/src/{panels → views}/modals/memory-modal.ts +8 -8
  304. package/src/{panels → views}/modals/modal-surface-helpers.ts +15 -5
  305. package/src/{panels → views}/modals/pairing-modal.ts +9 -9
  306. package/src/{panels → views}/modals/planning-modal.ts +15 -20
  307. package/src/{panels → views}/modals/plugins-modal.ts +6 -6
  308. package/src/{panels → views}/modals/policy-modal.ts +13 -5
  309. package/src/{panels → views}/modals/provider-health-modal.ts +4 -4
  310. package/src/{panels → views}/modals/remote-modal.ts +3 -3
  311. package/src/{panels → views}/modals/sandbox-modal.ts +4 -4
  312. package/src/{panels → views}/modals/security-modal.ts +22 -16
  313. package/src/{panels → views}/modals/services-modal.ts +3 -3
  314. package/src/{panels → views}/modals/settings-sync-modal.ts +4 -4
  315. package/src/{panels → views}/modals/skills-modal.ts +9 -9
  316. package/src/{panels → views}/modals/subscription-modal.ts +3 -3
  317. package/src/{panels → views}/modals/work-plan-modal.ts +10 -13
  318. package/src/views/notifications-feed.ts +314 -0
  319. package/src/{panels → views}/polish-core.ts +38 -36
  320. package/src/{panels → views}/polish-tables.ts +35 -26
  321. package/src/{panels → views}/polish.ts +101 -95
  322. package/src/{panels → views}/project-planning-answer-actions.ts +3 -3
  323. package/src/{panels → views}/provider-health-routes.ts +14 -14
  324. package/src/{panels → views}/search-focus.ts +8 -8
  325. package/src/{panels → views}/session-maintenance.ts +11 -11
  326. package/src/views/skills-discovery.ts +159 -0
  327. package/src/views/view-deps.ts +80 -0
  328. package/src/views/view-panel-adapter.ts +53 -0
  329. package/src/{panels → views}/workstream-graph-render.ts +1 -1
  330. package/src/core/conversation-fold.ts +0 -101
  331. package/src/core/conversation-turn-structure.ts +0 -464
  332. package/src/core/conversation-user-receipts.ts +0 -42
  333. package/src/input/commands/operator-panel-runtime.ts +0 -186
  334. package/src/input/panel-integration-actions.ts +0 -33
  335. package/src/input/panel-mouse-geometry.ts +0 -97
  336. package/src/input/panel-paste-flood-guard.ts +0 -86
  337. package/src/panels/base-panel.ts +0 -301
  338. package/src/panels/builtin/agent.ts +0 -27
  339. package/src/panels/builtin/development.ts +0 -92
  340. package/src/panels/builtin/knowledge.ts +0 -12
  341. package/src/panels/builtin/operations.ts +0 -177
  342. package/src/panels/builtin/session.ts +0 -81
  343. package/src/panels/builtin/shared.ts +0 -357
  344. package/src/panels/builtin-panels.ts +0 -28
  345. package/src/panels/cost-tracker-panel.ts +0 -746
  346. package/src/panels/diff-panel.ts +0 -797
  347. package/src/panels/diff-review-panel.ts +0 -395
  348. package/src/panels/expandable-list-panel.ts +0 -189
  349. package/src/panels/fleet-deep-link.ts +0 -31
  350. package/src/panels/fleet-panel.ts +0 -799
  351. package/src/panels/git-panel.ts +0 -800
  352. package/src/panels/hosted-session-panel.ts +0 -221
  353. package/src/panels/index.ts +0 -21
  354. package/src/panels/local-auth-panel.ts +0 -478
  355. package/src/panels/notifications-feed.ts +0 -127
  356. package/src/panels/notifications-panel.ts +0 -160
  357. package/src/panels/panel-confirm-overlay.ts +0 -72
  358. package/src/panels/panel-manager.ts +0 -791
  359. package/src/panels/plugins-panel.ts +0 -371
  360. package/src/panels/scrollable-list-panel.ts +0 -498
  361. package/src/panels/skills-panel.ts +0 -454
  362. package/src/panels/token-budget-panel.ts +0 -688
  363. package/src/panels/types.ts +0 -191
  364. package/src/panels/wrfc-panel-format.ts +0 -133
  365. package/src/renderer/diff-view.ts +0 -134
  366. package/src/renderer/fleet-tab-strip.ts +0 -56
  367. package/src/renderer/footer-tips.ts +0 -53
  368. package/src/renderer/fullscreen-primitives.ts +0 -146
  369. package/src/renderer/fullscreen-workspace.ts +0 -194
  370. package/src/renderer/hint-grammar.ts +0 -52
  371. package/src/renderer/modal-factory.ts +0 -480
  372. package/src/renderer/overlay-box.ts +0 -154
  373. package/src/renderer/overlay-viewport.ts +0 -104
  374. package/src/renderer/panel-composite.ts +0 -145
  375. package/src/renderer/panel-workspace-bar.ts +0 -54
  376. package/src/renderer/process-indicator.ts +0 -163
  377. package/src/renderer/tab-strip.ts +0 -222
  378. package/src/renderer/text-layout.ts +0 -31
  379. package/src/renderer/tool-call.ts +0 -276
  380. package/src/renderer/tool-result-expanded-lines.ts +0 -48
  381. package/src/renderer/tool-result-summary.ts +0 -219
  382. package/src/runtime/diagnostics/panels/index.ts +0 -21
  383. package/src/runtime/diagnostics/panels/ops.ts +0 -156
  384. package/src/runtime/perf/panel-contracts.ts +0 -32
  385. package/src/runtime/store/domains/panels.ts +0 -117
  386. /package/src/{panels → views}/memory-consolidation-gateway.ts +0 -0
  387. /package/src/{panels → views}/modals/modal-theme.ts +0 -0
  388. /package/src/{panels → views}/provider-health-domains.ts +0 -0
@@ -1,191 +0,0 @@
1
- import type { Line } from '@pellux/goodvibes-sdk/platform/types';
2
- import type { StatusState } from '../renderer/status-glyphs.ts';
3
- import type { ComponentResourceContract, ComponentHealthState } from '../runtime/perf/panel-contracts.ts';
4
- // Routed through the `@/` alias (not `./panel-manager.ts`) so this foundational
5
- // types module stays a leaf in the relative-import graph the architecture
6
- // cycle-checker walks. Type-only, erased at runtime, no real dependency edge.
7
- import type { PanelManager } from '@/panels/panel-manager.ts';
8
-
9
- /**
10
- * Context passed to a panel's `handlePanelIntegrationAction` hook so it can
11
- * drive cross-panel behavior (e.g. file-explorer opening the preview panel)
12
- * without the input layer needing `instanceof` knowledge of each panel type.
13
- */
14
- export interface PanelIntegrationContext {
15
- readonly panelManager: PanelManager;
16
- readonly executeCommand?: (name: string, args: string[]) => Promise<unknown>;
17
- }
18
-
19
- /**
20
- * A cross-panel deep-link target (item 4): a specific node a panel
21
- * should select + reveal when opened via `PanelManager.open(id, pane, target)`,
22
- * e.g. a Fleet tree node keyed by its process id and (optionally) its
23
- * ProcessKind for disambiguation. Panel-agnostic on purpose, only panels that
24
- * have a "node" concept implement `Panel.receiveDeepLink`.
25
- */
26
- export interface PanelDeepLinkTarget {
27
- readonly id: string;
28
- readonly kind?: string;
29
- }
30
-
31
- /**
32
- * Named logical key identifiers emitted by the input tokenizer.
33
- * These are the ONLY key names that will appear in `handleInput` calls;
34
- * the tokenizer never emits DOM/browser-style names like 'ArrowUp' or 'Enter'.
35
- *
36
- * Printable single-character input is passed through as-is; the `string & {}`
37
- * fallback preserves that handling while making named-key completions discoverable
38
- * in editors and keeping non-null single-character values compatible.
39
- */
40
- export type NamedKey =
41
- | 'up' | 'down' | 'left' | 'right'
42
- | 'home' | 'end' | 'pageup' | 'pagedown'
43
- | 'insert' | 'delete' | 'backspace'
44
- | 'enter' | 'return' | 'escape' | 'space' | 'tab'
45
- | 'f1' | 'f2' | 'f3' | 'f4' | 'f5' | 'f6'
46
- | 'f7' | 'f8' | 'f9' | 'f10' | 'f11' | 'f12';
47
-
48
- /**
49
- * The full key type accepted by `Panel.handleInput`.
50
- *
51
- * Named keys (arrow keys, modifiers, function keys) are represented by
52
- * lowercase `NamedKey` members. Single printable characters are passed
53
- * verbatim via the `string & {}` escape hatch so panels can handle 'j', 'k',
54
- * 'r', etc. without losing type safety on the named members.
55
- */
56
- export type KeyName = NamedKey | (string & {});
57
-
58
- /**
59
- * the former single 'monitoring' bucket held 33 panels pre-merge,
60
- * too coarse for the picker to be useful and too large for any one operator
61
- * mental model. Split into named operator domains so each category holds a
62
- * bounded, coherent set (no category may exceed 10 registrations):
63
- * - providers: provider/model connectivity, cost, and token usage
64
- * - security-policy: auth, policy governance, and isolation posture
65
- * - automation-control: hooks, plugins, marketplace, automation jobs, worktrees
66
- * - incidents-diagnostics: failure review, eval gates, API call debugging
67
- * - runtime-ops: live operator consoles (cockpit, tasks, orchestration, comms)
68
- */
69
- export type PanelCategory =
70
- | 'development'
71
- | 'agent'
72
- | 'session'
73
- | 'ai'
74
- | 'providers'
75
- | 'security-policy'
76
- | 'automation-control'
77
- | 'incidents-diagnostics'
78
- | 'runtime-ops';
79
-
80
- export interface Panel {
81
- id: string;
82
- name: string;
83
- icon: string; // single char for tab bar
84
- category: PanelCategory;
85
-
86
- // Lifecycle
87
- onActivate(): void;
88
- onDeactivate(): void;
89
- onDestroy(): void;
90
-
91
- // Rendering
92
- render(width: number, height: number): Line[];
93
-
94
- // State
95
- isTransient: boolean;
96
- isPinned: boolean;
97
- needsRender: boolean;
98
-
99
- // Dirty-flag contract (activated panel render skipping)
100
- /** Mark this panel as needing a re-render on the next frame. */
101
- invalidate(): void;
102
- /** Called by the compositor after a successful render to clear the dirty flag. */
103
- markRendered(): void;
104
-
105
- // Resource contract (optional, panels may declare resource requirements)
106
- resourceContract?: Readonly<ComponentResourceContract>;
107
-
108
- // Health state (optional, set by ComponentHealthMonitor when panel is registered)
109
- healthState?: Readonly<ComponentHealthState>;
110
-
111
- // Input (optional)
112
- handleInput?(key: KeyName): boolean;
113
-
114
- /**
115
- * Optional: report `true` while this panel has an active inline text
116
- * capture (e.g. a `/`-to-filter or search buffer) that deliberately wants
117
- * every character of a burst, paste, or several keystrokes typed fast
118
- * enough to land in one `input.feed()` call, delivered to `handleInput`
119
- * one at a time, same as it always has. When this returns `false` or is
120
- * not implemented, the input router treats a printable burst as never a
121
- * deliberate single-key panel hotkey and routes it to the composer
122
- * instead of exploding it into per-char `handleInput` calls (see
123
- * `handlePanelFocusToken` in `src/input/handler-feed-routes.ts`).
124
- */
125
- isCapturingTextBurst?(): boolean;
126
-
127
- // Scroll input (optional)
128
- // Positive delta scrolls down; negative delta scrolls up.
129
- handleScroll?(deltaRows: number): boolean;
130
-
131
- /**
132
- * Cross-panel integration hook (optional). Called before the panel's own
133
- * `handleInput` when a navigation/confirm key is pressed, so a panel can
134
- * drive another panel (e.g. open a file in the preview panel). Return `true`
135
- * to consume the key. The legacy `handlePanelIntegrationAction` router in
136
- * `src/input/panel-integration-actions.ts` consults this first, then falls
137
- * back to its built-in `instanceof` routing.
138
- */
139
- handlePanelIntegrationAction?(key: string, ctx: PanelIntegrationContext): boolean;
140
-
141
- /**
142
- * Optional: called by the global Ctrl+X (`panel-close`) shortcut BEFORE it
143
- * closes this panel (handler-shortcuts.ts). Return `true` to consume
144
- * Ctrl+X for an in-panel action instead, e.g. FleetPanel (session
145
- * tabs) detaches its active tab and leaves the panel open. Return `false`
146
- * (or omit this hook) to fall through to the ordinary close behavior.
147
- * Ctrl+X never reaches a panel's own `handleInput` (ctrl/meta combos are
148
- * intercepted earlier, see handlePanelFocusToken in
149
- * src/input/handler-feed-routes.ts), so this is the one seam a panel has
150
- * to intervene before the global shortcut acts.
151
- */
152
- interceptPanelClose?(): boolean;
153
-
154
- /**
155
- * Optional: consume a deep-link target handed in by `PanelManager.open(id,
156
- * pane, target)` (item 4), select + reveal the matching node on the
157
- * panel's next snapshot. A panel without a "node" concept simply doesn't
158
- * implement this (the call is a no-op via optional chaining in
159
- * PanelManager). A panel that DOES implement it owns its own honest
160
- * "not found" surface (e.g. FleetPanel.setError) when the target no longer
161
- * resolves, PanelManager has no transcript/print seam to report on its
162
- * behalf.
163
- */
164
- receiveDeepLink?(target: PanelDeepLinkTarget): void;
165
- }
166
-
167
- export interface PanelRegistration extends Pick<Panel, 'id' | 'name' | 'icon' | 'category'> {
168
- factory: () => Panel;
169
- description: string;
170
- /**
171
- * lifecycle flags. `preload` and `retainOnClose` are independent,
172
- * a panel can eagerly instantiate without being kept alive on close, or be
173
- * kept alive on close without eager bootstrap instantiation. They happened
174
- * to be identical for all builtin panels before this split (both driven by
175
- * a single `preload: true`); that existing 10-panel retained set is
176
- * preserved unchanged by giving each of those 10 registrations both flags.
177
- *
178
- * - `preload`, instantiate this panel during `PanelManager.prewarmRegistered()`
179
- * (called once at bootstrap) so its factory runs and it starts
180
- * accumulating background data (subscriptions, timers) before the user
181
- * ever opens the workspace. Panels without `preload` are instantiated
182
- * lazily on first `open()`.
183
- * - `retainOnClose`, when this panel is closed, keep the live instance in
184
- * `PanelManager`'s retained-panel map (background subscriptions/timers
185
- * keep running) instead of calling `onDestroy()`. Reopening returns the
186
- * same instance with its accumulated state intact. Panels without
187
- * `retainOnClose` are destroyed on close and rebuilt fresh next open.
188
- */
189
- preload?: boolean;
190
- retainOnClose?: boolean;
191
- }
@@ -1,133 +0,0 @@
1
- import { truncateDisplay } from '../utils/terminal-width.ts';
2
- import type { WrfcState, Constraint, ConstraintFinding } from '@pellux/goodvibes-sdk/platform/agents';
3
- import { DEFAULT_PANEL_PALETTE, extendPalette } from './polish.ts';
4
-
5
- // ---------------------------------------------------------------------------
6
- // Colour palette + formatting helpers for the WRFC panel.
7
- //
8
- // Extracted from wrfc-panel.ts to keep that module under the architecture
9
- // line-count cap. Leaf module (only polish + terminal-width + sdk types); the
10
- // panel re-exports the public helpers so ./wrfc-panel.ts stays their import site.
11
- // ---------------------------------------------------------------------------
12
- export const C = extendPalette(DEFAULT_PANEL_PALETTE, {
13
- // WRFC state-machine colours (domain status -- no shared equivalent)
14
- passed: '#22c55e', // green
15
- failed: '#ef4444', // red
16
- reviewing: '#eab308', // yellow
17
- engineering:'#22d3ee', // cyan
18
- fixing: '#f97316', // orange
19
- pending: '#6b7280', // grey
20
- gating: '#a78bfa', // violet
21
- committing: '#38bdf8', // sky
22
- integrating:'#818cf8', // indigo
23
-
24
- // Issue-severity ramp (domain -- no shared equivalent)
25
- issueCrit: '#ef4444',
26
- issueMaj: '#f97316',
27
- issueMin: '#eab308',
28
- issueSug: '#6b7280',
29
-
30
- // Selection + divider chrome with no shared equivalent
31
- selected: '#1e40af', // selection bg
32
- selectedFg: '#f8fafc',
33
- border: '#334155',
34
- });
35
-
36
- // ---------------------------------------------------------------------------
37
- // Helpers
38
- // ---------------------------------------------------------------------------
39
- const SPARKLINE_CHARS = '._-:=+*#';
40
-
41
- export function sparkline(scores: number[], maxScore = 10): string {
42
- if (scores.length === 0) return '';
43
- return scores
44
- .map(s => {
45
- const ratio = Math.max(0, Math.min(1, s / maxScore));
46
- const idx = Math.round(ratio * (SPARKLINE_CHARS.length - 1));
47
- return SPARKLINE_CHARS[idx];
48
- })
49
- .join('');
50
- }
51
-
52
- export function stateColor(state: WrfcState): string {
53
- switch (state) {
54
- case 'passed': return C.passed;
55
- case 'failed': return C.failed;
56
- case 'reviewing': return C.reviewing;
57
- case 'engineering': return C.engineering;
58
- case 'fixing': return C.fixing;
59
- case 'gating':
60
- case 'awaiting_gates': return C.gating;
61
- case 'committing': return C.committing;
62
- case 'integrating': return C.integrating;
63
- default: return C.pending;
64
- }
65
- }
66
-
67
- export function stateLabel(state: WrfcState): string {
68
- switch (state) {
69
- case 'engineering': return 'ENG';
70
- case 'reviewing': return 'REV';
71
- case 'fixing': return 'FIX';
72
- case 'gating': return 'GATE';
73
- case 'awaiting_gates': return 'WAIT';
74
- case 'committing': return 'COMMIT';
75
- case 'integrating': return 'INTG';
76
- case 'passed': return 'PASS';
77
- case 'failed': return 'FAIL';
78
- default: return 'PEND';
79
- }
80
- }
81
-
82
- export function issueColor(severity: string): string {
83
- switch (severity) {
84
- case 'critical': return C.issueCrit;
85
- case 'major': return C.issueMaj;
86
- case 'minor': return C.issueMin;
87
- default: return C.issueSug;
88
- }
89
- }
90
-
91
- export function issuePrefix(severity: string): string {
92
- switch (severity) {
93
- case 'critical': return '[CRIT] ';
94
- case 'major': return '[MAJR] ';
95
- case 'minor': return '[MINR] ';
96
- default: return '[SUGG] ';
97
- }
98
- }
99
-
100
- export function truncate(s: string, max: number): string {
101
- return truncateDisplay(s, max);
102
- }
103
-
104
- // ---------------------------------------------------------------------------
105
- // Constraint helpers
106
- // ---------------------------------------------------------------------------
107
-
108
- /**
109
- * Returns display tag, foreground colour, and dim flag for a single constraint
110
- * based on whether a reviewer finding exists for it.
111
- */
112
- export function constraintStatusMarker(
113
- constraint: Constraint,
114
- findings: ConstraintFinding[] | undefined,
115
- ): { tag: string; fg: string; dim: boolean } {
116
- const finding = findings?.find(f => f.constraintId === constraint.id);
117
- if (!finding) {
118
- return { tag: '[UNV]', fg: C.dim, dim: true };
119
- }
120
- if (finding.satisfied) {
121
- return { tag: '[SAT]', fg: C.good, dim: false };
122
- }
123
- // Unsatisfied, use severity to pick colour and tag text
124
- const sev = finding.severity ?? 'major';
125
- let sevTag: string;
126
- let fg: string;
127
- switch (sev) {
128
- case 'critical': sevTag = '[UNS CRIT]'; fg = C.issueCrit; break;
129
- case 'minor': sevTag = '[UNS MINOR]'; fg = C.issueMin; break;
130
- default: sevTag = '[UNS MAJOR]'; fg = C.issueMaj; break;
131
- }
132
- return { tag: sevTag, fg, dim: false };
133
- }
@@ -1,134 +0,0 @@
1
- import { type Line, type Cell, createStyledCell } from '@pellux/goodvibes-sdk/platform/types';
2
- import { UIFactory } from './ui-factory.ts';
3
- import { getDisplayWidth, padDisplayEnd } from '../utils/terminal-width.ts';
4
- import { DIFF_TONES } from './ui-primitives.ts';
5
-
6
- /**
7
- * renderDiffView - Render a unified diff string as styled Line[].
8
- * '+' lines in green, '-' lines in red, '@@' hunks in blue (DIFF_TONES.hunk,
9
- * shared with diff-panel.ts and git-panel.ts's inline diff).
10
- */
11
- export function renderDiffView(diffText: string, width: number, filename?: string): Line[] {
12
- const lines: Line[] = [];
13
- const BG = '#0a0a0a';
14
-
15
- // Filename header
16
- if (filename) {
17
- const header = ` ≡ ${filename} `;
18
- lines.push(UIFactory.stringToLine(padDisplayEnd(header, width), width, { fg: '#1a1a1a', bg: '#569cd6', bold: true }));
19
- }
20
-
21
- const diffLines = diffText.split('\n');
22
- let oldLineNo = 0;
23
- let newLineNo = 0;
24
-
25
- for (const raw of diffLines) {
26
- if (raw === '') {
27
- const emptyLine = makeFilledLine(width, BG);
28
- lines.push(emptyLine);
29
- continue;
30
- }
31
-
32
- // Hunk header: @@ -old,count +new,count @@
33
- if (raw.startsWith('@@')) {
34
- const hunkMatch = raw.match(/@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
35
- if (hunkMatch) {
36
- oldLineNo = parseInt(hunkMatch[1], 10) - 1;
37
- newLineNo = parseInt(hunkMatch[2], 10) - 1;
38
- }
39
- lines.push(makeStyledLine(raw, width, DIFF_TONES.hunk, '#0f1f1f', false));
40
- continue;
41
- }
42
-
43
- // File headers: --- and +++
44
- if (raw.startsWith('--- ') || raw.startsWith('+++ ')) {
45
- lines.push(makeStyledLine(raw, width, '244', BG, false));
46
- continue;
47
- }
48
-
49
- // Added line
50
- if (raw.startsWith('+')) {
51
- newLineNo++;
52
- const lineLabel = `${String(newLineNo).padStart(4)} `;
53
- const content = raw.slice(1);
54
- lines.push(makeGutterLine('+', lineLabel, content, width, DIFF_TONES.add, '#0a1a0a'));
55
- continue;
56
- }
57
-
58
- // Removed line
59
- if (raw.startsWith('-')) {
60
- oldLineNo++;
61
- const lineLabel = `${String(oldLineNo).padStart(4)} `;
62
- const content = raw.slice(1);
63
- lines.push(makeGutterLine('-', lineLabel, content, width, DIFF_TONES.del, '#1a0a0a'));
64
- continue;
65
- }
66
-
67
- // Context line
68
- if (raw.startsWith(' ') || (!raw.startsWith('\\') && raw.length > 0)) {
69
- oldLineNo++;
70
- newLineNo++;
71
- const lineLabel = `${String(oldLineNo).padStart(4)} `;
72
- const content = raw.startsWith(' ') ? raw.slice(1) : raw;
73
- lines.push(makeGutterLine(' ', lineLabel, content, width, '244', BG));
74
- }
75
- }
76
-
77
- return lines;
78
- }
79
-
80
- /** Build a line with gutter indicator, line number, and content. */
81
- function makeGutterLine(
82
- gutter: string,
83
- lineLabel: string,
84
- content: string,
85
- width: number,
86
- fg: string,
87
- bg: string
88
- ): Line {
89
- const line = makeFilledLine(width, bg);
90
- let cx = 0;
91
-
92
- // Gutter char
93
- line[cx++] = createStyledCell(gutter, { fg, bg, bold: gutter !== ' ' });
94
-
95
- // Line number
96
- for (const ch of lineLabel) {
97
- if (cx >= width) break;
98
- line[cx++] = createStyledCell(ch, { fg: '238', bg, dim: true });
99
- }
100
-
101
- // Content
102
- for (const ch of content) {
103
- if (cx >= width) break;
104
- const cw = getDisplayWidth(ch);
105
- const code = ch.charCodeAt(0);
106
- if (code < 32) { cx++; continue; }
107
- line[cx] = createStyledCell(ch, { fg, bg });
108
- if (cw === 2 && cx + 1 < width) line[cx + 1] = { ...line[cx], char: '' };
109
- cx += cw;
110
- }
111
-
112
- return line;
113
- }
114
-
115
- /** Build a simple styled line from text. */
116
- function makeStyledLine(text: string, width: number, fg: string, bg: string, bold: boolean): Line {
117
- const line = makeFilledLine(width, bg);
118
- let cx = 0;
119
- for (const ch of text) {
120
- if (cx >= width) break;
121
- const cw = getDisplayWidth(ch);
122
- const code = ch.charCodeAt(0);
123
- if (code < 32) { cx++; continue; }
124
- line[cx] = createStyledCell(ch, { fg, bg, bold });
125
- if (cw === 2 && cx + 1 < width) line[cx + 1] = { ...line[cx], char: '' };
126
- cx += cw;
127
- }
128
- return line;
129
- }
130
-
131
- /** Create a line filled with bg color. */
132
- function makeFilledLine(width: number, bg: string): Cell[] {
133
- return Array.from({ length: width }, () => createStyledCell(' ', { bg }));
134
- }
@@ -1,56 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // fleet-tab-strip.ts
3
- //
4
- // Renders FleetPanel's session-tab strip by reusing
5
- // renderTabStrip exactly as panel-workspace-bar.ts does for the workspace
6
- // tab bar. Deliberately a SEPARATE, visually distinct strip from the
7
- // workspace bar: workspace tabs switch PANELS, fleet session tabs switch
8
- // ATTACHED PROCESSES within one panel, conflating their styling would blur
9
- // that distinction for the operator.
10
- // ---------------------------------------------------------------------------
11
-
12
- import type { Line } from '@pellux/goodvibes-sdk/platform/types';
13
- import type { FleetTabsState } from '../panels/fleet-tabs.ts';
14
- import { renderTabStrip, type TabHitRegion } from './tab-strip.ts';
15
- import { UI_TONES } from './ui-primitives.ts';
16
-
17
- const ACTIVE_FG = UI_TONES.fg.primary;
18
- const ACTIVE_BG = UI_TONES.bg.selected;
19
- const INACTIVE_FG = UI_TONES.fg.muted;
20
- const SEPARATOR_FG = UI_TONES.fg.dim;
21
- const LABEL_FG = UI_TONES.fg.secondary;
22
-
23
- /**
24
- * Render the fleet session-tab strip, or `null` when there are no attached
25
- * tabs, the panel omits the strip entirely in that case (root-tab-only),
26
- * which is what keeps the pre-session-tab fleet-panel goldens byte-identical.
27
- */
28
- export function renderFleetTabStrip(
29
- state: FleetTabsState,
30
- width: number,
31
- onLayout?: (regions: readonly TabHitRegion[]) => void,
32
- ): Line | null {
33
- if (state.tabs.length === 0) return null;
34
- return renderTabStrip({
35
- width,
36
- onLayout,
37
- tabs: [
38
- { label: 'Tree', active: state.activeTabIndex === 0 },
39
- ...state.tabs.map((tab, index) => ({
40
- label: tab.label,
41
- active: state.activeTabIndex === index + 1,
42
- })),
43
- ],
44
- prefixLabel: ' SESSIONS ',
45
- style: {
46
- activeFg: ACTIVE_FG,
47
- activeBg: ACTIVE_BG,
48
- activeBold: true,
49
- inactiveFg: INACTIVE_FG,
50
- separatorFg: SEPARATOR_FG,
51
- labelFg: LABEL_FG,
52
- overflowFg: SEPARATOR_FG,
53
- trailingFg: INACTIVE_FG,
54
- },
55
- });
56
- }
@@ -1,53 +0,0 @@
1
- /**
2
- * footer-tips.ts, the persistent discoverability hint shown in the shell
3
- * footer's tip slot.
4
- *
5
- * instead of a single frozen "/help for commands" line, the footer
6
- * surfaces a rotating set of the highest-value affordances (panels, process
7
- * monitor, help, quit). Rotation is *contextual, not timed*: when an agent turn
8
- * is actively running, the process-monitor tip is promoted to the front so the
9
- * operator can jump to F2 while work is in flight. Selection is a pure function
10
- * of context so the footer renders deterministically (golden frames stay
11
- * stable), no wall-clock input.
12
- */
13
-
14
- export interface FooterTipContext {
15
- /** True while an agent turn is actively running (streaming / tools / hooks). */
16
- readonly agentActive: boolean;
17
- }
18
-
19
- /** Composer status labels that mean an agent turn is actively in flight. */
20
- const ACTIVE_TURN_STATUSES = new Set(['preflight', 'streaming', 'tools', 'post-hooks']);
21
-
22
- /** Derive agent-active state from the composer status label passed to the footer. */
23
- export function isAgentActive(composerStatus: string | undefined): boolean {
24
- return composerStatus !== undefined && ACTIVE_TURN_STATUSES.has(composerStatus);
25
- }
26
-
27
- // Ctrl+P is a TOGGLE (open+focus when nothing is open or unfocused,
28
- // hide when the workspace already has focus, see openPanelPicker in
29
- // shell/ui-openers.ts). The bare noun 'panels' undersold that; naming the verb
30
- // keeps the tip honest about what the chord actually does.
31
- const TIP_PANELS = 'Ctrl+P toggle panels';
32
- // F2 now opens the Fleet panel (the process modal was retired), so the
33
- // tip names 'fleet', not 'processes'.
34
- const TIP_PROCESSES = 'F2 fleet';
35
- const TIP_HELP = '? help';
36
- // f: an empty-composer Ctrl+C does NOT quit on the first press, it arms a
37
- // ~1s "press again to exit" confirm, and only a SECOND Ctrl+C within that window
38
- // exits (an intentional accidental-exit guard). The old 'Ctrl+C quit' tip
39
- // implied a single press quits, so two presses seconds apart appeared to do
40
- // nothing. 'Ctrl+C x2 quit' matches the real double-press contract (and the
41
- // help overlay's "Ctrl+C x2 Exit" row).
42
- const TIP_QUIT = 'Ctrl+C x2 quit';
43
-
44
- /**
45
- * Build the footer discoverability tip. Segments join with the shared middle
46
- * dot. Agent-active state promotes the process-monitor tip to the front.
47
- */
48
- export function buildFooterTip(ctx: FooterTipContext): string {
49
- const lead = ctx.agentActive
50
- ? [TIP_PROCESSES, TIP_PANELS, TIP_HELP]
51
- : [TIP_PANELS, TIP_PROCESSES, TIP_HELP];
52
- return [...lead, TIP_QUIT].join(' · ');
53
- }