gloomberb 0.9.9 → 0.10.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 (519) hide show
  1. package/README.md +41 -3
  2. package/README.zh-CN.md +294 -0
  3. package/package.json +10 -4
  4. package/patches/@opentui%2Fcore@0.3.2.patch +26 -69
  5. package/src/api-client/auth.ts +2 -0
  6. package/src/api-client/index.test.ts +4 -0
  7. package/src/api-client/types.ts +3 -0
  8. package/src/app/pane-runtime/pane-settings-runtime.tsx +1 -0
  9. package/src/app/pane-template-dialog-wizard.test.tsx +36 -0
  10. package/src/app/pane-template-dialog-wizard.tsx +10 -3
  11. package/src/app/runtime/desktop-deeplink.test.ts +15 -0
  12. package/src/app/runtime/desktop-deeplink.ts +21 -6
  13. package/src/app.tsx +40 -33
  14. package/src/capabilities/service-capabilities.ts +7 -2
  15. package/src/cli/commands/automation.test.ts +202 -0
  16. package/src/cli/commands/automation.ts +153 -36
  17. package/src/cli/commands/market.ts +1 -14
  18. package/src/cli/commands/system.ts +4 -1
  19. package/src/cli/context.ts +1 -1
  20. package/src/cli/desktop-pane-shot.ts +65 -4
  21. package/src/cli/entry.ts +1 -1
  22. package/src/cli/pane-functions/capabilities.ts +532 -0
  23. package/src/cli/pane-functions/catalog.ts +39 -4
  24. package/src/cli/pane-functions/data.test.ts +17 -0
  25. package/src/cli/pane-functions/data.ts +55 -13
  26. package/src/cli/pane-functions/discovery.ts +36 -9
  27. package/src/cli/pane-functions/index.test.ts +104 -1
  28. package/src/cli/pane-functions/index.ts +64 -5
  29. package/src/cli/pane-functions/options.ts +21 -6
  30. package/src/cli/pane-functions/report.ts +735 -72
  31. package/src/cli/pane-functions/resolver.ts +70 -6
  32. package/src/cli/pane-functions/screenshot.test.ts +431 -0
  33. package/src/cli/pane-functions/screenshot.ts +952 -8
  34. package/src/components/chart/composite/column-layout.ts +215 -0
  35. package/src/components/chart/composite/composite-chart.test.tsx +630 -0
  36. package/src/components/chart/composite/composite-chart.tsx +1148 -0
  37. package/src/components/chart/composite/format.test.ts +137 -0
  38. package/src/components/chart/composite/format.ts +135 -0
  39. package/src/components/chart/composite/index.ts +38 -0
  40. package/src/components/chart/composite/interactions.test.ts +109 -0
  41. package/src/components/chart/composite/interactions.ts +247 -0
  42. package/src/components/chart/composite/price-series.test.ts +39 -0
  43. package/src/components/chart/composite/price-series.ts +78 -0
  44. package/src/components/chart/composite/rasterizer.ts +359 -0
  45. package/src/components/chart/composite/renderers.test.ts +610 -0
  46. package/src/components/chart/composite/scene.test.ts +464 -0
  47. package/src/components/chart/composite/scene.ts +553 -0
  48. package/src/components/chart/composite/text-renderer.ts +285 -0
  49. package/src/components/chart/composite/time-scale.test.ts +88 -0
  50. package/src/components/chart/composite/time-scale.ts +217 -0
  51. package/src/components/chart/composite/types.ts +141 -0
  52. package/src/components/chart/core/data.ts +81 -5
  53. package/src/components/chart/core/index.test.ts +128 -43
  54. package/src/components/chart/core/resolution.ts +0 -6
  55. package/src/components/chart/native/chart-rasterizer.ts +1 -3
  56. package/src/components/chart/native/kitty/index.test.ts +99 -120
  57. package/src/components/chart/native/kitty/manager.ts +3 -0
  58. package/src/components/chart/native/kitty/protocol.ts +4 -1
  59. package/src/components/chart/native/raster/crosshair.ts +79 -46
  60. package/src/components/chart/native/raster/types.ts +2 -11
  61. package/src/components/chart/native/surface/manager.ts +48 -3
  62. package/src/components/chart/price-axis-labels.tsx +18 -4
  63. package/src/components/command-bar/commands/direct/index.ts +25 -0
  64. package/src/components/command-bar/commands/registry.ts +9 -0
  65. package/src/components/command-bar/helpers.test.ts +4 -1
  66. package/src/components/command-bar/list/view.tsx +18 -6
  67. package/src/components/command-bar/multi-select-picker.tsx +6 -5
  68. package/src/components/command-bar/pane-settings.test.ts +141 -0
  69. package/src/components/command-bar/pane-settings.ts +61 -1
  70. package/src/components/command-bar/panel/body.tsx +7 -6
  71. package/src/components/command-bar/routes/root/command-items.ts +4 -4
  72. package/src/components/command-bar/routes/root/results.ts +10 -1
  73. package/src/components/command-bar/routes/root/selection.test.ts +54 -0
  74. package/src/components/command-bar/routes/root/selection.ts +13 -0
  75. package/src/components/command-bar/routing/actions.ts +18 -2
  76. package/src/components/command-bar/routing/list-state.ts +2 -1
  77. package/src/components/command-bar/surface/index.test.tsx +36 -4
  78. package/src/components/command-bar/surface/pane.test.tsx +93 -0
  79. package/src/components/command-bar/theme-picker.tsx +2 -1
  80. package/src/components/command-bar/view-model.ts +19 -20
  81. package/src/components/command-bar/workflow/body.tsx +2 -1
  82. package/src/components/command-bar/workflow/field-row.tsx +3 -2
  83. package/src/components/command-bar/workflow/fields.ts +4 -2
  84. package/src/components/command-bar/workflow/ops.test.ts +161 -0
  85. package/src/components/command-bar/workflow/ops.ts +20 -50
  86. package/src/components/command-bar/workflow/route-actions.test.ts +34 -0
  87. package/src/components/command-bar/workflow/route-actions.ts +4 -0
  88. package/src/components/command-bar/workflow/types.ts +1 -0
  89. package/src/components/feed-data-table/stack-view.tsx +6 -5
  90. package/src/components/index.ts +13 -1
  91. package/src/components/layout/detached-pane-shell.tsx +2 -1
  92. package/src/components/layout/floating-pane.tsx +3 -0
  93. package/src/components/layout/header.tsx +15 -8
  94. package/src/components/layout/pane/footer/index.test.tsx +22 -3
  95. package/src/components/layout/pane/footer/index.tsx +3 -1
  96. package/src/components/layout/pane/footer/model.ts +9 -2
  97. package/src/components/layout/pane/header.tsx +4 -6
  98. package/src/components/layout/pane/index.tsx +3 -0
  99. package/src/components/layout/pane/sidebar.test.tsx +100 -0
  100. package/src/components/layout/pane/sidebar.tsx +239 -0
  101. package/src/components/layout/pane/title.ts +4 -3
  102. package/src/components/layout/shell/action-menu-overlay.tsx +5 -3
  103. package/src/components/layout/shell/drag/runtime.ts +2 -0
  104. package/src/components/layout/shell/menu.test.ts +19 -0
  105. package/src/components/layout/shell/menu.ts +8 -5
  106. package/src/components/layout/shell/native/pointer-runtime.ts +4 -1
  107. package/src/components/layout/shell/pane/layers.tsx +2 -2
  108. package/src/components/layout/status-bar.tsx +8 -7
  109. package/src/components/layout/window-controls.tsx +4 -3
  110. package/src/components/metric-treemap/index.tsx +3 -2
  111. package/src/components/onboarding/onboarding-steps.tsx +30 -29
  112. package/src/components/onboarding/onboarding-wizard.tsx +5 -4
  113. package/src/components/onboarding/portfolio-step/broker-fields-panel.tsx +15 -12
  114. package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +17 -16
  115. package/src/components/onboarding/portfolio-step/broker-sync-panel.tsx +6 -5
  116. package/src/components/onboarding/portfolio-step/choose-panel.tsx +5 -4
  117. package/src/components/pane-settings-dialog/desktop.tsx +25 -3
  118. package/src/components/pane-settings-dialog/field-dialogs.tsx +5 -4
  119. package/src/components/pane-settings-dialog/tui.tsx +11 -9
  120. package/src/components/pane-settings-dialog/value.ts +8 -5
  121. package/src/components/pane-settings-dialog.test.tsx +235 -0
  122. package/src/components/pane-settings-dialog.tsx +24 -0
  123. package/src/components/pane-template-wizard.tsx +6 -2
  124. package/src/components/ticker/list-table-view.tsx +3 -2
  125. package/src/components/ui/button.tsx +3 -1
  126. package/src/components/ui/choice-dialog.tsx +6 -1
  127. package/src/components/ui/confirm-dialog.tsx +3 -2
  128. package/src/components/ui/fields.tsx +10 -1
  129. package/src/components/ui/frame.tsx +4 -1
  130. package/src/components/ui/index.ts +5 -0
  131. package/src/components/ui/inline-quick-add.tsx +104 -0
  132. package/src/components/ui/list-view.tsx +5 -4
  133. package/src/components/ui/loading.tsx +2 -1
  134. package/src/components/ui/multi-select/dialog.tsx +188 -44
  135. package/src/components/ui/popover.tsx +10 -0
  136. package/src/components/ui/shortcut-hint.tsx +2 -0
  137. package/src/components/ui/status.tsx +4 -3
  138. package/src/components/ui/tabs.tsx +19 -8
  139. package/src/components/ui/toggle.tsx +44 -3
  140. package/src/components/ui/ui.test.tsx +67 -5
  141. package/src/core/app-services.ts +4 -6
  142. package/src/core/state/session-persistence.ts +3 -2
  143. package/src/data/config/chart-settings.ts +712 -0
  144. package/src/data/config/layout.ts +24 -5
  145. package/src/data/config/store/index.test.ts +377 -14
  146. package/src/data/config/store/normalize.ts +79 -65
  147. package/src/data/fred-series.ts +137 -0
  148. package/src/i18n/index.test.ts +114 -0
  149. package/src/i18n/index.ts +147 -0
  150. package/src/i18n/ja.ts +1013 -0
  151. package/src/i18n/ko.ts +1011 -0
  152. package/src/i18n/languages.test.ts +31 -0
  153. package/src/i18n/languages.ts +72 -0
  154. package/src/i18n/zh-cn.ts +1013 -0
  155. package/src/i18n/zh-tw.ts +1013 -0
  156. package/src/plugins/builtin/account-management/footer.ts +3 -2
  157. package/src/plugins/builtin/account-management/form-components.tsx +3 -2
  158. package/src/plugins/builtin/account-management/keyboard.ts +6 -0
  159. package/src/plugins/builtin/account-management/model.ts +25 -21
  160. package/src/plugins/builtin/account-management/navigation.test.ts +27 -0
  161. package/src/plugins/builtin/account-management/navigation.ts +24 -0
  162. package/src/plugins/builtin/account-management/pane.tsx +120 -85
  163. package/src/plugins/builtin/account-management/password-dialog.tsx +10 -9
  164. package/src/plugins/builtin/ai/agent-history.ts +139 -0
  165. package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +133 -51
  166. package/src/plugins/builtin/ai/ask-ai.test.tsx +83 -22
  167. package/src/plugins/builtin/ai/index.test.ts +302 -0
  168. package/src/plugins/builtin/ai/index.tsx +374 -40
  169. package/src/plugins/builtin/ai/pane-settings.test.ts +155 -0
  170. package/src/plugins/builtin/ai/pane-settings.ts +319 -0
  171. package/src/plugins/builtin/ai/pi/credential-store.test.ts +80 -0
  172. package/src/plugins/builtin/ai/pi/credential-store.ts +138 -0
  173. package/src/plugins/builtin/ai/pi/file-store.ts +138 -0
  174. package/src/plugins/builtin/ai/pi/host.test.ts +500 -0
  175. package/src/plugins/builtin/ai/pi/host.ts +564 -0
  176. package/src/plugins/builtin/ai/pi/index.ts +5 -0
  177. package/src/plugins/builtin/ai/pi/models-store.test.ts +44 -0
  178. package/src/plugins/builtin/ai/pi/models-store.ts +141 -0
  179. package/src/plugins/builtin/ai/pi/providers.ts +68 -0
  180. package/src/plugins/builtin/ai/pi/runtime.test.ts +240 -0
  181. package/src/plugins/builtin/ai/pi/runtime.ts +635 -0
  182. package/src/plugins/builtin/ai/providers.test.ts +68 -0
  183. package/src/plugins/builtin/ai/providers.ts +163 -38
  184. package/src/plugins/builtin/ai/runner-selection.test.ts +174 -0
  185. package/src/plugins/builtin/ai/runner-selection.ts +193 -0
  186. package/src/plugins/builtin/ai/runner-selector.tsx +153 -0
  187. package/src/plugins/builtin/ai/runner.test.ts +198 -0
  188. package/src/plugins/builtin/ai/runner.ts +276 -73
  189. package/src/plugins/builtin/ai/screener/contract.test.ts +26 -73
  190. package/src/plugins/builtin/ai/screener/contract.ts +14 -52
  191. package/src/plugins/builtin/ai/screener/editor-runtime.ts +55 -5
  192. package/src/plugins/builtin/ai/screener/editor.tsx +42 -36
  193. package/src/plugins/builtin/ai/screener/footer.ts +82 -67
  194. package/src/plugins/builtin/ai/screener/keyboard.ts +27 -11
  195. package/src/plugins/builtin/ai/screener/model.test.ts +24 -0
  196. package/src/plugins/builtin/ai/screener/model.ts +9 -3
  197. package/src/plugins/builtin/ai/screener/pane.test.tsx +142 -55
  198. package/src/plugins/builtin/ai/screener/pane.tsx +95 -97
  199. package/src/plugins/builtin/ai/screener/results-view.tsx +8 -41
  200. package/src/plugins/builtin/ai/screener/runner.ts +41 -25
  201. package/src/plugins/builtin/ai/screener/tabs-bar.tsx +2 -2
  202. package/src/plugins/builtin/ai/use-runtime-providers.ts +28 -0
  203. package/src/plugins/builtin/ai/workspace/model.test.ts +227 -0
  204. package/src/plugins/builtin/ai/workspace/model.ts +308 -0
  205. package/src/plugins/builtin/ai/workspace/pane.test.tsx +197 -0
  206. package/src/plugins/builtin/ai/workspace/pane.tsx +896 -0
  207. package/src/plugins/builtin/analytics/index.test.tsx +3 -3
  208. package/src/plugins/builtin/analytics/index.tsx +3 -8
  209. package/src/plugins/builtin/broker-manager/detail.tsx +25 -24
  210. package/src/plugins/builtin/broker-manager/index.test.tsx +1 -1
  211. package/src/plugins/builtin/broker-manager/index.tsx +9 -11
  212. package/src/plugins/builtin/broker-manager/model.ts +11 -10
  213. package/src/plugins/builtin/broker-manager/pane-actions.tsx +22 -21
  214. package/src/plugins/builtin/broker-manager/table.ts +9 -8
  215. package/src/plugins/builtin/changelog/index.tsx +3 -8
  216. package/src/plugins/builtin/chart-composer/chart-spec.ts +89 -0
  217. package/src/plugins/builtin/chart-composer/cli-options.ts +98 -0
  218. package/src/plugins/builtin/chart-composer/date-window-dialog.tsx +120 -0
  219. package/src/plugins/builtin/chart-composer/editor.test.tsx +332 -0
  220. package/src/plugins/builtin/chart-composer/editor.tsx +1107 -0
  221. package/src/plugins/builtin/chart-composer/index.tsx +228 -0
  222. package/src/plugins/builtin/chart-composer/pane.tsx +645 -0
  223. package/src/plugins/builtin/chart-composer/presets.test.ts +561 -0
  224. package/src/plugins/builtin/chart-composer/presets.ts +759 -0
  225. package/src/plugins/builtin/chart-composer/quick-add.test.tsx +245 -0
  226. package/src/plugins/builtin/chart-composer/quick-add.tsx +409 -0
  227. package/src/plugins/builtin/chart-composer/semantic.ts +86 -0
  228. package/src/plugins/builtin/chart-composer/series-catalog.test.ts +65 -0
  229. package/src/plugins/builtin/chart-composer/series-catalog.ts +295 -0
  230. package/src/plugins/builtin/chart-composer/settings.test.ts +163 -0
  231. package/src/plugins/builtin/chart-composer/settings.ts +397 -0
  232. package/src/plugins/builtin/chart-composer/shortcuts.test.ts +44 -0
  233. package/src/plugins/builtin/chart-composer/shortcuts.ts +35 -0
  234. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +103 -0
  235. package/src/plugins/builtin/chat/channel-labels.ts +5 -4
  236. package/src/plugins/builtin/chat/channels.ts +12 -11
  237. package/src/plugins/builtin/chat/chat.test.tsx +32 -0
  238. package/src/plugins/builtin/chat/content/composer-runtime.ts +6 -1
  239. package/src/plugins/builtin/chat/content/composer.tsx +9 -8
  240. package/src/plugins/builtin/chat/content/index.tsx +36 -1
  241. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +8 -7
  242. package/src/plugins/builtin/chat/content/transcript.tsx +9 -3
  243. package/src/plugins/builtin/chat/controller/utils.ts +10 -9
  244. package/src/plugins/builtin/chat/message/desktop.tsx +17 -10
  245. package/src/plugins/builtin/chat/message/profile-popover.test.tsx +122 -3
  246. package/src/plugins/builtin/chat/message/profile-popover.tsx +38 -1
  247. package/src/plugins/builtin/chat/message/terminal.tsx +19 -10
  248. package/src/plugins/builtin/chat/pane-state.test.ts +31 -0
  249. package/src/plugins/builtin/chat/pane-state.ts +30 -0
  250. package/src/plugins/builtin/chat/pane.tsx +27 -4
  251. package/src/plugins/builtin/chat/profile-popover.ts +62 -5
  252. package/src/plugins/builtin/chat/sidebar.test.tsx +4 -7
  253. package/src/plugins/builtin/chat/sidebar.tsx +107 -168
  254. package/src/plugins/builtin/chat/test-harness.tsx +6 -0
  255. package/src/plugins/builtin/cloud/auth-actions.tsx +5 -4
  256. package/src/plugins/builtin/cloud/plugin.tsx +150 -127
  257. package/src/plugins/builtin/composite-plugins.ts +71 -0
  258. package/src/plugins/builtin/correlation/index.test.tsx +4 -4
  259. package/src/plugins/builtin/correlation/index.tsx +3 -8
  260. package/src/plugins/builtin/earnings/index.tsx +37 -21
  261. package/src/plugins/builtin/earnings/model.test.ts +52 -0
  262. package/src/plugins/builtin/earnings/model.ts +32 -0
  263. package/src/plugins/builtin/econ/detail-view.tsx +17 -4
  264. package/src/plugins/builtin/econ/fred-cache.test.ts +57 -11
  265. package/src/plugins/builtin/econ/index.tsx +16 -20
  266. package/src/plugins/builtin/fear-greed/index.tsx +2 -8
  267. package/src/plugins/builtin/fx-matrix/index.tsx +3 -8
  268. package/src/plugins/builtin/help/components.tsx +5 -4
  269. package/src/plugins/builtin/help/index.tsx +14 -17
  270. package/src/plugins/builtin/holders/index.tsx +2 -8
  271. package/src/plugins/builtin/insider/index.tsx +2 -7
  272. package/src/plugins/builtin/kelly-sizer/index.test.tsx +2 -2
  273. package/src/plugins/builtin/kelly-sizer/index.tsx +3 -7
  274. package/src/plugins/builtin/kelly-sizer/test-support.tsx +3 -3
  275. package/src/plugins/builtin/layout-manager/index.tsx +3 -7
  276. package/src/plugins/builtin/market-heatmap/index.tsx +3 -8
  277. package/src/plugins/builtin/market-movers/index.tsx +3 -8
  278. package/src/plugins/builtin/news/index.tsx +12 -16
  279. package/src/plugins/builtin/news/wire/breaking/pane.test.tsx +3 -3
  280. package/src/plugins/builtin/news/wire/index.tsx +83 -73
  281. package/src/plugins/builtin/options/index.tsx +2 -8
  282. package/src/plugins/builtin/plugin-module.test.ts +89 -0
  283. package/src/plugins/builtin/plugin-module.ts +116 -0
  284. package/src/plugins/builtin/portfolio-list/header.tsx +4 -3
  285. package/src/plugins/builtin/portfolio-list/index.test.ts +17 -0
  286. package/src/plugins/builtin/portfolio-list/index.tsx +3 -5
  287. package/src/plugins/builtin/portfolio-list/pane/index.test.tsx +3 -3
  288. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +53 -53
  289. package/src/plugins/builtin/portfolio-list/settings.ts +5 -3
  290. package/src/plugins/builtin/portfolio-list/summary/index.tsx +4 -3
  291. package/src/plugins/builtin/research/index.tsx +2 -8
  292. package/src/plugins/builtin/sec/index.tsx +2 -8
  293. package/src/plugins/builtin/sectors/index.tsx +3 -8
  294. package/src/plugins/builtin/thirteenf/index.tsx +3 -8
  295. package/src/plugins/builtin/thirteenf/pane.test.tsx +1 -1
  296. package/src/plugins/builtin/ticker-detail/chart-tab-switch.test.tsx +49 -23
  297. package/src/plugins/builtin/ticker-detail/index.test.tsx +15 -136
  298. package/src/plugins/builtin/ticker-detail/index.tsx +2 -93
  299. package/src/plugins/builtin/ticker-detail/overview/components.tsx +6 -5
  300. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +41 -17
  301. package/src/plugins/builtin/ticker-detail/pane.tsx +4 -3
  302. package/src/plugins/builtin/ticker-detail/quote-monitor/index.test.tsx +1 -1
  303. package/src/plugins/builtin/ticker-detail/settings.ts +3 -50
  304. package/src/plugins/builtin/ticker-research-backend-plugin.ts +17 -0
  305. package/src/plugins/builtin/ticker-research-plugin.ts +27 -0
  306. package/src/plugins/builtin/tv/channels.ts +27 -0
  307. package/src/plugins/builtin/tv/index.tsx +40 -0
  308. package/src/plugins/builtin/tv/pane.tsx +286 -0
  309. package/src/plugins/builtin/tv/youtube-stream.ts +100 -0
  310. package/src/plugins/builtin/world-indices/index.tsx +3 -8
  311. package/src/plugins/builtin/yield-curve/index.tsx +8 -8
  312. package/src/plugins/catalog-backend.test.ts +21 -0
  313. package/src/plugins/catalog-backend.ts +42 -0
  314. package/src/plugins/catalog-ui.ts +6 -14
  315. package/src/plugins/ibkr/instance-selection.test.ts +0 -1
  316. package/src/plugins/ownership.ts +143 -0
  317. package/src/plugins/prediction-markets/backend-plugin.ts +19 -0
  318. package/src/plugins/prediction-markets/chart.test.tsx +7 -5
  319. package/src/plugins/prediction-markets/chart.tsx +25 -7
  320. package/src/plugins/registry/index.test.ts +51 -0
  321. package/src/plugins/registry/index.ts +8 -0
  322. package/src/plugins/registry/pane-settings.ts +1 -1
  323. package/src/plugins/runtime/index.test.tsx +2 -2
  324. package/src/remote/app-host.tsx +16 -3
  325. package/src/remote/controller.test.ts +102 -1
  326. package/src/remote/controller.ts +122 -0
  327. package/src/remote/types.ts +11 -0
  328. package/src/renderers/electrobun/bun/core-capabilities.ts +123 -27
  329. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +5 -1
  330. package/src/renderers/electrobun/bun/desktop/initialization.ts +5 -1
  331. package/src/renderers/electrobun/bun/desktop/media.ts +15 -0
  332. package/src/renderers/electrobun/bun/desktop/window-style.ts +4 -1
  333. package/src/renderers/electrobun/bun/desktop/workspace/index.test.ts +32 -1
  334. package/src/renderers/electrobun/bun/desktop/workspace/index.ts +10 -0
  335. package/src/renderers/electrobun/bun/index.ts +5 -0
  336. package/src/renderers/electrobun/bun/tui-entry.ts +1 -6
  337. package/src/renderers/electrobun/view/ai-host.ts +124 -19
  338. package/src/renderers/electrobun/view/backend-rpc.ts +4 -0
  339. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +151 -39
  340. package/src/renderers/electrobun/view/desktop/popover.tsx +166 -0
  341. package/src/renderers/electrobun/view/dialog-host.test.ts +25 -0
  342. package/src/renderers/electrobun/view/dialog-host.tsx +75 -12
  343. package/src/renderers/electrobun/view/host/box.tsx +5 -0
  344. package/src/renderers/electrobun/view/host/chart-surface.tsx +10 -9
  345. package/src/renderers/electrobun/view/host/input.tsx +9 -19
  346. package/src/renderers/electrobun/view/host/media-surface.tsx +170 -0
  347. package/src/renderers/electrobun/view/host/mouse.ts +1 -0
  348. package/src/renderers/electrobun/view/host/style.ts +1 -1
  349. package/src/renderers/electrobun/view/host/tabs.tsx +4 -3
  350. package/src/renderers/electrobun/view/main.tsx +10 -3
  351. package/src/renderers/electrobun/view/styles.css +17 -0
  352. package/src/renderers/electrobun/view/ui-host.tsx +7 -0
  353. package/src/renderers/opentui/chart-surface.test.tsx +52 -6
  354. package/src/renderers/opentui/chart-surface.tsx +95 -11
  355. package/src/renderers/opentui/dialog-host.tsx +36 -5
  356. package/src/renderers/opentui/host.tsx +39 -0
  357. package/src/renderers/opentui/start.tsx +30 -0
  358. package/src/renderers/opentui/ui-host.tsx +2 -0
  359. package/src/sources/provider-router/index.test.ts +43 -0
  360. package/src/sources/provider-router/index.ts +4 -0
  361. package/src/sources/provider-router/supplemental.ts +46 -0
  362. package/src/sources/sec-edgar.test.ts +203 -2
  363. package/src/sources/sec-edgar.ts +70 -15
  364. package/src/state/app/context/index.tsx +13 -1
  365. package/src/state/app/context/selector.test.tsx +62 -1
  366. package/src/state/session-persistence.test.ts +13 -2
  367. package/src/sync/controller.test.ts +190 -3
  368. package/src/sync/controller.ts +76 -45
  369. package/src/sync/core-contributors.test.ts +121 -0
  370. package/src/sync/core-contributors.ts +104 -27
  371. package/src/sync/react.ts +6 -8
  372. package/src/sync/types.ts +3 -0
  373. package/src/time-series/alignment.ts +158 -0
  374. package/src/time-series/economic.ts +49 -0
  375. package/src/time-series/field-catalog.ts +306 -0
  376. package/src/time-series/fundamentals.test.ts +505 -0
  377. package/src/time-series/fundamentals.ts +842 -0
  378. package/src/time-series/hooks.ts +45 -0
  379. package/src/time-series/index.ts +14 -0
  380. package/src/time-series/live-quotes.test.ts +219 -0
  381. package/src/time-series/live-quotes.ts +203 -0
  382. package/src/time-series/market-resolution.ts +53 -0
  383. package/src/time-series/market.ts +125 -0
  384. package/src/time-series/reporting.ts +98 -0
  385. package/src/time-series/resolve.test.ts +1281 -0
  386. package/src/time-series/resolve.ts +783 -0
  387. package/src/time-series/spec-studies.test.ts +400 -0
  388. package/src/time-series/spec.ts +487 -0
  389. package/src/time-series/studies.ts +563 -0
  390. package/src/time-series/transforms.test.ts +105 -0
  391. package/src/time-series/transforms.ts +152 -0
  392. package/src/time-series/types.ts +162 -0
  393. package/src/time-series/use-chart-resolution.ts +166 -0
  394. package/src/types/config.ts +9 -11
  395. package/src/types/desktop-window.ts +1 -0
  396. package/src/types/financials.ts +4 -0
  397. package/src/types/media.ts +17 -0
  398. package/src/types/plugin.ts +32 -1
  399. package/src/ui/context-menu.tsx +15 -3
  400. package/src/ui/dialog.tsx +14 -2
  401. package/src/ui/host.tsx +40 -1
  402. package/src/ui/index.tsx +9 -0
  403. package/src/utils/exchanges.test.ts +13 -1
  404. package/src/utils/exchanges.ts +10 -0
  405. package/src/utils/financial-statements.test.ts +138 -0
  406. package/src/utils/financial-statements.ts +115 -8
  407. package/src/utils/format.test.ts +11 -1
  408. package/src/utils/format.ts +7 -0
  409. package/src/version.ts +1 -1
  410. package/src/components/chart/bar-chart-renderer.test.ts +0 -233
  411. package/src/components/chart/bar-chart-renderer.ts +0 -445
  412. package/src/components/chart/comparison/data.test.ts +0 -159
  413. package/src/components/chart/comparison/data.ts +0 -302
  414. package/src/components/chart/comparison/renderer.test.ts +0 -187
  415. package/src/components/chart/comparison/renderer.ts +0 -282
  416. package/src/components/chart/comparison/scene.ts +0 -178
  417. package/src/components/chart/comparison-stock-chart/axis-width.ts +0 -99
  418. package/src/components/chart/comparison-stock-chart/canvas.ts +0 -148
  419. package/src/components/chart/comparison-stock-chart/controls.ts +0 -252
  420. package/src/components/chart/comparison-stock-chart/helpers.ts +0 -101
  421. package/src/components/chart/comparison-stock-chart/interactions.ts +0 -208
  422. package/src/components/chart/comparison-stock-chart/layout-metrics.ts +0 -62
  423. package/src/components/chart/comparison-stock-chart/layout.tsx +0 -155
  424. package/src/components/chart/comparison-stock-chart/legend.tsx +0 -74
  425. package/src/components/chart/comparison-stock-chart/native-surfaces.ts +0 -89
  426. package/src/components/chart/comparison-stock-chart/render-data.ts +0 -227
  427. package/src/components/chart/comparison-stock-chart/render-output.ts +0 -140
  428. package/src/components/chart/comparison-stock-chart/selection-runtime.ts +0 -128
  429. package/src/components/chart/comparison-stock-chart/sources.ts +0 -51
  430. package/src/components/chart/comparison-stock-chart/surface-runtime.ts +0 -159
  431. package/src/components/chart/comparison-stock-chart/toolbar.tsx +0 -117
  432. package/src/components/chart/comparison-stock-chart/types.ts +0 -22
  433. package/src/components/chart/comparison-stock-chart/view.tsx +0 -572
  434. package/src/components/chart/comparison-stock-chart/viewport-runtime.ts +0 -239
  435. package/src/components/chart/comparison-stock-chart.tsx +0 -24
  436. package/src/components/chart/core/axis-measure.ts +0 -33
  437. package/src/components/chart/core/controller.test.ts +0 -157
  438. package/src/components/chart/core/controller.ts +0 -349
  439. package/src/components/chart/core/indicator-selector.tsx +0 -75
  440. package/src/components/chart/core/keyboard.ts +0 -24
  441. package/src/components/chart/core/pane-settings.test.ts +0 -52
  442. package/src/components/chart/core/pane-settings.ts +0 -141
  443. package/src/components/chart/core/scroll.test.ts +0 -64
  444. package/src/components/chart/core/scroll.ts +0 -82
  445. package/src/components/chart/core/window-viewport.test.ts +0 -69
  446. package/src/components/chart/core/window-viewport.ts +0 -162
  447. package/src/components/chart/display-cursor.ts +0 -153
  448. package/src/components/chart/indicators/bands.test.ts +0 -36
  449. package/src/components/chart/indicators/bands.ts +0 -29
  450. package/src/components/chart/indicators/moving-averages.test.ts +0 -39
  451. package/src/components/chart/indicators/moving-averages.ts +0 -42
  452. package/src/components/chart/indicators/options.test.ts +0 -32
  453. package/src/components/chart/indicators/options.ts +0 -107
  454. package/src/components/chart/indicators/oscillators.test.ts +0 -58
  455. package/src/components/chart/indicators/oscillators.ts +0 -92
  456. package/src/components/chart/native/canvas-bitmaps.ts +0 -140
  457. package/src/components/chart/native/raster/comparison-chart.ts +0 -162
  458. package/src/components/chart/native/surface/hooks.ts +0 -144
  459. package/src/components/chart/native/surface/rendering.ts +0 -211
  460. package/src/components/chart/static/bar-chart-surface.test.tsx +0 -101
  461. package/src/components/chart/static/bar-chart-surface.tsx +0 -292
  462. package/src/components/chart/stock-chart/auto.ts +0 -216
  463. package/src/components/chart/stock-chart/axis-width.ts +0 -146
  464. package/src/components/chart/stock-chart/bitmaps.ts +0 -22
  465. package/src/components/chart/stock-chart/canvas.ts +0 -202
  466. package/src/components/chart/stock-chart/controls.tsx +0 -149
  467. package/src/components/chart/stock-chart/cursor.ts +0 -60
  468. package/src/components/chart/stock-chart/data-runtime.ts +0 -128
  469. package/src/components/chart/stock-chart/footer.test.ts +0 -65
  470. package/src/components/chart/stock-chart/footer.ts +0 -303
  471. package/src/components/chart/stock-chart/geometry.ts +0 -160
  472. package/src/components/chart/stock-chart/index.test.ts +0 -532
  473. package/src/components/chart/stock-chart/index.tsx +0 -29
  474. package/src/components/chart/stock-chart/indicators.ts +0 -226
  475. package/src/components/chart/stock-chart/interaction-runtime.ts +0 -44
  476. package/src/components/chart/stock-chart/interactions.ts +0 -300
  477. package/src/components/chart/stock-chart/keyboard.ts +0 -373
  478. package/src/components/chart/stock-chart/layout-metrics.ts +0 -62
  479. package/src/components/chart/stock-chart/layout.tsx +0 -177
  480. package/src/components/chart/stock-chart/native-surfaces.ts +0 -121
  481. package/src/components/chart/stock-chart/presentation.ts +0 -67
  482. package/src/components/chart/stock-chart/renderer-switch.test.tsx +0 -263
  483. package/src/components/chart/stock-chart/rendering/bounds.ts +0 -116
  484. package/src/components/chart/stock-chart/rendering/candidates.ts +0 -145
  485. package/src/components/chart/stock-chart/rendering/data.ts +0 -370
  486. package/src/components/chart/stock-chart/rendering/invalidation.ts +0 -68
  487. package/src/components/chart/stock-chart/rendering/output.ts +0 -304
  488. package/src/components/chart/stock-chart/rendering/planning.ts +0 -122
  489. package/src/components/chart/stock-chart/rendering/projection.test.tsx +0 -98
  490. package/src/components/chart/stock-chart/rendering/projection.ts +0 -112
  491. package/src/components/chart/stock-chart/rendering/state.test.ts +0 -70
  492. package/src/components/chart/stock-chart/rendering/state.ts +0 -283
  493. package/src/components/chart/stock-chart/requests.ts +0 -337
  494. package/src/components/chart/stock-chart/resolution-support.ts +0 -96
  495. package/src/components/chart/stock-chart/resolved/runtime.ts +0 -289
  496. package/src/components/chart/stock-chart/resolved.tsx +0 -359
  497. package/src/components/chart/stock-chart/settings.ts +0 -81
  498. package/src/components/chart/stock-chart/surface-runtime.ts +0 -62
  499. package/src/components/chart/stock-chart/types.ts +0 -25
  500. package/src/components/chart/stock-chart/view.tsx +0 -155
  501. package/src/components/chart/stock-chart/viewport/effects.ts +0 -293
  502. package/src/components/chart/stock-chart/viewport/index.ts +0 -144
  503. package/src/components/chart/stock-chart/viewport/runtime.ts +0 -375
  504. package/src/components/chart/time-axis-label.tsx +0 -175
  505. package/src/plugins/builtin/ai/gloomberb-cli.ts +0 -71
  506. package/src/plugins/builtin/ai/screener/action-bar.tsx +0 -58
  507. package/src/plugins/builtin/comparison-chart/index.test.tsx +0 -848
  508. package/src/plugins/builtin/comparison-chart/index.tsx +0 -194
  509. package/src/plugins/builtin/econ/fred-cache.ts +0 -106
  510. package/src/plugins/builtin/plugin-groups.ts +0 -130
  511. package/src/plugins/builtin/ticker-detail/chart-pane.tsx +0 -91
  512. package/src/plugins/builtin/ticker-detail/chart-tab.tsx +0 -100
  513. package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/content.tsx +0 -296
  514. package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/data.ts +0 -62
  515. package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/model.ts +0 -608
  516. package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/settings.ts +0 -65
  517. package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/types.ts +0 -58
  518. package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph.tsx +0 -138
  519. package/src/plugins/builtin/ticker-detail/data-panes.test.ts +0 -220
@@ -28,9 +28,11 @@ import { PaneFooterBar, PaneFooterProvider } from "../../../components/layout/pa
28
28
  import type { PluginRegistry } from "../../registry";
29
29
  import { setSharedRegistryForTests } from "../../registry";
30
30
  import { PluginRenderProvider } from "../../runtime";
31
- import { tickerDetailPlugin } from ".";
31
+ import { tickerDetailModule } from ".";
32
+ import { chartComposerModule } from "../chart-composer";
32
33
  import { FinancialsTab } from "./financials/tab";
33
34
  import { isUsEquityTicker } from "../../../utils/sec";
35
+ import { MemoryPluginPersistence } from "../../../test-support/plugin-persistence";
34
36
 
35
37
  const TEST_PANE_ID = "ticker-research:test";
36
38
 
@@ -43,7 +45,7 @@ let sharedCoordinator: MarketDataCoordinator | null = null;
43
45
  const runtime = createTestPluginRuntime();
44
46
  const TICKER_TAB_SETTLE_MS = 160;
45
47
 
46
- const DetailPane = tickerDetailPlugin.panes![0]!.component as (props: {
48
+ const DetailPane = tickerDetailModule.panes![0]!.component as (props: {
47
49
  paneId: string;
48
50
  paneType: string;
49
51
  focused: boolean;
@@ -161,18 +163,18 @@ function setOptionsProvider(provider: DataProvider | undefined): void {
161
163
  setSharedMarketDataCoordinator(sharedCoordinator);
162
164
  }
163
165
 
164
- function makeRegistry(options: { stubFundamentalGraphs?: boolean } = {}): PluginRegistry {
166
+ function makeRegistry(): PluginRegistry {
165
167
  const stubTab = (_props: { width: number; height: number; focused: boolean; onCapture: (capturing: boolean) => void }) => (
166
168
  <text>stub</text>
167
169
  );
168
170
  const tickerResearchTabs = new Map<string, TickerResearchTabDef>();
169
- tickerDetailPlugin.setup?.({
171
+ tickerDetailModule.setup?.({
172
+ registerTickerResearchTab: (tab: TickerResearchTabDef) => tickerResearchTabs.set(tab.id, tab),
173
+ } as any);
174
+ chartComposerModule.setup?.({
175
+ persistence: new MemoryPluginPersistence(),
170
176
  registerTickerResearchTab: (tab: TickerResearchTabDef) => tickerResearchTabs.set(tab.id, tab),
171
177
  } as any);
172
- if (options.stubFundamentalGraphs) {
173
- const tab = tickerResearchTabs.get("fundamental-graphs");
174
- if (tab) tickerResearchTabs.set(tab.id, { ...tab, component: stubTab });
175
- }
176
178
  for (const tab of [
177
179
  ["ibkr-trade", {
178
180
  id: "ibkr-trade",
@@ -211,6 +213,7 @@ function createDetailConfig(symbol: string, brokerInstances: BrokerInstanceConfi
211
213
  binding: { kind: "fixed" as const, symbol },
212
214
  }],
213
215
  floating: [],
216
+ detached: [],
214
217
  };
215
218
 
216
219
  return {
@@ -265,7 +268,7 @@ function DetailHarness({
265
268
  <AppContext value={{ state, dispatch }}>
266
269
  <PaneInstanceProvider paneId={TEST_PANE_ID}>
267
270
  <text>{`active:${state.paneState[TEST_PANE_ID]?.activeTabId ?? ""}`}</text>
268
- <PluginRenderProvider pluginId={tickerDetailPlugin.id} runtime={runtime}>
271
+ <PluginRenderProvider pluginId="ticker-research" runtime={runtime}>
269
272
  <DetailPane
270
273
  paneId={TEST_PANE_ID}
271
274
  paneType={TICKER_RESEARCH_PANE_ID}
@@ -513,7 +516,7 @@ describe("TickerResearchPane", () => {
513
516
  });
514
517
 
515
518
  test("lets ticker detail tab arrows leave the embedded financials tab", async () => {
516
- setSharedRegistryForTests(makeRegistry({ stubFundamentalGraphs: true }));
519
+ setSharedRegistryForTests(makeRegistry());
517
520
  setOptionsProvider(createProvider(false));
518
521
 
519
522
  testSetup = await testRender(
@@ -538,7 +541,7 @@ describe("TickerResearchPane", () => {
538
541
  await flushFrame();
539
542
 
540
543
  await settleTickerTabCommit();
541
- expect(detailHarnessState?.paneState[TEST_PANE_ID]?.activeTabId).toBe("fundamental-graphs");
544
+ expect(detailHarnessState?.paneState[TEST_PANE_ID]?.activeTabId).toBe("chart");
542
545
 
543
546
  await act(async () => {
544
547
  testSetup!.mockInput.pressArrow("left");
@@ -550,130 +553,6 @@ describe("TickerResearchPane", () => {
550
553
  expect(detailHarnessState?.paneState[TEST_PANE_ID]?.activeTabId).toBe("financials");
551
554
  });
552
555
 
553
- test("shows metric tabs for fundamental graph charts and defaults them to quarterly data", async () => {
554
- setSharedRegistryForTests(makeRegistry());
555
- setOptionsProvider(createProvider(false));
556
-
557
- testSetup = await testRender(
558
- <DetailHarness
559
- config={createDetailConfig("AAPL")}
560
- ticker={makeTicker("AAPL")}
561
- financials={makeFinancials({
562
- annualStatements: [{ date: "2024-12-31", totalRevenue: 1_000 }],
563
- quarterlyStatements: [
564
- { date: "2025-03-31", totalRevenue: 200 },
565
- { date: "2025-06-30", totalRevenue: 250 },
566
- ],
567
- })}
568
- activeTabId="fundamental-graphs"
569
- height={28}
570
- />,
571
- { width: 90, height: 28 },
572
- );
573
-
574
- await flushFrame();
575
- const frame = testSetup.captureCharFrame();
576
- expect(frame).toContain("Revenue");
577
- expect(frame).toContain("Gross Profit");
578
- expect(frame).not.toContain("Revenue (quarterly)");
579
- expect(frame).not.toContain("[g]roup");
580
- expect(frame).toContain("2025-03-31");
581
- expect(frame).toContain("2025-06-30");
582
- expect(frame.indexOf("2025-06-30")).toBeLessThan(frame.indexOf("2025-03-31"));
583
- });
584
-
585
- test("captures arrows for graph metric tabs between enter and escape", async () => {
586
- setSharedRegistryForTests(makeRegistry());
587
- setOptionsProvider(createProvider(false));
588
-
589
- testSetup = await testRender(
590
- <DetailHarness
591
- config={createDetailConfig("AAPL")}
592
- ticker={makeTicker("AAPL")}
593
- financials={makeFinancials({
594
- annualStatements: [{ date: "2024-12-31", totalRevenue: 1_000, grossProfit: 400 }],
595
- quarterlyStatements: [
596
- { date: "2025-03-31", totalRevenue: 200, grossProfit: 80 },
597
- { date: "2025-06-30", totalRevenue: 250, grossProfit: 120 },
598
- ],
599
- })}
600
- activeTabId="fundamental-graphs"
601
- height={28}
602
- />,
603
- { width: 90, height: 28 },
604
- );
605
-
606
- await flushFrame();
607
- expect(detailHarnessState?.paneState[TEST_PANE_ID]?.activeTabId).toBe("fundamental-graphs");
608
-
609
- await act(async () => {
610
- testSetup!.mockInput.pressEnter();
611
- await testSetup!.renderOnce();
612
- });
613
- await flushFrame();
614
-
615
- await act(async () => {
616
- testSetup!.mockInput.pressArrow("right");
617
- await testSetup!.renderOnce();
618
- });
619
- await flushFrame();
620
-
621
- expect(detailHarnessState?.paneState[TEST_PANE_ID]?.pluginState?.["ticker-detail"]?.detailMetric).toBe("grossProfit");
622
- expect(detailHarnessState?.paneState[TEST_PANE_ID]?.activeTabId).toBe("fundamental-graphs");
623
-
624
- await emitKeypress({ name: "escape", sequence: "\u001b" });
625
- expect(detailHarnessState?.inputCaptured).toBe(false);
626
-
627
- await act(async () => {
628
- testSetup!.mockInput.pressArrow("right");
629
- await testSetup!.renderOnce();
630
- });
631
- await flushFrame();
632
-
633
- await settleTickerTabCommit();
634
- expect(detailHarnessState?.paneState[TEST_PANE_ID]?.activeTabId).toBe("chart");
635
- });
636
-
637
- test("clicking graph content focuses metric tabs for arrow navigation", async () => {
638
- setSharedRegistryForTests(makeRegistry());
639
- setOptionsProvider(createProvider(false));
640
-
641
- testSetup = await testRender(
642
- <DetailHarness
643
- config={createDetailConfig("AAPL")}
644
- ticker={makeTicker("AAPL")}
645
- financials={makeFinancials({
646
- annualStatements: [{ date: "2024-12-31", totalRevenue: 1_000, grossProfit: 400 }],
647
- quarterlyStatements: [
648
- { date: "2025-03-31", totalRevenue: 200, grossProfit: 80 },
649
- { date: "2025-06-30", totalRevenue: 250, grossProfit: 120 },
650
- ],
651
- })}
652
- activeTabId="fundamental-graphs"
653
- height={28}
654
- />,
655
- { width: 90, height: 28 },
656
- );
657
-
658
- await flushFrame();
659
-
660
- await act(async () => {
661
- await testSetup!.mockMouse.click(24, 6);
662
- await testSetup!.renderOnce();
663
- });
664
- await flushFrame();
665
- expect(detailHarnessState?.inputCaptured).toBe(true);
666
-
667
- await act(async () => {
668
- testSetup!.mockInput.pressArrow("right");
669
- await testSetup!.renderOnce();
670
- });
671
- await flushFrame();
672
-
673
- expect(detailHarnessState?.paneState[TEST_PANE_ID]?.pluginState?.["ticker-detail"]?.detailMetric).toBe("grossProfit");
674
- expect(detailHarnessState?.paneState[TEST_PANE_ID]?.activeTabId).toBe("fundamental-graphs");
675
- });
676
-
677
556
  test("shows Trade when an IBKR gateway profile exists", async () => {
678
557
  setSharedRegistryForTests(makeRegistry());
679
558
  setOptionsProvider(createProvider(false));
@@ -818,7 +697,7 @@ describe("TickerResearchPane", () => {
818
697
 
819
698
  await flushFrame();
820
699
  const frame = testSetup.captureCharFrame();
821
- expect(receivedHeight).toBe(17);
700
+ expect(Number(receivedHeight)).toBe(17);
822
701
  expect(frame).toContain("height:17");
823
702
  });
824
703
 
@@ -1,15 +1,8 @@
1
- import type { GloomPlugin } from "../../../types/plugin";
1
+ import type { PluginModule } from "../plugin-module";
2
2
  import type { TickerFinancials } from "../../../types/financials";
3
3
  import { TICKER_RESEARCH_PANE_ID } from "../../../types/config";
4
4
  import { normalizeTickerInput } from "../../../tickers/search";
5
5
  import { createTickerSurfacePaneTemplate } from "../shared/ticker-surface";
6
- import { TickerChartPane, ChartResearchTab } from "./chart-pane";
7
- import {
8
- buildGraphPaneSettingsDef,
9
- createGraphPaneTemplate,
10
- FundamentalGraphPane,
11
- FundamentalGraphsResearchTab,
12
- } from "./data-panes/fundamental-graph";
13
6
  import { FinancialAnalysisPane, FinancialsResearchTab } from "./financials/pane";
14
7
  import { HistoricalPricesPane } from "./data-panes/historical-prices";
15
8
  import {
@@ -22,7 +15,6 @@ import { QuoteMonitorPane } from "./quote-monitor";
22
15
  import {
23
16
  buildQuoteMonitorSettingsDef,
24
17
  buildQuoteMonitorPaneTitle,
25
- buildTickerChartSettingsDef,
26
18
  buildTickerResearchSettingsDef,
27
19
  getTickerResearchPaneSettings,
28
20
  } from "./settings";
@@ -32,11 +24,7 @@ function hasStatementFinancials(financials: TickerFinancials | null | undefined)
32
24
  return (financials?.annualStatements.length ?? 0) > 0 || (financials?.quarterlyStatements.length ?? 0) > 0;
33
25
  }
34
26
 
35
- export const tickerDetailPlugin: GloomPlugin = {
36
- id: "ticker-detail",
37
- name: "Ticker Research",
38
- version: "1.0.0",
39
-
27
+ export const tickerDetailModule: PluginModule = {
40
28
  setup(ctx) {
41
29
  ctx.registerTickerResearchTab({
42
30
  id: "overview",
@@ -52,25 +40,6 @@ export const tickerDetailPlugin: GloomPlugin = {
52
40
  component: FinancialsResearchTab,
53
41
  isVisible: ({ financials }) => hasStatementFinancials(financials),
54
42
  });
55
- ctx.registerTickerResearchTab({
56
- id: "chart",
57
- name: "Chart",
58
- order: 30,
59
- component: ChartResearchTab,
60
- isVisible: ({ ticker }) => !!ticker,
61
- });
62
- ctx.registerTickerResearchTab({
63
- id: "fundamental-graphs",
64
- name: "Graphs",
65
- order: 28,
66
- component: FundamentalGraphsResearchTab,
67
- isVisible: ({ ticker, financials }) => !!ticker && (
68
- (financials?.annualStatements.length ?? 0) > 0
69
- || (financials?.quarterlyStatements.length ?? 0) > 0
70
- || !!financials?.fundamentals
71
- || !!financials?.quote?.marketCap
72
- ),
73
- });
74
43
  },
75
44
 
76
45
  panes: [
@@ -92,16 +61,6 @@ export const tickerDetailPlugin: GloomPlugin = {
92
61
  defaultMode: "floating",
93
62
  defaultFloatingSize: { width: 98, height: 30 },
94
63
  },
95
- {
96
- id: "ticker-chart",
97
- name: "Chart",
98
- icon: "G",
99
- component: TickerChartPane,
100
- defaultPosition: "right",
101
- defaultMode: "floating",
102
- defaultFloatingSize: { width: 92, height: 30 },
103
- settings: () => buildTickerChartSettingsDef(),
104
- },
105
64
  {
106
65
  id: "quote-monitor",
107
66
  name: "Quote Monitor",
@@ -121,16 +80,6 @@ export const tickerDetailPlugin: GloomPlugin = {
121
80
  defaultMode: "floating",
122
81
  defaultFloatingSize: { width: 92, height: 26 },
123
82
  },
124
- {
125
- id: "fundamental-graph",
126
- name: "Fundamental Graph",
127
- icon: "G",
128
- component: FundamentalGraphPane,
129
- defaultPosition: "right",
130
- defaultMode: "floating",
131
- defaultFloatingSize: { width: 82, height: 22 },
132
- settings: buildGraphPaneSettingsDef(),
133
- },
134
83
  {
135
84
  id: "provider-search-results",
136
85
  name: "Provider Search",
@@ -206,20 +155,6 @@ export const tickerDetailPlugin: GloomPlugin = {
206
155
  keywords: ["historical", "prices", "hp", "ohlc", "volume"],
207
156
  shortcut: "HP",
208
157
  }),
209
- createGraphPaneTemplate({
210
- id: "fundamental-graph-pane",
211
- label: "Fundamental Graph",
212
- description: "Graph statement metrics for one or more tickers.",
213
- shortcut: "GF",
214
- chartKind: "fundamental",
215
- }),
216
- createGraphPaneTemplate({
217
- id: "valuation-graph-pane",
218
- label: "Valuation Graph",
219
- description: "Graph valuation multiples for one or more tickers.",
220
- shortcut: "GE",
221
- chartKind: "valuation",
222
- }),
223
158
  createProviderSearchPaneTemplate(),
224
159
  createTickerSurfacePaneTemplate({
225
160
  id: "financial-analysis-pane",
@@ -230,31 +165,5 @@ export const tickerDetailPlugin: GloomPlugin = {
230
165
  shortcut: "FA",
231
166
  titlePrefix: "FA",
232
167
  }),
233
- createTickerSurfacePaneTemplate({
234
- id: "graph-price-pane",
235
- paneId: "ticker-chart",
236
- label: "Graph Price",
237
- description: "Open a price chart for a ticker.",
238
- keywords: ["gp", "graph", "price", "chart"],
239
- shortcut: "GP",
240
- viewKey: "price",
241
- settings: () => ({
242
- chartRangePreset: "5Y",
243
- chartResolution: "auto",
244
- }),
245
- }),
246
- createTickerSurfacePaneTemplate({
247
- id: "graph-intraday-price-pane",
248
- paneId: "ticker-chart",
249
- label: "Intraday Price Graph",
250
- description: "Open an intraday price chart for a ticker.",
251
- keywords: ["gip", "intraday", "graph", "chart"],
252
- shortcut: "GIP",
253
- viewKey: "intraday",
254
- settings: () => ({
255
- chartRangePreset: "1D",
256
- chartResolution: "1m",
257
- }),
258
- }),
259
168
  ],
260
169
  };
@@ -2,6 +2,7 @@ import { Box, Text, TextAttributes } from "../../../../ui";
2
2
  import { colors, priceColor } from "../../../../theme/colors";
3
3
  import { displayWidth, formatNumber, padTo } from "../../../../utils/format";
4
4
  import { formatMarketPriceWithCurrency } from "../../../../market-data/market/format";
5
+ import { t } from "../../../../i18n";
5
6
  import type { Quote } from "../../../../types/financials";
6
7
  import type { PositionTableRow, StatField } from "./types";
7
8
 
@@ -115,9 +116,9 @@ export function QuoteBook({ quote, assetCategory, width }: { quote: Quote; asset
115
116
 
116
117
  return (
117
118
  <Box flexDirection="column" width={width} flexShrink={0}>
118
- <BookRow label="Bid" value={bidText} width={width} valueColor={colors.borderFocused} />
119
- <BookRow label="Ask" value={askText} width={width} valueColor={colors.negative} />
120
- <BookRow label="Spr" value={spreadText} width={width} valueColor={colors.textDim} />
119
+ <BookRow label={t("Bid")} value={bidText} width={width} valueColor={colors.borderFocused} />
120
+ <BookRow label={t("Ask")} value={askText} width={width} valueColor={colors.negative} />
121
+ <BookRow label={t("Spr")} value={spreadText} width={width} valueColor={colors.textDim} />
121
122
  </Box>
122
123
  );
123
124
  }
@@ -154,7 +155,7 @@ export function StatGrid({ fields, width }: { fields: StatField[]; width: number
154
155
  {j > 0 && <Box width={STAT_COLUMN_GAP} />}
155
156
  <Box width={colWidth} flexDirection="row">
156
157
  <Box width={labelWidth} overflow="hidden">
157
- <Text fg={colors.textDim}>{field.label}</Text>
158
+ <Text fg={colors.textDim}>{t(field.label)}</Text>
158
159
  </Box>
159
160
  <Box flexDirection="row" width={valueWidth} justifyContent="flex-end" overflow="hidden">
160
161
  <Text fg={field.valueColor ?? colors.text}>{field.value}</Text>
@@ -219,7 +220,7 @@ export function PositionTable({ rows, width }: { rows: PositionTableRow[]; width
219
220
  {columns.map((column, index) => (
220
221
  <Box key={column.key} flexDirection="row">
221
222
  {index > 0 && <Box width={POSITION_COLUMN_GAP} />}
222
- <Text fg={colors.textDim}>{padTo(column.label, column.width, column.align)}</Text>
223
+ <Text fg={colors.textDim}>{padTo(t(column.label), column.width, column.align)}</Text>
223
224
  </Box>
224
225
  ))}
225
226
  </Box>
@@ -2,6 +2,7 @@ import { Box, ScrollBox, Text, useUiCapabilities } from "../../../ui";
2
2
  import { TextAttributes } from "../../../ui";
3
3
  import { useViewport } from "../../../react/input";
4
4
  import { useFxRatesMap } from "../../../market-data/hooks";
5
+ import { t } from "../../../i18n";
5
6
  import { useAppSelector } from "../../../state/app/context";
6
7
  import { colors, priceColor } from "../../../theme/colors";
7
8
  import { convertCurrency, formatPercentRaw } from "../../../utils/format";
@@ -14,7 +15,12 @@ import {
14
15
  } from "../../../market-data/market/status";
15
16
  import { selectEffectiveExchangeRates } from "../../../utils/exchange-rate-map";
16
17
  import { EmptyState } from "../../../components";
17
- import { ResolvedStockChart } from "../../../components/chart/stock-chart";
18
+ import {
19
+ CompositeChart,
20
+ pricePointsToResolvedSeries,
21
+ } from "../../../components/chart/composite";
22
+ import { resolveExchangeTimeZone } from "../../../utils/exchanges";
23
+ import { appendLiveQuotePoint } from "../../../components/chart/core/data";
18
24
  import { PriceReturnStrip } from "../../../components/price-performance";
19
25
  import {
20
26
  appendQuoteToPriceReturnHistory,
@@ -45,7 +51,7 @@ export function OverviewTab({
45
51
  const { width: termWidth } = useViewport();
46
52
  const { fractionalViewport = false } = useUiCapabilities();
47
53
 
48
- if (!ticker) return <EmptyState title="No ticker selected." />;
54
+ if (!ticker) return <EmptyState title={t("No ticker selected.")} />;
49
55
 
50
56
  const quote = financials?.quote;
51
57
  const fundamentals = financials?.fundamentals;
@@ -83,6 +89,22 @@ export function OverviewTab({
83
89
  const contentWidth = Math.max((width || Math.floor(termWidth * 0.5)) - (fractionalViewport ? 2 : 4), 20);
84
90
  const chartWidth = contentWidth;
85
91
  const hasHistory = (financials?.priceHistory?.length ?? 0) > 2;
92
+ const chartHistory = appendLiveQuotePoint(financials?.priceHistory ?? [], quote);
93
+ const chartDelta = (chartHistory.at(-1)?.close ?? 0) - (chartHistory[0]?.close ?? 0);
94
+ const chartTimeZone = resolveExchangeTimeZone(
95
+ ticker.metadata.exchange || quote?.listingExchangeName || quote?.exchangeName,
96
+ );
97
+ const priceSeries = pricePointsToResolvedSeries(chartHistory, {
98
+ id: `${ticker.metadata.ticker}:price`,
99
+ label: `${ticker.metadata.ticker} Price`,
100
+ color: priceColor(chartDelta),
101
+ unit: quoteCurrency,
102
+ style: "area",
103
+ axis: "right",
104
+ panelId: "price",
105
+ providerId: quote?.provenance?.price?.providerId ?? quote?.providerId,
106
+ timeBasis: chartTimeZone ? { kind: "market", timeZone: chartTimeZone } : undefined,
107
+ });
86
108
  const hasBidAsk = quote?.bid != null || quote?.ask != null;
87
109
  const quoteBookInline = hasBidAsk && contentWidth >= 68;
88
110
  const quoteBookWidth = quoteBookInline ? Math.min(32, Math.max(24, Math.floor(contentWidth * 0.3))) : Math.min(contentWidth, 32);
@@ -141,7 +163,7 @@ export function OverviewTab({
141
163
  )}
142
164
  {quote?.marketState && (
143
165
  <Text fg={marketStateColor(quote.marketState)}>
144
- {" "}{marketStateLabel(quote.marketState)}
166
+ {" "}{t(marketStateLabel(quote.marketState))}
145
167
  </Text>
146
168
  )}
147
169
  </Box>
@@ -158,7 +180,7 @@ export function OverviewTab({
158
180
  )}
159
181
  {quote && (quote.marketState === "PRE" || quote.marketState === "PREPRE") && quote.preMarketPrice != null && (
160
182
  <Box flexDirection="row" gap={2}>
161
- <Text fg={colors.textDim}>Pre-Market:</Text>
183
+ <Text fg={colors.textDim}>{t("Pre-Market")}:</Text>
162
184
  <Text fg={priceColor(quote.preMarketChange ?? 0)}>
163
185
  {formatMarketPriceWithCurrency(quote.preMarketPrice, quote.currency, { assetCategory: ticker.metadata.assetCategory })}
164
186
  </Text>
@@ -169,7 +191,7 @@ export function OverviewTab({
169
191
  )}
170
192
  {quote && (quote.marketState === "POST" || quote.marketState === "POSTPOST") && quote.postMarketPrice != null && (
171
193
  <Box flexDirection="row" gap={2}>
172
- <Text fg={colors.textDim}>After-Hours:</Text>
194
+ <Text fg={colors.textDim}>{t("After-Hours")}:</Text>
173
195
  <Text fg={priceColor(quote.postMarketChange ?? 0)}>
174
196
  {formatMarketPriceWithCurrency(quote.postMarketPrice, quote.currency, { assetCategory: ticker.metadata.assetCategory })}
175
197
  </Text>
@@ -218,33 +240,35 @@ export function OverviewTab({
218
240
  )}
219
241
 
220
242
  {hasHistory && (
221
- <ResolvedStockChart
243
+ <CompositeChart
222
244
  width={chartWidth}
223
245
  height={10}
224
246
  focused={false}
225
- compact
226
- ticker={ticker}
227
- financials={financials}
247
+ interactive={false}
248
+ series={[priceSeries]}
249
+ panels={[{ id: "price" }]}
250
+ axisWidth={8}
251
+ showLegend={false}
228
252
  />
229
253
  )}
230
254
 
231
255
  {hasPerformance && (
232
256
  <Box flexDirection="column">
233
- <SectionHeader title="Price Return" />
257
+ <SectionHeader title={t("Price Return")} />
234
258
  <PriceReturnStrip fields={performanceFields} width={contentWidth} />
235
259
  </Box>
236
260
  )}
237
261
 
238
262
  {stats.length > 0 && (
239
263
  <Box flexDirection="column">
240
- <SectionHeader title="Fundamentals" />
264
+ <SectionHeader title={t("Fundamentals")} />
241
265
  <StatGrid fields={stats} width={contentWidth} />
242
266
  </Box>
243
267
  )}
244
268
 
245
269
  {positionRows.length > 0 && (
246
270
  <Box flexDirection="column">
247
- <SectionHeader title="Positions" />
271
+ <SectionHeader title={t("Positions")} />
248
272
  <PositionTable rows={positionRows} width={contentWidth} />
249
273
  </Box>
250
274
  )}
@@ -254,19 +278,19 @@ export function OverviewTab({
254
278
  <Box flexDirection="row" height={1} gap={3}>
255
279
  {ticker.metadata.assetCategory && (
256
280
  <Box flexDirection="row">
257
- <Text fg={colors.textDim}>Type: </Text>
281
+ <Text fg={colors.textDim}>{t("Type")}: </Text>
258
282
  <Text fg={colors.text}>{ticker.metadata.assetCategory}</Text>
259
283
  </Box>
260
284
  )}
261
285
  {sector && (
262
286
  <Box flexDirection="row">
263
- <Text fg={colors.textDim}>Sector: </Text>
287
+ <Text fg={colors.textDim}>{t("Sector")}: </Text>
264
288
  <Text fg={colors.text}>{sector}</Text>
265
289
  </Box>
266
290
  )}
267
291
  {industry && (
268
292
  <Box flexDirection="row">
269
- <Text fg={colors.textDim}>Industry: </Text>
293
+ <Text fg={colors.textDim}>{t("Industry")}: </Text>
270
294
  <Text fg={colors.text}>{industry}</Text>
271
295
  </Box>
272
296
  )}
@@ -276,7 +300,7 @@ export function OverviewTab({
276
300
  {/* ISIN */}
277
301
  {ticker.metadata.isin && (
278
302
  <Box flexDirection="row" height={1}>
279
- <Text fg={colors.textDim}>ISIN: </Text>
303
+ <Text fg={colors.textDim}>{t("ISIN")}: </Text>
280
304
  <Text fg={colors.text}>{ticker.metadata.isin}</Text>
281
305
  </Box>
282
306
  )}
@@ -284,7 +308,7 @@ export function OverviewTab({
284
308
  {/* Description — last, collapsed */}
285
309
  {description && (
286
310
  <Box flexDirection="column" width={contentWidth}>
287
- <SectionHeader title="Description" />
311
+ <SectionHeader title={t("Description")} />
288
312
  <Text fg={colors.text} width={contentWidth} wrapMode="word" wrapText>{description}</Text>
289
313
  </Box>
290
314
  )}
@@ -1,6 +1,7 @@
1
1
  import { Box } from "../../../ui";
2
2
  import { useCallback, useEffect, useMemo, useState, useSyncExternalStore } from "react";
3
3
  import type { PaneProps, TickerResearchTabDef } from "../../../types/plugin";
4
+ import { t, tf } from "../../../i18n";
4
5
  import { quoteSubscriptionTargetFromTicker } from "../../../market-data/request-types";
5
6
  import {
6
7
  useAppDispatch,
@@ -159,8 +160,8 @@ export function TickerResearchPane({ focused, width, height }: PaneProps) {
159
160
  if (!ticker) {
160
161
  const isEmptyFollowCollection = paneInstance?.binding?.kind === "follow" && !!collectionId && collectionTickerCount === 0;
161
162
  const message = isEmptyFollowCollection
162
- ? `No tickers in ${collectionName || "this collection"}.`
163
- : "No ticker selected.";
163
+ ? tf("No tickers in {name}.", { name: collectionName || t("this collection") })
164
+ : t("No ticker selected.");
164
165
 
165
166
  return (
166
167
  <Box flexDirection="column" flexGrow={1} paddingX={1}>
@@ -173,7 +174,7 @@ export function TickerResearchPane({ focused, width, height }: PaneProps) {
173
174
  <Box flexDirection="column" flexGrow={1} flexBasis={0} overflow="hidden">
174
175
  {!paneSettings.hideTabs && (
175
176
  <Tabs
176
- tabs={allTabs.map((tab) => ({ label: tab.name, value: tab.id }))}
177
+ tabs={allTabs.map((tab) => ({ label: t(tab.name), value: tab.id }))}
177
178
  activeValue={resolvedTabId}
178
179
  onSelect={setActiveTabId}
179
180
  focused={focused && !pluginCaptured}
@@ -152,7 +152,7 @@ function createQuoteMonitorHarness(options: {
152
152
  return (
153
153
  <AppContext value={{ state, dispatch: () => {} }}>
154
154
  <PaneInstanceProvider paneId="quote-monitor:test">
155
- <PluginRenderProvider pluginId="ticker-detail" runtime={makeRuntime({
155
+ <PluginRenderProvider pluginId="ticker-research" runtime={makeRuntime({
156
156
  pinCalls: options.pinCalls,
157
157
  settingsCalls: options.settingsCalls,
158
158
  })}>