gloomberb 0.10.0 → 0.10.2

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 (353) hide show
  1. package/package.json +8 -1
  2. package/src/api-client/auth.ts +1 -0
  3. package/src/api-client/index.test.ts +359 -108
  4. package/src/api-client/index.ts +24 -13
  5. package/src/api-client/socket.ts +70 -35
  6. package/src/api-client/types.ts +1 -1
  7. package/src/app/language-observer.test.tsx +82 -0
  8. package/src/app/language-observer.tsx +13 -0
  9. package/src/app/pane-runtime/index.tsx +2 -2
  10. package/src/app/pane-runtime/pane-settings-runtime.tsx +2 -2
  11. package/src/app/pane-runtime/pane-template-runtime.ts +2 -2
  12. package/src/app/pane-runtime/plugin-bindings.ts +2 -2
  13. package/src/app/pane-runtime/ticker-open-runtime.ts +2 -2
  14. package/src/app/runtime/broker-import.ts +2 -2
  15. package/src/app/runtime/plugin-bindings.ts +2 -2
  16. package/src/app/runtime/startup.ts +2 -2
  17. package/src/app.tsx +16 -7
  18. package/src/brokers/account-cache.ts +6 -6
  19. package/src/brokers/broker-ticker-sync.ts +3 -3
  20. package/src/brokers/remote-broker-adapter.ts +2 -2
  21. package/src/brokers/sync-broker-instance.ts +5 -6
  22. package/src/cli/commands/api.ts +3 -6
  23. package/src/cli/commands/automation.ts +7 -15
  24. package/src/cli/commands/market.ts +26 -61
  25. package/src/cli/commands/overview.ts +34 -45
  26. package/src/cli/commands/search.ts +25 -27
  27. package/src/cli/commands/system.ts +27 -57
  28. package/src/cli/commands/ticker.ts +62 -63
  29. package/src/cli/context.test.ts +63 -0
  30. package/src/cli/context.ts +15 -1
  31. package/src/cli/index.ts +1 -1
  32. package/src/cli/pane-functions/data.ts +2 -19
  33. package/src/cli/pane-functions/index.ts +26 -25
  34. package/src/cli/pane-functions/report.ts +1 -1
  35. package/src/cli/pane-functions/screenshot.ts +3 -3
  36. package/src/cli/scoped-context.ts +41 -0
  37. package/src/components/chart/composite/composite-chart.test.tsx +615 -18
  38. package/src/components/chart/composite/composite-chart.tsx +179 -79
  39. package/src/components/chart/composite/format.test.ts +20 -7
  40. package/src/components/chart/composite/index.ts +0 -21
  41. package/src/components/chart/composite/interactions.test.ts +90 -3
  42. package/src/components/chart/composite/interactions.ts +189 -24
  43. package/src/components/chart/composite/price-series.ts +0 -2
  44. package/src/components/chart/composite/rasterizer.ts +10 -9
  45. package/src/components/chart/composite/renderers.test.ts +108 -2
  46. package/src/components/chart/composite/scene.test.ts +36 -0
  47. package/src/components/chart/composite/scene.ts +5 -2
  48. package/src/components/chart/composite/text-renderer.ts +37 -25
  49. package/src/components/chart/composite/time-axis.test.ts +243 -0
  50. package/src/components/chart/composite/time-axis.ts +608 -0
  51. package/src/components/chart/composite/types.ts +12 -1
  52. package/src/components/chart/core/data.ts +2 -159
  53. package/src/components/chart/core/date-window.ts +6 -225
  54. package/src/components/chart/core/palette.ts +1 -12
  55. package/src/components/chart/core/pointer.ts +0 -142
  56. package/src/components/chart/core/types.ts +1 -58
  57. package/src/components/chart/cursor-motion.ts +2 -4
  58. package/src/components/chart/indicators/types.ts +0 -9
  59. package/src/components/chart/market-session.ts +0 -11
  60. package/src/components/chart/native/kitty/protocol.ts +1 -1
  61. package/src/components/chart/native/raster/layout.ts +3 -10
  62. package/src/components/chart/static/chart/axis-overlays.test.tsx +64 -0
  63. package/src/components/chart/static/chart/axis-overlays.tsx +59 -14
  64. package/src/components/chart/static/chart/surface.tsx +1 -2
  65. package/src/components/command-bar/action-runtime.ts +2 -2
  66. package/src/components/command-bar/commands/direct/index.ts +1 -1
  67. package/src/components/command-bar/panel/body.tsx +2 -2
  68. package/src/components/command-bar/panel/index.tsx +11 -9
  69. package/src/components/command-bar/routes/ticker-search/actions.ts +2 -2
  70. package/src/components/command-bar/surface/index.tsx +2 -2
  71. package/src/components/command-bar/workflow/body.tsx +3 -3
  72. package/src/components/command-bar/workflow/collection-actions.ts +2 -2
  73. package/src/components/command-bar/workflow/coordinator.ts +2 -2
  74. package/src/components/command-bar/workflow/field-row.tsx +25 -11
  75. package/src/components/command-bar/workflow/tickers.ts +2 -2
  76. package/src/components/feed-data-table/stack-view.test.tsx +28 -36
  77. package/src/components/feed-data-table/stack-view.tsx +3 -1
  78. package/src/components/layout/detached-pane-shell.tsx +6 -6
  79. package/src/components/layout/header.tsx +13 -9
  80. package/src/components/layout/pane/content.test.tsx +42 -3
  81. package/src/components/layout/pane/content.tsx +3 -1
  82. package/src/components/layout/pane/footer/index.test.tsx +45 -2
  83. package/src/components/layout/pane/footer/registration.tsx +3 -1
  84. package/src/components/layout/shell/index.tsx +1 -2
  85. package/src/components/layout/shell/native/surfaces.ts +1 -1
  86. package/src/components/layout/shell/native/window-state.ts +1 -1
  87. package/src/components/layout/status-bar.tsx +12 -8
  88. package/src/components/layout/window-controls.tsx +8 -6
  89. package/src/components/onboarding/onboarding-wizard.tsx +3 -1
  90. package/src/components/pane-settings-dialog/desktop.tsx +0 -2
  91. package/src/components/pane-settings-dialog.tsx +0 -2
  92. package/src/components/pane-template-wizard.tsx +10 -9
  93. package/src/components/price-performance.tsx +2 -113
  94. package/src/components/price-sparkline/model.ts +15 -17
  95. package/src/components/price-sparkline/view.tsx +8 -7
  96. package/src/components/speedometer-gauge/desktop.tsx +2 -1
  97. package/src/components/speedometer-gauge/index.tsx +0 -2
  98. package/src/components/speedometer-gauge/terminal.tsx +24 -5
  99. package/src/components/ticker/badge/index.tsx +1 -18
  100. package/src/components/ui/data-table/opentui/index.tsx +3 -3
  101. package/src/components/ui/frame.tsx +1 -2
  102. package/src/components/ui/page-stack-view.test.tsx +126 -0
  103. package/src/components/ui/page-stack-view.tsx +24 -12
  104. package/src/components/ui/tabs.tsx +7 -3
  105. package/src/components/ui/ui.test.tsx +23 -2
  106. package/src/components/use-external-link-footer.ts +4 -2
  107. package/src/core/app-service-ports.ts +46 -0
  108. package/src/core/app-services.test.ts +66 -0
  109. package/src/core/app-services.ts +17 -15
  110. package/src/data/config/chart-settings.ts +3 -10
  111. package/src/data/config/store/index.test.ts +99 -2
  112. package/src/data/config/store/migrations.ts +278 -0
  113. package/src/data/config/store/normalize.ts +44 -186
  114. package/src/data/resource-store.ts +73 -12
  115. package/src/data/sqlite/cache.test.ts +104 -15
  116. package/src/i18n/index.test.ts +17 -0
  117. package/src/i18n/index.ts +23 -6
  118. package/src/i18n/ja.ts +13 -0
  119. package/src/i18n/ko.ts +13 -0
  120. package/src/i18n/react.ts +6 -0
  121. package/src/i18n/zh-cn.ts +13 -0
  122. package/src/i18n/zh-tw.ts +13 -0
  123. package/src/market-data/coordinator/auxiliary.ts +7 -3
  124. package/src/market-data/coordinator/chart.ts +1 -1
  125. package/src/market-data/coordinator/index.test.ts +26 -0
  126. package/src/market-data/coordinator/index.ts +11 -5
  127. package/src/market-data/coordinator/quotes.ts +4 -40
  128. package/src/market-data/coordinator/subscriptions.test.ts +89 -1
  129. package/src/market-data/hooks.tsx +47 -1
  130. package/src/market-data/market/status.ts +6 -6
  131. package/src/market-data/performance.ts +1 -1
  132. package/src/market-data/quote-subscription-target.test.ts +37 -0
  133. package/src/market-data/quote-subscription-target.ts +60 -0
  134. package/src/market-data/quotes/freshness.ts +1 -0
  135. package/src/market-data/quotes/resolution.ts +4 -0
  136. package/src/market-data/request-types.ts +3 -3
  137. package/src/news/aggregator.test.ts +97 -1
  138. package/src/news/aggregator.ts +100 -57
  139. package/src/news/hooks.test.tsx +64 -0
  140. package/src/news/hooks.ts +18 -25
  141. package/src/plugins/builtin/account-management/footer.ts +4 -2
  142. package/src/plugins/builtin/account-management/pane.tsx +9 -4
  143. package/src/plugins/builtin/ai/agent-history.ts +11 -7
  144. package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +0 -5
  145. package/src/plugins/builtin/ai/ask-ai.test.tsx +3 -4
  146. package/src/plugins/builtin/ai/index.test.ts +2 -2
  147. package/src/plugins/builtin/ai/index.tsx +10 -11
  148. package/src/plugins/builtin/ai/pane-settings.ts +1 -1
  149. package/src/plugins/builtin/ai/pi/runtime.ts +6 -5
  150. package/src/plugins/builtin/ai/providers.ts +1 -9
  151. package/src/plugins/builtin/ai/runner.ts +0 -6
  152. package/src/plugins/builtin/ai/screener/footer.ts +4 -1
  153. package/src/plugins/builtin/ai/screener/pane.test.tsx +9 -9
  154. package/src/plugins/builtin/ai/workspace/model.ts +2 -27
  155. package/src/plugins/builtin/ai/workspace/pane.tsx +2 -2
  156. package/src/plugins/builtin/analytics/metrics.ts +1 -7
  157. package/src/plugins/builtin/broker-manager/detail.tsx +3 -2
  158. package/src/plugins/builtin/broker-manager/index.tsx +4 -2
  159. package/src/plugins/builtin/chart-composer/editor/controller.ts +643 -0
  160. package/src/plugins/builtin/chart-composer/editor/desktop-view.tsx +134 -0
  161. package/src/plugins/builtin/chart-composer/editor/model.test.ts +85 -0
  162. package/src/plugins/builtin/chart-composer/editor/model.ts +292 -0
  163. package/src/plugins/builtin/chart-composer/editor/opentui-view.tsx +108 -0
  164. package/src/plugins/builtin/chart-composer/editor.tsx +65 -947
  165. package/src/plugins/builtin/chart-composer/index.tsx +0 -6
  166. package/src/plugins/builtin/chart-composer/pane.tsx +69 -36
  167. package/src/plugins/builtin/chart-composer/presets.ts +1 -19
  168. package/src/plugins/builtin/chart-composer/settings.ts +1 -1
  169. package/src/plugins/builtin/chat/content/composer-runtime.ts +1 -1
  170. package/src/plugins/builtin/chat/content/shortcuts.ts +0 -1
  171. package/src/plugins/builtin/chat/controller/fetch.ts +8 -2
  172. package/src/plugins/builtin/chat/controller/persistence.ts +2 -0
  173. package/src/plugins/builtin/chat/controller/session.test.ts +25 -0
  174. package/src/plugins/builtin/chat/controller/session.ts +2 -0
  175. package/src/plugins/builtin/chat/controller/state.ts +7 -0
  176. package/src/plugins/builtin/chat/controller.test.ts +73 -20
  177. package/src/plugins/builtin/chat/message/desktop.tsx +2 -0
  178. package/src/plugins/builtin/cloud-tweets/footer.ts +9 -28
  179. package/src/plugins/builtin/cloud-tweets/pane.tsx +0 -5
  180. package/src/plugins/builtin/cloud-tweets/table.tsx +12 -17
  181. package/src/plugins/builtin/correlation/compute.ts +4 -10
  182. package/src/plugins/builtin/econ/index.tsx +17 -19
  183. package/src/plugins/builtin/holders/types.ts +0 -1
  184. package/src/plugins/builtin/insider/index.tsx +6 -31
  185. package/src/plugins/builtin/news/index.tsx +5 -7
  186. package/src/plugins/builtin/news/wire/breaking/pane.test.tsx +6 -8
  187. package/src/plugins/builtin/news/wire/news/footer.ts +10 -11
  188. package/src/plugins/builtin/news/wire/read-state.test.ts +7 -0
  189. package/src/plugins/builtin/news/wire/read-state.ts +18 -28
  190. package/src/plugins/builtin/news/wire/rss/parser.ts +1 -11
  191. package/src/plugins/builtin/options/footer.test.ts +115 -0
  192. package/src/plugins/builtin/options/footer.ts +110 -0
  193. package/src/plugins/builtin/options/live-quotes.test.ts +238 -0
  194. package/src/plugins/builtin/options/live-quotes.ts +147 -0
  195. package/src/plugins/builtin/options/view.test.tsx +71 -1
  196. package/src/plugins/builtin/options/view.tsx +39 -24
  197. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +103 -117
  198. package/src/plugins/builtin/portfolio-list/cli/render.ts +11 -5
  199. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +120 -135
  200. package/src/plugins/builtin/portfolio-list/header.tsx +9 -4
  201. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +6 -1
  202. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +4 -2
  203. package/src/plugins/builtin/research/corporate-actions-pane.tsx +24 -52
  204. package/src/plugins/builtin/sec/filing-content.test.ts +41 -0
  205. package/src/plugins/builtin/sec/filing-content.ts +94 -0
  206. package/src/plugins/builtin/sec/index.tsx +21 -104
  207. package/src/plugins/builtin/sectors/sector-model.ts +1 -7
  208. package/src/plugins/builtin/shared/cloud-upgrade.ts +1 -0
  209. package/src/plugins/builtin/shared/pane-footer.ts +82 -0
  210. package/src/plugins/builtin/shared/read-state.ts +64 -3
  211. package/src/plugins/builtin/substack/read-state.ts +16 -41
  212. package/src/plugins/builtin/thirteenf/pane.tsx +24 -73
  213. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +10 -10
  214. package/src/plugins/builtin/yield-curve/index.tsx +11 -9
  215. package/src/plugins/ibkr/dialogs.tsx +3 -3
  216. package/src/plugins/ibkr/gateway/fundamentals.ts +1 -1
  217. package/src/plugins/ibkr/gateway/history-requests.ts +2 -2
  218. package/src/plugins/ibkr/gateway/history.ts +2 -2
  219. package/src/plugins/ibkr/gateway/selection.ts +2 -2
  220. package/src/plugins/ibkr/gateway/service/index.ts +2 -2
  221. package/src/plugins/ibkr/gateway/service/native.ts +2 -2
  222. package/src/plugins/plugin-persistence.ts +3 -4
  223. package/src/plugins/prediction-markets/controller/keyboard.ts +1 -1
  224. package/src/plugins/prediction-markets/controller/live-updates.ts +6 -5
  225. package/src/plugins/prediction-markets/detail/book.tsx +2 -2
  226. package/src/plugins/prediction-markets/detail/outcomes.tsx +3 -1
  227. package/src/plugins/prediction-markets/detail/pane.tsx +3 -1
  228. package/src/plugins/prediction-markets/detail/trades.tsx +3 -3
  229. package/src/plugins/registry/context.ts +3 -4
  230. package/src/plugins/registry/index.ts +5 -6
  231. package/src/react/input.test.ts +126 -3
  232. package/src/react/input.ts +120 -1
  233. package/src/remote/app-host.tsx +2 -13
  234. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +44 -60
  235. package/src/renderers/electrobun/bun/desktop/capability-bridge.ts +15 -13
  236. package/src/renderers/electrobun/bun/desktop/host-requests.ts +26 -22
  237. package/src/renderers/electrobun/bun/desktop/http-fetch.ts +5 -1
  238. package/src/renderers/electrobun/bun/desktop/initialization.ts +11 -6
  239. package/src/renderers/electrobun/bun/desktop/media.ts +5 -3
  240. package/src/renderers/electrobun/bun/desktop/plugin-state.ts +21 -22
  241. package/src/renderers/electrobun/bun/desktop/window-controls.ts +3 -1
  242. package/src/renderers/electrobun/bun/desktop/workspace/requests.ts +18 -18
  243. package/src/renderers/electrobun/bun/index.ts +123 -83
  244. package/src/renderers/electrobun/shared/protocol.ts +146 -7
  245. package/src/renderers/electrobun/view/app-services.ts +5 -8
  246. package/src/renderers/electrobun/view/backend-rpc.ts +18 -8
  247. package/src/renderers/electrobun/view/broker-remote-client.ts +2 -2
  248. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +5 -22
  249. package/src/renderers/electrobun/view/config-host.ts +1 -1
  250. package/src/renderers/electrobun/view/context-menu.ts +1 -17
  251. package/src/renderers/electrobun/view/data-table/index.tsx +0 -1
  252. package/src/renderers/electrobun/view/data-table/row.tsx +0 -4
  253. package/src/renderers/electrobun/view/desktop/control-styles.ts +37 -34
  254. package/src/renderers/electrobun/view/desktop/controls.tsx +36 -33
  255. package/src/renderers/electrobun/view/desktop/list-view.tsx +15 -12
  256. package/src/renderers/electrobun/view/desktop/popover.tsx +2 -3
  257. package/src/renderers/electrobun/view/dialog-host.tsx +2 -3
  258. package/src/renderers/electrobun/view/fatal-screen.tsx +0 -1
  259. package/src/renderers/electrobun/view/host/box.tsx +0 -1
  260. package/src/renderers/electrobun/view/host/chart-surface.tsx +0 -1
  261. package/src/renderers/electrobun/view/host/input.tsx +0 -1
  262. package/src/renderers/electrobun/view/host/media-surface.tsx +0 -1
  263. package/src/renderers/electrobun/view/host/native.ts +0 -1
  264. package/src/renderers/electrobun/view/host/scroll-box.tsx +0 -1
  265. package/src/renderers/electrobun/view/host/tabs.tsx +0 -1
  266. package/src/renderers/electrobun/view/host/text.tsx +0 -1
  267. package/src/renderers/electrobun/view/http-fetch.ts +3 -11
  268. package/src/renderers/electrobun/view/input-host.tsx +10 -53
  269. package/src/renderers/electrobun/view/key-event.ts +0 -1
  270. package/src/renderers/electrobun/view/main.tsx +3 -3
  271. package/src/renderers/electrobun/view/native-renderer.ts +0 -1
  272. package/src/renderers/electrobun/view/native-stubs/backend-rpc.ts +13 -1
  273. package/src/renderers/electrobun/view/native-stubs/chart/surface-manager.ts +11 -0
  274. package/src/renderers/electrobun/view/native-stubs/native-stubs.test.ts +47 -0
  275. package/src/renderers/electrobun/view/remote/asset-data-client.ts +6 -44
  276. package/src/renderers/electrobun/view/remote/persistence.ts +6 -2
  277. package/src/renderers/electrobun/view/remote/quote-subscription-registry.test.ts +86 -0
  278. package/src/renderers/electrobun/view/remote/quote-subscription-registry.ts +72 -0
  279. package/src/renderers/electrobun/view/remote/ticker-repository.ts +2 -2
  280. package/src/renderers/electrobun/view/toast-host.tsx +0 -1
  281. package/src/renderers/electrobun/view/ui-host.tsx +1 -2
  282. package/src/renderers/electrobun/view/update-host.ts +1 -1
  283. package/src/renderers/opentui/chart-surface.tsx +2 -1
  284. package/src/renderers/opentui/dialog-host.tsx +20 -4
  285. package/src/renderers/opentui/image/loader.ts +12 -2
  286. package/src/renderers/opentui/input-host.tsx +7 -49
  287. package/src/renderers/opentui/start.tsx +2 -0
  288. package/src/sources/gloomberb-cloud/history-quality.ts +44 -0
  289. package/src/sources/gloomberb-cloud/index.test.ts +173 -0
  290. package/src/sources/gloomberb-cloud/index.ts +42 -20
  291. package/src/sources/gloomberb-cloud/normalizers.ts +9 -3
  292. package/src/sources/provider-router/cache.ts +1 -1
  293. package/src/sources/provider-router/document-routes.ts +10 -5
  294. package/src/sources/provider-router/financials.test.ts +14 -0
  295. package/src/sources/provider-router/financials.ts +6 -1
  296. package/src/sources/provider-router/history.test.ts +163 -1
  297. package/src/sources/provider-router/history.ts +278 -347
  298. package/src/sources/provider-router/index.ts +2 -2
  299. package/src/sources/provider-router/routing.test.ts +39 -0
  300. package/src/sources/provider-router/routing.ts +24 -11
  301. package/src/sources/provider-router/supplemental.ts +37 -17
  302. package/src/sources/sec-edgar/content.ts +2 -12
  303. package/src/sources/sec-edgar.ts +2 -13
  304. package/src/sources/yahoo-finance/history.ts +2 -2
  305. package/src/sources/yahoo-finance/options.ts +5 -0
  306. package/src/sources/yahoo-finance.ts +2 -2
  307. package/src/state/app/bootstrap.ts +2 -2
  308. package/src/state/app/context/index.tsx +2 -2
  309. package/src/state/hooks/quote-streaming.ts +66 -1
  310. package/src/state/hooks/session-snapshot.ts +2 -2
  311. package/src/state/selectors.ts +0 -9
  312. package/src/sync/controller.test.ts +98 -0
  313. package/src/sync/controller.ts +29 -5
  314. package/src/sync/react.ts +2 -2
  315. package/src/sync/types.ts +2 -2
  316. package/src/theme/colors.test.ts +10 -0
  317. package/src/theme/colors.ts +75 -78
  318. package/src/theme/theme-context.test.tsx +67 -0
  319. package/src/theme/theme-context.tsx +9 -5
  320. package/src/tickers/open-target.ts +2 -2
  321. package/src/tickers/search/upsert.ts +2 -2
  322. package/src/time-series/alignment.ts +0 -7
  323. package/src/time-series/chart-data.ts +145 -0
  324. package/src/time-series/date-window.ts +44 -0
  325. package/src/time-series/history-window.ts +21 -0
  326. package/src/time-series/hooks.test.ts +59 -0
  327. package/src/time-series/hooks.ts +33 -12
  328. package/src/time-series/market-resolution.ts +2 -2
  329. package/src/time-series/market.ts +1 -1
  330. package/src/time-series/range.ts +9 -0
  331. package/src/{components/chart/core → time-series}/resolution.ts +3 -102
  332. package/src/time-series/resolve.test.ts +203 -1
  333. package/src/time-series/resolve.ts +96 -18
  334. package/src/time-series/spec-studies.test.ts +15 -0
  335. package/src/time-series/spec.ts +2 -2
  336. package/src/time-series/studies.ts +5 -2
  337. package/src/time-series/types.ts +3 -1
  338. package/src/time-series/use-chart-resolution.test.tsx +358 -0
  339. package/src/time-series/use-chart-resolution.ts +46 -4
  340. package/src/types/broker.ts +2 -2
  341. package/src/types/data-provider.ts +3 -3
  342. package/src/types/financials.ts +12 -0
  343. package/src/types/plugin.ts +2 -2
  344. package/src/ui/context-menu.tsx +3 -2
  345. package/src/ui/dialog.tsx +2 -2
  346. package/src/utils/html-entities.ts +3 -5
  347. package/src/utils/main-thread-monitor.ts +1 -1
  348. package/src/utils/price-history.ts +5 -5
  349. package/src/version.ts +3 -1
  350. package/src/components/chart/core/viewport.test.ts +0 -8
  351. package/src/components/chart/core/viewport.ts +0 -24
  352. package/src/time-series/index.ts +0 -14
  353. /package/src/{components/chart/core → time-series}/resolution.test.ts +0 -0
@@ -1,4 +1,5 @@
1
1
  import type { CliCommandDef } from "../../types/plugin";
2
+ import { withCliServices } from "../context";
2
3
  import { parseJsonPayload, requireArg, takeOption } from "./command-utils";
3
4
 
4
5
  function splitOperationTarget(target: string): { capabilityId: string; operationId: string } {
@@ -34,9 +35,7 @@ export const apiCliCommand: CliCommandDef = {
34
35
  execute: async (rawArgs, ctx) => {
35
36
  const action = rawArgs[0] ?? "list";
36
37
  const args = rawArgs.slice(1);
37
- const services = await ctx.initServices();
38
-
39
- try {
38
+ await withCliServices(ctx, async (services) => {
40
39
  if (action === "list") {
41
40
  const kind = takeOption(args, "--kind");
42
41
  const manifests = services.services.pluginRegistry.capabilities
@@ -112,8 +111,6 @@ export const apiCliCommand: CliCommandDef = {
112
111
  }
113
112
 
114
113
  ctx.fail("Usage: gloomberb api list|get|invoke|subscribe");
115
- } finally {
116
- services.destroy();
117
- }
114
+ });
118
115
  },
119
116
  };
@@ -10,6 +10,7 @@ import {
10
10
  } from "../../plugins/builtin/ai/providers";
11
11
  import { createRssNewsCapability } from "../../plugins/builtin/news/wire/rss/source";
12
12
  import type { CliCommandDef } from "../../types/plugin";
13
+ import { withCliServices, withConfigData } from "../context";
13
14
  import { requireArg, takeOption } from "./command-utils";
14
15
 
15
16
  function deferredResult(command: string, code: "auth_required" | "not_implemented", message: string) {
@@ -28,8 +29,7 @@ export const brokerCliCommand: CliCommandDef = {
28
29
  help: { usage: ["broker list", "broker status", "broker add|edit|remove|connect|sync"] },
29
30
  execute: async (args, ctx) => {
30
31
  const action = args[0] ?? "list";
31
- const services = await ctx.initServices();
32
- try {
32
+ await withCliServices(ctx, async (services) => {
33
33
  if (action === "list" || action === "status") {
34
34
  const rows = services.config.brokerInstances.map((instance) => ({
35
35
  id: instance.id,
@@ -46,9 +46,7 @@ export const brokerCliCommand: CliCommandDef = {
46
46
  ctx.printResult({
47
47
  data: deferredResult("broker", "not_implemented", "Broker mutation and connection commands need shared non-UI broker service extraction before they can safely run headless."),
48
48
  });
49
- } finally {
50
- services.destroy();
51
- }
49
+ });
52
50
  },
53
51
  };
54
52
 
@@ -63,8 +61,7 @@ export const ibkrCliCommand: CliCommandDef = {
63
61
  if ((action === "place" || action === "cancel") && (!profile || !account || !ctx.cliOptions.yes)) {
64
62
  ctx.fail(`ibkr ${action} requires --profile, --account, and --yes.`);
65
63
  }
66
- const services = await ctx.initServices();
67
- try {
64
+ await withCliServices(ctx, async (services) => {
68
65
  const ibkrProfiles = services.config.brokerInstances.filter((instance) => instance.brokerType === "ibkr");
69
66
  if (action === "accounts" || action === "status") {
70
67
  ctx.printResult({ data: ibkrProfiles.map((instance) => ({
@@ -86,9 +83,7 @@ export const ibkrCliCommand: CliCommandDef = {
86
83
  confirmed: ctx.cliOptions.yes,
87
84
  },
88
85
  });
89
- } finally {
90
- services.destroy();
91
- }
86
+ });
92
87
  },
93
88
  };
94
89
 
@@ -161,8 +156,7 @@ export function createAiCliCommand(options: CreateAiCliCommandOptions = {}): Cli
161
156
  ctx.fail("Usage: gloomberb ai ask [--provider id] [--model id] <prompt>");
162
157
  }
163
158
 
164
- const context = await ctx.initConfigData();
165
- try {
159
+ await withConfigData(ctx, async (context) => {
166
160
  const runtime = createRuntime(context.dataDir);
167
161
  const catalog = await runtime.getCatalog();
168
162
  if (action === "providers") {
@@ -229,9 +223,7 @@ export function createAiCliCommand(options: CreateAiCliCommandOptions = {}): Cli
229
223
  text,
230
224
  },
231
225
  });
232
- } finally {
233
- context.persistence.close();
234
- }
226
+ });
235
227
  },
236
228
  };
237
229
  }
@@ -1,5 +1,5 @@
1
1
  import type { CliCommandDef } from "../../types/plugin";
2
- import type { TimeRange } from "../../components/chart/core/types";
2
+ import type { TimeRange } from "../../time-series/range";
3
3
  import type { EarningsEvent, QuoteBatchResult, SecFilingItem } from "../../types/data-provider";
4
4
  import type { NewsArticle, NewsFeed, NewsQuery } from "../../news/types";
5
5
  import type {
@@ -12,6 +12,7 @@ import type {
12
12
  } from "../../types/financials";
13
13
  import { formatMarketPriceWithCurrency } from "../../market-data/market/format";
14
14
  import { formatCompact } from "../../utils/format";
15
+ import { withCliServices, withMarketData } from "../context";
15
16
  import { isoDate, parsePositiveInt, requireArg, takeOption } from "./command-utils";
16
17
 
17
18
  const VALID_RANGES = new Set<TimeRange>(["1D", "1W", "1M", "3M", "6M", "1Y", "5Y", "ALL"]);
@@ -202,8 +203,7 @@ async function runQuote(rawArgs: string[], ctx: Parameters<CliCommandDef["execut
202
203
  const symbols = normalizeSymbols(args);
203
204
  if (symbols.length === 0) ctx.fail("Usage: gloomberb quote <symbol...>");
204
205
 
205
- const market = await ctx.initMarketData();
206
- try {
206
+ await withMarketData(ctx, async (market) => {
207
207
  const results = await market.dataProvider.getQuotesBatch(
208
208
  symbols.map((symbol) => ({ symbol, exchange })),
209
209
  { forceRefresh: ctx.cliOptions.refresh },
@@ -214,9 +214,7 @@ async function runQuote(rawArgs: string[], ctx: Parameters<CliCommandDef["execut
214
214
  error: errorMessage(result.error),
215
215
  }));
216
216
  ctx.printResult({ data }, { rows: quoteRows, columns: quoteColumns() });
217
- } finally {
218
- market.persistence.close();
219
- }
217
+ });
220
218
  }
221
219
 
222
220
  async function runHistory(rawArgs: string[], ctx: Parameters<CliCommandDef["execute"]>[1]) {
@@ -224,8 +222,7 @@ async function runHistory(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
224
222
  const range = parseRange(takeOption(args, "--range"));
225
223
  const requestedExchange = takeOption(args, "--exchange") ?? "";
226
224
  const symbol = requireArg(args[0]?.toUpperCase(), "Usage: gloomberb history <symbol> [--range 1Y]", ctx);
227
- const market = await ctx.initMarketData();
228
- try {
225
+ await withMarketData(ctx, async (market) => {
229
226
  const localTicker = requestedExchange ? null : await market.store.loadTicker(symbol);
230
227
  const exchange = requestedExchange || localTicker?.metadata.exchange || "";
231
228
  const points = await market.dataProvider.getPriceHistory(symbol, exchange, range);
@@ -240,17 +237,14 @@ async function runHistory(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
240
237
  { key: "volume", header: "Volume", align: "right" },
241
238
  ],
242
239
  });
243
- } finally {
244
- market.persistence.close();
245
- }
240
+ });
246
241
  }
247
242
 
248
243
  async function runFinancials(rawArgs: string[], ctx: Parameters<CliCommandDef["execute"]>[1], fundamentalsOnly = false) {
249
244
  const args = [...rawArgs];
250
245
  const exchange = takeOption(args, "--exchange") ?? "";
251
246
  const symbol = requireArg(args[0]?.toUpperCase(), fundamentalsOnly ? "Usage: gloomberb fundamentals <symbol>" : "Usage: gloomberb financials <symbol>", ctx);
252
- const market = await ctx.initMarketData();
253
- try {
247
+ await withMarketData(ctx, async (market) => {
254
248
  const financials = await market.dataProvider.getTickerFinancials(symbol, exchange, {
255
249
  cacheMode: ctx.cliOptions.refresh ? "refresh" : "default",
256
250
  });
@@ -285,17 +279,14 @@ async function runFinancials(rawArgs: string[], ctx: Parameters<CliCommandDef["e
285
279
  { key: "eps", header: "EPS", align: "right" },
286
280
  ],
287
281
  });
288
- } finally {
289
- market.persistence.close();
290
- }
282
+ });
291
283
  }
292
284
 
293
285
  async function runNews(rawArgs: string[], ctx: Parameters<CliCommandDef["execute"]>[1]) {
294
286
  const args = [...rawArgs];
295
287
  const feed = parseNewsFeed(takeOption(args, "--feed"));
296
288
  const ticker = args[0]?.toUpperCase();
297
- const market = await ctx.initMarketData();
298
- try {
289
+ await withMarketData(ctx, async (market) => {
299
290
  const limit = ctx.cliOptions.limit ?? 20;
300
291
  const articles = await market.dataProvider.getNews({
301
292
  feed: feed ?? (ticker ? "ticker" : "latest"),
@@ -313,9 +304,7 @@ async function runNews(rawArgs: string[], ctx: Parameters<CliCommandDef["execute
313
304
  { key: "url", header: "URL" },
314
305
  ],
315
306
  });
316
- } finally {
317
- market.persistence.close();
318
- }
307
+ });
319
308
  }
320
309
 
321
310
  async function runFilings(rawArgs: string[], ctx: Parameters<CliCommandDef["execute"]>[1]) {
@@ -323,8 +312,7 @@ async function runFilings(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
323
312
  const count = parsePositiveInt(takeOption(args, "--count"), ctx.cliOptions.limit ?? 15, "Count", ctx);
324
313
  const exchange = takeOption(args, "--exchange") ?? "";
325
314
  const symbol = requireArg(args[0]?.toUpperCase(), "Usage: gloomberb filings <symbol>", ctx);
326
- const market = await ctx.initMarketData();
327
- try {
315
+ await withMarketData(ctx, async (market) => {
328
316
  const filings = await market.dataProvider.getSecFilings(symbol, count, exchange);
329
317
  ctx.printResult({ data: filings, metadata: { symbol } }, {
330
318
  rows: filingRows,
@@ -335,17 +323,14 @@ async function runFilings(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
335
323
  { key: "url", header: "URL" },
336
324
  ],
337
325
  });
338
- } finally {
339
- market.persistence.close();
340
- }
326
+ });
341
327
  }
342
328
 
343
329
  async function runHolders(rawArgs: string[], ctx: Parameters<CliCommandDef["execute"]>[1], ownerTypes?: Set<string>) {
344
330
  const args = [...rawArgs];
345
331
  const exchange = takeOption(args, "--exchange") ?? "";
346
332
  const symbol = requireArg(args[0]?.toUpperCase(), "Usage: gloomberb holders <symbol>", ctx);
347
- const market = await ctx.initMarketData();
348
- try {
333
+ await withMarketData(ctx, async (market) => {
349
334
  const data = await market.dataProvider.getHolders(symbol, exchange);
350
335
  ctx.printResult({ data, metadata: { symbol, summary: data.summary } }, {
351
336
  rows: (holderData) => holderRows(holderData, ownerTypes),
@@ -358,17 +343,14 @@ async function runHolders(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
358
343
  { key: "percentHeld", header: "% Held", align: "right" },
359
344
  ],
360
345
  });
361
- } finally {
362
- market.persistence.close();
363
- }
346
+ });
364
347
  }
365
348
 
366
349
  async function runAnalyst(rawArgs: string[], ctx: Parameters<CliCommandDef["execute"]>[1]) {
367
350
  const args = [...rawArgs];
368
351
  const exchange = takeOption(args, "--exchange") ?? "";
369
352
  const symbol = requireArg(args[0]?.toUpperCase(), "Usage: gloomberb analyst <symbol>", ctx);
370
- const market = await ctx.initMarketData();
371
- try {
353
+ await withMarketData(ctx, async (market) => {
372
354
  const data = await market.dataProvider.getAnalystResearch(symbol, exchange);
373
355
  ctx.printResult({
374
356
  data,
@@ -388,17 +370,14 @@ async function runAnalyst(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
388
370
  { key: "target", header: "Target", align: "right" },
389
371
  ],
390
372
  });
391
- } finally {
392
- market.persistence.close();
393
- }
373
+ });
394
374
  }
395
375
 
396
376
  async function runEvents(rawArgs: string[], ctx: Parameters<CliCommandDef["execute"]>[1]) {
397
377
  const args = [...rawArgs];
398
378
  const exchange = takeOption(args, "--exchange") ?? "";
399
379
  const symbol = requireArg(args[0]?.toUpperCase(), "Usage: gloomberb events <symbol>", ctx);
400
- const market = await ctx.initMarketData();
401
- try {
380
+ await withMarketData(ctx, async (market) => {
402
381
  const data = await market.dataProvider.getCorporateActions(symbol, exchange);
403
382
  ctx.printResult({ data, metadata: { symbol } }, {
404
383
  rows: corporateActionRows,
@@ -408,9 +387,7 @@ async function runEvents(rawArgs: string[], ctx: Parameters<CliCommandDef["execu
408
387
  { key: "detail", header: "Detail" },
409
388
  ],
410
389
  });
411
- } finally {
412
- market.persistence.close();
413
- }
390
+ });
414
391
  }
415
392
 
416
393
  async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["execute"]>[1]) {
@@ -418,8 +395,7 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
418
395
  const expiration = takeOption(args, "--expiration");
419
396
  const exchange = takeOption(args, "--exchange") ?? "";
420
397
  const symbol = requireArg(args[0]?.toUpperCase(), "Usage: gloomberb options <symbol>", ctx);
421
- const market = await ctx.initMarketData();
422
- try {
398
+ await withMarketData(ctx, async (market) => {
423
399
  const chain = await market.dataProvider.getOptionsChain(
424
400
  symbol,
425
401
  exchange,
@@ -439,15 +415,12 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
439
415
  { key: "openInterest", header: "OI", align: "right" },
440
416
  ],
441
417
  });
442
- } finally {
443
- market.persistence.close();
444
- }
418
+ });
445
419
  }
446
420
 
447
421
  async function runFx(rawArgs: string[], ctx: Parameters<CliCommandDef["execute"]>[1]) {
448
422
  const currency = requireArg(rawArgs[0]?.toUpperCase(), "Usage: gloomberb fx <currency>", ctx);
449
- const market = await ctx.initMarketData();
450
- try {
423
+ await withMarketData(ctx, async (market) => {
451
424
  const rate = await market.dataProvider.getExchangeRate(currency);
452
425
  ctx.printResult({ data: [{ currency, baseCurrency: market.config.baseCurrency, rate }] }, {
453
426
  columns: [
@@ -456,16 +429,13 @@ async function runFx(rawArgs: string[], ctx: Parameters<CliCommandDef["execute"]
456
429
  { key: "rate", header: "Rate", align: "right" },
457
430
  ],
458
431
  });
459
- } finally {
460
- market.persistence.close();
461
- }
432
+ });
462
433
  }
463
434
 
464
435
  async function runEarnings(rawArgs: string[], ctx: Parameters<CliCommandDef["execute"]>[1]) {
465
436
  const symbols = normalizeSymbols([...rawArgs]);
466
437
  if (symbols.length === 0) ctx.fail("Usage: gloomberb earnings <symbol...>");
467
- const services = await ctx.initServices();
468
- try {
438
+ await withCliServices(ctx, async (services) => {
469
439
  const events = await services.dataProvider.getEarningsCalendar(symbols);
470
440
  ctx.printResult({ data: events }, {
471
441
  rows: earningsRows,
@@ -478,9 +448,7 @@ async function runEarnings(rawArgs: string[], ctx: Parameters<CliCommandDef["exe
478
448
  { key: "epsActual", header: "EPS", align: "right" },
479
449
  ],
480
450
  });
481
- } finally {
482
- services.destroy();
483
- }
451
+ });
484
452
  }
485
453
 
486
454
  export const marketDataCliCommands: CliCommandDef[] = [
@@ -488,13 +456,10 @@ export const marketDataCliCommands: CliCommandDef[] = [
488
456
  { name: "provider-search", description: "Search provider instruments", help: { usage: ["provider-search <query>"] }, execute: async (args, ctx) => {
489
457
  const query = args.join(" ");
490
458
  if (!query) ctx.fail("Usage: gloomberb provider-search <query>");
491
- const market = await ctx.initMarketData();
492
- try {
459
+ await withMarketData(ctx, async (market) => {
493
460
  const results = await market.dataProvider.search(query);
494
461
  ctx.printResult({ data: results.slice(0, ctx.cliOptions.limit ?? results.length) });
495
- } finally {
496
- market.persistence.close();
497
- }
462
+ });
498
463
  } },
499
464
  { name: "history", description: "Fetch historical prices", help: { usage: ["history <symbol> [--range 1Y]"] }, execute: runHistory },
500
465
  { name: "financials", description: "Fetch annual financial statements", help: { usage: ["financials <symbol>"] }, execute: (args, ctx) => runFinancials(args, ctx, false) },
@@ -1,5 +1,6 @@
1
1
  import { apiClient } from "../../api-client";
2
2
  import type { CliCommandDef } from "../../types/plugin";
3
+ import { withCliServices, withConfigData } from "../context";
3
4
  import { formatCompact } from "../../utils/format";
4
5
  import { attachFearGreedPersistence, loadFearGreed, resetFearGreedPersistence } from "../../plugins/builtin/fear-greed/cache";
5
6
  import { createPluginPersistence } from "../../plugins/plugin-persistence";
@@ -43,17 +44,14 @@ async function runMoverCommand(args: string[], ctx: Parameters<CliCommandDef["ex
43
44
  const category = screenerCategory(args[0]);
44
45
  const limit = ctx.cliOptions.limit ?? 25;
45
46
  if (category === "trending") {
46
- const services = await ctx.initServices();
47
- try {
47
+ await withCliServices(ctx, async (services) => {
48
48
  const trending = await fetchTrending(limit, undefined, { forceRefresh: ctx.cliOptions.refresh });
49
49
  const results = await services.dataProvider.getQuotesBatch(
50
50
  trending.map(({ symbol }) => ({ symbol, exchange: "" })),
51
51
  { forceRefresh: ctx.cliOptions.refresh },
52
52
  );
53
53
  ctx.printResult({ data: quoteRows(results), metadata: { category } });
54
- } finally {
55
- services.destroy();
56
- }
54
+ });
57
55
  return;
58
56
  }
59
57
 
@@ -71,8 +69,7 @@ async function runMoverCommand(args: string[], ctx: Parameters<CliCommandDef["ex
71
69
  }
72
70
 
73
71
  async function runQuoteBasket(symbols: string[], ctx: Parameters<CliCommandDef["execute"]>[1], metadata: Record<string, unknown>) {
74
- const services = await ctx.initServices();
75
- try {
72
+ await withCliServices(ctx, async (services) => {
76
73
  const results = await services.dataProvider.getQuotesBatch(
77
74
  symbols.map((symbol) => ({ symbol, exchange: "" })),
78
75
  { forceRefresh: ctx.cliOptions.refresh },
@@ -86,45 +83,42 @@ async function runQuoteBasket(symbols: string[], ctx: Parameters<CliCommandDef["
86
83
  { key: "marketCap", header: "Mkt Cap", align: "right", value: (row) => row.marketCap == null ? "" : formatCompact(Number(row.marketCap)) },
87
84
  ],
88
85
  });
89
- } finally {
90
- services.destroy();
91
- }
86
+ });
92
87
  }
93
88
 
94
89
  async function runFearGreed(_args: string[], ctx: Parameters<CliCommandDef["execute"]>[1]) {
95
- const context = await ctx.initConfigData();
96
- attachFearGreedPersistence(createPluginPersistence(
97
- context.persistence.pluginState,
98
- context.persistence.resources,
99
- "plugin:fear-greed",
100
- "fear-greed",
101
- ));
102
- try {
103
- const data = await loadFearGreed(ctx.cliOptions.refresh);
104
- ctx.printResult({
105
- data: [{
106
- score: data.overall.score,
107
- rating: data.overall.rating,
108
- updatedAt: data.overall.updatedAt?.toISOString() ?? "",
109
- previousClose: data.overall.previousClose,
110
- previousWeek: data.overall.previousWeek,
111
- previousMonth: data.overall.previousMonth,
112
- previousYear: data.overall.previousYear,
113
- }],
114
- metadata: { indicators: data.indicators.map((indicator) => ({ id: indicator.definition.id, score: indicator.score, rating: indicator.rating })) },
115
- });
116
- } finally {
117
- resetFearGreedPersistence();
118
- context.persistence.close();
119
- }
90
+ await withConfigData(ctx, async (context) => {
91
+ attachFearGreedPersistence(createPluginPersistence(
92
+ context.persistence.pluginState,
93
+ context.persistence.resources,
94
+ "plugin:fear-greed",
95
+ "fear-greed",
96
+ ));
97
+ try {
98
+ const data = await loadFearGreed(ctx.cliOptions.refresh);
99
+ ctx.printResult({
100
+ data: [{
101
+ score: data.overall.score,
102
+ rating: data.overall.rating,
103
+ updatedAt: data.overall.updatedAt?.toISOString() ?? "",
104
+ previousClose: data.overall.previousClose,
105
+ previousWeek: data.overall.previousWeek,
106
+ previousMonth: data.overall.previousMonth,
107
+ previousYear: data.overall.previousYear,
108
+ }],
109
+ metadata: { indicators: data.indicators.map((indicator) => ({ id: indicator.definition.id, score: indicator.score, rating: indicator.rating })) },
110
+ });
111
+ } finally {
112
+ resetFearGreedPersistence();
113
+ }
114
+ });
120
115
  }
121
116
 
122
117
  async function runEcon(args: string[], ctx: Parameters<CliCommandDef["execute"]>[1]) {
123
118
  const rawArgs = [...args];
124
119
  const country = (takeOption(rawArgs, "--country") ?? "all") as CountryFilter;
125
120
  const impact = (takeOption(rawArgs, "--impact") ?? "all") as ImpactFilter;
126
- const services = await ctx.initServices();
127
- try {
121
+ await withCliServices(ctx, async (services) => {
128
122
  const events = await loadCalendar(ctx.cliOptions.refresh);
129
123
  const rows = events
130
124
  .filter((event) => matchesCountry(event, country) && matchesImpact(event, impact))
@@ -152,9 +146,7 @@ async function runEcon(args: string[], ctx: Parameters<CliCommandDef["execute"]>
152
146
  { key: "prior", header: "Prior" },
153
147
  ],
154
148
  });
155
- } finally {
156
- services.destroy();
157
- }
149
+ });
158
150
  }
159
151
 
160
152
  async function runFred(args: string[], ctx: Parameters<CliCommandDef["execute"]>[1]) {
@@ -185,8 +177,7 @@ async function runYieldCurve(args: string[], ctx: Parameters<CliCommandDef["exec
185
177
  async function runCorrelation(args: string[], ctx: Parameters<CliCommandDef["execute"]>[1]) {
186
178
  const left = requireArg(args[0]?.toUpperCase(), "Usage: gloomberb correlation <symbol-a> <symbol-b>", ctx);
187
179
  const right = requireArg(args[1]?.toUpperCase(), "Usage: gloomberb correlation <symbol-a> <symbol-b>", ctx);
188
- const services = await ctx.initServices();
189
- try {
180
+ await withCliServices(ctx, async (services) => {
190
181
  const [leftHistory, rightHistory] = await Promise.all([
191
182
  services.dataProvider.getPriceHistory(left, "", "1Y"),
192
183
  services.dataProvider.getPriceHistory(right, "", "1Y"),
@@ -204,9 +195,7 @@ async function runCorrelation(args: string[], ctx: Parameters<CliCommandDef["exe
204
195
  ? numerator / Math.sqrt(leftVariance * rightVariance)
205
196
  : null;
206
197
  ctx.printResult({ data: [{ left, right, samples: pairs.length, correlation }] });
207
- } finally {
208
- services.destroy();
209
- }
198
+ });
210
199
  }
211
200
 
212
201
  export const overviewCliCommands: CliCommandDef[] = [
@@ -9,7 +9,7 @@ import {
9
9
  searchTickerCandidates,
10
10
  type TickerSearchCandidate,
11
11
  } from "../../tickers/search";
12
- import { initMarketData } from "../context";
12
+ import { initMarketData, withMarketData } from "../context";
13
13
  import { fail } from "../errors";
14
14
  import type { MarketContext } from "../types";
15
15
  import type { CliCommandContext } from "../../types/plugin";
@@ -135,33 +135,31 @@ export async function search(query: string, dependencies: SearchCommandDependenc
135
135
  failCommand("Usage: gloomberb search <query>");
136
136
  }
137
137
 
138
- const { store, dataProvider, persistence } = await initMarketDataFn();
139
- const tickers = await store.loadAllTickers();
140
- const candidates = await searchCandidatesForCli({
141
- query: trimmedQuery,
142
- tickers,
143
- dataProvider,
144
- });
145
-
146
- if (dependencies.printResult) {
147
- dependencies.printResult({ data: searchCandidateRows(candidates), metadata: { query: trimmedQuery } }, {
148
- columns: [
149
- { key: "category", header: "Category" },
150
- { key: "symbol", header: "Symbol" },
151
- { key: "name", header: "Name" },
152
- { key: "exchange", header: "Exchange" },
153
- { key: "type", header: "Type" },
154
- { key: "source", header: "Source" },
155
- ],
138
+ await withMarketData(initMarketDataFn, async ({ store, dataProvider }) => {
139
+ const tickers = await store.loadAllTickers();
140
+ const candidates = await searchCandidatesForCli({
141
+ query: trimmedQuery,
142
+ tickers,
143
+ dataProvider,
156
144
  });
157
- persistence.close();
158
- return;
159
- }
160
145
 
161
- console.log(buildSearchReport({
162
- query: trimmedQuery,
163
- candidates,
164
- }));
146
+ if (dependencies.printResult) {
147
+ dependencies.printResult({ data: searchCandidateRows(candidates), metadata: { query: trimmedQuery } }, {
148
+ columns: [
149
+ { key: "category", header: "Category" },
150
+ { key: "symbol", header: "Symbol" },
151
+ { key: "name", header: "Name" },
152
+ { key: "exchange", header: "Exchange" },
153
+ { key: "type", header: "Type" },
154
+ { key: "source", header: "Source" },
155
+ ],
156
+ });
157
+ return;
158
+ }
165
159
 
166
- persistence.close();
160
+ console.log(buildSearchReport({
161
+ query: trimmedQuery,
162
+ candidates,
163
+ }));
164
+ });
167
165
  }