@pellux/goodvibes-tui 2.0.21 → 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 +58 -0
  2. package/README.md +16 -16
  3. package/docs/README.md +4 -4
  4. package/docs/foundation-artifacts/operator-contract.json +1 -1
  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,31 +0,0 @@
1
- import { getDisplayWidth, truncateDisplay, wrapText } from '../utils/terminal-width.ts';
2
-
3
- export function wrapWithHangingIndent(
4
- text: string,
5
- width: number,
6
- indent: string,
7
- maxLines?: number,
8
- ): string[] {
9
- const safeWidth = Math.max(1, width);
10
- const indentWidth = getDisplayWidth(indent);
11
- const wrapped = wrapText(text, safeWidth);
12
- const lines = wrapped.map((line, index) => {
13
- if (index === 0) return truncateDisplay(line, safeWidth);
14
- return `${indent}${truncateDisplay(line, Math.max(1, safeWidth - indentWidth))}`;
15
- });
16
- return typeof maxLines === 'number' ? lines.slice(0, maxLines) : lines;
17
- }
18
-
19
- export function fitLabelDetailColumns(
20
- label: string,
21
- detail: string,
22
- totalWidth: number,
23
- labelRatio = 0.55,
24
- ): { labelWidth: number; detailWidth: number } {
25
- const safeWidth = Math.max(8, totalWidth);
26
- const labelWidth = Math.max(10, Math.min(safeWidth - 2, Math.floor(safeWidth * labelRatio)));
27
- return {
28
- labelWidth,
29
- detailWidth: Math.max(0, safeWidth - labelWidth - 2),
30
- };
31
- }
@@ -1,276 +0,0 @@
1
- import { type Line, createStyledCell, createEmptyLine } from '@pellux/goodvibes-sdk/platform/types';
2
- import { LAYOUT, TOOL_STATUS } from './layout.ts';
3
- import { getDisplayWidth, truncateDisplay } from '../utils/terminal-width.ts';
4
- import type { ToolCall } from '@pellux/goodvibes-sdk/platform/types';
5
- import { stripDangerousAnsi } from './ansi-sanitize.ts';
6
- import { formatElapsed } from '../utils/format-elapsed.ts';
7
- import { GLYPHS } from './ui-primitives.ts';
8
- import { activeUiTones } from './theme.ts';
9
- import { treeContentCol, treeTextCol, writeTreeStatusMarker } from '@pellux/goodvibes-terminal-shell';
10
-
11
- const TOOL_NAME_MIN_WIDTH = 8;
12
- const TOOL_NAME_MAX_WIDTH = 20;
13
-
14
- /** Tree placement for a tool-call row rendered as a branch of its turn. */
15
- export interface ToolCallTreeOptions {
16
- /** Effective indent in columns, already clamped by treeIndentCols(). */
17
- readonly indentCols?: number;
18
- readonly branchFg?: string;
19
- /** Suppress the tool label because the turn header already carries it. */
20
- readonly omitToolName?: boolean;
21
- }
22
-
23
- function writeStyledText(
24
- line: Line,
25
- startCol: number,
26
- endColExclusive: number,
27
- text: string,
28
- style: { readonly fg: string; readonly bold?: boolean; readonly dim?: boolean },
29
- ): number {
30
- let col = startCol;
31
- for (const ch of text) {
32
- const width = getDisplayWidth(ch);
33
- if (width <= 0) continue;
34
- if (col + width > endColExclusive) break;
35
- line[col] = createStyledCell(ch, {
36
- fg: style.fg,
37
- bold: style.bold ?? false,
38
- dim: style.dim ?? false,
39
- });
40
- if (width > 1 && col + 1 < endColExclusive) {
41
- line[col + 1] = createStyledCell('', {
42
- fg: style.fg,
43
- bold: style.bold ?? false,
44
- dim: style.dim ?? false,
45
- });
46
- }
47
- col += width;
48
- }
49
- return col;
50
- }
51
-
52
- function buildLeftSegments(
53
- toolName: string,
54
- keyArg: string,
55
- suffixText: string,
56
- leftBudget: number,
57
- omitToolName = false,
58
- ): Array<{ text: string; fg: string; bold?: boolean; dim?: boolean }> {
59
- if (leftBudget <= 0) return [];
60
-
61
- // When every call in the turn shares one label, the label rides on the turn
62
- // header and each row leads with the argument that actually distinguishes it
63
- // (`config.get`, `services.restart`). Falls back to showing the name when
64
- // there is no key argument, so a row can never render empty.
65
- if (omitToolName && keyArg) {
66
- return buildLeftSegments(keyArg, '', suffixText, leftBudget, false);
67
- }
68
-
69
- const t = activeUiTones();
70
- const segments: Array<{ text: string; fg: string; bold?: boolean; dim?: boolean }> = [];
71
- const suffixBudget = suffixText ? Math.min(Math.max(12, Math.floor(leftBudget * 0.3)), 20) : 0;
72
- const suffixDisplay = suffixBudget > 0 ? truncateDisplay(suffixText, suffixBudget) : '';
73
- const suffixWidth = getDisplayWidth(suffixDisplay);
74
- const separatorBeforeSuffix = suffixDisplay ? 2 : 0;
75
- const mainBudget = Math.max(1, leftBudget - suffixWidth - separatorBeforeSuffix);
76
-
77
- let toolNameDisplay = '';
78
- let keyArgDisplay = '';
79
- if (keyArg) {
80
- const rawToolWidth = getDisplayWidth(toolName);
81
- const preferredToolWidth = Math.min(
82
- Math.max(rawToolWidth, TOOL_NAME_MIN_WIDTH),
83
- TOOL_NAME_MAX_WIDTH,
84
- Math.max(TOOL_NAME_MIN_WIDTH, Math.floor(mainBudget * 0.4)),
85
- );
86
- const toolNameWidth = Math.min(preferredToolWidth, Math.max(1, mainBudget - 3));
87
- const keyArgWidth = Math.max(0, mainBudget - toolNameWidth - 2);
88
- toolNameDisplay = truncateDisplay(toolName, toolNameWidth);
89
- keyArgDisplay = truncateDisplay(keyArg, keyArgWidth);
90
- } else {
91
- toolNameDisplay = truncateDisplay(toolName, mainBudget);
92
- }
93
-
94
- if (toolNameDisplay) {
95
- segments.push({ text: toolNameDisplay, fg: '#00ffcc', bold: true });
96
- }
97
- if (keyArgDisplay) {
98
- segments.push({ text: ' ', fg: t.fg.primary });
99
- segments.push({ text: keyArgDisplay, fg: '252' });
100
- }
101
- if (suffixDisplay) {
102
- segments.push({ text: ' ', fg: t.fg.primary });
103
- segments.push({
104
- text: suffixDisplay,
105
- fg: suffixText.startsWith('- ') ? t.chrome.bad : '244',
106
- dim: true,
107
- });
108
- }
109
- return segments;
110
- }
111
-
112
- /**
113
- * Extract the most meaningful argument from a tool call for display.
114
- */
115
- function extractKeyArg(toolCall: ToolCall): string {
116
- const args = toolCall.arguments;
117
- // Path-based tools
118
- if (typeof args.path === 'string') return args.path;
119
- if (typeof args.file === 'string') return args.file;
120
- if (typeof args.query === 'string') return args.query;
121
- if (typeof args.title === 'string') return args.title;
122
- // Array-based (read/write)
123
- if (Array.isArray(args.files) && args.files.length > 0) {
124
- const first = args.files[0];
125
- if (typeof first === 'string') return first;
126
- if (first && typeof first === 'object' && typeof (first as Record<string, unknown>).path === 'string')
127
- return (first as Record<string, unknown>).path as string;
128
- }
129
- // Exec
130
- if (typeof args.command === 'string') return args.command;
131
- if (typeof args.cmd === 'string') return args.cmd;
132
- if (Array.isArray(args.commands) && args.commands.length > 0) {
133
- const first = args.commands[0];
134
- if (first && typeof first === 'object' && typeof (first as Record<string, unknown>).cmd === 'string')
135
- return (first as Record<string, unknown>).cmd as string;
136
- }
137
- // Find/grep
138
- if (typeof args.pattern === 'string') return args.pattern;
139
- if (Array.isArray(args.queries) && args.queries.length > 0) {
140
- const first = args.queries[0];
141
- if (first && typeof first === 'object') {
142
- const firstRecord = first as Record<string, unknown>;
143
- if (typeof firstRecord.query === 'string') return firstRecord.query;
144
- if (typeof firstRecord.pattern === 'string') return firstRecord.pattern;
145
- }
146
- }
147
- // Fetch
148
- if (Array.isArray(args.urls) && args.urls.length > 0) {
149
- const first = args.urls[0];
150
- if (first && typeof first === 'object' && typeof (first as Record<string, unknown>).url === 'string')
151
- return (first as Record<string, unknown>).url as string;
152
- }
153
- // Agent
154
- if (typeof args.task === 'string') return args.task.slice(0, 40);
155
- if (typeof args.mode === 'string') return args.mode;
156
- // Fallback: first string value
157
- for (const val of Object.values(args)) {
158
- if (typeof val === 'string' && val.length > 0) return val.slice(0, 40);
159
- }
160
- return '';
161
- }
162
-
163
- /**
164
- * Render a tool call as a single collapsed line.
165
- *
166
- * Layout: [margin] [icon] [space] [tool name padded] [key arg] [summary] [duration]
167
- *
168
- * @param toolCall - The tool call being executed
169
- * @param status - 'executing' | 'done' | 'error' | 'pending' | 'cancelled'
170
- * @param resultSummary - Optional brief summary (e.g., "3 files", "exit 0")
171
- * @param width - Terminal width
172
- * @param durationMs - Optional duration in milliseconds
173
- * @param errorMsg - Optional error message for failed calls
174
- * @param frameIndex - Spinner frame index for animated icon
175
- * @param startedAtMs - Wall-clock ms when execution started; enables live elapsed timer
176
- */
177
- export function renderToolCallBlock(
178
- toolCall: ToolCall,
179
- status: 'executing' | 'done' | 'error' | 'pending' | 'cancelled',
180
- resultSummary: string | undefined,
181
- width: number,
182
- durationMs?: number,
183
- errorMsg?: string,
184
- frameIndex?: number,
185
- startedAtMs?: number,
186
- tree?: ToolCallTreeOptions,
187
- ): Line[] {
188
- const line = createEmptyLine(width);
189
- const t = activeUiTones();
190
- const indent = Math.max(0, tree?.indentCols ?? 0);
191
- const inTree = indent > 0;
192
- // In tree mode the row's columns come from the shared grid: the branch glyph
193
- // where the parent's content began, the status marker in the bullet column,
194
- // and the row's text at this depth's text column.
195
- const margin = inTree ? treeContentCol(indent) : LAYOUT.LEFT_MARGIN;
196
- const rightMargin = LAYOUT.RIGHT_MARGIN;
197
- const contentEnd = width - rightMargin;
198
-
199
-
200
- // Status icon. 'pending' means the tool is still awaiting a decision
201
- // (e.g. an approval prompt) and has NOT run yet, it uses the hollow idle
202
- // glyph so a not-yet-run tool never shows the completed green ✓ (2c).
203
- // 'cancelled' means the user stopped THIS call mid-flight, the blocked glyph
204
- // in the warn tone, distinct from both success and a real error.
205
- const icon = status === 'done' ? TOOL_STATUS.SUCCESS_ICON
206
- : status === 'error' ? TOOL_STATUS.FAIL_ICON
207
- : status === 'cancelled' ? GLYPHS.status.blocked
208
- : status === 'pending' ? GLYPHS.status.idle
209
- : TOOL_STATUS.SPINNER_FRAMES[(frameIndex ?? 0) % TOOL_STATUS.SPINNER_FRAMES.length];
210
- const iconColor = status === 'done' ? t.chrome.good
211
- : status === 'error' ? t.chrome.bad
212
- : status === 'cancelled' ? t.chrome.warn
213
- : '244';
214
- const rightText = (() => {
215
- if (durationMs !== undefined && status === 'done') {
216
- return formatElapsed(durationMs);
217
- }
218
- if (status === 'executing') {
219
- if (startedAtMs !== undefined) {
220
- return formatElapsed(Date.now() - startedAtMs);
221
- }
222
- return '...';
223
- }
224
- return '';
225
- })();
226
- const rightWidth = getDisplayWidth(rightText);
227
- const rightStart = rightText
228
- ? Math.max(margin + 2, contentEnd - rightWidth)
229
- : contentEnd;
230
- const leftStart = inTree ? treeTextCol(indent) : margin;
231
- const leftEndExclusive = rightText
232
- ? Math.max(leftStart, rightStart - 1)
233
- : contentEnd;
234
- let col: number = leftStart;
235
-
236
- // In tree mode the status glyph goes in the bullet column, the same column
237
- // as the `●` of the `● assistant` header this row hangs under, so a turn's
238
- // markers read as that bullet's column continuing down the turn. The row's
239
- // own text then starts at its depth's text column with no inline icon slot.
240
- if (inTree) {
241
- writeTreeStatusMarker(line, icon, iconColor, width);
242
- } else {
243
- if (col < leftEndExclusive) {
244
- line[col] = createStyledCell(icon, { fg: iconColor, bold: status === 'done' || status === 'error' || status === 'cancelled' });
245
- }
246
- col += 2; // icon + space
247
- }
248
-
249
- // Tool name, extract short name for long MCP tool names, but keep a readable dynamic width.
250
- const rawName = toolCall.name.includes('__')
251
- ? toolCall.name.split('__').pop()!
252
- : toolCall.name;
253
- const keyArg = stripDangerousAnsi(extractKeyArg(toolCall));
254
- const suffixText = status === 'error' && errorMsg
255
- ? `- ${stripDangerousAnsi(errorMsg).slice(0, 40)}`
256
- : status === 'cancelled'
257
- ? '- cancelled'
258
- : status === 'done' && resultSummary
259
- ? `(${stripDangerousAnsi(resultSummary)})`
260
- : '';
261
- const leftBudget = Math.max(0, leftEndExclusive - col);
262
- const leftSegments = buildLeftSegments(rawName, keyArg, suffixText, leftBudget, tree?.omitToolName ?? false);
263
- for (const segment of leftSegments) {
264
- col = writeStyledText(line, col, leftEndExclusive, segment.text, {
265
- fg: segment.fg,
266
- bold: segment.bold ?? false,
267
- dim: segment.dim ?? false,
268
- });
269
- }
270
-
271
- if (rightText) {
272
- writeStyledText(line, rightStart, contentEnd, rightText, { fg: '238', dim: true });
273
- }
274
-
275
- return [line];
276
- }
@@ -1,48 +0,0 @@
1
- /**
2
- * tool-result-expanded-lines.ts, the single source of truth for how many
3
- * screen lines a tool-result message's EXPANDED form actually renders to.
4
- *
5
- * Tool-result content gets pretty-printed (JSON.stringify(parsed, null, 2))
6
- * or diff-rendered before display, so the raw message's `content.split('\n')`
7
- * length is not what the user sees once expanded, a one-line JSON blob can
8
- * pretty-print to 50 lines. Both the per-block "N lines" badge
9
- * (conversation-rendering.ts) and the folded-group total (conversation-tool-
10
- * groups.ts) must count the SAME post-render lines, or the two disagree with
11
- * each other and both can disagree with what Tab actually reveals.
12
- */
13
-
14
- import type { Line } from '@pellux/goodvibes-sdk/platform/types';
15
- import { renderMarkdownTracked } from './markdown.ts';
16
- import { renderDiffView } from './diff-view.ts';
17
-
18
- /** True when `content` looks like a unified diff (matches the detection used
19
- * by renderConversationToolMessage to pick the diff block type). */
20
- export function isDiffContent(content: string): boolean {
21
- const contentLines = content.split('\n');
22
- const hasDiffHeader = contentLines.some((l) => l.startsWith('--- ')) && contentLines.some((l) => l.startsWith('+++ '));
23
- const hasHunk = contentLines.some((l) => l.startsWith('@@ '));
24
- return hasDiffHeader && hasHunk;
25
- }
26
-
27
- /**
28
- * Render a tool result's content exactly as its EXPANDED form would appear in
29
- * the transcript (diff view for diffs; pretty-printed JSON, when parseable,
30
- * for everything else). The caller decides whether to actually display these
31
- * lines or just count them.
32
- */
33
- export function renderExpandedToolResultLines(content: string, width: number): Line[] {
34
- if (isDiffContent(content)) {
35
- return renderDiffView(content, width);
36
- }
37
- let contentToRender = content;
38
- const trimmed = contentToRender.trimStart();
39
- if ((trimmed.startsWith('{') || trimmed.startsWith('[')) && contentToRender.length < 100_000) {
40
- try {
41
- const parsed = JSON.parse(contentToRender);
42
- contentToRender = `\`\`\`json\n${JSON.stringify(parsed, null, 2)}\n\`\`\``;
43
- } catch {
44
- // Leave invalid JSON as-is, falls through to the plain markdown render below.
45
- }
46
- }
47
- return renderMarkdownTracked(contentToRender, width).lines;
48
- }
@@ -1,219 +0,0 @@
1
- /**
2
- * summarizeToolResult, one-line human summaries for tool RESULTS, so the
3
- * transcript (and the fleet attach view, which shares the same rendering seam
4
- * in conversation-rendering.ts) shows "wrote haiku.txt (532 B)" instead of a
5
- * raw `{"files_written":1,"bytes_written":532,...}` JSON blob. The full payload
6
- * stays reachable behind the existing collapse/expand toggle, this only
7
- * changes the collapsed preview line, never destroys data. (item 3.)
8
- *
9
- * Returning `null` means "no honest summary for this shape", the caller then
10
- * falls back to the previous raw-first-line preview, so an unrecognised tool or
11
- * an unexpected payload is never mis-summarised.
12
- */
13
-
14
- /** Compact byte count: "87 B", "1.2 KB", "3.4 MB". */
15
- function formatBytes(n: number): string {
16
- if (!Number.isFinite(n) || n < 0) return '? B';
17
- if (n < 1024) return `${n} B`;
18
- if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
19
- return `${(n / (1024 * 1024)).toFixed(1)} MB`;
20
- }
21
-
22
- /** Compact duration: "820ms", "1.2s", "1m3s". */
23
- function formatDuration(ms: number): string {
24
- if (!Number.isFinite(ms) || ms < 0) return '?';
25
- if (ms < 1000) return `${Math.round(ms)}ms`;
26
- if (ms < 60_000) return `${(ms / 1000).toFixed(1)}s`;
27
- const s = Math.round(ms / 1000);
28
- return `${Math.floor(s / 60)}m${s % 60}s`;
29
- }
30
-
31
- /** Trailing filename for compact display (paths can be long/absolute). */
32
- function baseName(p: string): string {
33
- const cleaned = p.replace(/[/\\]+$/, '');
34
- const idx = Math.max(cleaned.lastIndexOf('/'), cleaned.lastIndexOf('\\'));
35
- return idx >= 0 ? cleaned.slice(idx + 1) : cleaned;
36
- }
37
-
38
- function asNumber(v: unknown): number | undefined {
39
- return typeof v === 'number' && Number.isFinite(v) ? v : undefined;
40
- }
41
-
42
- function firstPath(files: unknown): string | undefined {
43
- if (!Array.isArray(files) || files.length === 0) return undefined;
44
- const first = files[0];
45
- if (typeof first === 'string') return first;
46
- if (first && typeof first === 'object') {
47
- const rec = first as Record<string, unknown>;
48
- if (typeof rec.path === 'string') return rec.path;
49
- if (typeof rec.resolved_path === 'string') return rec.resolved_path;
50
- }
51
- return undefined;
52
- }
53
-
54
- /** write: { files_written, bytes_written, files?: [{path, bytes_written}], dry_run? } */
55
- function summarizeWrite(obj: Record<string, unknown>): string | null {
56
- const count = asNumber(obj.files_written);
57
- const bytes = asNumber(obj.bytes_written);
58
- if (count === undefined) return null;
59
- const verb = obj.dry_run === true ? 'would write' : 'wrote';
60
- const size = bytes !== undefined ? ` (${formatBytes(bytes)})` : '';
61
- if (count === 1) {
62
- const path = firstPath(obj.files);
63
- return path ? `${verb} ${baseName(path)}${size}` : `${verb} 1 file${size}`;
64
- }
65
- return `${verb} ${count} files${size}`;
66
- }
67
-
68
- /** read: { summary: { files_read, total_lines }, files?: [{path, lineCount}] } */
69
- function summarizeRead(obj: Record<string, unknown>): string | null {
70
- const summary = (obj.summary && typeof obj.summary === 'object')
71
- ? obj.summary as Record<string, unknown>
72
- : obj;
73
- const count = asNumber(summary.files_read);
74
- const lines = asNumber(summary.total_lines);
75
- if (count === undefined && lines === undefined) return null;
76
- const lineText = lines !== undefined ? ` (${lines} line${lines === 1 ? '' : 's'})` : '';
77
- if (count === 1) {
78
- const path = firstPath(obj.files);
79
- return path ? `read ${baseName(path)}${lineText}` : `read 1 file${lineText}`;
80
- }
81
- return `read ${count ?? '?'} files${lineText}`;
82
- }
83
-
84
- /** edit: { applied, failed, dry_run } or richer with a path. */
85
- function summarizeEdit(obj: Record<string, unknown>): string | null {
86
- const applied = asNumber(obj.applied);
87
- if (applied === undefined) return null;
88
- const failed = asNumber(obj.failed) ?? 0;
89
- const verb = obj.dry_run === true ? 'would apply' : 'applied';
90
- const path = typeof obj.path === 'string' ? obj.path : firstPath(obj.files);
91
- const target = path ? ` to ${baseName(path)}` : '';
92
- const failText = failed > 0 ? `, ${failed} failed` : '';
93
- return `${verb} ${applied} edit${applied === 1 ? '' : 's'}${target}${failText}`;
94
- }
95
-
96
- // The credential scrub's withheld_env report stays OUT of the collapsed line
97
- // entirely. It withholds the same standing set of names on every spawn, so any
98
- // per-result rendering repeats identical env-var noise all session long, the
99
- // dominant transcript spam for anyone with several keys exported. The report
100
- // only matters when a command fails because a needed credential was scrubbed,
101
- // and for that case the full name list is one expand away in the raw payload.
102
-
103
- /**
104
- * Compact per-command exec-sandbox suffix: `sandboxed` fields are present
105
- * only when the sandbox was active for the run (SDK's attachSandboxMeta stays
106
- * quiet otherwise), so absence here means "ran unsandboxed" and the suffix is
107
- * empty, never a fabricated claim either way.
108
- *
109
- * sandboxed, network disabled -> " · sandboxed (net off)"
110
- * sandboxed, network enabled, escalation -> " · sandboxed (net on, +1 escalation)"
111
- * requested but host couldn't provide it -> " · sandbox unavailable (<reason>)"
112
- */
113
- function sandboxSuffix(obj: Record<string, unknown>): string {
114
- const sandboxed = obj.sandboxed;
115
- if (sandboxed === undefined) return '';
116
- if (sandboxed === false) {
117
- const reason = typeof obj.sandbox_boundary === 'string' ? obj.sandbox_boundary : undefined;
118
- return reason ? ` · sandbox unavailable (${reason})` : ' · sandbox unavailable';
119
- }
120
- const network = typeof obj.sandbox_network === 'string' ? obj.sandbox_network : undefined;
121
- const escalations = Array.isArray(obj.sandbox_escalations)
122
- ? obj.sandbox_escalations.filter((e): e is string => typeof e === 'string')
123
- : [];
124
- const netText = network ? `net ${network}` : undefined;
125
- const escText = escalations.length > 0 ? `+${escalations.length} escalation${escalations.length === 1 ? '' : 's'}` : undefined;
126
- const detail = [netText, escText].filter((s): s is string => s !== undefined).join(', ');
127
- return detail ? ` · sandboxed (${detail})` : ' · sandboxed';
128
- }
129
-
130
- /** A single exec command result. */
131
- function summarizeExecOne(obj: Record<string, unknown>): string | null {
132
- const exit = obj.exit_code;
133
- const dur = asNumber(obj.duration_ms);
134
- const durText = dur !== undefined ? ` · ${formatDuration(dur)}` : '';
135
- const sandboxText = sandboxSuffix(obj);
136
- if (obj.timed_out === true) return `timed out${durText}${sandboxText}`;
137
- if (obj.cancelled === true) return `cancelled${durText}${sandboxText}`;
138
- const stdout = typeof obj.stdout === 'string' ? obj.stdout : '';
139
- const lineCount = stdout.length === 0
140
- ? 0
141
- : stdout.replace(/\n$/, '').split('\n').length;
142
- const lineText = lineCount > 0 ? ` · ${lineCount} line${lineCount === 1 ? '' : 's'}` : '';
143
- const code = typeof exit === 'number' ? String(exit) : '?';
144
- return `exit ${code}${durText}${lineText}${sandboxText}`;
145
- }
146
-
147
- /** exec: single { cmd, exit_code, ... } or multi { commands: [...], total }. */
148
- function summarizeExec(obj: Record<string, unknown>): string | null {
149
- if (Array.isArray(obj.commands)) {
150
- const total = asNumber(obj.total) ?? obj.commands.length;
151
- const failed = obj.commands.filter(
152
- (c) => c && typeof c === 'object' && (c as Record<string, unknown>).success === false,
153
- ).length;
154
- // Count sandboxed commands across the batch, a compact "N sandboxed" beats
155
- // repeating each command's full boundary detail on the collapsed line.
156
- const sandboxedCount = obj.commands.filter(
157
- (c) => c && typeof c === 'object' && (c as Record<string, unknown>).sandboxed === true,
158
- ).length;
159
- const sandboxText = sandboxedCount > 0 ? ` · ${sandboxedCount} sandboxed` : '';
160
- return failed > 0
161
- ? `${total} commands · ${failed} failed${sandboxText}`
162
- : `${total} commands · all ok${sandboxText}`;
163
- }
164
- if ('exit_code' in obj || 'timed_out' in obj || 'cancelled' in obj) {
165
- return summarizeExecOne(obj);
166
- }
167
- return null;
168
- }
169
-
170
- /**
171
- * agent status/get/wait: an optional `failure` field (ChildFailureEnvelope,
172
- * see the SDK's tools/agent/child-failure-envelope.ts) is present once the
173
- * child agent terminated abnormally (max_turns, circuit_breaker,
174
- * watchdog_timeout, budget_exhausted, claim_unverified, api_error, killed,
175
- * interrupted, error). Renders it compactly on the collapsed preview line so
176
- * a failed child is visible without expanding the full result; absent
177
- * `failure` (the common, successful case) falls through to the raw preview.
178
- */
179
- function summarizeAgentFailure(obj: Record<string, unknown>): string | null {
180
- const failure = obj.failure;
181
- if (!failure || typeof failure !== 'object') return null;
182
- const f = failure as Record<string, unknown>;
183
- const agentId = typeof f.agentId === 'string' ? f.agentId : '?';
184
- const phase = typeof f.phase === 'string' ? f.phase : undefined;
185
- const reason = f.reason && typeof f.reason === 'object' ? f.reason as Record<string, unknown> : undefined;
186
- const code = reason && typeof reason.code === 'string' ? reason.code : 'error';
187
- const message = reason && typeof reason.message === 'string' ? reason.message : '';
188
- const partialOutputs = f.partialOutputs && typeof f.partialOutputs === 'object' ? f.partialOutputs as Record<string, unknown> : undefined;
189
- const turnsCompleted = asNumber(partialOutputs?.turnsCompleted);
190
-
191
- const MAX_MSG_LEN = 80;
192
- const truncatedMessage = message.length > MAX_MSG_LEN ? `${message.slice(0, MAX_MSG_LEN - 3)}...` : message;
193
- const phaseText = phase ? ` at ${phase}` : '';
194
- const turnsText = turnsCompleted !== undefined ? ` (${turnsCompleted} turn${turnsCompleted === 1 ? '' : 's'} completed)` : '';
195
- const msgText = truncatedMessage.length > 0 ? `: ${truncatedMessage}` : '';
196
- return `agent ${agentId} failed [${code}]${phaseText}${msgText}${turnsText}`;
197
- }
198
-
199
- export function summarizeToolResult(toolName: string | undefined, content: string): string | null {
200
- if (!toolName) return null;
201
- const family = toolName.includes('__') ? toolName.split('__').pop()! : toolName;
202
- let data: unknown;
203
- try {
204
- data = JSON.parse(content);
205
- } catch {
206
- return null;
207
- }
208
- if (data === null || typeof data !== 'object' || Array.isArray(data)) return null;
209
- const obj = data as Record<string, unknown>;
210
-
211
- switch (family) {
212
- case 'write': return summarizeWrite(obj);
213
- case 'read': return summarizeRead(obj);
214
- case 'edit': return summarizeEdit(obj);
215
- case 'exec': return summarizeExec(obj);
216
- case 'agent': return summarizeAgentFailure(obj);
217
- default: return null;
218
- }
219
- }
@@ -1,21 +0,0 @@
1
- /**
2
- * Diagnostics panels barrel, re-exports all panel data provider classes.
3
- *
4
- * Import from this module to access the individual diagnostic panel providers.
5
- */
6
- export { ToolCallsPanel } from '@/runtime/index.ts';
7
- export { AgentsPanel } from '@/runtime/index.ts';
8
- export { TasksPanel } from '@/runtime/index.ts';
9
- export { EventsPanel } from '@/runtime/index.ts';
10
- export { StateInspectorPanel } from '@/runtime/index.ts';
11
- export type { InspectableDomain } from '@/runtime/index.ts';
12
- export { HealthPanel } from '@/runtime/index.ts';
13
- export { DivergencePanel } from '@/runtime/index.ts';
14
- export { ReplayPanel } from '@/runtime/index.ts';
15
- export { ToolContractsPanel } from '@/runtime/index.ts';
16
- export { TransportPanel } from '@/runtime/index.ts';
17
- export type { TransportPanelSnapshot } from '@/runtime/index.ts';
18
- export { OpsPanel } from './ops.ts';
19
- export type { OpsAuditEntry } from './ops.ts';
20
- export { SecurityPanel } from '@/runtime/index.ts';
21
- export type { SecurityPanelSnapshot } from '@/runtime/index.ts';