gloomberb 0.5.0 → 0.6.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 (500) hide show
  1. package/README.md +91 -11
  2. package/package.json +12 -5
  3. package/src/app.tsx +414 -191
  4. package/src/architecture/import-boundaries.test.ts +118 -0
  5. package/src/assets/gloomberb-logo.png +0 -0
  6. package/src/assets/gloomberb-logo.svg +73 -0
  7. package/src/brokers/account-cache.ts +157 -0
  8. package/src/brokers/profile-form.test.ts +73 -0
  9. package/src/brokers/profile-form.ts +109 -0
  10. package/src/brokers/remote-broker-adapter.ts +91 -0
  11. package/src/brokers/sync-broker-instance.test.ts +124 -1
  12. package/src/brokers/sync-broker-instance.ts +113 -17
  13. package/src/capabilities/factories.ts +100 -0
  14. package/src/capabilities/index.ts +4 -0
  15. package/src/capabilities/registry.test.ts +137 -0
  16. package/src/capabilities/registry.ts +131 -0
  17. package/src/capabilities/service-capabilities.ts +27 -0
  18. package/src/capabilities/types.ts +84 -0
  19. package/src/cli/commands/ticker.ts +11 -3
  20. package/src/cli/context.ts +19 -13
  21. package/src/cli/helpers.ts +1 -0
  22. package/src/cli/types.ts +2 -2
  23. package/src/components/chart/chart-controller.ts +4 -24
  24. package/src/components/chart/chart-data.ts +3 -14
  25. package/src/components/chart/chart-indicator-selector.tsx +28 -6
  26. package/src/components/chart/chart-pane-settings.ts +15 -28
  27. package/src/components/chart/chart-renderer.ts +74 -99
  28. package/src/components/chart/chart-resolution.ts +10 -10
  29. package/src/components/chart/chart-scroll.test.ts +6 -5
  30. package/src/components/chart/chart-scroll.ts +2 -2
  31. package/src/components/chart/chart-types.ts +0 -1
  32. package/src/components/chart/chart-viewport.ts +2 -1
  33. package/src/components/chart/chart.test.ts +37 -0
  34. package/src/components/chart/comparison-chart-data.ts +3 -17
  35. package/src/components/chart/comparison-chart-renderer.test.ts +27 -4
  36. package/src/components/chart/comparison-chart-renderer.ts +1 -1
  37. package/src/components/chart/comparison-stock-chart.tsx +304 -108
  38. package/src/components/chart/cursor-motion.ts +3 -2
  39. package/src/components/chart/indicators/bands.test.ts +0 -14
  40. package/src/components/chart/indicators/moving-averages.test.ts +0 -15
  41. package/src/components/chart/indicators/options.ts +3 -3
  42. package/src/components/chart/indicators/oscillators.test.ts +0 -21
  43. package/src/components/chart/indicators/types.ts +1 -2
  44. package/src/components/chart/native/chart-rasterizer.ts +37 -44
  45. package/src/components/chart/native/kitty-adapter.ts +2 -5
  46. package/src/components/chart/native/kitty-manager.ts +1 -1
  47. package/src/components/chart/native/kitty-protocol.ts +0 -1
  48. package/src/components/chart/native/kitty-support.ts +1 -1
  49. package/src/components/chart/native/kitty.test.ts +30 -13
  50. package/src/components/chart/native/renderer-selection.ts +1 -1
  51. package/src/components/chart/native/surface-manager.ts +1 -1
  52. package/src/components/chart/static-chart-surface.test.tsx +51 -0
  53. package/src/components/chart/static-chart-surface.tsx +191 -0
  54. package/src/components/chart/stock-chart-renderer-switch.test.tsx +242 -35
  55. package/src/components/chart/stock-chart.tsx +438 -141
  56. package/src/components/command-bar/__snapshots__/command-bar.test.tsx.snap +4 -4
  57. package/src/components/command-bar/command-bar.test.tsx +269 -20
  58. package/src/components/command-bar/command-bar.tsx +830 -353
  59. package/src/components/command-bar/command-registry.ts +10 -20
  60. package/src/components/command-bar/helpers.test.ts +1 -1
  61. package/src/components/command-bar/helpers.ts +9 -11
  62. package/src/components/command-bar/pane-template-display.ts +4 -8
  63. package/src/components/command-bar/root-shortcuts.ts +12 -11
  64. package/src/components/command-bar/view-model.test.ts +8 -42
  65. package/src/components/command-bar/view-model.ts +8 -36
  66. package/src/components/command-bar/workflow-ops.test.ts +76 -2
  67. package/src/components/command-bar/workflow-ops.ts +40 -9
  68. package/src/components/command-bar/workflow-types.ts +2 -1
  69. package/src/components/data-table-stack-view.test.tsx +206 -0
  70. package/src/components/data-table-stack-view.tsx +152 -0
  71. package/src/components/data-table-view.test.tsx +188 -0
  72. package/src/components/data-table-view.tsx +279 -0
  73. package/src/components/feed-data-table-stack-view.test.tsx +225 -0
  74. package/src/components/feed-data-table-stack-view.tsx +365 -0
  75. package/src/components/index.ts +26 -31
  76. package/src/components/layout/detached-pane-shell.tsx +185 -0
  77. package/src/components/layout/floating-pane.tsx +87 -13
  78. package/src/components/layout/header.tsx +139 -49
  79. package/src/components/layout/pane-content.tsx +40 -0
  80. package/src/components/layout/pane-footer.test.tsx +195 -0
  81. package/src/components/layout/pane-footer.tsx +410 -0
  82. package/src/components/layout/pane-header.test.tsx +39 -0
  83. package/src/components/layout/pane-header.tsx +192 -14
  84. package/src/components/layout/pane-sizing.ts +13 -4
  85. package/src/components/layout/pane-title.ts +35 -0
  86. package/src/components/layout/pane.tsx +56 -8
  87. package/src/components/layout/shell.test.tsx +322 -19
  88. package/src/components/layout/shell.tsx +1010 -366
  89. package/src/components/layout/status-bar.test.tsx +17 -10
  90. package/src/components/layout/status-bar.tsx +367 -100
  91. package/src/components/layout/titlebar-overlay.ts +2 -0
  92. package/src/components/markdown-editor.tsx +29 -14
  93. package/src/components/markdown-text.tsx +25 -24
  94. package/src/components/onboarding/onboarding-wizard.test.tsx +8 -3
  95. package/src/components/onboarding/onboarding-wizard.tsx +347 -473
  96. package/src/components/pane-settings-dialog.tsx +521 -89
  97. package/src/components/pane-template-wizard.test.tsx +1 -1
  98. package/src/components/pane-template-wizard.tsx +38 -37
  99. package/src/components/price-selector-dialog.tsx +22 -21
  100. package/src/components/ticker-badge-list.tsx +53 -0
  101. package/src/components/ticker-badge-text.test.tsx +44 -1
  102. package/src/components/ticker-badge-text.tsx +78 -38
  103. package/src/components/ticker-badge.tsx +28 -7
  104. package/src/components/ticker-list-table-view.tsx +248 -0
  105. package/src/components/ticker-list-table.test.tsx +47 -1
  106. package/src/components/ticker-list-table.tsx +212 -41
  107. package/src/components/toggle-list.tsx +114 -8
  108. package/src/components/ui/button.tsx +24 -16
  109. package/src/components/ui/choice-dialog.tsx +89 -0
  110. package/src/components/ui/data-table.tsx +313 -114
  111. package/src/components/ui/external-link.tsx +52 -13
  112. package/src/components/ui/fields.tsx +44 -30
  113. package/src/components/ui/frame.tsx +24 -57
  114. package/src/components/ui/index.ts +15 -50
  115. package/src/components/ui/list-view.tsx +65 -25
  116. package/src/components/ui/loading.tsx +5 -60
  117. package/src/components/ui/message-composer.test.tsx +81 -0
  118. package/src/components/ui/message-composer.tsx +139 -0
  119. package/src/components/ui/multi-select-dialog.tsx +100 -32
  120. package/src/components/ui/multi-select.ts +112 -0
  121. package/src/components/ui/native-select.tsx +120 -0
  122. package/src/components/ui/page-stack-view.tsx +49 -19
  123. package/src/components/ui/remote-image.tsx +75 -0
  124. package/src/components/ui/row-value-cache.test.ts +17 -0
  125. package/src/components/ui/row-value-cache.ts +41 -0
  126. package/src/components/ui/shortcut-hint.tsx +55 -0
  127. package/src/components/ui/status.tsx +12 -67
  128. package/src/components/ui/table-layout.ts +59 -0
  129. package/src/components/ui/tabs.tsx +249 -27
  130. package/src/components/ui/toggle.tsx +19 -127
  131. package/src/components/ui/ui.test.tsx +266 -53
  132. package/src/components/use-double-click-activation.ts +7 -2
  133. package/src/components/use-external-link-footer.ts +79 -0
  134. package/src/core/app-services.ts +95 -0
  135. package/src/core/state/app-state.ts +886 -0
  136. package/src/{state → core/state}/session-persistence.ts +7 -6
  137. package/src/data/config-layout.ts +225 -0
  138. package/src/data/config-store-node.ts +390 -0
  139. package/src/data/config-store.test.ts +72 -0
  140. package/src/data/config-store.ts +35 -478
  141. package/src/data/sqlite-json.ts +2 -5
  142. package/src/data/sqlite-retry.ts +1 -0
  143. package/src/index.tsx +2 -68
  144. package/src/market-data/coordinator-subscriptions.test.ts +125 -0
  145. package/src/market-data/coordinator.test.ts +73 -4
  146. package/src/market-data/coordinator.ts +190 -24
  147. package/src/market-data/hooks.test.tsx +1 -1
  148. package/src/market-data/hooks.tsx +109 -87
  149. package/src/market-data/query-store.ts +3 -3
  150. package/src/market-data/request-types.test.ts +0 -14
  151. package/src/market-data/result-types.ts +1 -0
  152. package/src/news/aggregator.test.ts +267 -0
  153. package/src/news/aggregator.ts +452 -0
  154. package/src/news/hooks.ts +39 -0
  155. package/src/news/ticker-symbols.ts +21 -0
  156. package/src/news/types.ts +77 -0
  157. package/src/notifications/app-notifier.ts +21 -10
  158. package/src/pane-settings.test.ts +0 -2
  159. package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +124 -134
  160. package/src/plugins/builtin/ai/gloomberb-cli.ts +14 -13
  161. package/src/plugins/builtin/ai/providers.ts +1 -9
  162. package/src/plugins/builtin/ai/runner.ts +41 -5
  163. package/src/plugins/builtin/ai/screener-pane.test.tsx +37 -55
  164. package/src/plugins/builtin/ai/screener-pane.tsx +231 -276
  165. package/src/plugins/builtin/ai/settings.ts +0 -1
  166. package/src/plugins/builtin/ai/utils.ts +1 -71
  167. package/src/plugins/builtin/alerts/alert-engine.test.ts +1 -38
  168. package/src/plugins/builtin/alerts/index.test.tsx +61 -82
  169. package/src/plugins/builtin/alerts/index.tsx +263 -155
  170. package/src/plugins/builtin/alerts/types.ts +7 -0
  171. package/src/plugins/builtin/analytics/index.test.tsx +13 -8
  172. package/src/plugins/builtin/analytics/index.tsx +78 -120
  173. package/src/plugins/builtin/analytics/metrics.test.ts +0 -4
  174. package/src/plugins/builtin/ask-ai.test.tsx +55 -54
  175. package/src/plugins/builtin/broker-manager/index.test.tsx +168 -0
  176. package/src/plugins/builtin/broker-manager/index.tsx +759 -0
  177. package/src/plugins/builtin/broker-manager/model.test.ts +107 -0
  178. package/src/plugins/builtin/broker-manager/model.ts +142 -0
  179. package/src/plugins/builtin/chat-controller.test.ts +150 -0
  180. package/src/plugins/builtin/chat-controller.ts +88 -16
  181. package/src/plugins/builtin/chat.test.tsx +283 -36
  182. package/src/plugins/builtin/chat.tsx +373 -172
  183. package/src/plugins/builtin/cloud-auth-actions.tsx +72 -0
  184. package/src/plugins/builtin/cloud-tweets.tsx +896 -0
  185. package/src/plugins/builtin/comparison-chart.test.tsx +46 -57
  186. package/src/plugins/builtin/comparison-chart.tsx +11 -11
  187. package/src/plugins/builtin/correlation/compute.test.ts +0 -17
  188. package/src/plugins/builtin/correlation/index.tsx +51 -46
  189. package/src/plugins/builtin/correlation/settings.ts +1 -2
  190. package/src/plugins/builtin/debug.tsx +99 -70
  191. package/src/plugins/builtin/earnings/earnings-cache.test.ts +2 -2
  192. package/src/plugins/builtin/earnings/earnings-cache.ts +12 -3
  193. package/src/plugins/builtin/earnings/earnings-data.test.ts +42 -11
  194. package/src/plugins/builtin/earnings/earnings-data.ts +70 -5
  195. package/src/plugins/builtin/earnings/index.tsx +187 -94
  196. package/src/plugins/builtin/econ/calendar-source.ts +9 -116
  197. package/src/plugins/builtin/econ/fred-client.test.ts +1 -14
  198. package/src/plugins/builtin/econ/fred-series-map.ts +1 -0
  199. package/src/plugins/builtin/econ/index.tsx +236 -421
  200. package/src/plugins/builtin/econ/types.ts +1 -0
  201. package/src/plugins/builtin/fx-matrix/index.tsx +43 -45
  202. package/src/plugins/builtin/fx-matrix/pairs.ts +1 -0
  203. package/src/plugins/builtin/help.test.tsx +120 -60
  204. package/src/plugins/builtin/help.tsx +266 -82
  205. package/src/plugins/builtin/holders/index.test.ts +45 -0
  206. package/src/plugins/builtin/holders/index.tsx +949 -0
  207. package/src/plugins/builtin/insider/index.tsx +207 -253
  208. package/src/plugins/builtin/insider/insider-data.test.ts +1 -11
  209. package/src/plugins/builtin/insider/insider-data.ts +1 -0
  210. package/src/plugins/builtin/layout-manager.tsx +12 -40
  211. package/src/plugins/builtin/market-movers/index.tsx +70 -144
  212. package/src/plugins/builtin/market-movers/screener.test.ts +0 -18
  213. package/src/plugins/builtin/news-wire/breaking-notifications.test.ts +98 -0
  214. package/src/plugins/builtin/news-wire/breaking-notifications.ts +110 -0
  215. package/src/plugins/builtin/news-wire/breaking-pane.tsx +157 -0
  216. package/src/plugins/builtin/news-wire/categories.ts +114 -0
  217. package/src/plugins/builtin/news-wire/default-feeds.ts +3 -0
  218. package/src/plugins/builtin/news-wire/digest-store.ts +44 -0
  219. package/src/plugins/builtin/news-wire/feed-config.test.ts +90 -0
  220. package/src/plugins/builtin/news-wire/feed-config.ts +216 -0
  221. package/src/plugins/builtin/news-wire/feed-pane.tsx +21 -0
  222. package/src/plugins/builtin/news-wire/hash.ts +9 -0
  223. package/src/plugins/builtin/news-wire/index.tsx +92 -0
  224. package/src/plugins/builtin/news-wire/industry-pane.tsx +140 -0
  225. package/src/plugins/builtin/news-wire/news-detail-view.tsx +256 -0
  226. package/src/plugins/builtin/news-wire/news-footer.ts +28 -0
  227. package/src/plugins/builtin/news-wire/news-preset-pane.tsx +94 -0
  228. package/src/plugins/builtin/news-wire/news-query-presets.ts +40 -0
  229. package/src/plugins/builtin/news-wire/news-table.test.tsx +206 -0
  230. package/src/plugins/builtin/news-wire/news-table.tsx +296 -0
  231. package/src/plugins/builtin/news-wire/persisted-articles.ts +92 -0
  232. package/src/plugins/builtin/news-wire/read-state.test.ts +30 -0
  233. package/src/plugins/builtin/news-wire/read-state.ts +76 -0
  234. package/src/plugins/builtin/news-wire/rss-parser.test.ts +184 -0
  235. package/src/plugins/builtin/news-wire/rss-parser.ts +213 -0
  236. package/src/plugins/builtin/news-wire/rss-source.test.ts +159 -0
  237. package/src/plugins/builtin/news-wire/rss-source.ts +181 -0
  238. package/src/plugins/builtin/news-wire/top-pane.tsx +21 -0
  239. package/src/plugins/builtin/news.tsx +98 -25
  240. package/src/plugins/builtin/notes-files.ts +51 -10
  241. package/src/plugins/builtin/notes.tsx +332 -131
  242. package/src/plugins/builtin/options.test.tsx +185 -0
  243. package/src/plugins/builtin/options.tsx +346 -206
  244. package/src/plugins/builtin/plugin-groups.ts +92 -0
  245. package/src/plugins/builtin/portfolio-list/header.tsx +72 -37
  246. package/src/plugins/builtin/portfolio-list/index.tsx +25 -42
  247. package/src/plugins/builtin/portfolio-list/metrics.ts +1 -1
  248. package/src/plugins/builtin/portfolio-list/pane.tsx +246 -164
  249. package/src/plugins/builtin/portfolio-list/settings.ts +19 -51
  250. package/src/plugins/builtin/portfolio-list/summary.tsx +21 -16
  251. package/src/plugins/builtin/portfolio-list/table.tsx +66 -25
  252. package/src/plugins/builtin/portfolio-list/use-throttled-cursor-symbol.test.tsx +1 -1
  253. package/src/plugins/builtin/portfolio-list/use-throttled-cursor-symbol.ts +1 -1
  254. package/src/plugins/builtin/portfolio-list.test.ts +60 -1
  255. package/src/plugins/builtin/portfolio-list.test.tsx +122 -55
  256. package/src/plugins/builtin/quote-monitor.test.tsx +2 -27
  257. package/src/plugins/builtin/research/index.tsx +724 -0
  258. package/src/plugins/builtin/sec.tsx +67 -19
  259. package/src/plugins/builtin/sectors/index.tsx +42 -80
  260. package/src/plugins/builtin/sectors/sector-data.ts +1 -0
  261. package/src/plugins/builtin/ticker-detail/chart-tab.tsx +25 -39
  262. package/src/plugins/builtin/ticker-detail/financials-tab.tsx +108 -58
  263. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +383 -271
  264. package/src/plugins/builtin/ticker-detail/pane.tsx +135 -49
  265. package/src/plugins/builtin/ticker-detail/quote-monitor.tsx +43 -27
  266. package/src/plugins/builtin/ticker-detail/settings.ts +3 -6
  267. package/src/plugins/builtin/ticker-detail-chart-tab-switch.test.tsx +16 -10
  268. package/src/plugins/builtin/ticker-detail.test.tsx +156 -33
  269. package/src/plugins/builtin/ticker-surface.ts +68 -0
  270. package/src/plugins/builtin/world-indices/index.tsx +44 -82
  271. package/src/plugins/builtin/world-indices/indices.ts +1 -0
  272. package/src/plugins/builtin/yahoo.ts +55 -1
  273. package/src/plugins/builtin/yield-curve/index.tsx +87 -145
  274. package/src/plugins/builtin/yield-curve/treasury-data.ts +6 -77
  275. package/src/plugins/catalog-ui.test.ts +24 -0
  276. package/src/plugins/catalog-ui.ts +44 -0
  277. package/src/plugins/catalog.ts +2 -50
  278. package/src/plugins/ibkr/__snapshots__/trade-tab.test.tsx.snap +5 -5
  279. package/src/plugins/ibkr/account-cache.test.ts +15 -14
  280. package/src/plugins/ibkr/account-cache.ts +15 -120
  281. package/src/plugins/ibkr/broker-adapter.ts +67 -0
  282. package/src/plugins/ibkr/config.test.ts +0 -18
  283. package/src/plugins/ibkr/dialogs.tsx +14 -56
  284. package/src/plugins/ibkr/flex.test.ts +57 -2
  285. package/src/plugins/ibkr/flex.ts +116 -12
  286. package/src/plugins/ibkr/gateway-helpers.ts +8 -3
  287. package/src/plugins/ibkr/gateway-service-native.ts +2381 -0
  288. package/src/plugins/ibkr/gateway-service.test.ts +47 -9
  289. package/src/plugins/ibkr/gateway-service.ts +264 -2235
  290. package/src/plugins/ibkr/gateway-types.ts +27 -0
  291. package/src/plugins/ibkr/index.test.tsx +3 -11
  292. package/src/plugins/ibkr/index.tsx +1 -0
  293. package/src/plugins/ibkr/price-normalization.test.ts +1 -6
  294. package/src/plugins/ibkr/price-normalization.ts +1 -0
  295. package/src/plugins/ibkr/trade-badge.tsx +6 -5
  296. package/src/plugins/ibkr/trade-tab.test.tsx +2 -2
  297. package/src/plugins/ibkr/trade-tab.tsx +164 -117
  298. package/src/plugins/ibkr/trading-pane.tsx +117 -83
  299. package/src/plugins/pane-manager.test.ts +3 -1
  300. package/src/plugins/pane-manager.ts +93 -19
  301. package/src/plugins/plugin-runtime.test.tsx +176 -74
  302. package/src/plugins/plugin-runtime.tsx +228 -10
  303. package/src/plugins/prediction-markets/cache.ts +49 -0
  304. package/src/plugins/prediction-markets/categories.ts +0 -10
  305. package/src/plugins/prediction-markets/chart.test.tsx +1 -1
  306. package/src/plugins/prediction-markets/chart.tsx +21 -20
  307. package/src/plugins/prediction-markets/cli.ts +1 -0
  308. package/src/plugins/prediction-markets/controller-data.ts +135 -89
  309. package/src/plugins/prediction-markets/controller.ts +37 -108
  310. package/src/plugins/prediction-markets/detail/book.tsx +23 -22
  311. package/src/plugins/prediction-markets/detail/outcomes.tsx +33 -32
  312. package/src/plugins/prediction-markets/detail/overview.tsx +17 -12
  313. package/src/plugins/prediction-markets/detail/pane.tsx +59 -45
  314. package/src/plugins/prediction-markets/detail/rules.tsx +22 -7
  315. package/src/plugins/prediction-markets/detail/shared.tsx +3 -2
  316. package/src/plugins/prediction-markets/detail/trades.tsx +12 -11
  317. package/src/plugins/prediction-markets/detail.test.tsx +1 -1
  318. package/src/plugins/prediction-markets/keyboard.ts +1 -0
  319. package/src/plugins/prediction-markets/launch.test.ts +1 -1
  320. package/src/plugins/prediction-markets/launch.ts +1 -1
  321. package/src/plugins/prediction-markets/metrics.ts +25 -12
  322. package/src/plugins/prediction-markets/pane.test.tsx +16 -7
  323. package/src/plugins/prediction-markets/pane.tsx +180 -82
  324. package/src/plugins/prediction-markets/plugin.test.tsx +37 -45
  325. package/src/plugins/prediction-markets/services/fetch.ts +27 -10
  326. package/src/plugins/prediction-markets/services/kalshi-adapter.ts +20 -3
  327. package/src/plugins/prediction-markets/services/polymarket-adapter.ts +29 -11
  328. package/src/plugins/prediction-markets/settings.ts +0 -5
  329. package/src/plugins/prediction-markets/test-helpers.tsx +19 -44
  330. package/src/plugins/registry.test.ts +307 -0
  331. package/src/plugins/registry.ts +293 -82
  332. package/src/react/input.ts +53 -0
  333. package/src/react/plugins/plugin-slot.tsx +21 -0
  334. package/src/react/use-raf-callback.ts +44 -0
  335. package/src/renderers/electrobun/bun/application-menu-click.test.ts +41 -0
  336. package/src/renderers/electrobun/bun/application-menu-click.ts +55 -0
  337. package/src/renderers/electrobun/bun/application-menu.ts +118 -0
  338. package/src/renderers/electrobun/bun/context-menu-click.test.ts +67 -0
  339. package/src/renderers/electrobun/bun/context-menu-click.ts +61 -0
  340. package/src/renderers/electrobun/bun/context-menu-normalize.test.ts +52 -0
  341. package/src/renderers/electrobun/bun/context-menu-normalize.ts +67 -0
  342. package/src/renderers/electrobun/bun/core-capabilities.ts +328 -0
  343. package/src/renderers/electrobun/bun/desktop-workspace.test.ts +63 -0
  344. package/src/renderers/electrobun/bun/desktop-workspace.ts +162 -0
  345. package/src/renderers/electrobun/bun/index.ts +1149 -0
  346. package/src/renderers/electrobun/bun/window-frame.test.ts +40 -0
  347. package/src/renderers/electrobun/bun/window-frame.ts +46 -0
  348. package/src/renderers/electrobun/shared/protocol.ts +72 -0
  349. package/src/renderers/electrobun/view/ai-host.ts +93 -0
  350. package/src/renderers/electrobun/view/app-services.ts +348 -0
  351. package/src/renderers/electrobun/view/application-menu-bridge.ts +12 -0
  352. package/src/renderers/electrobun/view/backend-rpc.ts +173 -0
  353. package/src/renderers/electrobun/view/broker-remote-client.ts +154 -0
  354. package/src/renderers/electrobun/view/config-host.ts +35 -0
  355. package/src/renderers/electrobun/view/context-menu.test.ts +140 -0
  356. package/src/renderers/electrobun/view/context-menu.ts +164 -0
  357. package/src/renderers/electrobun/view/data-table.tsx +773 -0
  358. package/src/renderers/electrobun/view/desktop-controls.tsx +651 -0
  359. package/src/renderers/electrobun/view/desktop-window-bridge.ts +59 -0
  360. package/src/renderers/electrobun/view/desktop-window-snapshot.test.ts +57 -0
  361. package/src/renderers/electrobun/view/desktop-window-snapshot.ts +41 -0
  362. package/src/renderers/electrobun/view/dialog-host.tsx +62 -0
  363. package/src/renderers/electrobun/view/http-fetch.ts +113 -0
  364. package/src/renderers/electrobun/view/input-host.tsx +65 -0
  365. package/src/renderers/electrobun/view/key-event.test.ts +34 -0
  366. package/src/renderers/electrobun/view/key-event.ts +134 -0
  367. package/src/renderers/electrobun/view/main.tsx +104 -0
  368. package/src/renderers/electrobun/view/native-renderer.ts +110 -0
  369. package/src/renderers/electrobun/view/native-stubs/chart-kitty-support.ts +9 -0
  370. package/src/renderers/electrobun/view/native-stubs/chart-surface-manager.ts +25 -0
  371. package/src/renderers/electrobun/view/native-stubs/chart-surface-sync.ts +1 -0
  372. package/src/renderers/electrobun/view/notes-files.ts +56 -0
  373. package/src/renderers/electrobun/view/resource-store.test.ts +44 -0
  374. package/src/renderers/electrobun/view/resource-store.ts +106 -0
  375. package/src/renderers/electrobun/view/rpc-codec.ts +42 -0
  376. package/src/renderers/electrobun/view/scrollbar-activity.ts +23 -0
  377. package/src/renderers/electrobun/view/toast-host.tsx +65 -0
  378. package/src/renderers/electrobun/view/ui-host.tsx +1490 -0
  379. package/src/renderers/electrobun/view/update-host.ts +38 -0
  380. package/src/renderers/opentui/dialog-host.test.tsx +44 -0
  381. package/src/renderers/opentui/dialog-host.tsx +56 -0
  382. package/src/renderers/opentui/host.tsx +134 -0
  383. package/src/renderers/opentui/input-host.tsx +24 -0
  384. package/src/renderers/opentui/start.tsx +71 -0
  385. package/src/renderers/opentui/test-utils.tsx +76 -0
  386. package/src/renderers/opentui/toast-host.tsx +10 -0
  387. package/src/renderers/opentui/ui-host.tsx +97 -0
  388. package/src/sources/gloomberb-cloud.test.ts +288 -17
  389. package/src/sources/gloomberb-cloud.ts +176 -9
  390. package/src/sources/provider-errors.ts +1 -0
  391. package/src/sources/provider-router.test.ts +220 -81
  392. package/src/sources/provider-router.ts +294 -111
  393. package/src/sources/sec-edgar.ts +19 -6
  394. package/src/sources/yahoo-finance.test.ts +0 -5
  395. package/src/sources/yahoo-finance.ts +420 -11
  396. package/src/state/app-activity.ts +7 -7
  397. package/src/state/app-bootstrap.ts +114 -40
  398. package/src/state/app-context-selector.test.tsx +70 -1
  399. package/src/state/app-context.test.ts +71 -3
  400. package/src/state/app-context.test.tsx +14 -7
  401. package/src/state/app-context.tsx +205 -869
  402. package/src/state/config-save-scheduler.ts +35 -0
  403. package/src/state/persist-scheduler.test.ts +67 -0
  404. package/src/state/persist-scheduler.ts +69 -0
  405. package/src/state/selectors-ui.ts +55 -0
  406. package/src/state/selectors.ts +15 -71
  407. package/src/state/session-persistence.test.ts +1 -1
  408. package/src/state/ticker-refresh-queue.ts +52 -3
  409. package/src/state/use-inline-tickers.ts +18 -16
  410. package/src/state/use-quote-streaming.test.ts +0 -6
  411. package/src/state/use-quote-streaming.test.tsx +1 -1
  412. package/src/state/use-quote-streaming.ts +3 -2
  413. package/src/state/use-session-snapshot.ts +32 -17
  414. package/src/test-support/plugin-runtime.ts +149 -0
  415. package/src/theme/color-utils.ts +1 -0
  416. package/src/theme/colors.ts +16 -0
  417. package/src/types/broker.ts +16 -1
  418. package/src/types/capability-route-source.ts +23 -0
  419. package/src/types/config.test.ts +23 -0
  420. package/src/types/config.ts +145 -10
  421. package/src/types/context-menu.ts +95 -0
  422. package/src/types/data-provider.ts +34 -3
  423. package/src/types/desktop-menu.ts +13 -0
  424. package/src/types/desktop-window.ts +29 -0
  425. package/src/types/financials.ts +123 -2
  426. package/src/types/instrument.ts +1 -0
  427. package/src/types/news-source.ts +9 -0
  428. package/src/types/persistence.ts +1 -0
  429. package/src/types/plugin.ts +32 -8
  430. package/src/ui/ascii-font.ts +85 -0
  431. package/src/ui/context-menu.test.ts +94 -0
  432. package/src/ui/context-menu.tsx +433 -0
  433. package/src/ui/dialog.tsx +55 -0
  434. package/src/ui/host.tsx +361 -0
  435. package/src/ui/index.tsx +126 -0
  436. package/src/ui/toast.tsx +40 -0
  437. package/src/updater.test.ts +69 -0
  438. package/src/updater.ts +61 -18
  439. package/src/utils/api-client.test.ts +186 -6
  440. package/src/utils/api-client.ts +433 -33
  441. package/src/utils/back-navigation.ts +6 -0
  442. package/src/utils/cli-output.ts +1 -0
  443. package/src/utils/currency-units.test.ts +1 -6
  444. package/src/utils/currency-units.ts +1 -0
  445. package/src/utils/debug-log.ts +68 -0
  446. package/src/utils/dom-screenshot.ts +326 -0
  447. package/src/utils/exchange-rate-map.ts +1 -0
  448. package/src/utils/exchanges.ts +214 -0
  449. package/src/utils/format.test.ts +7 -0
  450. package/src/utils/format.ts +1 -0
  451. package/src/utils/fuzzy-search.ts +1 -0
  452. package/src/utils/html-entities.test.ts +8 -0
  453. package/src/utils/html-entities.ts +32 -0
  454. package/src/utils/http-transport.ts +11 -0
  455. package/src/utils/main-thread-monitor.ts +127 -0
  456. package/src/utils/perf-marks.ts +54 -0
  457. package/src/utils/quote-freshness.ts +27 -50
  458. package/src/utils/quote-resolution.test.ts +5 -5
  459. package/src/utils/quote-resolution.ts +0 -1
  460. package/src/utils/quote-time.ts +1 -5
  461. package/src/utils/sec.test.ts +0 -12
  462. package/src/utils/selection-clipboard.ts +14 -6
  463. package/src/utils/shortcut-labels.test.ts +20 -0
  464. package/src/utils/shortcut-labels.ts +67 -0
  465. package/src/utils/slugify.ts +1 -0
  466. package/src/utils/terminal-input-reset.ts +1 -0
  467. package/src/utils/text-wrap.ts +82 -0
  468. package/src/utils/throttled-fetch.test.ts +19 -0
  469. package/src/utils/throttled-fetch.ts +11 -9
  470. package/src/utils/ticker-list.test.ts +1 -7
  471. package/src/utils/ticker-list.ts +1 -0
  472. package/src/utils/timestamp.ts +29 -0
  473. package/src/utils/tweet-text.test.ts +13 -0
  474. package/src/utils/tweet-text.ts +18 -0
  475. package/src/utils/url.ts +11 -0
  476. package/src/version.ts +1 -1
  477. package/src/components/chart/chart-control-hint.tsx +0 -39
  478. package/src/components/detail-feed-view.test.tsx +0 -180
  479. package/src/components/detail-feed-view.tsx +0 -531
  480. package/src/components/layout/pixel-mouse-mode.test.ts +0 -122
  481. package/src/components/layout/pixel-mouse.test.ts +0 -40
  482. package/src/components/spinner.tsx +0 -2
  483. package/src/components/tab-bar.tsx +0 -17
  484. package/src/components/ui/multi-select-chips.tsx +0 -69
  485. package/src/plugins/builtin/ai/index.test.tsx +0 -139
  486. package/src/plugins/builtin/ask-ai.tsx +0 -9
  487. package/src/plugins/builtin/correlation/plugin.test.ts +0 -44
  488. package/src/plugins/builtin/correlation/settings.test.ts +0 -34
  489. package/src/plugins/builtin/econ/calendar-source.test.ts +0 -219
  490. package/src/plugins/builtin/econ/fred-client.ts +0 -79
  491. package/src/plugins/builtin/fred-settings.ts +0 -10
  492. package/src/plugins/builtin/options-availability.test.tsx +0 -179
  493. package/src/plugins/builtin/options-availability.ts +0 -158
  494. package/src/plugins/builtin/portfolio-list/metrics.test.ts +0 -61
  495. package/src/plugins/builtin/yield-curve/treasury-data.test.ts +0 -212
  496. package/src/plugins/prediction-markets/status.ts +0 -24
  497. package/src/plugins/prediction-markets/table.tsx +0 -87
  498. package/src/utils/quote-time.test.ts +0 -22
  499. package/src/utils/selection-clipboard.test.ts +0 -43
  500. package/src/utils/terminal-input-reset.test.ts +0 -50
@@ -1,4 +1,13 @@
1
- import type { Quote, Fundamentals, TickerFinancials, PricePoint, OptionsChain } from "./financials";
1
+ import type {
2
+ AnalystResearchData,
3
+ CorporateActionsData,
4
+ Quote,
5
+ Fundamentals,
6
+ TickerFinancials,
7
+ PricePoint,
8
+ OptionsChain,
9
+ HolderData,
10
+ } from "./financials";
2
11
  import type { TimeRange } from "../components/chart/chart-types";
3
12
  import type { ChartResolutionSupport, ManualChartResolution } from "../components/chart/chart-resolution";
4
13
  import type { BrokerContractRef, InstrumentSearchResult } from "./instrument";
@@ -30,9 +39,27 @@ export interface EarningsEvent {
30
39
  symbol: string;
31
40
  name: string;
32
41
  earningsDate: Date;
42
+ earningsCallDate?: Date | null;
43
+ isDateEstimate?: boolean | null;
33
44
  epsEstimate: number | null;
45
+ epsLow?: number | null;
46
+ epsHigh?: number | null;
47
+ epsYearAgo?: number | null;
48
+ epsGrowth?: number | null;
49
+ epsAnalysts?: number | null;
50
+ epsTrend7dAgo?: number | null;
51
+ epsTrend30dAgo?: number | null;
52
+ epsRevisionUp7d?: number | null;
53
+ epsRevisionUp30d?: number | null;
54
+ epsRevisionDown7d?: number | null;
55
+ epsRevisionDown30d?: number | null;
34
56
  epsActual: number | null;
35
57
  revenueEstimate: number | null;
58
+ revenueLow?: number | null;
59
+ revenueHigh?: number | null;
60
+ revenueYearAgo?: number | null;
61
+ revenueGrowth?: number | null;
62
+ revenueAnalysts?: number | null;
36
63
  revenueActual: number | null;
37
64
  surprise: number | null;
38
65
  timing: "BMO" | "AMC" | "TNS" | "";
@@ -66,7 +93,7 @@ export interface QuoteSubscriptionTarget {
66
93
  route?: "auto" | "provider" | "broker";
67
94
  }
68
95
 
69
- export interface DataProvider {
96
+ export interface AssetDataProvider {
70
97
  readonly id: string;
71
98
  readonly name: string;
72
99
  readonly priority?: number;
@@ -78,8 +105,10 @@ export interface DataProvider {
78
105
  getQuote(ticker: string, exchange?: string, context?: MarketDataRequestContext): Promise<Quote>;
79
106
  getExchangeRate(fromCurrency: string): Promise<number>;
80
107
  search(query: string, context?: SearchRequestContext): Promise<InstrumentSearchResult[]>;
81
- getNews(ticker: string, count?: number, exchange?: string, context?: MarketDataRequestContext): Promise<NewsItem[]>;
82
108
  getSecFilings?(ticker: string, count?: number, exchange?: string, context?: MarketDataRequestContext): Promise<SecFilingItem[]>;
109
+ getHolders?(ticker: string, exchange?: string, context?: MarketDataRequestContext): Promise<HolderData>;
110
+ getAnalystResearch?(ticker: string, exchange?: string, context?: MarketDataRequestContext): Promise<AnalystResearchData>;
111
+ getCorporateActions?(ticker: string, exchange?: string, context?: MarketDataRequestContext): Promise<CorporateActionsData>;
83
112
  getEarningsCalendar?(symbols: string[], context?: MarketDataRequestContext): Promise<EarningsEvent[]>;
84
113
  getSecFilingContent?(filing: SecFilingItem): Promise<string | null>;
85
114
  /** Fetch article summary/description by URL (lazy-loaded on selection) */
@@ -110,3 +139,5 @@ export interface DataProvider {
110
139
  onQuote: (target: QuoteSubscriptionTarget, quote: Quote) => void,
111
140
  ): () => void;
112
141
  }
142
+
143
+ export type DataProvider = AssetDataProvider;
@@ -0,0 +1,13 @@
1
+ export type DesktopApplicationMenuCommand =
2
+ | { type: "open-command-bar"; query?: string }
3
+ | { type: "open-plugin-workflow"; commandId: string }
4
+ | { type: "open-url"; url: string }
5
+ | { type: "check-for-updates" }
6
+ | { type: "toggle-status-bar" }
7
+ | { type: "layout-undo" }
8
+ | { type: "layout-redo" }
9
+ | { type: "layout-gridlock" };
10
+
11
+ export interface DesktopApplicationMenuBridge {
12
+ subscribe(listener: (command: DesktopApplicationMenuCommand) => void): () => void;
13
+ }
@@ -0,0 +1,29 @@
1
+ import type { PaneRuntimeState } from "../core/state/app-state";
2
+ import type { AppConfig } from "./config";
3
+
4
+ export interface DesktopSharedStateSnapshot {
5
+ config: AppConfig;
6
+ paneState: Record<string, PaneRuntimeState>;
7
+ focusedPaneId: string | null;
8
+ activePanel: "left" | "right";
9
+ statusBarVisible: boolean;
10
+ layoutChanged?: boolean;
11
+ }
12
+
13
+ export interface DesktopDockPreviewState {
14
+ paneId: string | null;
15
+ edge: "left" | "right" | "top" | "bottom" | null;
16
+ }
17
+
18
+ export interface DesktopWindowBridge {
19
+ kind: "main" | "detached";
20
+ paneId?: string;
21
+ syncMainState?(snapshot: DesktopSharedStateSnapshot): Promise<void>;
22
+ replaceDetachedPaneState?(paneId: string, paneState: PaneRuntimeState): Promise<void>;
23
+ popOutPane?(paneId: string): Promise<void>;
24
+ dockDetachedPane?(paneId: string): Promise<void>;
25
+ closeDetachedPane?(paneId: string): Promise<void>;
26
+ focusDetachedPane?(paneId: string): Promise<void>;
27
+ subscribeState(listener: (snapshot: DesktopSharedStateSnapshot) => void): () => void;
28
+ subscribeDockPreview?(listener: (preview: DesktopDockPreviewState) => void): () => void;
29
+ }
@@ -1,6 +1,7 @@
1
+
1
2
  export type MarketState = "PRE" | "REGULAR" | "POST" | "PREPRE" | "POSTPOST" | "CLOSED";
2
3
  export type SessionConfidence = "explicit" | "derived" | "unknown";
3
- export type QuoteDataSource = "live" | "delayed" | "yahoo";
4
+ export type QuoteDataSource = "live" | "delayed" | "snapshot";
4
5
 
5
6
  export interface QuoteFieldProvenance {
6
7
  providerId: string;
@@ -54,7 +55,7 @@ export interface Quote {
54
55
  low?: number;
55
56
  mark?: number;
56
57
  provenance?: QuoteProvenance;
57
- /** Where the quote data came from: live broker feed, delayed broker feed, or a fallback like Yahoo. */
58
+ /** Freshness class for the quote data. Provider identity lives in providerId/provenance. */
58
59
  dataSource?: QuoteDataSource;
59
60
  }
60
61
 
@@ -84,6 +85,126 @@ export interface Fundamentals {
84
85
  sharesOutstanding?: number;
85
86
  }
86
87
 
88
+ export type HolderOwnerType = "institution" | "fund" | "direct" | "insider";
89
+
90
+ export interface HolderRecord {
91
+ providerId?: string;
92
+ ownerType: HolderOwnerType;
93
+ name: string;
94
+ reportDate?: string;
95
+ shares?: number;
96
+ value?: number;
97
+ percentHeld?: number;
98
+ changeShares?: number;
99
+ changePercent?: number;
100
+ }
101
+
102
+ export interface HolderSummary {
103
+ insidersPercentHeld?: number;
104
+ institutionsPercentHeld?: number;
105
+ institutionsFloatPercentHeld?: number;
106
+ institutionsCount?: number;
107
+ }
108
+
109
+ export interface HolderData {
110
+ providerId?: string;
111
+ symbol: string;
112
+ name?: string;
113
+ currency?: string;
114
+ exchange?: string;
115
+ asOf?: string;
116
+ summary?: HolderSummary;
117
+ holders: HolderRecord[];
118
+ }
119
+
120
+ export interface AnalystPriceTarget {
121
+ high?: number;
122
+ median?: number;
123
+ low?: number;
124
+ average?: number;
125
+ current?: number;
126
+ currency?: string;
127
+ }
128
+
129
+ export interface AnalystRecommendationTrend {
130
+ period: string;
131
+ strongBuy?: number;
132
+ buy?: number;
133
+ hold?: number;
134
+ sell?: number;
135
+ strongSell?: number;
136
+ }
137
+
138
+ export interface AnalystRatingRecord {
139
+ date: string;
140
+ firm: string;
141
+ action?: string;
142
+ current?: string;
143
+ prior?: string;
144
+ }
145
+
146
+ export interface AnalystEstimateRecord {
147
+ date: string;
148
+ period: string;
149
+ analysts?: number;
150
+ average?: number;
151
+ low?: number;
152
+ high?: number;
153
+ yearAgo?: number;
154
+ growth?: number;
155
+ }
156
+
157
+ export interface AnalystResearchData {
158
+ providerId?: string;
159
+ symbol: string;
160
+ name?: string;
161
+ currency?: string;
162
+ exchange?: string;
163
+ micCode?: string;
164
+ exchangeTimezone?: string;
165
+ priceTarget?: AnalystPriceTarget;
166
+ recommendationRating?: number;
167
+ recommendations: AnalystRecommendationTrend[];
168
+ ratings: AnalystRatingRecord[];
169
+ earningsEstimates: AnalystEstimateRecord[];
170
+ revenueEstimates: AnalystEstimateRecord[];
171
+ }
172
+
173
+ export interface DividendAction {
174
+ exDate: string;
175
+ amount: number;
176
+ }
177
+
178
+ export interface SplitAction {
179
+ date: string;
180
+ description?: string;
181
+ ratio?: number;
182
+ fromFactor?: number;
183
+ toFactor?: number;
184
+ }
185
+
186
+ export interface EarningsAction {
187
+ date: string;
188
+ time?: string;
189
+ epsEstimate?: number;
190
+ epsActual?: number;
191
+ difference?: number;
192
+ surprisePercent?: number;
193
+ }
194
+
195
+ export interface CorporateActionsData {
196
+ providerId?: string;
197
+ symbol: string;
198
+ name?: string;
199
+ currency?: string;
200
+ exchange?: string;
201
+ micCode?: string;
202
+ exchangeTimezone?: string;
203
+ dividends: DividendAction[];
204
+ splits: SplitAction[];
205
+ earnings: EarningsAction[];
206
+ }
207
+
87
208
  export interface CompanyProfile {
88
209
  description?: string;
89
210
  sector?: string;
@@ -1,3 +1,4 @@
1
+
1
2
  export interface BrokerContractRef {
2
3
  brokerId: string;
3
4
  brokerInstanceId?: string;
@@ -0,0 +1,9 @@
1
+ export type {
2
+ NewsArticle,
3
+ NewsQuery,
4
+ NewsQueryPhase,
5
+ NewsQueryState,
6
+ NewsStoryItem,
7
+ } from "../news/types";
8
+
9
+ export type { NewsArticle as MarketNewsItem } from "../news/types";
@@ -1,3 +1,4 @@
1
+
1
2
  export interface CachePolicy {
2
3
  staleMs: number;
3
4
  expireMs: number;
@@ -3,6 +3,8 @@ import type { TickerRepository } from "../data/ticker-repository";
3
3
  import type { PluginEvents } from "../plugins/event-bus";
4
4
  import type { PluginLogger } from "../utils/debug-log";
5
5
  import type { BrokerAdapter } from "./broker";
6
+ import type { PluginCapability } from "../capabilities";
7
+ import type { ContextMenuContext, ContextMenuItem } from "./context-menu";
6
8
  import type {
7
9
  AppConfig,
8
10
  BrokerInstanceConfig,
@@ -72,6 +74,7 @@ interface PaneSettingFieldBase {
72
74
  key: string;
73
75
  label: string;
74
76
  description?: string;
77
+ storage?: "pane" | "plugin";
75
78
  }
76
79
 
77
80
  export interface PaneSettingToggleField extends PaneSettingFieldBase {
@@ -214,9 +217,9 @@ export interface CliLaunchRequest<TLaunchState = unknown> {
214
217
  applyConfig(config: AppConfig, env: CliLaunchEnvironment): CliLaunchConfigResult<TLaunchState>;
215
218
  applySessionSnapshot?(
216
219
  config: AppConfig,
217
- snapshot: import("../state/session-persistence").AppSessionSnapshot | null,
220
+ snapshot: import("../core/state/session-persistence").AppSessionSnapshot | null,
218
221
  launchState: TLaunchState | undefined,
219
- ): import("../state/session-persistence").AppSessionSnapshot;
222
+ ): import("../core/state/session-persistence").AppSessionSnapshot;
220
223
  }
221
224
 
222
225
  export type CliDispatchResult =
@@ -293,9 +296,9 @@ export interface DetailTabProps {
293
296
  }
294
297
 
295
298
  export interface DetailTabVisibilityContext {
299
+ config: AppConfig;
296
300
  ticker: TickerRecord | null;
297
301
  financials: TickerFinancials | null | undefined;
298
- hasIbkrGatewayTrading: boolean;
299
302
  hasOptionsChain: boolean;
300
303
  }
301
304
 
@@ -324,6 +327,13 @@ export interface TickerAction {
324
327
  execute: (ticker: TickerRecord, financials: TickerFinancials | null) => void | Promise<void>;
325
328
  }
326
329
 
330
+ export interface ContextMenuProviderDef {
331
+ id: string;
332
+ order?: number;
333
+ contexts?: ContextMenuContext["kind"][];
334
+ getItems(context: ContextMenuContext): ContextMenuItem[] | null | undefined;
335
+ }
336
+
327
337
  export interface PluginPersistence {
328
338
  getState<T = unknown>(key: string, options?: { schemaVersion?: number }): T | null;
329
339
  setState(key: string, value: unknown, options?: { schemaVersion?: number }): void;
@@ -379,8 +389,10 @@ export interface AppNotificationRequest {
379
389
  duration?: number;
380
390
  type?: AppNotificationType;
381
391
  toast?: boolean;
382
- desktop?: AppDesktopNotificationMode;
392
+ /** If true, in-app toast stays visible until user dismisses it */
383
393
  persistent?: boolean;
394
+ desktop?: AppDesktopNotificationMode;
395
+ /** macOS sound name (e.g., "Glass", "Ping", "Hero"). Ignored on other platforms. */
384
396
  sound?: string;
385
397
  action?: {
386
398
  label: string;
@@ -388,22 +400,34 @@ export interface AppNotificationRequest {
388
400
  };
389
401
  }
390
402
 
403
+ export interface BrokerInstanceUpdateOptions {
404
+ label?: string;
405
+ enabled?: boolean;
406
+ replaceConfig?: boolean;
407
+ }
408
+
391
409
  export interface GloomPluginContext {
392
410
  registerPane(pane: PaneDef): void;
393
411
  registerPaneTemplate(template: PaneTemplateDef): void;
394
412
  registerCommand(command: CommandDef): void;
395
413
  registerColumn(column: CustomColumnDef): void;
396
414
  registerBroker(broker: BrokerAdapter): void;
397
- registerDataProvider(provider: DataProvider): void;
415
+ registerCapability(capability: PluginCapability): void;
398
416
  registerDetailTab(tab: DetailTabDef): void;
399
417
  registerShortcut(shortcut: KeyboardShortcut): void;
400
418
  registerTickerAction(action: TickerAction): void;
419
+ registerContextMenuProvider(provider: ContextMenuProviderDef): void;
420
+ watchNewsQuery?(
421
+ query: import("./news-source").NewsQuery,
422
+ listener: (state: import("./news-source").NewsQueryState) => void,
423
+ ): () => void;
401
424
 
402
425
  getData(ticker: string): TickerFinancials | null;
403
426
  getTicker(ticker: string): TickerRecord | null;
404
427
  getConfig(): import("./config").AppConfig;
428
+ getPaneDef(paneId: string): PaneDef | undefined;
405
429
 
406
- readonly dataProvider: DataProvider;
430
+ readonly marketData: DataProvider;
407
431
  readonly tickerRepository: TickerRepository;
408
432
  readonly persistence: PluginPersistence;
409
433
  readonly log: PluginLogger;
@@ -412,7 +436,7 @@ export interface GloomPluginContext {
412
436
  readonly paneSettings: PluginPaneSettingsState;
413
437
 
414
438
  createBrokerInstance(brokerType: string, label: string, values: Record<string, unknown>): Promise<BrokerInstanceConfig>;
415
- updateBrokerInstance(instanceId: string, values: Record<string, unknown>): Promise<void>;
439
+ updateBrokerInstance(instanceId: string, values: Record<string, unknown>, options?: BrokerInstanceUpdateOptions): Promise<void>;
416
440
  syncBrokerInstance(instanceId: string): Promise<void>;
417
441
  removeBrokerInstance(instanceId: string): Promise<void>;
418
442
 
@@ -451,7 +475,7 @@ export interface GloomPlugin {
451
475
  panes?: PaneDef[];
452
476
  paneTemplates?: PaneTemplateDef[];
453
477
  broker?: BrokerAdapter;
454
- dataProvider?: DataProvider;
478
+ capabilities?: PluginCapability[];
455
479
  slots?: Partial<{
456
480
  [K in keyof GloomSlots]: (props: GloomSlots[K]) => ReactNode;
457
481
  }>;
@@ -0,0 +1,85 @@
1
+ export type AsciiFontName = "tiny" | "wordmark";
2
+
3
+ type TinyFontChar = readonly [string, string];
4
+
5
+ const TINY_FONT: Record<string, TinyFontChar> = {
6
+ A: ["▄▀█", "█▀█"],
7
+ B: ["█▄▄", "█▄█"],
8
+ C: ["█▀▀", "█▄▄"],
9
+ D: ["█▀▄", "█▄▀"],
10
+ E: ["█▀▀", "██▄"],
11
+ F: ["█▀▀", "█▀ "],
12
+ G: ["█▀▀", "█▄█"],
13
+ H: ["█ █", "█▀█"],
14
+ I: ["█", "█"],
15
+ J: [" █", "█▄█"],
16
+ K: ["█▄▀", "█ █"],
17
+ L: ["█ ", "█▄▄"],
18
+ M: ["█▀▄▀█", "█ ▀ █"],
19
+ N: ["█▄ █", "█ ▀█"],
20
+ O: ["█▀█", "█▄█"],
21
+ P: ["█▀█", "█▀▀"],
22
+ Q: ["█▀█", "▀▀█"],
23
+ R: ["█▀█", "█▀▄"],
24
+ S: ["█▀▀", "▄▄█"],
25
+ T: ["▀█▀", " █ "],
26
+ U: ["█ █", "█▄█"],
27
+ V: ["█ █", "▀▄▀"],
28
+ W: ["█ █ █", "▀▄▀▄▀"],
29
+ X: ["▀▄▀", "█ █"],
30
+ Y: ["█▄█", " █ "],
31
+ Z: ["▀█", "█▄"],
32
+ "0": ["▞█▚", "▚█▞"],
33
+ "1": ["▄█", " █"],
34
+ "2": ["▀█", "█▄"],
35
+ "3": ["▀▀█", "▄██"],
36
+ "4": ["█ █", "▀▀█"],
37
+ "5": ["█▀", "▄█"],
38
+ "6": ["█▄▄", "█▄█"],
39
+ "7": ["▀▀█", " █"],
40
+ "8": ["███", "█▄█"],
41
+ "9": ["█▀█", "▀▀█"],
42
+ "!": ["█", "▄"],
43
+ "?": ["▀█", " ▄"],
44
+ ".": [" ", "▄"],
45
+ "+": ["▄█▄", " ▀ "],
46
+ "-": ["▄▄", " "],
47
+ _: [" ", "▄▄"],
48
+ "=": ["▀▀", "▀▀"],
49
+ "@": ["▛█▜", "▙▟▃"],
50
+ "#": ["▟▄▙", "▜▀▛"],
51
+ $: ["▖█▗", "▘█▝"],
52
+ "%": ["▀ ▄▀", "▄▀ ▄"],
53
+ "&": ["▄▄█", "█▄█"],
54
+ "(": ["▄▀", "▀▄"],
55
+ ")": ["▀▄", "▄▀"],
56
+ "/": [" ▄▀", "▄▀ "],
57
+ ":": ["▀", "▄"],
58
+ ";": [" ", "▄▀"],
59
+ ",": [" ", "█"],
60
+ "'": ["▀", " "],
61
+ "\"": ["▛ ▜", " "],
62
+ " ": [" ", " "],
63
+ };
64
+
65
+ const GLOOMBERB_WORDMARK = [
66
+ "▞▀▖▜ ▌ ▌ ",
67
+ "▌▄▖▐ ▞▀▖▞▀▖▛▚▀▖▛▀▖▞▀▖▙▀▖▛▀▖",
68
+ "▌ ▌▐ ▌ ▌▌ ▌▌▐ ▌▌ ▌▛▀ ▌ ▌ ▌",
69
+ "▝▀ ▘▝▀ ▝▀ ▘▝ ▘▀▀ ▝▀▘▘ ▀▀ ",
70
+ ];
71
+
72
+ export function renderAsciiText(text: string, font: AsciiFontName = "tiny"): string[] {
73
+ if (font === "wordmark") {
74
+ return text.trim().toLowerCase() === "gloomberb" ? GLOOMBERB_WORDMARK : [text];
75
+ }
76
+
77
+ const lines = ["", ""];
78
+ for (let index = 0; index < text.length; index += 1) {
79
+ const glyph = TINY_FONT[text[index]!.toUpperCase()] ?? TINY_FONT[" "]!;
80
+ const spacer = index < text.length - 1 ? " " : "";
81
+ lines[0] += `${glyph[0]}${spacer}`;
82
+ lines[1] += `${glyph[1]}${spacer}`;
83
+ }
84
+ return lines;
85
+ }
@@ -0,0 +1,94 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import type { PluginRegistry } from "../plugins/registry";
3
+ import type { ContextMenuItem } from "../types/context-menu";
4
+ import type { TickerRecord } from "../types/ticker";
5
+ import {
6
+ editableTextContextMenuItems,
7
+ linkContextMenuItems,
8
+ tickerContextMenuItems,
9
+ } from "./context-menu";
10
+
11
+ function ticker(overrides: Partial<TickerRecord["metadata"]> = {}): TickerRecord {
12
+ return {
13
+ metadata: {
14
+ ticker: "AAPL",
15
+ exchange: "NASDAQ",
16
+ currency: "USD",
17
+ name: "Apple",
18
+ portfolios: [],
19
+ watchlists: [],
20
+ positions: [],
21
+ custom: {},
22
+ tags: [],
23
+ ...overrides,
24
+ },
25
+ };
26
+ }
27
+
28
+ function menuLabels(items: ContextMenuItem[]): string[] {
29
+ return items.flatMap((item) => item.type === "divider" ? [] : [item.label ?? ""]);
30
+ }
31
+
32
+ describe("context menu item builders", () => {
33
+ test("editable text menu returns native edit roles", () => {
34
+ expect(editableTextContextMenuItems().map((item) => item.type === "role" ? item.role : "divider")).toEqual([
35
+ "undo",
36
+ "redo",
37
+ "divider",
38
+ "cut",
39
+ "copy",
40
+ "paste",
41
+ "divider",
42
+ "selectAll",
43
+ ]);
44
+ });
45
+
46
+ test("link menu includes open and copy actions", () => {
47
+ const labels = menuLabels(linkContextMenuItems({
48
+ url: "https://example.com",
49
+ open: () => {},
50
+ copy: () => {},
51
+ }));
52
+
53
+ expect(labels).toEqual(["Open Link", "Copy Link"]);
54
+ });
55
+
56
+ test("ticker menu includes plugin ticker actions and hides remove actions without memberships", () => {
57
+ const registry = {
58
+ tickerActions: new Map([
59
+ ["alert", {
60
+ id: "alert",
61
+ label: "Set Alert",
62
+ execute: () => {},
63
+ }],
64
+ ]),
65
+ navigateTicker: () => {},
66
+ pinTicker: () => {},
67
+ openCommandBar: () => {},
68
+ } as unknown as PluginRegistry;
69
+
70
+ const labels = menuLabels(tickerContextMenuItems({
71
+ ticker: ticker(),
72
+ financials: null,
73
+ registry,
74
+ copyText: async () => {},
75
+ }));
76
+
77
+ expect(labels).toContain("Set Alert");
78
+ expect(labels).toContain("Add to Watchlist...");
79
+ expect(labels).not.toContain("Remove from Watchlist...");
80
+ expect(labels).not.toContain("Remove from Portfolio...");
81
+ });
82
+
83
+ test("ticker menu includes remove actions when memberships exist", () => {
84
+ const labels = menuLabels(tickerContextMenuItems({
85
+ ticker: ticker({ watchlists: ["watchlist:tech"], portfolios: ["portfolio:main"] }),
86
+ financials: null,
87
+ registry: null,
88
+ copyText: async () => {},
89
+ }));
90
+
91
+ expect(labels).toContain("Remove from Watchlist...");
92
+ expect(labels).toContain("Remove from Portfolio...");
93
+ });
94
+ });