gloomberb 0.11.3 → 0.12.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 (489) hide show
  1. package/README.md +6 -4
  2. package/README.zh-CN.md +4 -2
  3. package/package.json +28 -1
  4. package/src/api-client/auth.ts +10 -0
  5. package/src/api-client/data.ts +103 -1
  6. package/src/api-client/index.test.ts +127 -0
  7. package/src/api-client/index.ts +129 -1
  8. package/src/api-client/normalizers.ts +39 -0
  9. package/src/api-client/paths.ts +85 -1
  10. package/src/api-client/types.ts +196 -0
  11. package/src/app/pane-runtime/index.tsx +15 -12
  12. package/src/app/pane-runtime/layout-placement.test.ts +27 -0
  13. package/src/app/pane-runtime/layout-placement.ts +13 -0
  14. package/src/app/pane-runtime/plugin-bindings.ts +62 -0
  15. package/src/app.tsx +60 -18
  16. package/src/architecture/browser-entry-graph.test.ts +96 -0
  17. package/src/brokers/profile-form.test.ts +25 -27
  18. package/src/brokers/test-broker.ts +68 -0
  19. package/src/cli/commands/plugins.ts +39 -11
  20. package/src/cli/desktop-pane-shot.ts +285 -16
  21. package/src/cli/index.ts +1 -1
  22. package/src/cli/pane-functions/capabilities.ts +58 -28
  23. package/src/cli/pane-functions/catalog.ts +16 -4
  24. package/src/cli/pane-functions/discovery.ts +1 -0
  25. package/src/cli/pane-functions/headless.test.ts +247 -0
  26. package/src/cli/pane-functions/headless.ts +423 -0
  27. package/src/cli/pane-functions/index.test.ts +9 -0
  28. package/src/cli/pane-functions/index.ts +6 -2
  29. package/src/cli/pane-functions/options.ts +27 -2
  30. package/src/cli/pane-functions/report.ts +4 -0
  31. package/src/cli/pane-functions/resolver.ts +26 -8
  32. package/src/cli/pane-functions/screenshot.test.ts +76 -0
  33. package/src/cli/pane-functions/screenshot.ts +236 -20
  34. package/src/cli/restore-plugins.ts +34 -0
  35. package/src/components/chart/{static/chart → composite}/axis-overlays.test.tsx +3 -3
  36. package/src/components/chart/{static/chart → composite}/axis-overlays.tsx +6 -11
  37. package/src/components/chart/{static/chart → composite}/bitmap.ts +17 -3
  38. package/src/components/chart/composite/composite-chart.test.tsx +68 -20
  39. package/src/components/chart/composite/composite-chart.tsx +301 -204
  40. package/src/components/chart/composite/format.ts +8 -2
  41. package/src/components/chart/composite/interactions.test.ts +68 -102
  42. package/src/components/chart/composite/interactions.ts +214 -264
  43. package/src/components/chart/composite/price-axis-labels.test.ts +21 -0
  44. package/src/components/chart/{price-axis-labels.tsx → composite/price-axis-labels.tsx} +9 -4
  45. package/src/components/chart/composite/scene.ts +57 -3
  46. package/src/components/chart/composite/text-renderer.ts +3 -2
  47. package/src/components/chart/composite/time-scale.ts +138 -57
  48. package/src/components/chart/composite/types.ts +25 -1
  49. package/src/components/chart/core/data.ts +9 -13
  50. package/src/components/chart/core/date-window.ts +7 -1
  51. package/src/components/chart/core/pointer.ts +3 -0
  52. package/src/components/chart/core/types.ts +0 -45
  53. package/src/components/chart/native/chart-rasterizer.ts +0 -1
  54. package/src/components/chart/native/kitty/index.test.ts +0 -188
  55. package/src/components/chart/native/raster/crosshair.ts +6 -5
  56. package/src/components/chart/native/raster/primitives.ts +0 -23
  57. package/src/components/chart/native/renderer-selection.ts +81 -31
  58. package/src/components/chart/static/{chart/surface.test.tsx → chart-surface.test.tsx} +28 -80
  59. package/src/components/chart/static/chart-surface.tsx +150 -0
  60. package/src/components/chart/static/index.ts +8 -0
  61. package/src/components/chart/static/multi-line-chart-surface.tsx +51 -166
  62. package/src/components/chart/static/scatter-chart-surface.test.ts +30 -0
  63. package/src/components/chart/static/scatter-chart-surface.tsx +135 -34
  64. package/src/components/chart/static/series.ts +49 -0
  65. package/src/components/command-bar/action-runtime.ts +1 -3
  66. package/src/components/command-bar/assist/model.test.ts +17 -2
  67. package/src/components/command-bar/assist/model.ts +40 -9
  68. package/src/components/command-bar/commands/direct/index.ts +1 -1
  69. package/src/components/command-bar/commands/direct/runtime.ts +1 -1
  70. package/src/components/command-bar/commands/registry.ts +0 -11
  71. package/src/components/command-bar/helpers.test.ts +2 -2
  72. package/src/components/command-bar/helpers.ts +2 -6
  73. package/src/components/command-bar/keyboard-shortcuts.ts +0 -11
  74. package/src/components/command-bar/list/badge.test.ts +54 -0
  75. package/src/components/command-bar/list/badge.ts +62 -0
  76. package/src/components/command-bar/list/model.test.ts +103 -0
  77. package/src/components/command-bar/list/model.ts +61 -4
  78. package/src/components/command-bar/list/view.test.tsx +113 -0
  79. package/src/components/command-bar/list/view.tsx +147 -131
  80. package/src/components/command-bar/pane-templates/workflow.ts +1 -1
  81. package/src/components/command-bar/panel/body.tsx +51 -65
  82. package/src/components/command-bar/panel/index.tsx +48 -13
  83. package/src/components/command-bar/panel/layout.test.ts +139 -0
  84. package/src/components/command-bar/panel/layout.ts +65 -28
  85. package/src/components/command-bar/panel/native-surface.ts +24 -0
  86. package/src/components/command-bar/panel/prompt-binding.ts +54 -0
  87. package/src/components/command-bar/panel/runtime.ts +6 -3
  88. package/src/components/command-bar/panel/state.ts +41 -7
  89. package/src/components/command-bar/panel/types.ts +7 -1
  90. package/src/components/command-bar/routes/root/provider-search.ts +34 -15
  91. package/src/components/command-bar/routes/root/results.test.ts +161 -0
  92. package/src/components/command-bar/routes/root/results.ts +30 -28
  93. package/src/components/command-bar/routes/root/runtime.ts +37 -20
  94. package/src/components/command-bar/routes/root/search-providers.test.tsx +224 -0
  95. package/src/components/command-bar/routes/root/search-providers.ts +205 -0
  96. package/src/components/command-bar/routes/root/selection.ts +1 -12
  97. package/src/components/command-bar/routes/root/shortcuts.test.ts +8 -8
  98. package/src/components/command-bar/routes/ticker-search/actions.ts +10 -9
  99. package/src/components/command-bar/routes/ticker-search/results.test.ts +54 -1
  100. package/src/components/command-bar/routes/ticker-search/results.ts +60 -19
  101. package/src/components/command-bar/routes/ticker-search/route.ts +1 -0
  102. package/src/components/command-bar/routing/actions.ts +1 -81
  103. package/src/components/command-bar/routing/launch-request.ts +1 -1
  104. package/src/components/command-bar/routing/list-state.ts +6 -21
  105. package/src/components/command-bar/selection-runtime.ts +1 -1
  106. package/src/components/command-bar/surface/assist.test.tsx +14 -10
  107. package/src/components/command-bar/surface/environment.ts +8 -1
  108. package/src/components/command-bar/surface/index.test.tsx +84 -68
  109. package/src/components/command-bar/surface/index.tsx +33 -36
  110. package/src/components/command-bar/surface/test-harness.tsx +15 -3
  111. package/src/components/command-bar/theme-picker.tsx +43 -15
  112. package/src/components/command-bar/view-model.test.ts +53 -8
  113. package/src/components/command-bar/view-model.ts +43 -14
  114. package/src/components/command-bar/workflow/tickers.ts +1 -0
  115. package/src/components/command-bar/workflow/types.ts +1 -1
  116. package/src/components/data-table/view.test.tsx +45 -6
  117. package/src/components/data-table/view.tsx +55 -9
  118. package/src/components/index.ts +10 -2
  119. package/src/components/input-search-bar.test.tsx +36 -2
  120. package/src/components/input-search-bar.tsx +18 -1
  121. package/src/components/layout/header.test.tsx +57 -10
  122. package/src/components/layout/header.tsx +292 -149
  123. package/src/components/layout/market-summary.test.ts +81 -0
  124. package/src/components/layout/market-summary.ts +109 -0
  125. package/src/components/layout/shell/chrome.ts +96 -1
  126. package/src/components/layout/shell/index.tsx +11 -3
  127. package/src/components/layout/shell/menu.ts +9 -0
  128. package/src/components/layout/shell/pane/actions.ts +29 -0
  129. package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
  130. package/src/components/layout/shell/shortcuts.ts +3 -0
  131. package/src/components/layout/status-bar.test.tsx +9 -8
  132. package/src/components/layout/status-bar.tsx +85 -54
  133. package/src/components/onboarding/onboarding-frame.tsx +2 -26
  134. package/src/components/price-sparkline/index.ts +61 -34
  135. package/src/components/price-sparkline/view.tsx +1 -1
  136. package/src/components/sign-in-gate.test.tsx +128 -0
  137. package/src/components/sign-in-gate.tsx +149 -0
  138. package/src/components/speedometer-gauge/desktop.tsx +2 -12
  139. package/src/components/ticker/badge/list.tsx +17 -3
  140. package/src/components/ticker/list-table-view.tsx +6 -3
  141. package/src/components/ui/data-table/index.tsx +3 -2
  142. package/src/components/ui/data-table/opentui/index.tsx +165 -120
  143. package/src/components/ui/frame.tsx +28 -0
  144. package/src/components/ui/index.ts +3 -0
  145. package/src/components/ui/native-select.tsx +20 -10
  146. package/src/components/ui/select-button.tsx +138 -0
  147. package/src/components/ui/status.tsx +2 -2
  148. package/src/components/ui/table-layout.ts +1 -1
  149. package/src/components/use-double-click-activation.ts +7 -3
  150. package/src/core/app-services.ts +3 -3
  151. package/src/data/config/layout.ts +12 -6
  152. package/src/data/config/store/index.test.ts +97 -0
  153. package/src/data/config/store/migrations.ts +41 -0
  154. package/src/data/config/store/normalize.ts +5 -3
  155. package/src/i18n/es.ts +6 -2
  156. package/src/i18n/ja.ts +6 -2
  157. package/src/i18n/ko.ts +6 -2
  158. package/src/i18n/zh-cn.ts +6 -2
  159. package/src/i18n/zh-tw.ts +6 -2
  160. package/src/layout-marketplace/pane-imagery.ts +1 -0
  161. package/src/layout-marketplace/payload.test.ts +17 -0
  162. package/src/layout-marketplace/payload.ts +40 -5
  163. package/src/market-data/coordinator/index.ts +3 -2
  164. package/src/market-data/coordinator/quotes.ts +173 -66
  165. package/src/market-data/coordinator/subscriptions.test.ts +215 -37
  166. package/src/pane-settings.ts +1 -1
  167. package/src/plugins/builtin/analytics/pane-model.ts +1 -1
  168. package/src/plugins/builtin/analytics/view.tsx +1 -1
  169. package/src/plugins/builtin/broker-manager/index.test.tsx +3 -2
  170. package/src/plugins/builtin/broker-manager/model.test.ts +2 -2
  171. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +16 -2
  172. package/src/plugins/builtin/chart-composer/pane.tsx +22 -8
  173. package/src/plugins/builtin/chat/content/composer.tsx +8 -4
  174. package/src/plugins/builtin/cloud/auth-dialog.tsx +14 -228
  175. package/src/plugins/builtin/cloud/auth-form.tsx +277 -0
  176. package/src/plugins/builtin/cloud/plugin.tsx +1 -0
  177. package/src/plugins/builtin/composite-plugins.ts +14 -1
  178. package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
  179. package/src/plugins/builtin/correlation/relationship/pane.tsx +2 -6
  180. package/src/plugins/builtin/correlation/relationship/view-model.ts +2 -2
  181. package/src/plugins/builtin/credit-conditions/index.test.tsx +12 -6
  182. package/src/plugins/builtin/credit-conditions/index.tsx +2 -21
  183. package/src/plugins/builtin/dividend-yield/index.tsx +1 -0
  184. package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
  185. package/src/plugins/builtin/earnings-calls/data.ts +223 -0
  186. package/src/plugins/builtin/earnings-calls/format.ts +49 -0
  187. package/src/plugins/builtin/earnings-calls/index.tsx +69 -0
  188. package/src/plugins/builtin/earnings-calls/pane.tsx +756 -0
  189. package/src/plugins/builtin/earnings-calls/prose.test.ts +36 -0
  190. package/src/plugins/builtin/earnings-calls/prose.ts +59 -0
  191. package/src/plugins/builtin/earnings-calls/transcript-view.tsx +334 -0
  192. package/src/plugins/builtin/econ/detail-view.tsx +1 -2
  193. package/src/plugins/builtin/econ/fred-series-map.ts +16 -1
  194. package/src/plugins/builtin/econ/index.tsx +2 -1
  195. package/src/plugins/builtin/econ-statistics/cache.ts +4 -0
  196. package/src/plugins/builtin/econ-statistics/client.ts +92 -0
  197. package/src/plugins/builtin/econ-statistics/defs.ts +66 -0
  198. package/src/plugins/builtin/econ-statistics/detail.tsx +154 -0
  199. package/src/plugins/builtin/econ-statistics/headless.test.ts +54 -0
  200. package/src/plugins/builtin/econ-statistics/headless.ts +171 -0
  201. package/src/plugins/builtin/econ-statistics/index.tsx +54 -0
  202. package/src/plugins/builtin/econ-statistics/pane.tsx +356 -0
  203. package/src/plugins/builtin/econ-statistics/stats.ts +522 -0
  204. package/src/plugins/builtin/econ-statistics/transform.test.ts +86 -0
  205. package/src/plugins/builtin/econ-statistics/transform.ts +85 -0
  206. package/src/plugins/builtin/econ-statistics/trend.ts +57 -0
  207. package/src/plugins/builtin/econ-statistics/view.ts +90 -0
  208. package/src/plugins/builtin/fear-greed/charts.tsx +7 -18
  209. package/src/plugins/builtin/fear-greed/data.ts +6 -1
  210. package/src/plugins/builtin/help/index.tsx +4 -0
  211. package/src/plugins/builtin/holders/index.tsx +1 -0
  212. package/src/plugins/builtin/insider/index.tsx +1 -0
  213. package/src/plugins/builtin/kelly-sizer/pane.tsx +1 -1
  214. package/src/plugins/builtin/kelly-sizer/sections.tsx +2 -3
  215. package/src/plugins/builtin/market-valuation/align.ts +122 -0
  216. package/src/plugins/builtin/market-valuation/cache.ts +32 -0
  217. package/src/plugins/builtin/market-valuation/chart-projection.ts +217 -0
  218. package/src/plugins/builtin/market-valuation/chart-series.ts +89 -0
  219. package/src/plugins/builtin/market-valuation/client.test.ts +141 -0
  220. package/src/plugins/builtin/market-valuation/client.ts +116 -0
  221. package/src/plugins/builtin/market-valuation/defs.ts +251 -0
  222. package/src/plugins/builtin/market-valuation/detail.tsx +159 -0
  223. package/src/plugins/builtin/market-valuation/headless.test.ts +58 -0
  224. package/src/plugins/builtin/market-valuation/headless.ts +170 -0
  225. package/src/plugins/builtin/market-valuation/index.tsx +64 -0
  226. package/src/plugins/builtin/market-valuation/indicators.ts +422 -0
  227. package/src/plugins/builtin/market-valuation/model.test.ts +350 -0
  228. package/src/plugins/builtin/market-valuation/model.ts +8 -0
  229. package/src/plugins/builtin/market-valuation/pane.test.tsx +247 -0
  230. package/src/plugins/builtin/market-valuation/pane.tsx +344 -0
  231. package/src/plugins/builtin/market-valuation/series.ts +12 -0
  232. package/src/plugins/builtin/market-valuation/settings.ts +38 -0
  233. package/src/plugins/builtin/market-valuation/sources.ts +130 -0
  234. package/src/plugins/builtin/market-valuation/trend.ts +89 -0
  235. package/src/plugins/builtin/market-valuation/view.ts +137 -0
  236. package/src/plugins/builtin/market-valuation/zone-scale/desktop.tsx +123 -0
  237. package/src/plugins/builtin/market-valuation/zone-scale/index.tsx +12 -0
  238. package/src/plugins/builtin/market-valuation/zone-scale/model.ts +60 -0
  239. package/src/plugins/builtin/market-valuation/zone-scale/terminal.tsx +94 -0
  240. package/src/plugins/builtin/news/wire/breaking/filters.test.ts +99 -0
  241. package/src/plugins/builtin/news/wire/breaking/filters.ts +110 -0
  242. package/src/plugins/builtin/news/wire/breaking/notifications.test.ts +157 -53
  243. package/src/plugins/builtin/news/wire/breaking/notifications.ts +91 -25
  244. package/src/plugins/builtin/news/wire/index.tsx +31 -44
  245. package/src/plugins/builtin/options/index.tsx +1 -0
  246. package/src/plugins/builtin/options/view.test.tsx +29 -1
  247. package/src/plugins/builtin/options/view.tsx +1 -22
  248. package/src/plugins/builtin/plugin-marketplace/feed.ts +80 -0
  249. package/src/plugins/builtin/plugin-marketplace/index.tsx +31 -0
  250. package/src/plugins/builtin/plugin-marketplace/model.test.ts +200 -0
  251. package/src/plugins/builtin/plugin-marketplace/model.ts +204 -0
  252. package/src/plugins/builtin/plugin-marketplace/pane.tsx +385 -0
  253. package/src/plugins/builtin/plugin-marketplace/store.ts +46 -0
  254. package/src/plugins/builtin/plugin-module.ts +9 -1
  255. package/src/plugins/builtin/research/index.tsx +4 -0
  256. package/src/plugins/builtin/research-search/command-bar-search.test.ts +81 -0
  257. package/src/plugins/builtin/research-search/command-bar-search.ts +175 -0
  258. package/src/plugins/builtin/research-search/data.ts +109 -0
  259. package/src/plugins/builtin/research-search/document-view.test.tsx +75 -0
  260. package/src/plugins/builtin/research-search/document-view.tsx +254 -0
  261. package/src/plugins/builtin/research-search/filter-bar.tsx +62 -0
  262. package/src/plugins/builtin/research-search/focus-handoff.ts +47 -0
  263. package/src/plugins/builtin/research-search/index.tsx +85 -0
  264. package/src/plugins/builtin/research-search/model.test.ts +40 -0
  265. package/src/plugins/builtin/research-search/model.ts +291 -0
  266. package/src/plugins/builtin/research-search/pane.test.tsx +241 -0
  267. package/src/plugins/builtin/research-search/pane.tsx +678 -0
  268. package/src/plugins/builtin/research-search/saved-view.tsx +171 -0
  269. package/src/plugins/builtin/research-search/snippet-text.tsx +35 -0
  270. package/src/plugins/builtin/research-search/snippet.test.ts +78 -0
  271. package/src/plugins/builtin/research-search/snippet.ts +134 -0
  272. package/src/plugins/builtin/scanner/flow-model.test.ts +11 -1
  273. package/src/plugins/builtin/scanner/flow-model.ts +29 -1
  274. package/src/plugins/builtin/scanner/flow-pane.tsx +78 -22
  275. package/src/plugins/builtin/sec/index.tsx +1 -0
  276. package/src/plugins/builtin/shared/series-cache.ts +93 -0
  277. package/src/plugins/builtin/short-interest/index.tsx +1 -0
  278. package/src/plugins/builtin/short-interest/pane.tsx +1 -1
  279. package/src/plugins/builtin/thirteenf/index.tsx +1 -0
  280. package/src/plugins/builtin/ticker-detail/index.tsx +0 -14
  281. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +1 -1
  282. package/src/plugins/builtin/volatility/index.tsx +1 -1
  283. package/src/plugins/builtin/world-venue-map/map.desktop.test.tsx +106 -0
  284. package/src/plugins/builtin/world-venue-map/map.tsx +213 -69
  285. package/src/plugins/builtin/world-venue-map/model.test.ts +32 -0
  286. package/src/plugins/builtin/world-venue-map/model.ts +134 -13
  287. package/src/plugins/builtin/yield-curve/index.tsx +1 -1
  288. package/src/plugins/bundle.test.ts +109 -0
  289. package/src/plugins/bundle.ts +139 -0
  290. package/src/plugins/catalog-browser.test.ts +1 -0
  291. package/src/plugins/catalog-browser.ts +10 -0
  292. package/src/plugins/catalog-manifest.test.ts +43 -0
  293. package/src/plugins/catalog-manifest.ts +92 -0
  294. package/src/plugins/catalog-ui.ts +20 -4
  295. package/src/plugins/catalog.ts +9 -2
  296. package/src/plugins/current-target.ts +28 -0
  297. package/src/plugins/host-contract.ts +37 -0
  298. package/src/plugins/host-link.ts +158 -0
  299. package/src/plugins/host-modules.ts +61 -0
  300. package/src/plugins/loader.ts +41 -22
  301. package/src/plugins/ownership.ts +1 -0
  302. package/src/plugins/prediction-markets/index.tsx +1 -0
  303. package/src/plugins/registry/context.ts +3 -0
  304. package/src/plugins/registry/contributions.ts +27 -0
  305. package/src/plugins/registry/index.test.ts +25 -0
  306. package/src/plugins/registry/index.ts +8 -0
  307. package/src/plugins/registry/pane-settings.ts +6 -13
  308. package/src/plugins/seed.test.ts +83 -0
  309. package/src/plugins/seed.ts +80 -0
  310. package/src/public/broker.ts +31 -0
  311. package/src/public/market-data.ts +9 -0
  312. package/src/public/pane-hooks.ts +57 -0
  313. package/src/public/public-api.test.ts +285 -0
  314. package/src/public/react.ts +62 -0
  315. package/src/public/test-support.ts +23 -0
  316. package/src/public/time-series.ts +8 -0
  317. package/src/public/utils.ts +77 -0
  318. package/src/remote/layout-helpers.ts +6 -8
  319. package/src/remote/resources.ts +2 -0
  320. package/src/remote/schema.ts +1 -0
  321. package/src/remote/semantic-tree.test.tsx +105 -0
  322. package/src/remote/semantic-tree.tsx +53 -35
  323. package/src/renderers/browser/main.tsx +6 -0
  324. package/src/renderers/cloudflare/worker.test.ts +19 -0
  325. package/src/renderers/cloudflare/worker.ts +1 -1
  326. package/src/renderers/electrobun/bun/external-plugins.ts +140 -0
  327. package/src/renderers/electrobun/bun/index.ts +5 -2
  328. package/src/renderers/electrobun/shared/protocol.ts +21 -0
  329. package/src/renderers/electrobun/view/build-assets.ts +0 -1
  330. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +51 -1
  331. package/src/renderers/electrobun/view/external-plugins.test.ts +45 -0
  332. package/src/renderers/electrobun/view/external-plugins.ts +63 -0
  333. package/src/renderers/electrobun/view/host/ascii-text.test.ts +48 -0
  334. package/src/renderers/electrobun/view/host/ascii-text.ts +11 -1
  335. package/src/renderers/electrobun/view/host/chart-surface.tsx +38 -32
  336. package/src/renderers/electrobun/view/host/mouse.ts +16 -2
  337. package/src/renderers/electrobun/view/main.tsx +27 -2
  338. package/src/renderers/electrobun/view/styles.css +5 -0
  339. package/src/renderers/electrobun/view/toast-host.tsx +18 -0
  340. package/src/renderers/opentui/chart-surface.tsx +5 -1
  341. package/src/renderers/opentui/host.tsx +16 -2
  342. package/src/renderers/opentui/interaction-performance.test.ts +79 -0
  343. package/src/renderers/opentui/interaction-performance.ts +188 -0
  344. package/src/renderers/opentui/start.tsx +26 -1
  345. package/src/renderers/opentui/test-utils.tsx +13 -0
  346. package/src/renderers/opentui/toast-host.tsx +26 -2
  347. package/src/renderers/opentui/ui-host.tsx +1 -0
  348. package/src/sources/provider-router/search.test.ts +191 -0
  349. package/src/sources/provider-router/search.ts +92 -39
  350. package/src/state/app/context/index.tsx +2 -0
  351. package/src/state/app/context/selector.test.tsx +33 -1
  352. package/src/state/hooks/quote-streaming.test.tsx +93 -0
  353. package/src/state/hooks/quote-streaming.ts +106 -30
  354. package/src/state/pane-table-export-registry.ts +19 -0
  355. package/src/theme/color-utils.ts +1 -1
  356. package/src/theme/colors.ts +50 -0
  357. package/src/theme/themes.test.ts +15 -2
  358. package/src/theme/themes.ts +19 -1
  359. package/src/tickers/search/index.test.ts +26 -0
  360. package/src/tickers/search/index.ts +42 -17
  361. package/src/tickers/search/ranking.ts +14 -0
  362. package/src/time-series/chart-data.test.ts +216 -0
  363. package/src/time-series/resolution.test.ts +25 -26
  364. package/src/time-series/resolution.ts +41 -10
  365. package/src/time-series/resolve.ts +7 -0
  366. package/src/time-series/types.ts +3 -1
  367. package/src/time-series/use-chart-resolution.ts +5 -0
  368. package/src/types/config.ts +123 -3
  369. package/src/types/data-provider.ts +11 -0
  370. package/src/types/headless.ts +161 -0
  371. package/src/types/plugin.ts +102 -0
  372. package/src/ui/host.tsx +12 -1
  373. package/src/ui/index.tsx +1 -0
  374. package/src/ui/toast.tsx +8 -4
  375. package/src/utils/format.ts +35 -0
  376. package/src/utils/fuzzy-search.test.ts +94 -0
  377. package/src/utils/fuzzy-search.ts +81 -22
  378. package/src/utils/shortcut-labels.ts +14 -0
  379. package/src/components/chart/core/axis-format.ts +0 -157
  380. package/src/components/chart/core/index.test.ts +0 -1075
  381. package/src/components/chart/core/projection.ts +0 -357
  382. package/src/components/chart/core/render-utils.ts +0 -4
  383. package/src/components/chart/core/renderer.ts +0 -244
  384. package/src/components/chart/core/scene.ts +0 -180
  385. package/src/components/chart/core/time-axis.ts +0 -330
  386. package/src/components/chart/cursor-motion.ts +0 -47
  387. package/src/components/chart/indicators/types.ts +0 -26
  388. package/src/components/chart/market-session.ts +0 -176
  389. package/src/components/chart/multi-line/renderer.test.ts +0 -83
  390. package/src/components/chart/multi-line/renderer.ts +0 -161
  391. package/src/components/chart/multi-line/scene.ts +0 -188
  392. package/src/components/chart/native/raster/layout.ts +0 -129
  393. package/src/components/chart/native/raster/price-chart.ts +0 -244
  394. package/src/components/chart/rendering/chart-draw.ts +0 -270
  395. package/src/components/chart/rendering/geometry.ts +0 -95
  396. package/src/components/chart/rendering/pixel-buffer.ts +0 -267
  397. package/src/components/chart/scatter-chart-renderer.test.ts +0 -31
  398. package/src/components/chart/scatter-chart-renderer.ts +0 -223
  399. package/src/components/chart/static/chart/surface.tsx +0 -358
  400. package/src/components/command-bar/routes/root/article-results.test.ts +0 -83
  401. package/src/components/command-bar/routes/root/article-results.ts +0 -55
  402. package/src/plugins/builtin/news/wire/article-search.test.ts +0 -72
  403. package/src/plugins/builtin/news/wire/article-search.ts +0 -140
  404. package/src/plugins/builtin/substack/api/auth.ts +0 -185
  405. package/src/plugins/builtin/substack/api/cache.ts +0 -82
  406. package/src/plugins/builtin/substack/api/loaders.ts +0 -170
  407. package/src/plugins/builtin/substack/api/store.ts +0 -186
  408. package/src/plugins/builtin/substack/api/types.ts +0 -42
  409. package/src/plugins/builtin/substack/api.test.ts +0 -298
  410. package/src/plugins/builtin/substack/article-detail.tsx +0 -397
  411. package/src/plugins/builtin/substack/article-stack.tsx +0 -133
  412. package/src/plugins/builtin/substack/content.ts +0 -478
  413. package/src/plugins/builtin/substack/feed-tabs.tsx +0 -44
  414. package/src/plugins/builtin/substack/index.tsx +0 -49
  415. package/src/plugins/builtin/substack/login-view.tsx +0 -126
  416. package/src/plugins/builtin/substack/model.test.ts +0 -155
  417. package/src/plugins/builtin/substack/normalize.ts +0 -343
  418. package/src/plugins/builtin/substack/pane-footer.ts +0 -52
  419. package/src/plugins/builtin/substack/pane-state.ts +0 -170
  420. package/src/plugins/builtin/substack/pane.tsx +0 -547
  421. package/src/plugins/builtin/substack/read-state.ts +0 -30
  422. package/src/plugins/builtin/substack/table.ts +0 -111
  423. package/src/plugins/builtin/substack/types.ts +0 -71
  424. package/src/plugins/builtin/substack/utils.ts +0 -131
  425. package/src/plugins/builtin/ticker-detail/data-panes/provider-search.tsx +0 -229
  426. package/src/plugins/ibkr/account-cache.test.ts +0 -102
  427. package/src/plugins/ibkr/account-cache.ts +0 -24
  428. package/src/plugins/ibkr/broker-adapter.ts +0 -286
  429. package/src/plugins/ibkr/config.test.ts +0 -79
  430. package/src/plugins/ibkr/config.ts +0 -250
  431. package/src/plugins/ibkr/dialogs.tsx +0 -40
  432. package/src/plugins/ibkr/flex/index.test.ts +0 -264
  433. package/src/plugins/ibkr/flex/index.ts +0 -367
  434. package/src/plugins/ibkr/flex/statement-client.ts +0 -235
  435. package/src/plugins/ibkr/fundamental-parser.ts +0 -149
  436. package/src/plugins/ibkr/gateway/account-loaders.ts +0 -266
  437. package/src/plugins/ibkr/gateway/account-summary.ts +0 -164
  438. package/src/plugins/ibkr/gateway/client-lock.ts +0 -154
  439. package/src/plugins/ibkr/gateway/connection-events.ts +0 -114
  440. package/src/plugins/ibkr/gateway/connection.ts +0 -152
  441. package/src/plugins/ibkr/gateway/contracts.ts +0 -132
  442. package/src/plugins/ibkr/gateway/fundamentals.ts +0 -83
  443. package/src/plugins/ibkr/gateway/helpers.ts +0 -33
  444. package/src/plugins/ibkr/gateway/history-requests.ts +0 -158
  445. package/src/plugins/ibkr/gateway/history.ts +0 -120
  446. package/src/plugins/ibkr/gateway/instrument-lookup.ts +0 -117
  447. package/src/plugins/ibkr/gateway/market-data.ts +0 -345
  448. package/src/plugins/ibkr/gateway/order-execution.ts +0 -218
  449. package/src/plugins/ibkr/gateway/orders.ts +0 -63
  450. package/src/plugins/ibkr/gateway/price-normalization.test.ts +0 -44
  451. package/src/plugins/ibkr/gateway/price-normalization.ts +0 -50
  452. package/src/plugins/ibkr/gateway/quote-stream-controller.ts +0 -203
  453. package/src/plugins/ibkr/gateway/quote-stream.ts +0 -171
  454. package/src/plugins/ibkr/gateway/selection.ts +0 -51
  455. package/src/plugins/ibkr/gateway/service/index.test.ts +0 -675
  456. package/src/plugins/ibkr/gateway/service/index.ts +0 -429
  457. package/src/plugins/ibkr/gateway/service/lifecycle.ts +0 -191
  458. package/src/plugins/ibkr/gateway/service/manager.ts +0 -52
  459. package/src/plugins/ibkr/gateway/service/market-data.ts +0 -48
  460. package/src/plugins/ibkr/gateway/service/native-loader.ts +0 -12
  461. package/src/plugins/ibkr/gateway/service/native.ts +0 -543
  462. package/src/plugins/ibkr/gateway/timeouts.ts +0 -13
  463. package/src/plugins/ibkr/gateway/types.ts +0 -27
  464. package/src/plugins/ibkr/index.test.tsx +0 -162
  465. package/src/plugins/ibkr/index.tsx +0 -159
  466. package/src/plugins/ibkr/instance-selection.test.ts +0 -120
  467. package/src/plugins/ibkr/instance-selection.ts +0 -36
  468. package/src/plugins/ibkr/portfolio-performance.test.ts +0 -32
  469. package/src/plugins/ibkr/portfolio-performance.ts +0 -129
  470. package/src/plugins/ibkr/trade/badge.tsx +0 -28
  471. package/src/plugins/ibkr/trade/dialogs.tsx +0 -44
  472. package/src/plugins/ibkr/trade/preview-panel.tsx +0 -130
  473. package/src/plugins/ibkr/trade/tab/actions.tsx +0 -443
  474. package/src/plugins/ibkr/trade/tab/field-editors.tsx +0 -79
  475. package/src/plugins/ibkr/trade/tab/footer.ts +0 -53
  476. package/src/plugins/ibkr/trade/tab/header.tsx +0 -167
  477. package/src/plugins/ibkr/trade/tab/index.test.tsx +0 -178
  478. package/src/plugins/ibkr/trade/tab/index.tsx +0 -298
  479. package/src/plugins/ibkr/trade/tab/model.ts +0 -159
  480. package/src/plugins/ibkr/trade/tab/order-request.ts +0 -64
  481. package/src/plugins/ibkr/trade/tab/shortcuts.ts +0 -89
  482. package/src/plugins/ibkr/trade/tab/state-sync.ts +0 -86
  483. package/src/plugins/ibkr/trade/ticket-panel.tsx +0 -301
  484. package/src/plugins/ibkr/trade/utils.test.ts +0 -175
  485. package/src/plugins/ibkr/trade/utils.ts +0 -144
  486. package/src/plugins/ibkr/trading/pane-view.tsx +0 -237
  487. package/src/plugins/ibkr/trading/pane.tsx +0 -332
  488. package/src/plugins/ibkr/trading/state.test.ts +0 -109
  489. package/src/plugins/ibkr/trading/state.ts +0 -335
@@ -1,12 +1,16 @@
1
1
  import { dirname, resolve } from "path";
2
2
  import { mkdir } from "fs/promises";
3
3
  import type { PaneRuntimeState } from "../../core/state/app/state";
4
- import { CHART_COMPOSER_PANE_ID } from "../../types/config";
4
+ import { CHART_COMPOSER_PANE_ID, type AppConfig } from "../../types/config";
5
5
  import type { OptionsChain, PricePoint, TickerFinancials } from "../../types/financials";
6
6
  import type { TickerRecord } from "../../types/ticker";
7
7
  import { slugifyName } from "../../utils/slugify";
8
+ import { getTheme, getThemeIds } from "../../theme/themes";
9
+
10
+ const DEFAULT_SHOT_DEVICE_SCALE_FACTOR = 2;
8
11
  import {
9
12
  renderDesktopPaneScreenshot,
13
+ type DesktopPaneShotApiProxy,
10
14
  type DesktopPaneShotPayload,
11
15
  type DesktopPaneShotRenderResult,
12
16
  } from "../desktop-pane-shot";
@@ -39,8 +43,16 @@ import {
39
43
  getVisibleWindowForDateRange,
40
44
  } from "../../components/chart/core/date-window";
41
45
  import { parseChartSpec } from "../../plugins/builtin/chart-composer/chart-spec";
46
+ import {
47
+ defaultValuationSeriesLoader,
48
+ requiredSeries as valuationRequiredSeries,
49
+ } from "../../plugins/builtin/market-valuation/client";
50
+ import type { DatedObservation } from "../../plugins/builtin/market-valuation/series";
51
+ import { defaultStatLoader } from "../../plugins/builtin/econ-statistics/client";
52
+ import { STATS } from "../../plugins/builtin/econ-statistics/stats";
42
53
  import { publicTickerKey } from "../../utils/exchanges";
43
54
  import { apiClient } from "../../api-client";
55
+ import { getCloudApiBaseUrl } from "../../api-client/request";
44
56
  import type { FredSeriesCacheEntry } from "../../data/fred-series";
45
57
  import type { ResolvedSeries } from "../../time-series/types";
46
58
  import { chartSeriesSourceKey, createChartSeriesResolver } from "../../capabilities";
@@ -57,6 +69,102 @@ import {
57
69
  const DESKTOP_CELL_WIDTH_PX = 8;
58
70
  const DESKTOP_CELL_HEIGHT_PX = 18;
59
71
  const OPTIONS_PANE_ID = "options";
72
+ const MARKET_VALUATION_PANE_ID = "market-valuation";
73
+ const ECON_STATISTICS_PANE_ID = "econ-statistics";
74
+ const CLOUD_PLUGIN_ID = "gloomberb-cloud";
75
+ const CLOUD_SESSION_KEYS = ["resume:session", "session"] as const;
76
+ const CREDENTIAL_FIELD_NAMES = new Set([
77
+ "accesstoken",
78
+ "accessurl",
79
+ "apikey",
80
+ "apisecret",
81
+ "authorization",
82
+ "cookie",
83
+ "credentials",
84
+ "oauth",
85
+ "passphrase",
86
+ "password",
87
+ "privatekey",
88
+ "refreshtoken",
89
+ "secret",
90
+ "sessiontoken",
91
+ "token",
92
+ ]);
93
+
94
+ interface PersistedShotCloudSession {
95
+ sessionToken?: unknown;
96
+ }
97
+
98
+ /**
99
+ * The proxy receives the desktop session out of band. Keeping this separate
100
+ * from DesktopPaneShotPayload prevents the token from entering the page,
101
+ * semantic evidence, or JSON CLI output.
102
+ */
103
+ function isCredentialField(key: string): boolean {
104
+ const normalized = key.replace(/[^a-z0-9]/gi, "").toLowerCase();
105
+ return CREDENTIAL_FIELD_NAMES.has(normalized)
106
+ || normalized.endsWith("password")
107
+ || normalized.endsWith("passphrase")
108
+ || normalized.endsWith("secret")
109
+ || normalized.endsWith("token")
110
+ || normalized.endsWith("credential")
111
+ || normalized.endsWith("cookie")
112
+ || normalized.endsWith("apikey")
113
+ || normalized.endsWith("accesskey")
114
+ || normalized.endsWith("privatekey")
115
+ || normalized.endsWith("authorization")
116
+ || normalized.endsWith("accessurl");
117
+ }
118
+
119
+ /** Removes credential-shaped object fields before data enters the page or JSON output. */
120
+ export function stripDesktopShotCredentials<T>(value: T): T {
121
+ if (Array.isArray(value)) {
122
+ return value.map((entry) => stripDesktopShotCredentials(entry)) as T;
123
+ }
124
+ if (!value || typeof value !== "object" || value instanceof Date) return value;
125
+ const clean: Record<string, unknown> = {};
126
+ for (const [key, entry] of Object.entries(value as Record<string, unknown>)) {
127
+ if (isCredentialField(key)) continue;
128
+ clean[key] = stripDesktopShotCredentials(entry);
129
+ }
130
+ return clean as T;
131
+ }
132
+
133
+ export function resolveDesktopShotApiProxy(
134
+ context: Pick<MarketContext, "persistence">,
135
+ ): DesktopPaneShotApiProxy {
136
+ let sessionToken: string | null = null;
137
+ for (const key of CLOUD_SESSION_KEYS) {
138
+ const value = context.persistence.pluginState.get<PersistedShotCloudSession>(
139
+ CLOUD_PLUGIN_ID,
140
+ key,
141
+ 1,
142
+ )?.value;
143
+ if (typeof value?.sessionToken === "string" && value.sessionToken.length > 0) {
144
+ sessionToken = value.sessionToken;
145
+ break;
146
+ }
147
+ }
148
+ return {
149
+ baseUrl: getCloudApiBaseUrl(),
150
+ sessionToken,
151
+ };
152
+ }
153
+
154
+ /** Same reason as the valuation legs: the renderer cannot fill its own cache. */
155
+ async function collectShotStatSeries(
156
+ resolved: ResolvedPaneFunction,
157
+ ): Promise<Array<[string, DatedObservation[]]>> {
158
+ if (resolved.pane.id !== ECON_STATISTICS_PANE_ID) return [];
159
+ const loaded = await Promise.all(STATS.map(async (def) => {
160
+ try {
161
+ return [def.seriesId, await defaultStatLoader(def)] as [string, DatedObservation[]];
162
+ } catch {
163
+ return null;
164
+ }
165
+ }));
166
+ return loaded.filter((entry): entry is [string, DatedObservation[]] => !!entry);
167
+ }
60
168
 
61
169
  async function collectShotFredSeries(
62
170
  resolved: ResolvedPaneFunction,
@@ -81,6 +189,25 @@ async function collectShotFredSeries(
81
189
  return loaded.filter((entry): entry is [string, FredSeriesCacheEntry] => !!entry);
82
190
  }
83
191
 
192
+ /**
193
+ * The pane reads its legs from a client cache the shot renderer cannot fill itself,
194
+ * so fetch them here on the Bun side and hand them over with the payload.
195
+ */
196
+ async function collectShotValuationSeries(
197
+ resolved: ResolvedPaneFunction,
198
+ ): Promise<Array<[string, DatedObservation[]]>> {
199
+ if (resolved.pane.id !== MARKET_VALUATION_PANE_ID) return [];
200
+ const loaded = await Promise.all(valuationRequiredSeries().map(async (def) => {
201
+ try {
202
+ const series = await defaultValuationSeriesLoader(def);
203
+ return [def.key, series.observations] as [string, DatedObservation[]];
204
+ } catch {
205
+ return null;
206
+ }
207
+ }));
208
+ return loaded.filter((entry): entry is [string, DatedObservation[]] => !!entry);
209
+ }
210
+
84
211
  async function collectShotCapabilitySeries(
85
212
  resolved: ResolvedPaneFunction,
86
213
  ): Promise<Array<[string, ResolvedSeries]>> {
@@ -196,6 +323,27 @@ export type PaneScreenshotDataEvidence =
196
323
  | PaneScreenshotFundamentalSeriesEvidence
197
324
  | PaneScreenshotFinancialStatementEvidence;
198
325
 
326
+ export interface PaneScreenshotReadinessSignals {
327
+ rowCount: number;
328
+ loadingStateDetected: boolean;
329
+ errorStateDetected: boolean;
330
+ emptyStateDetected: boolean;
331
+ complete: boolean;
332
+ semanticMismatch: boolean;
333
+ requiresStructuredDataEvidence: boolean;
334
+ hasStructuredDataEvidence: boolean;
335
+ }
336
+
337
+ export function isPaneScreenshotUsable(signals: PaneScreenshotReadinessSignals): boolean {
338
+ return signals.rowCount > 0
339
+ && !signals.loadingStateDetected
340
+ && !signals.errorStateDetected
341
+ && !signals.emptyStateDetected
342
+ && signals.complete
343
+ && !signals.semanticMismatch
344
+ && (!signals.requiresStructuredDataEvidence || signals.hasStructuredDataEvidence);
345
+ }
346
+
199
347
  export interface PaneScreenshotResult {
200
348
  kind: "pane-screenshot";
201
349
  target: string;
@@ -238,9 +386,20 @@ async function buildDesktopShotPayload(
238
386
  options: Record<string, string | true>,
239
387
  widthPx: number,
240
388
  heightPx: number,
389
+ theme: string | null,
390
+ scale: number,
391
+ watermark: string | null,
241
392
  ): Promise<DesktopPaneShotPayload> {
242
- const widthCells = Math.max(1, Math.round(widthPx / DESKTOP_CELL_WIDTH_PX));
243
- const heightCells = Math.max(1, Math.round(heightPx / DESKTOP_CELL_HEIGHT_PX));
393
+ // The requested size is the output size. Scale shrinks the CSS viewport and
394
+ // raises the device scale factor by the same factor, so a 1200px wide shot at
395
+ // scale 1.5 lays out 100 cells instead of 150 and every glyph is 1.5x larger.
396
+ // Snap to whole cells: rounding up used to make the pane a few pixels taller
397
+ // than the capture, which clipped the bottom axis of charts.
398
+ const widthCells = Math.max(1, Math.floor(widthPx / scale / DESKTOP_CELL_WIDTH_PX));
399
+ const heightCells = Math.max(1, Math.floor(heightPx / scale / DESKTOP_CELL_HEIGHT_PX));
400
+ widthPx = widthCells * DESKTOP_CELL_WIDTH_PX;
401
+ heightPx = heightCells * DESKTOP_CELL_HEIGHT_PX;
402
+ const deviceScaleFactor = DEFAULT_SHOT_DEVICE_SCALE_FACTOR * scale;
244
403
  const initialPaneState = optionPaneState(resolved.options);
245
404
  const pluginState = capabilityPluginState(resolved.capability, resolved.options);
246
405
  if (Object.keys(pluginState).length > 0) {
@@ -252,9 +411,9 @@ async function buildDesktopShotPayload(
252
411
  if (isFinancialAnalysisFunction(resolved) && !initialPaneState.activeTabId) {
253
412
  initialPaneState.activeTabId = "financials";
254
413
  }
255
- const paneState: Record<string, PaneRuntimeState> = {
414
+ const paneState = stripDesktopShotCredentials<Record<string, PaneRuntimeState>>({
256
415
  [resolved.instance.instanceId]: initialPaneState,
257
- };
416
+ });
258
417
  const layout = {
259
418
  dockRoot: null,
260
419
  instances: [resolved.instance],
@@ -268,8 +427,9 @@ async function buildDesktopShotPayload(
268
427
  }],
269
428
  detached: [],
270
429
  };
271
- const config = {
430
+ const config = stripDesktopShotCredentials<AppConfig>({
272
431
  ...context.config,
432
+ ...(theme ? { theme: resolveShotTheme(theme) } : {}),
273
433
  layout,
274
434
  layouts: [{
275
435
  name: "CLI Shot",
@@ -280,14 +440,16 @@ async function buildDesktopShotPayload(
280
440
  }],
281
441
  activeLayoutIndex: 0,
282
442
  onboardingComplete: true,
283
- };
443
+ });
284
444
 
285
445
  const tickers: TickerRecord[] = [];
286
446
  const financials: Array<[string, TickerFinancials]> = [];
287
447
  const optionsChains: Array<[string, OptionsChain]> = [];
288
- const [fredSeries, capabilitySeries] = await Promise.all([
448
+ const [fredSeries, capabilitySeries, valuationSeries, statSeries] = await Promise.all([
289
449
  collectShotFredSeries(resolved),
290
450
  collectShotCapabilitySeries(resolved),
451
+ collectShotValuationSeries(resolved),
452
+ collectShotStatSeries(resolved),
291
453
  ]);
292
454
  const includeOptionsChains = resolved.pane.id === OPTIONS_PANE_ID || resolved.template?.paneId === OPTIONS_PANE_ID;
293
455
  for (const symbol of collectShotSymbols(resolved, rawArg)) {
@@ -327,15 +489,30 @@ async function buildDesktopShotPayload(
327
489
  heightCells,
328
490
  widthPx,
329
491
  heightPx,
492
+ deviceScaleFactor,
493
+ watermark,
330
494
  tickers,
331
495
  financials,
332
496
  optionsChains,
333
497
  fredSeries,
498
+ valuationSeries,
499
+ statSeries,
334
500
  capabilitySeries,
335
501
  paneState,
336
502
  };
337
503
  }
338
504
 
505
+ function resolveShotTheme(requested: string): string {
506
+ const normalized = requested.trim().toLowerCase().replace(/[\s_]+/g, "-");
507
+ const ids = getThemeIds();
508
+ const match = ids.find((id) => id.toLowerCase() === normalized)
509
+ ?? ids.find((id) => getTheme(id).name.toLowerCase().replace(/[\s_]+/g, "-") === normalized);
510
+ if (!match) {
511
+ throw new Error(`Unknown theme "${requested}". Available themes: ${ids.join(", ")}`);
512
+ }
513
+ return match;
514
+ }
515
+
339
516
  export function shotPriceHistoryRange(resolved: ResolvedPaneFunction): TimeRange | null {
340
517
  switch (resolved.capability.id) {
341
518
  case "chart-composer":
@@ -364,6 +541,9 @@ export async function renderDesktopShot({
364
541
  outputPath,
365
542
  width,
366
543
  height,
544
+ theme,
545
+ scale,
546
+ watermark,
367
547
  options,
368
548
  }: {
369
549
  resolved: ResolvedPaneFunction;
@@ -372,14 +552,41 @@ export async function renderDesktopShot({
372
552
  outputPath: string;
373
553
  width: number;
374
554
  height: number;
555
+ theme?: string | null;
556
+ scale?: number;
557
+ watermark?: string | null;
375
558
  options: Record<string, string | true>;
376
559
  }): Promise<PaneScreenshotResult> {
377
560
  await mkdir(dirname(outputPath), { recursive: true });
378
- const payload = await buildDesktopShotPayload(resolved, context, rawArg, options, width, height);
379
- const render = await renderDesktopPaneScreenshot(payload, outputPath);
561
+ const apiProxy = resolveDesktopShotApiProxy(context);
562
+ const previousSessionToken = apiClient.getSessionToken();
563
+ let payload: DesktopPaneShotPayload;
564
+ let render: DesktopPaneShotRenderResult;
565
+ apiClient.setSessionToken(apiProxy.sessionToken);
566
+ try {
567
+ payload = await buildDesktopShotPayload(
568
+ resolved,
569
+ context,
570
+ rawArg,
571
+ options,
572
+ width,
573
+ height,
574
+ theme ?? null,
575
+ scale ?? 1,
576
+ watermark ?? null,
577
+ );
578
+ render = await renderDesktopPaneScreenshot(payload, outputPath, apiProxy);
579
+ } finally {
580
+ apiClient.setSessionToken(previousSessionToken);
581
+ }
380
582
  const symbols = payload.financials.map(([symbol]) => symbol);
381
- const rowCount = shotSemanticRowCount(resolved, payload, render.semanticUi);
382
- const unavailableSymbols = shotUnavailableSymbols(resolved, payload, render.semanticUi);
583
+ const usesLiveDomEvidence = resolved.capability.screenshotReadiness === "live-dom";
584
+ const rowCount = usesLiveDomEvidence
585
+ ? render.rows.length
586
+ : shotSemanticRowCount(resolved, payload, render.semanticUi);
587
+ const unavailableSymbols = usesLiveDomEvidence
588
+ ? []
589
+ : shotUnavailableSymbols(resolved, payload, render.semanticUi);
383
590
  const complete = unavailableSymbols.length === 0;
384
591
  const expectedText = shotExpectedText(resolved, symbols, payload);
385
592
  const normalizedVisibleText = render.visibleText.toLowerCase();
@@ -397,12 +604,21 @@ export async function renderDesktopShot({
397
604
  const semanticMismatch = missingExpectedText.length > 0
398
605
  || missingExpectedSelections.length > 0
399
606
  || chartEvidenceMismatches.length > 0;
400
- const empty = render.emptyStateDetected || rowCount === 0 || semanticMismatch;
401
- const usable = resolved.capability.botSafe
402
- && resolved.capability.screenshotReadiness === "ready"
403
- && !empty
404
- && complete
405
- && (!requiresStructuredDataEvidence(resolved) || dataEvidence !== null);
607
+ const empty = render.loadingStateDetected
608
+ || render.errorStateDetected
609
+ || render.emptyStateDetected
610
+ || rowCount === 0
611
+ || semanticMismatch;
612
+ const usable = isPaneScreenshotUsable({
613
+ rowCount,
614
+ loadingStateDetected: render.loadingStateDetected,
615
+ errorStateDetected: render.errorStateDetected,
616
+ emptyStateDetected: render.emptyStateDetected,
617
+ complete,
618
+ semanticMismatch,
619
+ requiresStructuredDataEvidence: requiresStructuredDataEvidence(resolved),
620
+ hasStructuredDataEvidence: dataEvidence !== null,
621
+ });
406
622
  return {
407
623
  kind: "pane-screenshot",
408
624
  target: resolved.token,
@@ -414,7 +630,7 @@ export async function renderDesktopShot({
414
630
  screenshotReadiness: resolved.capability.screenshotReadiness,
415
631
  },
416
632
  symbols,
417
- options: resolved.options,
633
+ options: stripDesktopShotCredentials(resolved.options),
418
634
  rowCount,
419
635
  empty,
420
636
  complete,
@@ -424,7 +640,7 @@ export async function renderDesktopShot({
424
640
  dataEvidence,
425
641
  outputPath,
426
642
  render: {
427
- ...render,
643
+ ...stripDesktopShotCredentials(render),
428
644
  expectedText,
429
645
  missingExpectedText,
430
646
  expectedSelections,
@@ -0,0 +1,34 @@
1
+ import { saveConfig } from "../data/config/store";
2
+ import { loadCliConfigIfAvailable } from "./context";
3
+ import { seedExtractedPlugins } from "../plugins/seed";
4
+ import { debugLog } from "../utils/debug-log";
5
+
6
+ const log = debugLog.createLogger("plugin-seed");
7
+
8
+ /**
9
+ * Reinstalls plugins that moved out of this repository into their own.
10
+ *
11
+ * Runs before the plugin catalog is read so a restored plugin is available in
12
+ * the same session, and stays quiet on failure: an offline launch should start
13
+ * normally and try again next time, not block on a network request.
14
+ */
15
+ export async function restoreExtractedPlugins(): Promise<void> {
16
+ try {
17
+ const config = await loadCliConfigIfAvailable();
18
+ // No data directory yet means a first run: there is nothing to restore.
19
+ if (!config) return;
20
+ const { installPlugin } = await import("./commands/plugins");
21
+ const result = await seedExtractedPlugins(config, installPlugin);
22
+
23
+ const seeded = [...new Set(result.seeded)].sort();
24
+ const existing = [...new Set(config.seededPlugins ?? [])].sort();
25
+ if (seeded.join() === existing.join()) return;
26
+
27
+ await saveConfig({ ...config, seededPlugins: seeded });
28
+ if (result.installed.length > 0) {
29
+ log.info(`Restored ${result.installed.join(", ")} into ~/.gloomberb/plugins`);
30
+ }
31
+ } catch (error) {
32
+ log.error(`Plugin restore skipped: ${error}`);
33
+ }
34
+ }
@@ -4,9 +4,9 @@ import {
4
4
  UiHostProvider,
5
5
  type RendererHost,
6
6
  type UiHost,
7
- } from "../../../../ui";
8
- import { WebBox } from "../../../../renderers/electrobun/view/host/box";
9
- import { WebText } from "../../../../renderers/electrobun/view/host/text";
7
+ } from "../../../ui";
8
+ import { WebBox } from "../../../renderers/electrobun/view/host/box";
9
+ import { WebText } from "../../../renderers/electrobun/view/host/text";
10
10
  import { StaticXAxisLabels } from "./axis-overlays";
11
11
 
12
12
  const renderer: RendererHost = {
@@ -1,19 +1,14 @@
1
- import { Box, Text, useUiCapabilities, useUiHost } from "../../../../ui";
1
+ import { Box, Text, useUiCapabilities, useUiHost } from "../../../ui";
2
+ import type { CompositeChartXMarker } from "./types";
2
3
 
3
- export interface StaticChartXMarker {
4
- id: string;
5
- xRatio: number;
6
- label?: string;
7
- color?: string;
8
- lineChar?: string;
9
- }
4
+ export type StaticChartXMarker = CompositeChartXMarker;
10
5
 
11
6
  export interface StaticChartXAxisLabel {
12
7
  label: string;
13
8
  ratio: number;
14
9
  }
15
10
 
16
- export function clampRatio(value: number): number {
11
+ function clampRatio(value: number): number {
17
12
  if (!Number.isFinite(value)) return 0;
18
13
  return Math.max(0, Math.min(1, value));
19
14
  }
@@ -222,7 +217,7 @@ export function StaticXMarkerOverlay({
222
217
  height,
223
218
  fallbackColor,
224
219
  }: {
225
- markers: StaticChartXMarker[];
220
+ markers: readonly StaticChartXMarker[];
226
221
  width: number;
227
222
  height: number;
228
223
  fallbackColor?: string;
@@ -288,7 +283,7 @@ export function StaticXMarkerLabels({
288
283
  width,
289
284
  fallbackColor,
290
285
  }: {
291
- markers: StaticChartXMarker[];
286
+ markers: readonly StaticChartXMarker[];
292
287
  width: number;
293
288
  fallbackColor?: string;
294
289
  }) {
@@ -1,6 +1,9 @@
1
1
  import { useMemo } from "react";
2
- import { useNativeRenderer, useUiCapabilities } from "../../../../ui";
3
- import { resolveNativeBitmapSize, shouldRenderNativeBitmap } from "../../native/bitmap-support";
2
+ import { useNativeRenderer, useUiCapabilities } from "../../../ui";
3
+ import { useOptionalAppSelector } from "../../../state/app/context";
4
+ import type { ChartRendererPreference } from "../core/types";
5
+ import { resolveNativeBitmapSize, shouldRenderNativeBitmap } from "../native/bitmap-support";
6
+ import { useResolvedChartRendererState } from "../native/renderer-selection";
4
7
 
5
8
  export interface StaticChartBitmapSize {
6
9
  pixelWidth: number;
@@ -16,13 +19,22 @@ export function useStaticChartBitmapSize(width: number, height: number): StaticC
16
19
  pixelRatio = 1,
17
20
  } = useUiCapabilities();
18
21
  const nativeRenderer = useNativeRenderer();
22
+ const preferredRenderer = useOptionalAppSelector<ChartRendererPreference | null>(
23
+ (state) => state.config.chartPreferences.renderer,
24
+ null,
25
+ );
26
+ const rendererState = useResolvedChartRendererState(
27
+ nativeCharts === true ? preferredRenderer ?? "auto" : "braille",
28
+ nativeRenderer,
29
+ );
19
30
  const rendererCapabilities = nativeRenderer.capabilities;
20
31
  const rendererResolution = nativeRenderer.resolution;
21
32
  const rendererTerminalWidth = nativeRenderer.terminalWidth;
22
33
  const rendererTerminalHeight = nativeRenderer.terminalHeight;
23
34
 
24
35
  return useMemo(() => {
25
- if (shouldRenderNativeBitmap(nativeRenderer, nativeCharts === true)) {
36
+ const nativeRendererActive = preferredRenderer === null || rendererState.renderer === "kitty";
37
+ if (nativeRendererActive && shouldRenderNativeBitmap(nativeRenderer, nativeCharts === true)) {
26
38
  return resolveNativeBitmapSize({
27
39
  width,
28
40
  height,
@@ -48,8 +60,10 @@ export function useStaticChartBitmapSize(width: number, height: number): StaticC
48
60
  nativeCharts,
49
61
  nativeRenderer,
50
62
  pixelRatio,
63
+ preferredRenderer,
51
64
  rendererCapabilities,
52
65
  rendererResolution,
66
+ rendererState.renderer,
53
67
  rendererTerminalHeight,
54
68
  rendererTerminalWidth,
55
69
  width,