gloomberb 0.16.3 → 0.16.4

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 (451) hide show
  1. package/package.json +4 -1
  2. package/src/api-client/askg.ts +43 -0
  3. package/src/api-client/auth.ts +15 -0
  4. package/src/api-client/beneficial-owners.ts +4 -0
  5. package/src/api-client/chat.ts +19 -0
  6. package/src/api-client/company-kpis.ts +14 -2
  7. package/src/api-client/data.ts +34 -16
  8. package/src/api-client/index.ts +12 -0
  9. package/src/api-client/normalizers.ts +27 -0
  10. package/src/api-client/paths.ts +88 -23
  11. package/src/api-client/request.ts +2 -1
  12. package/src/api-client/research-activity.ts +31 -0
  13. package/src/api-client/socket.ts +39 -8
  14. package/src/api-client/types.ts +57 -1
  15. package/src/api-client/upgrade-experiment.ts +90 -0
  16. package/src/app/global-shortcuts.ts +11 -1
  17. package/src/app/keybindings/actions.ts +10 -0
  18. package/src/app/pane-runtime/index.tsx +8 -0
  19. package/src/app/pane-runtime/pane-template-runtime.ts +5 -0
  20. package/src/app/pane-runtime/plugin-bindings.ts +65 -25
  21. package/src/app/pane-runtime/ticker-inspector-runtime.ts +12 -0
  22. package/src/app/pane-runtime/ticker-open-runtime.ts +18 -1
  23. package/src/app/runtime/desktop-deeplink.ts +5 -0
  24. package/src/app/star-prompt/model.ts +98 -0
  25. package/src/app/star-prompt/runtime.ts +41 -0
  26. package/src/app/star-prompt/status-line.tsx +190 -0
  27. package/src/app.tsx +13 -7
  28. package/src/architecture/core-builtin-allowlist.json +70 -0
  29. package/src/brokers/signed-in/adapter.ts +33 -2
  30. package/src/brokers/signed-in/client.ts +10 -0
  31. package/src/brokers/signed-in/sign-in-dialog.tsx +23 -9
  32. package/src/brokers/signed-in/sign-in.ts +62 -5
  33. package/src/capabilities/registry.ts +8 -1
  34. package/src/capabilities/types.ts +2 -0
  35. package/src/cli/commands/crypto-hints.ts +12 -4
  36. package/src/cli/commands/market.ts +359 -99
  37. package/src/cli/commands/options-chain.ts +172 -0
  38. package/src/cli/commands/options-leaps.ts +422 -0
  39. package/src/cli/commands/overview.ts +164 -26
  40. package/src/cli/commands/search.ts +29 -8
  41. package/src/cli/commands/system.ts +99 -19
  42. package/src/cli/commands/themes.ts +64 -0
  43. package/src/cli/commands/ticker.ts +62 -30
  44. package/src/cli/desktop-pane-shot.ts +97 -16
  45. package/src/cli/errors.ts +25 -2
  46. package/src/cli/freshness.ts +7 -4
  47. package/src/cli/fx-pair.ts +57 -0
  48. package/src/cli/help.ts +14 -1
  49. package/src/cli/index-roots.ts +51 -0
  50. package/src/cli/index.ts +9 -6
  51. package/src/cli/listing-arg.ts +211 -3
  52. package/src/cli/not-a-ticker.ts +37 -0
  53. package/src/cli/options.ts +50 -6
  54. package/src/cli/pane-functions/capabilities.ts +8 -2
  55. package/src/cli/pane-functions/catalog.ts +13 -2
  56. package/src/cli/pane-functions/data.ts +36 -5
  57. package/src/cli/pane-functions/dom.ts +21 -13
  58. package/src/cli/pane-functions/freshness.ts +205 -26
  59. package/src/cli/pane-functions/function-help.ts +67 -22
  60. package/src/cli/pane-functions/headless.ts +5 -4
  61. package/src/cli/pane-functions/index.ts +3 -0
  62. package/src/cli/pane-functions/market-session.ts +133 -0
  63. package/src/cli/pane-functions/options.ts +15 -4
  64. package/src/cli/pane-functions/report-notices.ts +63 -0
  65. package/src/cli/pane-functions/report.ts +4 -0
  66. package/src/cli/pane-functions/resolver.ts +4 -6
  67. package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
  68. package/src/cli/pane-functions/screenshot.ts +105 -23
  69. package/src/cli/registry.ts +2 -1
  70. package/src/cli/result.ts +50 -13
  71. package/src/cli/row-window.ts +76 -0
  72. package/src/cli/scroll-truncation.ts +34 -0
  73. package/src/components/chart/composite/composite-chart.tsx +43 -4
  74. package/src/components/chart/composite/legend.tsx +39 -6
  75. package/src/components/chart/composite/rasterizer.ts +64 -4
  76. package/src/components/chart/composite/series-cues.ts +71 -0
  77. package/src/components/chart/composite/text-renderer.ts +16 -8
  78. package/src/components/chart/composite/types.ts +3 -0
  79. package/src/components/command-bar/commands/direct/index.ts +9 -1
  80. package/src/components/command-bar/commands/plugin/items.ts +3 -1
  81. package/src/components/command-bar/commands/registry.ts +7 -0
  82. package/src/components/command-bar/layout-items/focused-pane.ts +38 -0
  83. package/src/components/command-bar/pane-templates/workflow.ts +5 -0
  84. package/src/components/command-bar/routes/root/command-items.ts +2 -0
  85. package/src/components/command-bar/routes/root/plugin-turn-on.ts +92 -0
  86. package/src/components/command-bar/routes/root/results.ts +40 -10
  87. package/src/components/command-bar/routes/root/runtime.ts +8 -0
  88. package/src/components/command-bar/routes/root/search-providers.ts +97 -14
  89. package/src/components/command-bar/surface/index.tsx +18 -4
  90. package/src/components/command-bar/theme-picker.tsx +48 -13
  91. package/src/components/command-bar/workflow/ops.ts +5 -3
  92. package/src/components/data-table/view.tsx +28 -9
  93. package/src/components/layout/floating-pane.tsx +6 -2
  94. package/src/components/layout/market-summary.ts +23 -9
  95. package/src/components/layout/pane/content.tsx +46 -29
  96. package/src/components/layout/pane/cycle-order.ts +2 -11
  97. package/src/components/layout/pane/header.tsx +2 -1
  98. package/src/components/layout/pane/title.ts +1 -1
  99. package/src/components/layout/presentation.ts +22 -0
  100. package/src/components/layout/shell/active-drag.ts +1 -1
  101. package/src/components/layout/shell/drag/index.ts +4 -0
  102. package/src/components/layout/shell/drag/live.ts +76 -5
  103. package/src/components/layout/shell/drag/runtime.ts +8 -8
  104. package/src/components/layout/shell/index.tsx +47 -6
  105. package/src/components/layout/shell/layout-state.ts +5 -11
  106. package/src/components/layout/shell/menu.ts +28 -1
  107. package/src/components/layout/shell/pane/actions.ts +2 -1
  108. package/src/components/layout/shell/pane/layers.tsx +51 -10
  109. package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
  110. package/src/components/layout/shell/pane/new-layout.ts +116 -0
  111. package/src/components/layout/shell/shortcuts.ts +5 -2
  112. package/src/components/layout/shell/visible-layout.ts +44 -1
  113. package/src/components/layout/status-bar.tsx +4 -1
  114. package/src/components/markdown-text.tsx +9 -5
  115. package/src/components/metric-treemap/heat-surface.tsx +27 -8
  116. package/src/components/metric-treemap/heat-tiles.ts +48 -17
  117. package/src/components/onboarding/onboarding-frame.tsx +33 -10
  118. package/src/components/onboarding/onboarding-wizard.tsx +49 -40
  119. package/src/components/onboarding/portfolio-step/positions-panel.tsx +5 -2
  120. package/src/components/onboarding/pro-step-layout.ts +86 -0
  121. package/src/components/onboarding/use-onboarding-upgrade.ts +6 -2
  122. package/src/components/ui/button.tsx +10 -0
  123. package/src/components/ui/data-table/index.tsx +38 -0
  124. package/src/components/ui/data-table/types.ts +8 -1
  125. package/src/components/ui/data-table/visible-range.ts +2 -0
  126. package/src/components/ui/icon.tsx +11 -2
  127. package/src/components/ui/index.ts +1 -1
  128. package/src/core/connection-health.ts +1 -1
  129. package/src/core/state/app/layout-reducer.ts +89 -3
  130. package/src/core/state/app/state.ts +8 -5
  131. package/src/core/state/app/types.ts +13 -2
  132. package/src/data/config/layout.ts +55 -21
  133. package/src/data/config/store/fold-panes.ts +149 -0
  134. package/src/data/config/store/migrations.ts +7 -0
  135. package/src/data/config/store/node.ts +27 -6
  136. package/src/data/config/store/normalize.ts +37 -3
  137. package/src/i18n/es.ts +14 -1
  138. package/src/i18n/ja.ts +14 -1
  139. package/src/i18n/ko.ts +14 -1
  140. package/src/i18n/zh-cn.ts +14 -1
  141. package/src/i18n/zh-tw.ts +14 -1
  142. package/src/layout/desks.ts +1 -2
  143. package/src/layout/pane-layout-move.ts +264 -0
  144. package/src/layout/pane-manager/hidden-panes.ts +160 -0
  145. package/src/layout/pane-manager/index.ts +1 -0
  146. package/src/market-data/coordinator/entries.ts +7 -1
  147. package/src/market-data/coordinator/quotes.ts +2 -2
  148. package/src/market-data/market/freshness.ts +118 -18
  149. package/src/market-data/market/status.ts +40 -0
  150. package/src/market-data/options-alternatives.ts +69 -0
  151. package/src/market-data/quotes/contributions.ts +19 -2
  152. package/src/market-data/quotes/metadata.ts +16 -0
  153. package/src/market-data/quotes/screener-live-quotes.ts +56 -5
  154. package/src/plugins/builtin/account-management/keyboard.ts +3 -0
  155. package/src/plugins/builtin/account-management/model.ts +1 -0
  156. package/src/plugins/builtin/account-management/navigation.ts +1 -1
  157. package/src/plugins/builtin/account-management/pane.tsx +31 -4
  158. package/src/plugins/builtin/alerts/quotes.ts +3 -0
  159. package/src/plugins/builtin/analytics/risk-headless.ts +3 -1
  160. package/src/plugins/builtin/analytics/risk-model.ts +37 -8
  161. package/src/plugins/builtin/analytics/risk-pane.tsx +8 -4
  162. package/src/plugins/builtin/backtest/pane.tsx +1 -1
  163. package/src/plugins/builtin/broker-manager/detail.tsx +4 -0
  164. package/src/plugins/builtin/broker-manager/index.tsx +7 -3
  165. package/src/plugins/builtin/broker-manager/model.ts +8 -0
  166. package/src/plugins/builtin/broker-manager/pane-actions.tsx +8 -2
  167. package/src/plugins/builtin/broker-manager/sign-in-end.ts +82 -0
  168. package/src/plugins/builtin/broker-manager/table.ts +5 -0
  169. package/src/plugins/builtin/builtin-plugin-meta.ts +121 -11
  170. package/src/plugins/builtin/chart-composer/pane.tsx +1 -1
  171. package/src/plugins/builtin/chat/channels.ts +34 -36
  172. package/src/plugins/builtin/chat/command-bar.ts +138 -0
  173. package/src/plugins/builtin/chat/composer-commands.ts +21 -1
  174. package/src/plugins/builtin/chat/content/composer-runtime.ts +11 -1
  175. package/src/plugins/builtin/chat/content/footer.tsx +5 -3
  176. package/src/plugins/builtin/chat/content/index.tsx +21 -1
  177. package/src/plugins/builtin/chat/content/mentions.ts +2 -1
  178. package/src/plugins/builtin/chat/content/user-map.ts +3 -1
  179. package/src/plugins/builtin/chat/controller/index.ts +48 -0
  180. package/src/plugins/builtin/chat/conversations.ts +256 -0
  181. package/src/plugins/builtin/chat/discord-command.ts +91 -0
  182. package/src/plugins/builtin/chat/edit-window.ts +12 -6
  183. package/src/plugins/builtin/chat/ghost-user.ts +14 -0
  184. package/src/plugins/builtin/chat/index.tsx +40 -2
  185. package/src/plugins/builtin/chat/layout.ts +2 -0
  186. package/src/plugins/builtin/chat/message/desktop.tsx +2 -1
  187. package/src/plugins/builtin/chat/message/header.tsx +24 -15
  188. package/src/plugins/builtin/chat/message/profile-popover.tsx +2 -1
  189. package/src/plugins/builtin/chat/message/render-state.ts +3 -0
  190. package/src/plugins/builtin/chat/pane-requests.ts +60 -0
  191. package/src/plugins/builtin/chat/pane-state.ts +32 -2
  192. package/src/plugins/builtin/chat/pane.tsx +8 -0
  193. package/src/plugins/builtin/cloud/askg/controller.ts +112 -4
  194. package/src/plugins/builtin/cloud/askg/conversation-store.ts +21 -0
  195. package/src/plugins/builtin/cloud/askg/manifest.ts +1 -0
  196. package/src/plugins/builtin/cloud/askg/model.ts +129 -70
  197. package/src/plugins/builtin/cloud/askg/pane.tsx +772 -377
  198. package/src/plugins/builtin/cloud/askg/protocol.ts +40 -2
  199. package/src/plugins/builtin/cloud/askg/tool-display.ts +437 -0
  200. package/src/plugins/builtin/cloud/askg/tool-timeline.tsx +403 -0
  201. package/src/plugins/builtin/cloud/company-picker.tsx +1 -9
  202. package/src/plugins/builtin/cloud/mcp-connect/command.ts +24 -0
  203. package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +360 -0
  204. package/src/plugins/builtin/cloud/mcp-connect/model.ts +135 -0
  205. package/src/plugins/builtin/cloud/mcp-connect/sections.ts +62 -0
  206. package/src/plugins/builtin/cloud/plugin.tsx +36 -1
  207. package/src/plugins/builtin/cloud/starter-symbols.ts +8 -0
  208. package/src/plugins/builtin/cloud/terminal-relay/acm-tab.tsx +89 -0
  209. package/src/plugins/builtin/cloud/terminal-relay/client.ts +97 -0
  210. package/src/plugins/builtin/cloud/terminal-relay/connect-section.tsx +57 -0
  211. package/src/plugins/builtin/cloud/terminal-relay/engine.ts +666 -0
  212. package/src/plugins/builtin/cloud/terminal-relay/grants.ts +137 -0
  213. package/src/plugins/builtin/cloud/terminal-relay/host.tsx +81 -0
  214. package/src/plugins/builtin/cloud/terminal-relay/indicator.tsx +82 -0
  215. package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +234 -0
  216. package/src/plugins/builtin/cloud/terminal-relay/policy.ts +153 -0
  217. package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +168 -0
  218. package/src/plugins/builtin/cloud/terminal-relay/redact.ts +73 -0
  219. package/src/plugins/builtin/cloud/terminal-relay/summary.ts +62 -0
  220. package/src/plugins/builtin/cloud/upgrade-dialog.tsx +26 -2
  221. package/src/plugins/builtin/cloud/upgrade-personalization.ts +57 -0
  222. package/src/plugins/builtin/cloud/upgrade-tickers.ts +124 -0
  223. package/src/plugins/builtin/comment-letters/client.ts +1 -3
  224. package/src/plugins/builtin/company-kpis/client.ts +23 -8
  225. package/src/plugins/builtin/company-kpis/headless.ts +3 -1
  226. package/src/plugins/builtin/company-kpis/pane.tsx +15 -7
  227. package/src/plugins/builtin/company-kpis/screenshot-evidence.ts +10 -3
  228. package/src/plugins/builtin/composite-plugins.ts +107 -64
  229. package/src/plugins/builtin/credit-boards/cdx-pane.tsx +4 -4
  230. package/src/plugins/builtin/credit-boards/index.tsx +21 -21
  231. package/src/plugins/builtin/credit-boards/model.ts +0 -1
  232. package/src/plugins/builtin/credit-boards/pane.tsx +30 -0
  233. package/src/plugins/builtin/credit-boards/sovr-pane.tsx +4 -4
  234. package/src/plugins/builtin/debt-maturities/client.ts +37 -9
  235. package/src/plugins/builtin/debt-maturities/headless.ts +3 -1
  236. package/src/plugins/builtin/debt-maturities/pane.tsx +5 -4
  237. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  238. package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
  239. package/src/plugins/builtin/earnings-calls/data.ts +28 -7
  240. package/src/plugins/builtin/earnings-calls/headless.ts +3 -2
  241. package/src/plugins/builtin/earnings-calls/pane.tsx +10 -5
  242. package/src/plugins/builtin/econ/calendar-model.ts +42 -17
  243. package/src/plugins/builtin/econ/detail-view.tsx +2 -2
  244. package/src/plugins/builtin/econ/index.tsx +68 -22
  245. package/src/plugins/builtin/econ-statistics/headless.ts +12 -2
  246. package/src/plugins/builtin/econ-statistics/pane.tsx +1 -1
  247. package/src/plugins/builtin/econ-statistics/view.ts +17 -0
  248. package/src/plugins/builtin/executives/data.ts +17 -6
  249. package/src/plugins/builtin/executives/pane.tsx +16 -7
  250. package/src/plugins/builtin/filing-events/pane.tsx +22 -5
  251. package/src/plugins/builtin/fx-matrix/freshness.ts +65 -0
  252. package/src/plugins/builtin/fx-matrix/index.tsx +22 -1
  253. package/src/plugins/builtin/fx-matrix/pairs.ts +1 -1
  254. package/src/plugins/builtin/fx-matrix/settings.ts +42 -2
  255. package/src/plugins/builtin/gpu/headless.ts +9 -3
  256. package/src/plugins/builtin/gpu/model.ts +14 -5
  257. package/src/plugins/builtin/help/index.tsx +1 -0
  258. package/src/plugins/builtin/holders/beneficial-client.ts +29 -7
  259. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  260. package/src/plugins/builtin/holders/headless.ts +6 -1
  261. package/src/plugins/builtin/holders/pane.tsx +3 -0
  262. package/src/plugins/builtin/insider/index.tsx +4 -4
  263. package/src/plugins/builtin/iv-history/charts.tsx +21 -7
  264. package/src/plugins/builtin/iv-history/client.ts +12 -2
  265. package/src/plugins/builtin/iv-history/format.ts +33 -2
  266. package/src/plugins/builtin/iv-history/headless.ts +22 -10
  267. package/src/plugins/builtin/iv-history/index.tsx +3 -3
  268. package/src/plugins/builtin/iv-history/model.ts +61 -13
  269. package/src/plugins/builtin/iv-history/pane.tsx +11 -3
  270. package/src/plugins/builtin/iv-history/screen-pane.tsx +42 -18
  271. package/src/plugins/builtin/jobs/pane.tsx +1 -1
  272. package/src/plugins/builtin/kelly-sizer/headless.ts +149 -0
  273. package/src/plugins/builtin/kelly-sizer/history.ts +80 -0
  274. package/src/plugins/builtin/kelly-sizer/index.tsx +2 -0
  275. package/src/plugins/builtin/kelly-sizer/pane.tsx +109 -39
  276. package/src/plugins/builtin/kelly-sizer/sections.tsx +14 -0
  277. package/src/plugins/builtin/kelly-sizer/types.ts +9 -1
  278. package/src/plugins/builtin/layout-manager/index.tsx +9 -1
  279. package/src/plugins/builtin/macro-day/client.ts +24 -0
  280. package/src/plugins/builtin/macro-day/headless.ts +11 -8
  281. package/src/plugins/builtin/macro-day/index.tsx +3 -0
  282. package/src/plugins/builtin/macro-day/model.ts +11 -6
  283. package/src/plugins/builtin/macro-day/pane.tsx +12 -8
  284. package/src/plugins/builtin/macro-day/release-table.ts +40 -0
  285. package/src/plugins/builtin/macro-day/releases.ts +62 -44
  286. package/src/plugins/builtin/market-heatmap/data.ts +25 -5
  287. package/src/plugins/builtin/market-heatmap/evidence.ts +90 -0
  288. package/src/plugins/builtin/market-heatmap/index.tsx +144 -63
  289. package/src/plugins/builtin/market-heatmap/model.ts +94 -3
  290. package/src/plugins/builtin/market-heatmap/portfolio.ts +12 -2
  291. package/src/plugins/builtin/market-movers/headless.ts +31 -4
  292. package/src/plugins/builtin/market-movers/index.tsx +8 -1
  293. package/src/plugins/builtin/market-movers/model.ts +71 -17
  294. package/src/plugins/builtin/market-movers/table.ts +50 -23
  295. package/src/plugins/builtin/news/headless.ts +9 -2
  296. package/src/plugins/builtin/news/wire/news/footer.ts +10 -0
  297. package/src/plugins/builtin/openfda/client.ts +1 -1
  298. package/src/plugins/builtin/options/carry.ts +95 -0
  299. package/src/plugins/builtin/options/index.tsx +58 -5
  300. package/src/plugins/builtin/options/strike-window.ts +183 -0
  301. package/src/plugins/builtin/options/table.ts +55 -3
  302. package/src/plugins/builtin/options/types.ts +8 -1
  303. package/src/plugins/builtin/options/view.tsx +161 -12
  304. package/src/plugins/builtin/options-positioning/headless.ts +4 -2
  305. package/src/plugins/builtin/options-scenario/charts.tsx +2 -2
  306. package/src/plugins/builtin/options-scenario/client.ts +73 -17
  307. package/src/plugins/builtin/options-scenario/headless.ts +71 -24
  308. package/src/plugins/builtin/options-scenario/hedge.ts +284 -0
  309. package/src/plugins/builtin/options-scenario/index.tsx +9 -2
  310. package/src/plugins/builtin/options-scenario/model.ts +33 -0
  311. package/src/plugins/builtin/options-scenario/pane.tsx +40 -16
  312. package/src/plugins/builtin/pe-band/model.ts +2 -2
  313. package/src/plugins/builtin/pe-band/report-dates.ts +11 -7
  314. package/src/plugins/builtin/perps/equity-row.tsx +8 -5
  315. package/src/plugins/builtin/perps/model.ts +16 -5
  316. package/src/plugins/builtin/plugin-marketplace/model.ts +64 -21
  317. package/src/plugins/builtin/plugin-marketplace/packs.ts +118 -0
  318. package/src/plugins/builtin/plugin-marketplace/pane.tsx +344 -32
  319. package/src/plugins/builtin/plugin-marketplace/store.ts +7 -1
  320. package/src/plugins/builtin/plugin-module.ts +87 -4
  321. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +71 -36
  322. package/src/plugins/builtin/portfolio-list/cli/render.ts +87 -18
  323. package/src/plugins/builtin/portfolio-list/cli/shared.ts +2 -16
  324. package/src/plugins/builtin/portfolio-list/headless.ts +38 -7
  325. package/src/plugins/builtin/realized-vol/headless.ts +3 -0
  326. package/src/plugins/builtin/realized-vol/pane.tsx +1 -1
  327. package/src/plugins/builtin/research/corporate-actions-pane.tsx +2 -2
  328. package/src/plugins/builtin/research/equity-diagnostic-pane.tsx +1 -1
  329. package/src/plugins/builtin/revenue-breakdown/client.ts +13 -6
  330. package/src/plugins/builtin/revenue-breakdown/headless.ts +4 -1
  331. package/src/plugins/builtin/revenue-breakdown/pane.tsx +7 -4
  332. package/src/plugins/builtin/reverse-dcf/headless.ts +5 -1
  333. package/src/plugins/builtin/reverse-dcf/pane.tsx +1 -1
  334. package/src/plugins/builtin/risk-factors/data.ts +23 -9
  335. package/src/plugins/builtin/risk-factors/headless.ts +5 -2
  336. package/src/plugins/builtin/risk-factors/pane.tsx +6 -5
  337. package/src/plugins/builtin/seasonality/pane.tsx +1 -1
  338. package/src/plugins/builtin/sec/index.tsx +5 -5
  339. package/src/plugins/builtin/sectors/client.ts +10 -2
  340. package/src/plugins/builtin/sectors/headless.ts +35 -6
  341. package/src/plugins/builtin/sectors/index.tsx +18 -1
  342. package/src/plugins/builtin/sectors/sector-model.ts +150 -41
  343. package/src/plugins/builtin/shared/command-tab.ts +51 -0
  344. package/src/plugins/builtin/shared/headless-market-data.ts +33 -1
  345. package/src/plugins/builtin/shared/members-menu.tsx +4 -4
  346. package/src/plugins/builtin/shared/report-freshness.ts +50 -2
  347. package/src/plugins/builtin/shared/ticker-request.ts +25 -1
  348. package/src/plugins/builtin/shared/use-quote-board.ts +25 -5
  349. package/src/plugins/builtin/shared/volatility/options.ts +1 -46
  350. package/src/plugins/builtin/short-interest/index.tsx +19 -4
  351. package/src/plugins/builtin/short-interest/surface.tsx +4 -4
  352. package/src/plugins/builtin/short-volume/index.tsx +1 -10
  353. package/src/plugins/builtin/supply-chain/model.ts +1 -1
  354. package/src/plugins/builtin/ticker-detail/headless.ts +43 -21
  355. package/src/plugins/builtin/ticker-detail/pane.tsx +4 -5
  356. package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +94 -6
  357. package/src/plugins/builtin/treasury-auctions/cache.ts +5 -2
  358. package/src/plugins/builtin/treasury-auctions/client.ts +22 -8
  359. package/src/plugins/builtin/treasury-auctions/headless.ts +40 -4
  360. package/src/plugins/builtin/treasury-auctions/index.tsx +11 -9
  361. package/src/plugins/builtin/treasury-auctions/model.ts +197 -30
  362. package/src/plugins/builtin/treasury-auctions/pane.tsx +35 -11
  363. package/src/plugins/builtin/treasury-auctions/types.ts +11 -1
  364. package/src/plugins/builtin/vol-surface/charts.tsx +1 -3
  365. package/src/plugins/builtin/vol-surface/client.ts +6 -2
  366. package/src/plugins/builtin/vol-surface/evidence.ts +11 -6
  367. package/src/plugins/builtin/vol-surface/headless.ts +124 -20
  368. package/src/plugins/builtin/vol-surface/model.ts +23 -11
  369. package/src/plugins/builtin/vol-surface/pane.tsx +38 -27
  370. package/src/plugins/builtin/vol-surface/tables.ts +124 -0
  371. package/src/plugins/builtin/world-indices/client.ts +22 -4
  372. package/src/plugins/builtin/world-indices/headless.ts +54 -27
  373. package/src/plugins/builtin/world-indices/model.ts +4 -2
  374. package/src/plugins/builtin/world-indices/table.tsx +13 -2
  375. package/src/plugins/builtin/world-venue-map/geo-series.ts +1 -1
  376. package/src/plugins/builtin/world-venue-map/index.ts +1 -1
  377. package/src/plugins/builtin/yield-curve/index.tsx +1 -1
  378. package/src/plugins/builtin-editorial.ts +126 -0
  379. package/src/plugins/catalog-backend.ts +16 -9
  380. package/src/plugins/catalog-browser.ts +127 -63
  381. package/src/plugins/catalog-manifest.ts +73 -40
  382. package/src/plugins/catalog-ui.ts +26 -6
  383. package/src/plugins/extracted-plugins.ts +7 -1
  384. package/src/plugins/ownership.ts +150 -7
  385. package/src/plugins/plugin-functions.ts +54 -0
  386. package/src/plugins/plugin-off.ts +36 -0
  387. package/src/plugins/registry/host-actions.ts +16 -0
  388. package/src/plugins/registry/index.ts +84 -24
  389. package/src/plugins/registry/plugin-state.ts +25 -1
  390. package/src/plugins/runtime/context.tsx +29 -0
  391. package/src/react/input.ts +48 -1
  392. package/src/remote/app-host.tsx +5 -0
  393. package/src/remote/controller.ts +3 -53
  394. package/src/remote/matching.ts +69 -0
  395. package/src/remote/schema.ts +1 -1
  396. package/src/remote/semantic-tree.tsx +14 -0
  397. package/src/remote/types.ts +2 -0
  398. package/src/renderers/dom/desktop/icons.tsx +14 -0
  399. package/src/renderers/dom/desktop/query-bar.tsx +59 -32
  400. package/src/renderers/dom/host/box.tsx +1 -1
  401. package/src/renderers/dom/host/drag-shield.ts +17 -6
  402. package/src/renderers/dom/host/live-frame.ts +10 -2
  403. package/src/renderers/dom/input-host.tsx +6 -1
  404. package/src/renderers/dom/styles.css +13 -0
  405. package/src/renderers/electrobun/bun/desktop/backend.ts +5 -1
  406. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +12 -1
  407. package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -1
  408. package/src/renderers/electrobun/shared/protocol.ts +2 -0
  409. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
  410. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +101 -5
  411. package/src/renderers/electrobun/view/main.tsx +4 -1
  412. package/src/renderers/opentui/input-host.tsx +6 -1
  413. package/src/renderers/opentui/start.tsx +9 -0
  414. package/src/shares/portable-layout.ts +16 -6
  415. package/src/sources/gloomberb-cloud/index.ts +19 -10
  416. package/src/sources/gloomberb-cloud/normalizers.ts +4 -1
  417. package/src/sources/listing-symbols.ts +11 -5
  418. package/src/sources/provider-errors.ts +88 -3
  419. package/src/sources/provider-router/cached-routes.ts +8 -4
  420. package/src/sources/provider-router/financial-routes.ts +11 -5
  421. package/src/sources/provider-router/financials.ts +42 -15
  422. package/src/sources/provider-router/history.ts +27 -11
  423. package/src/sources/provider-router/index.ts +1 -1
  424. package/src/sources/provider-router/primary.ts +23 -5
  425. package/src/sources/sec-edgar.ts +68 -8
  426. package/src/sync/core-contributors.ts +4 -3
  427. package/src/test-support/cli-context.ts +2 -1
  428. package/src/test-support/data-provider.ts +34 -0
  429. package/src/test-support/shell-pane-keys.tsx +1 -0
  430. package/src/theme/series-colors.ts +46 -0
  431. package/src/theme/themes.ts +149 -0
  432. package/src/tickers/search/index.ts +22 -2
  433. package/src/tickers/search/ranking.ts +45 -1
  434. package/src/tickers/search/types.ts +3 -1
  435. package/src/time-series/resolve.ts +1 -14
  436. package/src/types/config.ts +61 -1
  437. package/src/types/headless.ts +11 -0
  438. package/src/types/instrument.ts +8 -0
  439. package/src/types/plugin.ts +49 -3
  440. package/src/ui/host.tsx +8 -4
  441. package/src/ui/index.tsx +2 -0
  442. package/src/utils/cli-output.ts +14 -1
  443. package/src/utils/exchanges.ts +13 -0
  444. package/src/utils/format.ts +2 -1
  445. package/src/utils/fx-market-hours.ts +34 -0
  446. package/src/utils/option-expiry.ts +126 -0
  447. package/src/utils/price-history.ts +39 -6
  448. package/src/utils/rpc-timeout-error.ts +6 -2
  449. package/src/utils/sec-eps-basis.ts +159 -30
  450. package/src/utils/sec.ts +38 -34
  451. package/src/utils/throttled-fetch.ts +51 -22
@@ -2,6 +2,7 @@ import { useCallback, useMemo, useRef } from "react";
2
2
  import { isAccessDenied } from "../../../api-client/errors";
3
3
  import { usePlanAccess } from "../../../api-client/plan-access";
4
4
  import type { KpiObservation } from "../../../api-client/company-kpis";
5
+ import { listingAbroad } from "../../../api-client/paths";
5
6
  import { ChartTableHeader, DataTableStackView, DetailScrollBody, EmptyState, KeyValueRow, PaneStatusBody, QueryBar, SectionHeading,
6
7
  useChartTableSelection, usePaneMenuItems, usePaneNoticeFooter, usePaneStatusFooter, usePaneTabs, type DataTableCell, type PaneHint } from "../../../components";
7
8
  import { usePaneRefreshKey } from "../../../components/data-table/table-pane";
@@ -57,15 +58,21 @@ function DisclosureEvidence({ row, sourceId, onSource, width }: { row: CompanyRo
57
58
  </Box>;
58
59
  }
59
60
 
61
+ /** The pane's ticker, with the venue and company a listing abroad is asked about by. */
62
+ function useCompanyListing() {
63
+ const { symbol, ticker } = usePaneTickerIdentity();
64
+ const abroad = symbol ? listingAbroad(symbol, ticker?.metadata.exchange, ticker?.metadata.name) : null;
65
+ return { symbol, exchange: abroad?.exchange, name: abroad?.name, key: JSON.stringify([symbol, abroad?.exchange, abroad?.name]) };
66
+ }
60
67
  export function CompanyKpisPane(props: PaneProps) {
61
- const { symbol } = usePaneTickerIdentity();
62
- return <CompanyView key={`${symbol}:kpis`} {...props} symbol={symbol} mode="kpis" />;
68
+ const { key, ...listing } = useCompanyListing();
69
+ return <CompanyView key={`${key}:kpis`} {...props} {...listing} mode="kpis" />;
63
70
  }
64
71
  export function CompanyGuidancePane(props: PaneProps) {
65
- const { symbol } = usePaneTickerIdentity();
66
- return <CompanyView key={`${symbol}:guidance`} {...props} symbol={symbol} mode="guidance" />;
72
+ const { key, ...listing } = useCompanyListing();
73
+ return <CompanyView key={`${key}:guidance`} {...props} {...listing} mode="guidance" />;
67
74
  }
68
- function CompanyView({ symbol, mode, width, height, focused }: PaneProps & { symbol: string | null; mode: CompanyMode }) {
75
+ function CompanyView({ symbol, exchange, name, mode, width, height, focused }: PaneProps & { symbol: string | null; exchange?: string; name?: string; mode: CompanyMode }) {
69
76
  const colors = useThemeColors();
70
77
  const host = useRendererHost();
71
78
  const desktop = !!useUiCapabilities().nativePaneChrome;
@@ -76,8 +83,9 @@ function CompanyView({ symbol, mode, width, height, focused }: PaneProps & { sym
76
83
  const openUpgrade = useCloudUpgradeAction(mode === "kpis" ? "kpis" : "guide");
77
84
  const [snapshotSetting] = usePaneSettingValue<CompanyDataset | null>("companySnapshot", null);
78
85
  const snapshot = useMemo(() => { try { return snapshotSetting ? validateCompanyData(snapshotSetting) : null; } catch { return null; } }, [snapshotSetting]);
79
- const loader = useCallback((force: boolean) => snapshot ? Promise.resolve({ payload: snapshot, stale: false, refreshError: null }) : loadCompanyData(mode, symbol!, accessKey, force), [mode, symbol, accessKey, snapshot]);
80
- const resource = useAsyncResource(symbol ? loader : null, { initialData: () => symbol ? cachedCompanyData(mode, symbol, accessKey) : null, clearOnError: isAccessDenied });
86
+ const loader = useCallback((force: boolean) => snapshot ? Promise.resolve({ payload: snapshot, stale: false, refreshError: null })
87
+ : loadCompanyData(mode, symbol!, accessKey, force, { exchange, name }), [mode, symbol, exchange, name, accessKey, snapshot]);
88
+ const resource = useAsyncResource(symbol ? loader : null, { initialData: () => symbol ? cachedCompanyData(mode, symbol, accessKey, { exchange, name }) : null, clearOnError: isAccessDenied });
81
89
  const data = resource.data?.payload;
82
90
  const kpis = data && "series" in data ? data : null;
83
91
  const guidance = data && "guidance" in data ? data : null;
@@ -1,6 +1,9 @@
1
+ import { apiClient } from "../../../api-client";
1
2
  import type { PaneScreenshotEvidenceHook } from "../../../cli/pane-functions/screenshot-evidence";
2
3
  import { useRemoteUiNode } from "../../../remote/semantic-tree";
4
+ import { parsePublicTickerKey } from "../../../utils/exchanges";
3
5
  import { isRecord } from "../../../utils/guards";
6
+ import { resolveIssuerListing } from "../shared/headless-market-data";
4
7
  import { companyQuery, fetchCompanyData, validateCompanyData, type CompanyDataset, type CompanyMode } from "./client";
5
8
  import { allGuidance, allObservations } from "./model";
6
9
 
@@ -13,11 +16,15 @@ export function useCompanyEvidence(payload: CompanyDataset | null, mode: Company
13
16
  function screenshotEvidence(mode: CompanyMode): PaneScreenshotEvidenceHook<Evidence> {
14
17
  return {
15
18
  paneId: mode === "kpis" ? "company-kpis" : "company-guidance", kind: "company-disclosures", label: "company disclosures",
16
- async prepare({ resolved }) {
19
+ async prepare({ resolved, context }) {
17
20
  const symbol = resolved.createOptions?.symbol ?? resolved.createOptions?.arg;
18
21
  if (!symbol) throw new Error("A company disclosure screenshot requires a ticker");
19
- const payload = await fetchCompanyData(mode, symbol, companyQuery(resolved.options));
20
- return { settings: { companySnapshot: payload }, financials: [[payload.symbol, { annualStatements: [], quarterlyStatements: [], priceHistory: [] }]] };
22
+ // A bare symbol takes the saved listing's venue, as the pane does.
23
+ const saved = parsePublicTickerKey(symbol).exchange ? null : await context.store.loadTicker(symbol).catch(() => null);
24
+ const listing = await resolveIssuerListing(symbol, saved?.metadata.exchange, context.dataProvider);
25
+ const payload = await fetchCompanyData(mode, symbol, companyQuery(resolved.options), apiClient, listing);
26
+ // Keyed by the requested ticker: a listing abroad is answered under its bare symbol.
27
+ return { settings: { companySnapshot: payload }, financials: [[symbol.trim().toUpperCase(), { annualStatements: [], quarterlyStatements: [], priceHistory: [] }]] };
21
28
  },
22
29
  read(value) {
23
30
  if (!isRecord(value) || value.kind !== "company-disclosures" || value.version !== 1 || value.mode !== mode || !isRecord(value.payload)
@@ -37,7 +37,7 @@ import { positionSizerModule } from "./kelly-sizer";
37
37
  import { layoutManagerModule } from "./layout-manager";
38
38
  import { marketMoversModule } from "./market-movers";
39
39
  import { volatilityModule } from "./volatility";
40
- import { composeBuiltinPlugin } from "./plugin-module";
40
+ import { composeBuiltinPlugin, type PluginModule } from "./plugin-module";
41
41
  import { portfolioListModule } from "./portfolio-list";
42
42
  import { scannerModule } from "./scanner";
43
43
  import { sectorsModule } from "./sectors";
@@ -85,11 +85,21 @@ import { thirteenFModule } from "./thirteenf";
85
85
  import { tickerDetailModule } from "./ticker-detail";
86
86
  import { macroSharedResourcesModule } from "./macro-resources";
87
87
  import {
88
+ altDataPluginMeta,
88
89
  applicationPluginMeta,
89
- macroPluginMeta,
90
- marketOverviewPluginMeta,
90
+ creditPluginMeta,
91
+ cryptoPluginMeta,
92
+ earningsPluginMeta,
93
+ futuresCommoditiesPluginMeta,
94
+ globalMarketsPluginMeta,
91
95
  portfolioPluginMeta,
92
- tickerResearchPluginMeta,
96
+ filingsPluginMeta,
97
+ optionsVolatilityPluginMeta,
98
+ ownershipPluginMeta,
99
+ quantPluginMeta,
100
+ ratesMacroPluginMeta,
101
+ screenersPluginMeta,
102
+ tickerCorePluginMeta,
93
103
  } from "./builtin-plugin-meta";
94
104
 
95
105
  export const applicationPlugin = composeBuiltinPlugin({
@@ -102,51 +112,59 @@ export const portfolioPlugin = composeBuiltinPlugin({
102
112
  modules: [portfolioListModule, portfolioAnalyticsModule, positionSizerModule],
103
113
  });
104
114
 
105
- export const tickerResearchPlugin = composeBuiltinPlugin({
106
- ...tickerResearchPluginMeta,
115
+ // Ticker Research's modules are drawn in the renderer: the desktop backend
116
+ // process runs none of them, and keeps only the identity of the plugins that
117
+ // hold nothing else.
118
+ const rendererOnly = (module: PluginModule) => ({ module, rendererOnly: true });
119
+ const tickerResearchModule = (module: PluginModule) => ({ module, stateId: "ticker-research", rendererOnly: true });
120
+
121
+ export const tickerCorePlugin = composeBuiltinPlugin({
122
+ ...tickerCorePluginMeta,
107
123
  modules: [
108
124
  tickerDetailModule,
109
125
  chartComposerModule,
110
- congressResearchModule,
126
+ researchModule,
127
+ estimateRevisionsModule,
128
+ companyKpisModule,
129
+ revenueBreakdownModule,
130
+ dividendYieldModule,
131
+ reverseDcfModule,
132
+ peBandModule,
133
+ executivesModule,
134
+ timeSalesModule,
135
+ ].map(rendererOnly),
136
+ });
137
+
138
+ export const optionsVolatilityPlugin = composeBuiltinPlugin({
139
+ ...optionsVolatilityPluginMeta,
140
+ modules: [
111
141
  optionsModule,
112
142
  optionsPositioningModule,
113
143
  optionsCalculatorModule,
114
144
  optionsScenarioModule,
115
145
  volSurfaceModule,
116
146
  realizedVolModule,
117
- seasonalityModule,
118
- earningsRippleModule,
119
- reverseDcfModule,
120
- peBandModule,
121
- macroDayModule,
122
147
  ivHistoryModule,
123
- backtestModule,
124
- estimateRevisionsModule,
125
- researchModule,
126
- shortVolumeModule,
127
- socialMentionsModule,
128
- debtMaturitiesModule,
129
- revenueBreakdownModule,
130
- supplyChainModule,
131
- creditDocumentsModule,
132
- companyAttentionModule,
133
- catalystsModule,
134
- companyKpisModule,
135
- awardsModule,
136
- exposureModule,
137
- mnaModule,
138
- dividendYieldModule,
148
+ ].map(rendererOnly),
149
+ });
150
+
151
+ export const ownershipPlugin = composeBuiltinPlugin({
152
+ ...ownershipPluginMeta,
153
+ description: "Holders, 13F funds, insider trades, short interest and volume, and congressional trades.",
154
+ modules: [
139
155
  holdersModule,
140
- shortInterestModule,
141
- timeSalesModule,
142
156
  thirteenFModule,
143
- secModule,
144
157
  insiderModule,
145
- jobsModule,
146
- executivesModule,
147
- riskFactorsModule,
148
- filingEventsModule,
149
- ],
158
+ shortInterestModule,
159
+ shortVolumeModule,
160
+ // The Congress research tab; the CONG pane is Gloom Cloud's.
161
+ congressResearchModule,
162
+ ].map(rendererOnly),
163
+ });
164
+
165
+ export const filingsPlugin = composeBuiltinPlugin({
166
+ ...filingsPluginMeta,
167
+ modules: [secModule, riskFactorsModule, filingEventsModule, catalystsModule, mnaModule].map(rendererOnly),
150
168
  });
151
169
 
152
170
  export const brokerPlugin = composeBuiltinPlugin({
@@ -158,35 +176,48 @@ export const brokerPlugin = composeBuiltinPlugin({
158
176
  modules: [brokerManagerModule],
159
177
  });
160
178
 
161
- export const marketOverviewPlugin = composeBuiltinPlugin({
162
- ...marketOverviewPluginMeta,
163
- description: "Global indices, movers, scanners, sectors, FX, futures, and correlations.",
179
+ export const globalMarketsPlugin = composeBuiltinPlugin({
180
+ ...globalMarketsPluginMeta,
181
+ modules: [worldIndicesModule, worldVenueMapModule, sectorsModule, fxMatrixModule, relativeRotationModule],
182
+ });
183
+
184
+ export const screenersPlugin = composeBuiltinPlugin({
185
+ ...screenersPluginMeta,
186
+ description: "Equity screener, top movers, session highs and lows, and unusual options flow.",
187
+ modules: [equityScreenerModule, marketMoversModule, scannerModule],
188
+ });
189
+
190
+ export const futuresCommoditiesPlugin = composeBuiltinPlugin({
191
+ ...futuresCommoditiesPluginMeta,
192
+ modules: [futuresModule, futuresCurveModule, cotModule, doeModule],
193
+ });
194
+
195
+ export const cryptoPlugin = composeBuiltinPlugin({
196
+ ...cryptoPluginMeta,
197
+ modules: [cryptoBoardModule, perpsModule],
198
+ });
199
+
200
+ export const altDataPlugin = composeBuiltinPlugin({
201
+ ...altDataPluginMeta,
164
202
  modules: [
165
- correlationModule,
166
- relativeRotationModule,
167
- equityScreenerModule,
168
- worldIndicesModule,
169
- worldVenueMapModule,
170
- marketMoversModule,
171
- scannerModule,
172
- sectorsModule,
173
- fxMatrixModule,
174
- futuresModule,
175
- futuresCurveModule,
176
- cotModule,
177
- doeModule,
178
- gpuModule,
179
- attentionModule,
180
- powerModule,
181
- cryptoBoardModule,
182
- perpsModule,
203
+ ...[attentionModule, gpuModule, powerModule].map((module) => ({ module, stateId: "market-overview" })),
204
+ ...[supplyChainModule, exposureModule, awardsModule, companyAttentionModule, jobsModule, socialMentionsModule].map(rendererOnly),
183
205
  ],
184
206
  });
185
207
 
186
- export const macroPlugin = composeBuiltinPlugin({
187
- ...macroPluginMeta,
188
- description: "Economic calendar, rates, volatility, credit spreads, single-name, index and sovereign CDS, Treasury auctions, and earnings.",
208
+ export const quantPlugin = composeBuiltinPlugin({
209
+ ...quantPluginMeta,
189
210
  modules: [
211
+ { module: correlationModule, stateId: "market-overview" },
212
+ ...[backtestModule, seasonalityModule, macroDayModule].map(rendererOnly),
213
+ ],
214
+ });
215
+
216
+ export const ratesMacroPlugin = composeBuiltinPlugin({
217
+ ...ratesMacroPluginMeta,
218
+ modules: [
219
+ // The FRED cache the other panes and the chart composer read too. Every
220
+ // plugin is set up whether or not it is switched on, so it stays attached.
190
221
  macroSharedResourcesModule,
191
222
  economicCalendarModule,
192
223
  econStatisticsModule,
@@ -194,15 +225,27 @@ export const macroPlugin = composeBuiltinPlugin({
194
225
  yieldCurveModule,
195
226
  ratePathModule,
196
227
  moneyMarketsModule,
197
- bondCalculatorModule,
198
228
  centralBankRatesModule,
199
229
  volatilityModule,
200
- creditConditionsModule,
201
230
  marketValuationModule,
231
+ ],
232
+ });
233
+
234
+ export const creditPlugin = composeBuiltinPlugin({
235
+ ...creditPluginMeta,
236
+ modules: [
202
237
  cdsModule,
203
238
  creditBoardsModule,
239
+ creditConditionsModule,
204
240
  treasuryAuctionsModule,
205
- earningsModule,
206
- earningsCallsModule,
241
+ bondCalculatorModule,
242
+ tickerResearchModule(creditDocumentsModule),
243
+ tickerResearchModule(debtMaturitiesModule),
207
244
  ],
208
245
  });
246
+
247
+ export const earningsPlugin = composeBuiltinPlugin({
248
+ ...earningsPluginMeta,
249
+ description: "Earnings calendar with surprises and implied moves, call transcripts, and the earnings ripple through customers and suppliers.",
250
+ modules: [earningsModule, earningsCallsModule, tickerResearchModule(earningsRippleModule)],
251
+ });
@@ -76,14 +76,14 @@ function IndexDetail({ row, width, height, focused }: { row: CdxRow; width: numb
76
76
  );
77
77
  }
78
78
 
79
- export function CdxPane({ paneId, focused, width, height }: PaneProps) {
79
+ export function CdxPane({ focused, width, height }: PaneProps) {
80
80
  const theme = useThemeColors();
81
81
  const resource = useAsyncResource(loadCdxBoard, { initialData: getCachedCdxBoard });
82
82
  const { loading, load: refresh, reload } = resource;
83
83
  const payload = resource.data?.payload ?? null;
84
84
  const rows = useMemo(() => payload ? cdxRows(payload.indexes, payload.asOf) : EMPTY_ROWS, [payload]);
85
- const [selectedId, setSelectedId] = usePluginPaneState<string | null>("selected", null);
86
- const [openId, setOpenId] = usePluginPaneState<string | null>("open", null);
85
+ const [selectedId, setSelectedId] = usePluginPaneState<string | null>("cdx:selected", null);
86
+ const [openId, setOpenId] = usePluginPaneState<string | null>("cdx:open", null);
87
87
  useAutoRefresh(resource.updatedAt, refresh);
88
88
  usePaneRefreshKey(reload, { focused, enabled: !loading });
89
89
 
@@ -94,7 +94,7 @@ export function CdxPane({ paneId, focused, width, height }: PaneProps) {
94
94
  ...(resource.data?.stale ? [{ id: "stale", parts: [{ text: "STALE", tone: "warning" as const }] }] : []),
95
95
  ], [asOf, payload, resource.data?.stale]);
96
96
  usePaneStatusFooter({
97
- registrationId: paneId,
97
+ registrationId: "cdx",
98
98
  loading,
99
99
  error: resource.error ?? resource.data?.refreshError ?? null,
100
100
  info,
@@ -1,34 +1,32 @@
1
+ import type { PaneTemplateContext, PaneTemplateInstanceConfig } from "../../../types/plugin";
2
+ import { commandTabParams } from "../shared/command-tab";
1
3
  import type { PluginModule } from "../plugin-module";
2
- import { CdxPane } from "./cdx-pane";
3
4
  import { cdxBoardCache, sovrBoardCache } from "./client";
4
5
  import { cdxHeadless, sovrHeadless } from "./headless";
5
- import { CDX_PANE_ID, SOVR_PANE_ID } from "./model";
6
- import { SovrPane } from "./sovr-pane";
6
+ import { CDX_PANE_ID } from "./model";
7
+ import { CreditBoardsPane } from "./pane";
8
+
9
+ /** One board. A later command retargets this instance; a fresh id would open a second window. */
10
+ function openCreditBoard(context: PaneTemplateContext, tab: "index" | "sovereign"): PaneTemplateInstanceConfig {
11
+ const existing = context.layout.instances.find((instance) => instance.paneId === CDX_PANE_ID);
12
+ return {
13
+ instanceId: existing?.instanceId ?? CDX_PANE_ID,
14
+ params: commandTabParams(tab),
15
+ };
16
+ }
7
17
 
8
18
  export const creditBoardsModule: PluginModule = {
9
19
  panes: [
10
20
  {
11
21
  id: CDX_PANE_ID,
12
- name: "Index CDS",
22
+ // The single-name pane already opens titled "CDS".
23
+ name: "CDS Boards",
13
24
  icon: "X",
14
- component: CdxPane,
15
- defaultPosition: "right",
16
- defaultMode: "floating",
17
- // Five indexes under their history, like Credit Spreads.
18
- defaultFloatingSize: { width: 92, height: 20 },
19
- tableExport: true,
20
- headless: cdxHeadless,
21
- },
22
- {
23
- id: SOVR_PANE_ID,
24
- name: "Sovereign CDS",
25
- icon: "S",
26
- component: SovrPane,
25
+ component: CreditBoardsPane,
27
26
  defaultPosition: "right",
28
27
  defaultMode: "floating",
29
28
  defaultFloatingSize: { width: 96, height: 28 },
30
29
  tableExport: true,
31
- headless: sovrHeadless,
32
30
  },
33
31
  ],
34
32
  paneTemplates: [
@@ -36,19 +34,21 @@ export const creditBoardsModule: PluginModule = {
36
34
  id: "cdx-pane",
37
35
  paneId: CDX_PANE_ID,
38
36
  label: "Index CDS",
39
- description: "CDX IG, HY, EM, iTraxx Main and Crossover on the run from DTCC public dissemination: level, 1D and 1W moves, 1Y rank.",
37
+ description: "CDX IG, HY, EM, iTraxx Main and Crossover on the run from DTCC public dissemination: level, 1D and 1W moves, 1Y rank. Sovereign CDS is the other tab.",
40
38
  keywords: ["cdx", "itraxx", "crossover", "xover", "index", "cds", "credit", "ig", "hy", "em", "spread", "dtcc"],
41
39
  shortcut: { prefix: "CDX" },
42
40
  headless: cdxHeadless,
41
+ createInstance: (context) => openCreditBoard(context, "index"),
43
42
  },
44
43
  {
45
44
  id: "sovr-pane",
46
- paneId: SOVR_PANE_ID,
45
+ paneId: CDX_PANE_ID,
47
46
  label: "Sovereign CDS",
48
- description: "Sovereign 5Y CDS from DTCC public dissemination, ranked by the month's move, beside each local currency's month.",
47
+ description: "The CDS pane on Sovereign: 5Y CDS from DTCC public dissemination, ranked by the month's move, beside each local currency's month.",
49
48
  keywords: ["sovr", "wcds", "sovereign", "country", "cds", "credit", "em", "emerging", "spread", "dtcc"],
50
49
  shortcut: { prefix: "SOVR", aliases: ["WCDS"] },
51
50
  headless: sovrHeadless,
51
+ createInstance: (context) => openCreditBoard(context, "sovereign"),
52
52
  },
53
53
  ],
54
54
  setup(ctx) {
@@ -10,7 +10,6 @@ import type { MarketBoardRow } from "../../../components/market-board";
10
10
  import type { PricePoint } from "../../../types/financials";
11
11
 
12
12
  export const CDX_PANE_ID = "cdx-board";
13
- export const SOVR_PANE_ID = "sovr-board";
14
13
 
15
14
  const YEAR_DAYS = 365;
16
15
  /** A level older than this is not the current market. */
@@ -0,0 +1,30 @@
1
+ import { useEffect, useState } from "react";
2
+ import { PaneFooterScope, usePaneTabs } from "../../../components";
3
+ import type { PaneProps } from "../../../types/plugin";
4
+ import { Box } from "../../../ui";
5
+ import { useCommandTab } from "../shared/command-tab";
6
+ import { CdxPane } from "./cdx-pane";
7
+ import { CDX_PANE_ID } from "./model";
8
+ import { SovrPane } from "./sovr-pane";
9
+
10
+ const TABS = [{ value: "index", label: "Index" }, { value: "sovereign", label: "Sovereign" }];
11
+
12
+ export function CreditBoardsPane(props: PaneProps) {
13
+ const [tab, setTab] = useCommandTab(CDX_PANE_ID, "credit-boards:tab", ["index", "sovereign"], "index");
14
+ const [mounted, setMounted] = useState<Set<string>>(() => new Set([tab]));
15
+ useEffect(() => { setMounted((current) => current.has(tab) ? current : new Set([...current, tab])); }, [tab]);
16
+ const { strip: tabStrip, rows: tabRows } = usePaneTabs({
17
+ tabs: TABS, activeValue: tab, onSelect: (value) => setTab(value === "sovereign" ? "sovereign" : "index"), focused: props.focused, dense: true,
18
+ });
19
+ const height = Math.max(1, props.height - tabRows);
20
+ return <Box width={props.width} height={props.height} flexDirection="column">
21
+ {tabStrip}
22
+ {TABS.map(({ value }) => mounted.has(value) || value === tab ? <Box key={value} visible={value === tab} height={height} flexGrow={1} flexBasis={0} overflow="hidden">
23
+ <PaneFooterScope active={value === tab}>
24
+ {value === "sovereign"
25
+ ? <SovrPane {...props} height={height} focused={props.focused && value === tab} />
26
+ : <CdxPane {...props} height={height} focused={props.focused && value === tab} />}
27
+ </PaneFooterScope>
28
+ </Box> : null)}
29
+ </Box>;
30
+ }
@@ -76,14 +76,14 @@ function SovereignDetail({ row, width, height, focused }: { row: SovrRow; width:
76
76
  );
77
77
  }
78
78
 
79
- export function SovrPane({ paneId, focused, width, height }: PaneProps) {
79
+ export function SovrPane({ focused, width, height }: PaneProps) {
80
80
  const theme = useThemeColors();
81
81
  const provider = useAssetData();
82
82
  const resource = useAsyncResource(loadSovrBoard, { initialData: getCachedSovrBoard });
83
83
  const { loading, load: refresh, reload } = resource;
84
84
  const payload = resource.data?.payload ?? null;
85
- const [selectedId, setSelectedId] = usePluginPaneState<string | null>("selected", null);
86
- const [openId, setOpenId] = usePluginPaneState<string | null>("open", null);
85
+ const [selectedId, setSelectedId] = usePluginPaneState<string | null>("sovr:selected", null);
86
+ const [openId, setOpenId] = usePluginPaneState<string | null>("sovr:open", null);
87
87
  useAutoRefresh(resource.updatedAt, refresh);
88
88
 
89
89
  // Each currency's month against the dollar, from the same daily closes the FX panes use.
@@ -107,7 +107,7 @@ export function SovrPane({ paneId, focused, width, height }: PaneProps) {
107
107
  ...(resource.data?.stale ? [{ id: "stale", parts: [{ text: "STALE", tone: "warning" as const }] }] : []),
108
108
  ], [asOf, payload, resource.data?.stale]);
109
109
  usePaneStatusFooter({
110
- registrationId: paneId,
110
+ registrationId: "sovr",
111
111
  loading: loading || moves.loading,
112
112
  error: resource.error ?? resource.data?.refreshError ?? null,
113
113
  info,
@@ -4,7 +4,10 @@ import type {
4
4
  DebtMaturitiesPayload,
5
5
  DebtMetric,
6
6
  } from "../../../api-client/debt-maturities";
7
+ import { ApiRequestError } from "../../../api-client/errors";
8
+ import { listingAbroad, type IssuerListingParams } from "../../../api-client/paths";
7
9
  import { createPluginCache } from "../../../data/plugin-cache";
10
+ import { secListingKey } from "../../../utils/sec";
8
11
  import {
9
12
  cachedCloudResource,
10
13
  loadCloudResource,
@@ -329,29 +332,54 @@ export function validateDebtMaturities(
329
332
  return data;
330
333
  }
331
334
 
335
+ /** The symbol the server answers with: a listing abroad's bare symbol, otherwise the one sent. */
336
+ const answeredSymbol = (symbol: string, listing?: IssuerListingParams) =>
337
+ listingAbroad(symbol, listing?.exchange)?.symbol ?? symbol;
338
+
339
+ /**
340
+ * The schedule of the issuer behind a listing. A listing abroad asks for its
341
+ * bare symbol with its venue and company (cloudDebtMaturitiesPath), and the
342
+ * server answers for the bare symbol; a 404 for it is no schedule, like the
343
+ * server's own empty answer, not a failure.
344
+ */
332
345
  export async function fetchDebtMaturities(
333
346
  symbol: string,
334
347
  client: Pick<typeof apiClient, "getCloudDebtMaturities"> = apiClient,
348
+ listing?: IssuerListingParams,
335
349
  ) {
350
+ const abroad = listingAbroad(symbol, listing?.exchange) !== null;
351
+ const answered = answeredSymbol(symbol, listing);
336
352
  try {
337
353
  return validateDebtMaturities(
338
- await client.getCloudDebtMaturities(symbol),
339
- symbol,
354
+ await client.getCloudDebtMaturities(symbol, listing),
355
+ answered,
340
356
  );
341
357
  } catch (error) {
358
+ if (abroad && error instanceof ApiRequestError && error.status === 404) return noSchedule(answered);
342
359
  throw unavailableOnServer(error, "Debt maturities are not available yet.");
343
360
  }
344
361
  }
345
- export function cachedDebtMaturities(symbol: string) {
346
- return cachedCloudResource(debtMaturitiesCache, symbol, (payload) =>
347
- validateDebtMaturities(payload, symbol),
362
+
363
+ function noSchedule(symbol: string): DebtMaturitiesPayload {
364
+ return {
365
+ version: 1, symbol, cik: null, entityName: null, taxonomy: null, status: "unavailable",
366
+ fetchedAt: new Date().toISOString(), asOf: null,
367
+ source: { name: "SEC EDGAR company facts", url: "https://www.sec.gov/edgar/search/", cadence: "" },
368
+ latest: null, history: [], warnings: [],
369
+ };
370
+ }
371
+
372
+ // SAN in Paris is not SAN in New York: a listing abroad is cached under its venue.
373
+ export function cachedDebtMaturities(symbol: string, listing?: IssuerListingParams) {
374
+ return cachedCloudResource(debtMaturitiesCache, secListingKey(symbol, listing?.exchange), (payload) =>
375
+ validateDebtMaturities(payload, answeredSymbol(symbol, listing)),
348
376
  );
349
377
  }
350
- export function loadDebtMaturities(symbol: string, force = false) {
378
+ export function loadDebtMaturities(symbol: string, listing?: IssuerListingParams, force = false) {
351
379
  return loadCloudResource(
352
380
  debtMaturitiesCache,
353
- symbol,
354
- () => fetchDebtMaturities(symbol),
355
- { force, validate: (payload) => validateDebtMaturities(payload, symbol) },
381
+ secListingKey(symbol, listing?.exchange),
382
+ () => fetchDebtMaturities(symbol, apiClient, listing),
383
+ { force, validate: (payload) => validateDebtMaturities(payload, answeredSymbol(symbol, listing)) },
356
384
  );
357
385
  }
@@ -2,6 +2,7 @@ import type { HeadlessPaneDefinition } from "../../../types/plugin";
2
2
  import { fetchDebtMaturities } from "./client";
3
3
  import { bucketShare, debtNotices } from "./model";
4
4
  import { SEC_FILINGS } from "../shared/report-freshness";
5
+ import { resolveHeadlessIssuerListing } from "../shared/headless-market-data";
5
6
 
6
7
  export const debtMaturitiesHeadless: HeadlessPaneDefinition<"bundle"> = {
7
8
  shape: "bundle",
@@ -38,7 +39,8 @@ export const debtMaturitiesHeadless: HeadlessPaneDefinition<"bundle"> = {
38
39
  ],
39
40
  describe: (args) => `Debt maturities | ${args.symbols[0]}`,
40
41
  async load(args, ctx) {
41
- const data = await fetchDebtMaturities(args.symbols[0]!, ctx.apiClient);
42
+ const symbol = args.symbols[0]!;
43
+ const data = await fetchDebtMaturities(symbol, ctx.apiClient, await resolveHeadlessIssuerListing(ctx, symbol));
42
44
  return {
43
45
  complete: data.status === "available",
44
46
  errors: debtNotices(data),
@@ -1,5 +1,5 @@
1
1
  import { useCallback, useMemo, type ReactNode } from "react";
2
- import { listingIdentity } from "../shared/ticker-request";
2
+ import { listingIdentity, useIssuerListing } from "../shared/ticker-request";
3
3
  import { Box, ScrollBox, Text, useUiCapabilities } from "../../../ui";
4
4
  import {
5
5
  useAsyncResource,
@@ -275,13 +275,14 @@ function HistoryDetail({
275
275
  export function DebtMaturitiesPane({ width, height, focused }: PaneProps) {
276
276
  const { ticker } = usePaneTickerIdentity();
277
277
  const symbol = listingIdentity(ticker?.metadata.ticker)?.symbol ?? null;
278
+ const listing = useIssuerListing(ticker);
278
279
  const session = useResearchCloudSession();
279
280
  const loader = useCallback(
280
- (force: boolean) => loadDebtMaturities(symbol!, force),
281
- [symbol, session.requestKey],
281
+ (force: boolean) => loadDebtMaturities(symbol!, listing, force),
282
+ [symbol, listing, session.requestKey],
282
283
  );
283
284
  const resource = useAsyncResource(symbol ? loader : null, {
284
- initialData: () => (symbol ? cachedDebtMaturities(symbol) : null),
285
+ initialData: () => (symbol ? cachedDebtMaturities(symbol, listing) : null),
285
286
  clearOnError: isAccessDenied,
286
287
  });
287
288
  const [initialTab] = usePaneSettingValue("tab", "maturities");
@@ -26,7 +26,7 @@ function createDividendYieldModule({
26
26
  id: DIVIDENDS_CONNECTION_ID,
27
27
  name: "Gloom Dividends",
28
28
  kind: "api",
29
- ownerId: "ticker-research",
29
+ ownerId: "ticker-core",
30
30
  detail: "api.gloom.sh",
31
31
  priority: 300,
32
32
  });
@@ -240,7 +240,7 @@ export function DividendYieldPane({ focused, width, height, loadData = fetchDivi
240
240
  ), [refresh]);
241
241
 
242
242
  const emptyTitle = !symbol
243
- ? "No ticker selected."
243
+ ? "Select a ticker."
244
244
  : loading
245
245
  ? "Loading dividends..."
246
246
  : error ?? (data?.historyAvailable ? "No cash distributions reported." : "Dividend history unavailable.");