gloomberb 0.16.2 → 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 (527) 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/account-cache.ts +45 -0
  30. package/src/brokers/signed-in/adapter.ts +33 -2
  31. package/src/brokers/signed-in/client.ts +10 -0
  32. package/src/brokers/signed-in/sign-in-dialog.tsx +23 -9
  33. package/src/brokers/signed-in/sign-in.ts +62 -5
  34. package/src/capabilities/registry.ts +8 -1
  35. package/src/capabilities/types.ts +2 -0
  36. package/src/cli/command-options.ts +74 -0
  37. package/src/cli/commands/command-utils.ts +29 -0
  38. package/src/cli/commands/crypto-hints.ts +12 -4
  39. package/src/cli/commands/market.ts +524 -148
  40. package/src/cli/commands/options-chain.ts +172 -0
  41. package/src/cli/commands/options-leaps.ts +422 -0
  42. package/src/cli/commands/overview.ts +223 -42
  43. package/src/cli/commands/search.ts +29 -8
  44. package/src/cli/commands/system.ts +99 -19
  45. package/src/cli/commands/themes.ts +64 -0
  46. package/src/cli/commands/ticker.ts +200 -73
  47. package/src/cli/desktop-pane-shot.ts +100 -16
  48. package/src/cli/errors.ts +25 -2
  49. package/src/cli/freshness.ts +7 -4
  50. package/src/cli/fx-pair.ts +57 -0
  51. package/src/cli/help.ts +40 -7
  52. package/src/cli/history-rows.ts +187 -15
  53. package/src/cli/index-roots.ts +51 -0
  54. package/src/cli/index.ts +21 -13
  55. package/src/cli/listing-arg.ts +211 -3
  56. package/src/cli/not-a-ticker.ts +37 -0
  57. package/src/cli/options.ts +55 -7
  58. package/src/cli/pane-functions/capabilities.ts +13 -2
  59. package/src/cli/pane-functions/catalog.ts +13 -2
  60. package/src/cli/pane-functions/data.ts +36 -5
  61. package/src/cli/pane-functions/dom.ts +89 -28
  62. package/src/cli/pane-functions/freshness.ts +205 -26
  63. package/src/cli/pane-functions/function-help.ts +71 -24
  64. package/src/cli/pane-functions/headless.ts +168 -35
  65. package/src/cli/pane-functions/index.ts +12 -2
  66. package/src/cli/pane-functions/market-session.ts +133 -0
  67. package/src/cli/pane-functions/options.ts +15 -4
  68. package/src/cli/pane-functions/report-notices.ts +63 -0
  69. package/src/cli/pane-functions/report.ts +12 -1
  70. package/src/cli/pane-functions/resolver.ts +32 -8
  71. package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
  72. package/src/cli/pane-functions/screenshot.ts +109 -23
  73. package/src/cli/registry.ts +8 -4
  74. package/src/cli/report-tables.ts +460 -0
  75. package/src/cli/result.ts +63 -16
  76. package/src/cli/row-window.ts +76 -0
  77. package/src/cli/scroll-truncation.ts +34 -0
  78. package/src/components/chart/composite/composite-chart.tsx +43 -4
  79. package/src/components/chart/composite/legend.tsx +39 -6
  80. package/src/components/chart/composite/rasterizer.ts +64 -4
  81. package/src/components/chart/composite/series-cues.ts +71 -0
  82. package/src/components/chart/composite/text-renderer.ts +16 -8
  83. package/src/components/chart/composite/types.ts +3 -0
  84. package/src/components/command-bar/commands/direct/index.ts +9 -1
  85. package/src/components/command-bar/commands/plugin/items.ts +3 -1
  86. package/src/components/command-bar/commands/registry.ts +7 -0
  87. package/src/components/command-bar/layout-items/focused-pane.ts +38 -0
  88. package/src/components/command-bar/pane-templates/workflow.ts +5 -0
  89. package/src/components/command-bar/routes/root/command-items.ts +2 -0
  90. package/src/components/command-bar/routes/root/plugin-turn-on.ts +92 -0
  91. package/src/components/command-bar/routes/root/results.ts +40 -10
  92. package/src/components/command-bar/routes/root/runtime.ts +8 -0
  93. package/src/components/command-bar/routes/root/search-providers.ts +97 -14
  94. package/src/components/command-bar/surface/index.tsx +18 -4
  95. package/src/components/command-bar/theme-picker.tsx +48 -13
  96. package/src/components/command-bar/workflow/ops.ts +5 -3
  97. package/src/components/data-table/export.ts +6 -51
  98. package/src/components/data-table/view.tsx +31 -10
  99. package/src/components/layout/floating-pane.tsx +6 -2
  100. package/src/components/layout/market-summary.ts +23 -9
  101. package/src/components/layout/pane/content.tsx +46 -29
  102. package/src/components/layout/pane/cycle-order.ts +2 -11
  103. package/src/components/layout/pane/header.tsx +2 -1
  104. package/src/components/layout/pane/title.ts +1 -1
  105. package/src/components/layout/presentation.ts +22 -0
  106. package/src/components/layout/shell/active-drag.ts +67 -35
  107. package/src/components/layout/shell/cursor-occlusion.ts +6 -5
  108. package/src/components/layout/shell/drag/index.ts +16 -7
  109. package/src/components/layout/shell/drag/live.ts +193 -0
  110. package/src/components/layout/shell/drag/overlays.tsx +179 -35
  111. package/src/components/layout/shell/drag/runtime.ts +62 -50
  112. package/src/components/layout/shell/drag/slide.ts +10 -0
  113. package/src/components/layout/shell/index.tsx +84 -57
  114. package/src/components/layout/shell/layout-state.ts +5 -11
  115. package/src/components/layout/shell/menu.ts +28 -1
  116. package/src/components/layout/shell/native/pointer-runtime.ts +13 -13
  117. package/src/components/layout/shell/native/surfaces.ts +30 -14
  118. package/src/components/layout/shell/pane/actions.ts +2 -1
  119. package/src/components/layout/shell/pane/layers.tsx +461 -180
  120. package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
  121. package/src/components/layout/shell/pane/new-layout.ts +116 -0
  122. package/src/components/layout/shell/shortcuts.ts +5 -2
  123. package/src/components/layout/shell/terminal-pointer-runtime.ts +18 -18
  124. package/src/components/layout/shell/visible-layout.ts +44 -1
  125. package/src/components/layout/shell/window-mode/overlays.tsx +12 -4
  126. package/src/components/layout/status-bar.tsx +4 -1
  127. package/src/components/markdown-text.tsx +9 -5
  128. package/src/components/metric-treemap/heat-surface.tsx +27 -8
  129. package/src/components/metric-treemap/heat-tiles.ts +48 -17
  130. package/src/components/onboarding/onboarding-frame.tsx +33 -10
  131. package/src/components/onboarding/onboarding-wizard.tsx +49 -40
  132. package/src/components/onboarding/portfolio-step/positions-panel.tsx +5 -2
  133. package/src/components/onboarding/pro-step-layout.ts +86 -0
  134. package/src/components/onboarding/use-onboarding-upgrade.ts +6 -2
  135. package/src/components/ui/button.tsx +10 -0
  136. package/src/components/ui/data-table/index.tsx +38 -0
  137. package/src/components/ui/data-table/types.ts +8 -1
  138. package/src/components/ui/data-table/visible-range.ts +2 -0
  139. package/src/components/ui/icon.tsx +11 -2
  140. package/src/components/ui/index.ts +1 -1
  141. package/src/core/connection-health.ts +1 -1
  142. package/src/core/state/app/layout-reducer.ts +89 -3
  143. package/src/core/state/app/state.ts +8 -5
  144. package/src/core/state/app/types.ts +13 -2
  145. package/src/data/config/layout.ts +55 -21
  146. package/src/data/config/store/fold-panes.ts +149 -0
  147. package/src/data/config/store/migrations.ts +7 -0
  148. package/src/data/config/store/node.ts +27 -6
  149. package/src/data/config/store/normalize.ts +37 -3
  150. package/src/data/json-persistence.ts +17 -3
  151. package/src/data/json-storage.ts +2 -0
  152. package/src/data/memory-resource-store.ts +46 -0
  153. package/src/i18n/es.ts +14 -1
  154. package/src/i18n/ja.ts +14 -1
  155. package/src/i18n/ko.ts +14 -1
  156. package/src/i18n/zh-cn.ts +14 -1
  157. package/src/i18n/zh-tw.ts +14 -1
  158. package/src/layout/desks.ts +1 -2
  159. package/src/layout/pane-layout-move.ts +264 -0
  160. package/src/layout/pane-manager/hidden-panes.ts +160 -0
  161. package/src/layout/pane-manager/index.ts +1 -0
  162. package/src/market-data/coordinator/entries.ts +7 -1
  163. package/src/market-data/coordinator/quotes.ts +2 -2
  164. package/src/market-data/market/freshness.ts +156 -11
  165. package/src/market-data/market/status.ts +40 -0
  166. package/src/market-data/options-alternatives.ts +69 -0
  167. package/src/market-data/quotes/contributions.ts +19 -2
  168. package/src/market-data/quotes/freshness.ts +5 -0
  169. package/src/market-data/quotes/metadata.ts +16 -0
  170. package/src/market-data/quotes/screener-live-quotes.ts +56 -5
  171. package/src/plugins/builtin/account-management/keyboard.ts +3 -0
  172. package/src/plugins/builtin/account-management/model.ts +1 -0
  173. package/src/plugins/builtin/account-management/navigation.ts +1 -1
  174. package/src/plugins/builtin/account-management/pane.tsx +31 -4
  175. package/src/plugins/builtin/alerts/quotes.ts +3 -0
  176. package/src/plugins/builtin/analytics/pane-model.ts +10 -6
  177. package/src/plugins/builtin/analytics/risk-headless.ts +3 -1
  178. package/src/plugins/builtin/analytics/risk-model.ts +37 -8
  179. package/src/plugins/builtin/analytics/risk-pane.tsx +8 -4
  180. package/src/plugins/builtin/attention/pane.tsx +1 -1
  181. package/src/plugins/builtin/backtest/pane.tsx +1 -1
  182. package/src/plugins/builtin/broker-manager/detail.tsx +4 -0
  183. package/src/plugins/builtin/broker-manager/index.tsx +7 -3
  184. package/src/plugins/builtin/broker-manager/model.ts +8 -0
  185. package/src/plugins/builtin/broker-manager/pane-actions.tsx +8 -2
  186. package/src/plugins/builtin/broker-manager/sign-in-end.ts +82 -0
  187. package/src/plugins/builtin/broker-manager/table.ts +5 -0
  188. package/src/plugins/builtin/builtin-plugin-meta.ts +121 -11
  189. package/src/plugins/builtin/catalysts/detail.tsx +1 -1
  190. package/src/plugins/builtin/chart-composer/pane.tsx +1 -1
  191. package/src/plugins/builtin/chat/channels.ts +34 -36
  192. package/src/plugins/builtin/chat/command-bar.ts +138 -0
  193. package/src/plugins/builtin/chat/composer-commands.ts +21 -1
  194. package/src/plugins/builtin/chat/content/composer-runtime.ts +11 -1
  195. package/src/plugins/builtin/chat/content/footer.tsx +5 -3
  196. package/src/plugins/builtin/chat/content/index.tsx +21 -1
  197. package/src/plugins/builtin/chat/content/mentions.ts +2 -1
  198. package/src/plugins/builtin/chat/content/user-map.ts +3 -1
  199. package/src/plugins/builtin/chat/controller/index.ts +48 -0
  200. package/src/plugins/builtin/chat/conversations.ts +256 -0
  201. package/src/plugins/builtin/chat/discord-command.ts +91 -0
  202. package/src/plugins/builtin/chat/edit-window.ts +12 -6
  203. package/src/plugins/builtin/chat/ghost-user.ts +14 -0
  204. package/src/plugins/builtin/chat/index.tsx +40 -2
  205. package/src/plugins/builtin/chat/layout.ts +2 -0
  206. package/src/plugins/builtin/chat/message/desktop.tsx +2 -1
  207. package/src/plugins/builtin/chat/message/header.tsx +24 -15
  208. package/src/plugins/builtin/chat/message/profile-popover.tsx +2 -1
  209. package/src/plugins/builtin/chat/message/render-state.ts +3 -0
  210. package/src/plugins/builtin/chat/pane-requests.ts +60 -0
  211. package/src/plugins/builtin/chat/pane-state.ts +32 -2
  212. package/src/plugins/builtin/chat/pane.tsx +8 -0
  213. package/src/plugins/builtin/cloud/askg/controller.ts +112 -4
  214. package/src/plugins/builtin/cloud/askg/conversation-store.ts +21 -0
  215. package/src/plugins/builtin/cloud/askg/manifest.ts +1 -0
  216. package/src/plugins/builtin/cloud/askg/model.ts +129 -70
  217. package/src/plugins/builtin/cloud/askg/pane.tsx +772 -377
  218. package/src/plugins/builtin/cloud/askg/protocol.ts +40 -2
  219. package/src/plugins/builtin/cloud/askg/tool-display.ts +437 -0
  220. package/src/plugins/builtin/cloud/askg/tool-timeline.tsx +403 -0
  221. package/src/plugins/builtin/cloud/company-picker.tsx +1 -9
  222. package/src/plugins/builtin/cloud/mcp-connect/command.ts +24 -0
  223. package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +360 -0
  224. package/src/plugins/builtin/cloud/mcp-connect/model.ts +135 -0
  225. package/src/plugins/builtin/cloud/mcp-connect/sections.ts +62 -0
  226. package/src/plugins/builtin/cloud/plugin.tsx +36 -1
  227. package/src/plugins/builtin/cloud/starter-symbols.ts +8 -0
  228. package/src/plugins/builtin/cloud/terminal-relay/acm-tab.tsx +89 -0
  229. package/src/plugins/builtin/cloud/terminal-relay/client.ts +97 -0
  230. package/src/plugins/builtin/cloud/terminal-relay/connect-section.tsx +57 -0
  231. package/src/plugins/builtin/cloud/terminal-relay/engine.ts +666 -0
  232. package/src/plugins/builtin/cloud/terminal-relay/grants.ts +137 -0
  233. package/src/plugins/builtin/cloud/terminal-relay/host.tsx +81 -0
  234. package/src/plugins/builtin/cloud/terminal-relay/indicator.tsx +82 -0
  235. package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +234 -0
  236. package/src/plugins/builtin/cloud/terminal-relay/policy.ts +153 -0
  237. package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +168 -0
  238. package/src/plugins/builtin/cloud/terminal-relay/redact.ts +73 -0
  239. package/src/plugins/builtin/cloud/terminal-relay/summary.ts +62 -0
  240. package/src/plugins/builtin/cloud/upgrade-dialog.tsx +26 -2
  241. package/src/plugins/builtin/cloud/upgrade-personalization.ts +57 -0
  242. package/src/plugins/builtin/cloud/upgrade-tickers.ts +124 -0
  243. package/src/plugins/builtin/comment-letters/client.ts +1 -3
  244. package/src/plugins/builtin/company-attention/pane.tsx +1 -1
  245. package/src/plugins/builtin/company-kpis/client.ts +23 -8
  246. package/src/plugins/builtin/company-kpis/headless.ts +3 -1
  247. package/src/plugins/builtin/company-kpis/pane.tsx +15 -7
  248. package/src/plugins/builtin/company-kpis/screenshot-evidence.ts +10 -3
  249. package/src/plugins/builtin/composite-plugins.ts +107 -64
  250. package/src/plugins/builtin/credit-boards/cdx-pane.tsx +4 -4
  251. package/src/plugins/builtin/credit-boards/index.tsx +21 -21
  252. package/src/plugins/builtin/credit-boards/model.ts +0 -1
  253. package/src/plugins/builtin/credit-boards/pane.tsx +30 -0
  254. package/src/plugins/builtin/credit-boards/sovr-pane.tsx +4 -4
  255. package/src/plugins/builtin/debt-maturities/client.ts +37 -9
  256. package/src/plugins/builtin/debt-maturities/headless.ts +3 -1
  257. package/src/plugins/builtin/debt-maturities/pane.tsx +5 -4
  258. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  259. package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
  260. package/src/plugins/builtin/earnings-calls/data.ts +28 -7
  261. package/src/plugins/builtin/earnings-calls/headless.ts +3 -2
  262. package/src/plugins/builtin/earnings-calls/pane.tsx +10 -5
  263. package/src/plugins/builtin/econ/calendar-model.ts +42 -17
  264. package/src/plugins/builtin/econ/detail-view.tsx +2 -2
  265. package/src/plugins/builtin/econ/index.tsx +68 -22
  266. package/src/plugins/builtin/econ-statistics/headless.ts +12 -2
  267. package/src/plugins/builtin/econ-statistics/pane.tsx +1 -1
  268. package/src/plugins/builtin/econ-statistics/view.ts +17 -0
  269. package/src/plugins/builtin/executives/data.ts +17 -6
  270. package/src/plugins/builtin/executives/pane.tsx +16 -7
  271. package/src/plugins/builtin/filing-events/pane.tsx +22 -5
  272. package/src/plugins/builtin/fx-matrix/freshness.ts +65 -0
  273. package/src/plugins/builtin/fx-matrix/index.tsx +22 -1
  274. package/src/plugins/builtin/fx-matrix/pairs.ts +1 -1
  275. package/src/plugins/builtin/fx-matrix/settings.ts +42 -2
  276. package/src/plugins/builtin/gpu/headless.ts +9 -3
  277. package/src/plugins/builtin/gpu/model.ts +14 -5
  278. package/src/plugins/builtin/help/index.tsx +1 -0
  279. package/src/plugins/builtin/holders/beneficial-client.ts +29 -7
  280. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  281. package/src/plugins/builtin/holders/client.ts +3 -6
  282. package/src/plugins/builtin/holders/format.ts +31 -1
  283. package/src/plugins/builtin/holders/headless.ts +32 -6
  284. package/src/plugins/builtin/holders/pane.tsx +25 -13
  285. package/src/plugins/builtin/holders/report-header.ts +46 -5
  286. package/src/plugins/builtin/insider/index.tsx +4 -4
  287. package/src/plugins/builtin/iv-history/charts.tsx +21 -7
  288. package/src/plugins/builtin/iv-history/client.ts +12 -2
  289. package/src/plugins/builtin/iv-history/format.ts +33 -2
  290. package/src/plugins/builtin/iv-history/headless.ts +22 -10
  291. package/src/plugins/builtin/iv-history/index.tsx +3 -3
  292. package/src/plugins/builtin/iv-history/model.ts +61 -13
  293. package/src/plugins/builtin/iv-history/pane.tsx +11 -3
  294. package/src/plugins/builtin/iv-history/screen-pane.tsx +42 -18
  295. package/src/plugins/builtin/jobs/pane.tsx +1 -1
  296. package/src/plugins/builtin/kelly-sizer/headless.ts +149 -0
  297. package/src/plugins/builtin/kelly-sizer/history.ts +80 -0
  298. package/src/plugins/builtin/kelly-sizer/index.tsx +2 -0
  299. package/src/plugins/builtin/kelly-sizer/pane.tsx +121 -45
  300. package/src/plugins/builtin/kelly-sizer/portfolio.ts +25 -0
  301. package/src/plugins/builtin/kelly-sizer/sections.tsx +14 -0
  302. package/src/plugins/builtin/kelly-sizer/types.ts +9 -1
  303. package/src/plugins/builtin/layout-manager/index.tsx +9 -1
  304. package/src/plugins/builtin/macro-day/client.ts +24 -0
  305. package/src/plugins/builtin/macro-day/headless.ts +11 -8
  306. package/src/plugins/builtin/macro-day/index.tsx +3 -0
  307. package/src/plugins/builtin/macro-day/model.ts +11 -6
  308. package/src/plugins/builtin/macro-day/pane.tsx +12 -8
  309. package/src/plugins/builtin/macro-day/release-table.ts +40 -0
  310. package/src/plugins/builtin/macro-day/releases.ts +62 -44
  311. package/src/plugins/builtin/market-heatmap/data.ts +25 -5
  312. package/src/plugins/builtin/market-heatmap/evidence.ts +90 -0
  313. package/src/plugins/builtin/market-heatmap/index.tsx +144 -63
  314. package/src/plugins/builtin/market-heatmap/model.ts +94 -3
  315. package/src/plugins/builtin/market-heatmap/portfolio.ts +12 -2
  316. package/src/plugins/builtin/market-movers/headless.ts +31 -4
  317. package/src/plugins/builtin/market-movers/index.tsx +8 -1
  318. package/src/plugins/builtin/market-movers/model.ts +71 -17
  319. package/src/plugins/builtin/market-movers/table.ts +50 -23
  320. package/src/plugins/builtin/members/pane.tsx +10 -0
  321. package/src/plugins/builtin/news/headless.ts +9 -2
  322. package/src/plugins/builtin/news/wire/news/footer.ts +10 -0
  323. package/src/plugins/builtin/openfda/client.ts +1 -1
  324. package/src/plugins/builtin/options/carry.ts +95 -0
  325. package/src/plugins/builtin/options/index.tsx +58 -5
  326. package/src/plugins/builtin/options/strike-window.ts +183 -0
  327. package/src/plugins/builtin/options/table.ts +55 -3
  328. package/src/plugins/builtin/options/types.ts +8 -1
  329. package/src/plugins/builtin/options/view.tsx +161 -12
  330. package/src/plugins/builtin/options-positioning/headless.ts +4 -2
  331. package/src/plugins/builtin/options-scenario/charts.tsx +2 -2
  332. package/src/plugins/builtin/options-scenario/client.ts +73 -17
  333. package/src/plugins/builtin/options-scenario/headless.ts +71 -24
  334. package/src/plugins/builtin/options-scenario/hedge.ts +284 -0
  335. package/src/plugins/builtin/options-scenario/index.tsx +9 -2
  336. package/src/plugins/builtin/options-scenario/model.ts +33 -0
  337. package/src/plugins/builtin/options-scenario/pane.tsx +40 -16
  338. package/src/plugins/builtin/pe-band/model.ts +2 -2
  339. package/src/plugins/builtin/pe-band/report-dates.ts +11 -7
  340. package/src/plugins/builtin/perps/equity-row.tsx +8 -5
  341. package/src/plugins/builtin/perps/model.ts +16 -5
  342. package/src/plugins/builtin/perps/pane.tsx +1 -1
  343. package/src/plugins/builtin/plugin-marketplace/model.ts +64 -21
  344. package/src/plugins/builtin/plugin-marketplace/packs.ts +118 -0
  345. package/src/plugins/builtin/plugin-marketplace/pane.tsx +344 -32
  346. package/src/plugins/builtin/plugin-marketplace/store.ts +7 -1
  347. package/src/plugins/builtin/plugin-module.ts +87 -4
  348. package/src/plugins/builtin/portfolio-list/account-metrics.ts +16 -1
  349. package/src/plugins/builtin/portfolio-list/allocation.ts +3 -0
  350. package/src/plugins/builtin/portfolio-list/cached-account.ts +18 -9
  351. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +71 -36
  352. package/src/plugins/builtin/portfolio-list/cli/render.ts +89 -18
  353. package/src/plugins/builtin/portfolio-list/cli/shared.ts +2 -16
  354. package/src/plugins/builtin/portfolio-list/headless.ts +40 -7
  355. package/src/plugins/builtin/portfolio-list/pane/index.tsx +7 -4
  356. package/src/plugins/builtin/portfolio-list/summary/index.tsx +22 -4
  357. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +11 -1
  358. package/src/plugins/builtin/realized-vol/headless.ts +3 -0
  359. package/src/plugins/builtin/realized-vol/pane.tsx +1 -1
  360. package/src/plugins/builtin/research/corporate-actions-pane.tsx +2 -2
  361. package/src/plugins/builtin/research/equity-diagnostic-pane.tsx +1 -1
  362. package/src/plugins/builtin/research/relative-valuation-model.ts +7 -3
  363. package/src/plugins/builtin/revenue-breakdown/client.ts +13 -6
  364. package/src/plugins/builtin/revenue-breakdown/headless.ts +4 -1
  365. package/src/plugins/builtin/revenue-breakdown/pane.tsx +7 -4
  366. package/src/plugins/builtin/reverse-dcf/headless.ts +5 -1
  367. package/src/plugins/builtin/reverse-dcf/model.ts +2 -1
  368. package/src/plugins/builtin/reverse-dcf/pane.tsx +1 -1
  369. package/src/plugins/builtin/risk-factors/data.ts +23 -9
  370. package/src/plugins/builtin/risk-factors/headless.ts +5 -2
  371. package/src/plugins/builtin/risk-factors/pane.tsx +6 -5
  372. package/src/plugins/builtin/seasonality/pane.tsx +1 -1
  373. package/src/plugins/builtin/sec/index.tsx +5 -5
  374. package/src/plugins/builtin/sectors/client.ts +10 -2
  375. package/src/plugins/builtin/sectors/headless.ts +35 -6
  376. package/src/plugins/builtin/sectors/index.tsx +18 -1
  377. package/src/plugins/builtin/sectors/sector-model.ts +150 -41
  378. package/src/plugins/builtin/shared/command-tab.ts +51 -0
  379. package/src/plugins/builtin/shared/headless-market-data.ts +33 -1
  380. package/src/plugins/builtin/shared/members-menu.tsx +260 -0
  381. package/src/plugins/builtin/shared/report-freshness.ts +50 -2
  382. package/src/plugins/builtin/shared/ticker-request.ts +25 -1
  383. package/src/plugins/builtin/shared/use-quote-board.ts +25 -5
  384. package/src/plugins/builtin/shared/volatility/options.ts +1 -46
  385. package/src/plugins/builtin/short-interest/index.tsx +19 -4
  386. package/src/plugins/builtin/short-interest/surface.tsx +4 -4
  387. package/src/plugins/builtin/short-volume/index.tsx +1 -10
  388. package/src/plugins/builtin/short-volume/pane.tsx +1 -1
  389. package/src/plugins/builtin/social-mentions/pane.tsx +1 -1
  390. package/src/plugins/builtin/supply-chain/model.ts +1 -1
  391. package/src/plugins/builtin/themes/pane.tsx +3 -0
  392. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +4 -0
  393. package/src/plugins/builtin/ticker-detail/financials/model.ts +25 -2
  394. package/src/plugins/builtin/ticker-detail/headless.ts +63 -25
  395. package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -4
  396. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +3 -2
  397. package/src/plugins/builtin/ticker-detail/pane.tsx +4 -5
  398. package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +94 -6
  399. package/src/plugins/builtin/treasury-auctions/cache.ts +5 -2
  400. package/src/plugins/builtin/treasury-auctions/client.ts +22 -8
  401. package/src/plugins/builtin/treasury-auctions/headless.ts +40 -4
  402. package/src/plugins/builtin/treasury-auctions/index.tsx +11 -9
  403. package/src/plugins/builtin/treasury-auctions/model.ts +197 -30
  404. package/src/plugins/builtin/treasury-auctions/pane.tsx +35 -11
  405. package/src/plugins/builtin/treasury-auctions/types.ts +11 -1
  406. package/src/plugins/builtin/vol-surface/charts.tsx +1 -3
  407. package/src/plugins/builtin/vol-surface/client.ts +6 -2
  408. package/src/plugins/builtin/vol-surface/evidence.ts +11 -6
  409. package/src/plugins/builtin/vol-surface/headless.ts +124 -20
  410. package/src/plugins/builtin/vol-surface/model.ts +23 -11
  411. package/src/plugins/builtin/vol-surface/pane.tsx +38 -27
  412. package/src/plugins/builtin/vol-surface/tables.ts +124 -0
  413. package/src/plugins/builtin/world-indices/client.ts +22 -4
  414. package/src/plugins/builtin/world-indices/headless.ts +54 -27
  415. package/src/plugins/builtin/world-indices/model.ts +4 -2
  416. package/src/plugins/builtin/world-indices/table.tsx +13 -2
  417. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +2 -0
  418. package/src/plugins/builtin/world-venue-map/basemap.ts +18 -0
  419. package/src/plugins/builtin/world-venue-map/country-labels.ts +78 -0
  420. package/src/plugins/builtin/world-venue-map/geo-series.ts +1 -1
  421. package/src/plugins/builtin/world-venue-map/geo-svg.tsx +2 -1
  422. package/src/plugins/builtin/world-venue-map/index.ts +6 -6
  423. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +27 -14
  424. package/src/plugins/builtin/world-venue-map/layers.ts +68 -10
  425. package/src/plugins/builtin/world-venue-map/map.tsx +198 -62
  426. package/src/plugins/builtin/world-venue-map/model.ts +16 -0
  427. package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +3 -0
  428. package/src/plugins/builtin/world-venue-map/natural-earth/labels.chunk.ts +244 -0
  429. package/src/plugins/builtin/world-venue-map/pane.tsx +16 -10
  430. package/src/plugins/builtin/yield-curve/index.tsx +1 -1
  431. package/src/plugins/builtin-editorial.ts +126 -0
  432. package/src/plugins/catalog-backend.ts +16 -9
  433. package/src/plugins/catalog-browser.ts +127 -63
  434. package/src/plugins/catalog-manifest.ts +73 -40
  435. package/src/plugins/catalog-ui.ts +26 -6
  436. package/src/plugins/extracted-plugins.ts +7 -1
  437. package/src/plugins/ownership.ts +150 -7
  438. package/src/plugins/plugin-functions.ts +54 -0
  439. package/src/plugins/plugin-off.ts +36 -0
  440. package/src/plugins/registry/host-actions.ts +16 -0
  441. package/src/plugins/registry/index.ts +84 -24
  442. package/src/plugins/registry/plugin-state.ts +25 -1
  443. package/src/plugins/runtime/context.tsx +29 -0
  444. package/src/react/input.ts +48 -1
  445. package/src/remote/app-host.tsx +5 -0
  446. package/src/remote/controller.ts +3 -53
  447. package/src/remote/matching.ts +69 -0
  448. package/src/remote/schema.ts +1 -1
  449. package/src/remote/semantic-tree.tsx +14 -0
  450. package/src/remote/types.ts +2 -0
  451. package/src/renderers/browser/app-services.ts +3 -1
  452. package/src/renderers/dom/data-table/dom.ts +31 -0
  453. package/src/renderers/dom/data-table/index.tsx +5 -0
  454. package/src/renderers/dom/desktop/icons.tsx +14 -0
  455. package/src/renderers/dom/desktop/query-bar.tsx +59 -32
  456. package/src/renderers/dom/host/box.tsx +113 -17
  457. package/src/renderers/dom/host/drag-shield.ts +35 -0
  458. package/src/renderers/dom/host/live-frame.ts +62 -0
  459. package/src/renderers/dom/host/mouse.ts +8 -1
  460. package/src/renderers/dom/host/scroll-box.tsx +6 -5
  461. package/src/renderers/dom/host/tabs.tsx +3 -2
  462. package/src/renderers/dom/input-host.tsx +6 -1
  463. package/src/renderers/dom/styles.css +26 -5
  464. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +7 -0
  465. package/src/renderers/electrobun/bun/desktop/backend.ts +7 -1
  466. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +12 -1
  467. package/src/renderers/electrobun/bun/desktop/initialization.ts +15 -1
  468. package/src/renderers/electrobun/shared/protocol.ts +12 -1
  469. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +4 -1
  470. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +101 -5
  471. package/src/renderers/electrobun/view/host/native.ts +0 -10
  472. package/src/renderers/electrobun/view/host/window-move.ts +28 -0
  473. package/src/renderers/electrobun/view/main.tsx +4 -1
  474. package/src/renderers/electrobun/view/remote/persistence.ts +15 -2
  475. package/src/renderers/electrobun/view/ui-host.tsx +2 -5
  476. package/src/renderers/opentui/input-host.tsx +6 -1
  477. package/src/renderers/opentui/start.tsx +9 -0
  478. package/src/renderers/opentui/ui-host.tsx +7 -1
  479. package/src/shares/portable-layout.ts +16 -6
  480. package/src/sources/gloomberb-cloud/index.ts +19 -10
  481. package/src/sources/gloomberb-cloud/normalizers.ts +20 -21
  482. package/src/sources/listing-symbols.ts +11 -5
  483. package/src/sources/provider-errors.ts +88 -3
  484. package/src/sources/provider-router/batches.ts +3 -3
  485. package/src/sources/provider-router/cached-routes.ts +8 -4
  486. package/src/sources/provider-router/financial-routes.ts +13 -7
  487. package/src/sources/provider-router/financials.ts +106 -16
  488. package/src/sources/provider-router/history.ts +27 -11
  489. package/src/sources/provider-router/index.ts +1 -1
  490. package/src/sources/provider-router/primary.ts +24 -6
  491. package/src/sources/sec-edgar.ts +68 -8
  492. package/src/state/pane-scroll-registry.tsx +67 -35
  493. package/src/sync/core-contributors.ts +4 -3
  494. package/src/test-support/cli-context.ts +2 -1
  495. package/src/test-support/data-provider.ts +34 -0
  496. package/src/test-support/margin-account.ts +108 -0
  497. package/src/test-support/shell-pane-keys.tsx +1 -0
  498. package/src/theme/series-colors.ts +46 -0
  499. package/src/theme/themes.ts +149 -0
  500. package/src/tickers/search/index.ts +22 -2
  501. package/src/tickers/search/ranking.ts +45 -1
  502. package/src/tickers/search/types.ts +3 -1
  503. package/src/time-series/resolution.ts +15 -0
  504. package/src/time-series/resolve.ts +1 -14
  505. package/src/types/config.ts +61 -1
  506. package/src/types/financials.ts +32 -3
  507. package/src/types/headless.ts +11 -0
  508. package/src/types/instrument.ts +8 -0
  509. package/src/types/plugin.ts +49 -3
  510. package/src/ui/host.tsx +16 -0
  511. package/src/ui/index.tsx +10 -3
  512. package/src/ui/scroll-box-axis.ts +26 -0
  513. package/src/utils/cli-output.ts +14 -1
  514. package/src/utils/currency-units.ts +8 -3
  515. package/src/utils/depositary-receipt.ts +54 -10
  516. package/src/utils/display-number.ts +63 -0
  517. package/src/utils/exchanges.ts +13 -0
  518. package/src/utils/format.ts +2 -1
  519. package/src/utils/fundamentals.ts +17 -1
  520. package/src/utils/fx-market-hours.ts +34 -0
  521. package/src/utils/option-expiry.ts +126 -0
  522. package/src/utils/price-history-integrity.ts +19 -6
  523. package/src/utils/price-history.ts +39 -6
  524. package/src/utils/rpc-timeout-error.ts +6 -2
  525. package/src/utils/sec-eps-basis.ts +159 -30
  526. package/src/utils/sec.ts +38 -34
  527. package/src/utils/throttled-fetch.ts +51 -22
@@ -1,5 +1,6 @@
1
1
  import { formatShortDate, parseDisplayDate } from "../../utils/datetime-format";
2
2
  import { formatReportedMoney } from "../../utils/reported-money";
3
+ import { fundamentalsCurrency, reportedEnterpriseValue } from "../../utils/fundamentals";
3
4
  import { latestFinancialPeriod } from "../../utils/latest-financial-period";
4
5
  import { exportedFundamentals, formatPriceEarnings, priceEarningsOnEarnings } from "../../utils/price-earnings";
5
6
  import { describeFundamentalMarketCap, selectMarketCapitalization } from "../../utils/market-capitalization";
@@ -21,8 +22,10 @@ import {
21
22
  type CliStatEntry,
22
23
  } from "../../utils/cli-output";
23
24
  import {
25
+ EXTENDED_SESSION_LABELS,
24
26
  exchangeShortName,
25
27
  getExtendedSessionDisplay,
28
+ getQuoteSessionFields,
26
29
  getRegularSessionDisplay,
27
30
  marketStateLabel,
28
31
  } from "../../market-data/market/status";
@@ -48,11 +51,15 @@ import {
48
51
  formatWatchlistNames,
49
52
  } from "../helpers";
50
53
  import { NotesFiles } from "../../plugins/builtin/notes/files";
51
- import { isUsEquityTicker } from "../../utils/sec";
54
+ import { isKnownNonUsListing } from "../../utils/sec";
52
55
  import { canonicalExchange, exchangeLabel, isKnownExchangeCode } from "../../utils/exchanges";
53
56
  import { failIfNotTraded, ListingArgError, listingIdentity, resolveCliListing, type CliListing } from "../listing-arg";
54
- import { isDepositaryReceipt } from "../../utils/depositary-receipt";
57
+ import { isNotATickerMessage } from "../not-a-ticker";
58
+ import { sharesOutstandingInReceipts } from "../../utils/depositary-receipt";
55
59
  import { cliFreshnessFooter } from "../result";
60
+ import { providerMissReason } from "../../sources/provider-errors";
61
+ import { exportEntriesTable, reportFooterLines, type CliReportTables } from "../report-tables";
62
+ import type { ReportFreshness } from "../pane-functions/freshness";
56
63
  import { fundamentalsFreshness, quotesFreshness } from "../freshness";
57
64
 
58
65
  const NEWS_ITEM_LIMIT = 5;
@@ -99,10 +106,26 @@ function buildStatementMetrics(statement: FinancialStatement, currency?: string)
99
106
  ["Total Debt", money(statement.totalDebt)],
100
107
  ["Equity", money(statement.totalEquity)],
101
108
  ["Diluted EPS", money(statement.eps, true)],
102
- ["Diluted Shares", formatCompact(statement.dilutedShares)],
109
+ // Labelled only when the service says the row counts receipts.
110
+ ["Diluted Shares", statement.dilutedShares != null && statement.shareBasis === "depositary_receipt"
111
+ ? `${formatCompact(statement.dilutedShares)} (ADR equivalent)`
112
+ : formatCompact(statement.dilutedShares)],
103
113
  ];
104
114
  }
105
115
 
116
+ /**
117
+ * A receipt's count is its ordinary shares expressed in receipts, as its
118
+ * market cap is; the ordinary count follows when the service gives it.
119
+ */
120
+ function sharesOutstandingText(fundamentals: TickerFinancials["fundamentals"], inReceipts: boolean): string {
121
+ const shares = fundamentals?.sharesOutstanding;
122
+ if (shares == null || !inReceipts) return formatCompact(shares);
123
+ const ordinary = fundamentals?.shareBasis === "depositary_receipt" ? fundamentals.underlyingOrdinaryShares : undefined;
124
+ return ordinary != null && Number.isFinite(ordinary) && ordinary > 0
125
+ ? `${formatCompact(shares)} (ADR equivalent = ${formatCompact(ordinary)} ordinary shares)`
126
+ : `${formatCompact(shares)} (ADR equivalent)`;
127
+ }
128
+
106
129
  /** Provider prose is wrapped; `verbatim` keeps the user's own spacing, such as a table in a note. */
107
130
  function appendTextSection(lines: string[], title: string, content: string | undefined, verbatim = false) {
108
131
  const text = content?.trim();
@@ -159,26 +182,35 @@ function getFilingDescription(filing: SecFilingItem): string | undefined {
159
182
  return description;
160
183
  }
161
184
 
162
- function shouldFetchSecFilings(tickerFile: TickerRecord | null, financials: TickerFinancials): boolean {
163
- if (isUsEquityTicker(tickerFile)) {
164
- return true;
165
- }
166
-
167
- const quote = financials.quote;
168
- if (!quote || quote.currency.toUpperCase() !== "USD") {
169
- return false;
170
- }
171
-
172
- const exchangeHints = [
173
- tickerFile?.metadata.exchange,
174
- quote.exchangeName,
175
- quote.fullExchangeName,
176
- ]
177
- .filter((value): value is string => !!value)
178
- .join(" ")
179
- .toUpperCase();
180
-
181
- return /(NASDAQ|NYSE|AMEX|ARCA|IEX|BATS|PINK|OTC|NMS)/.test(exchangeHints);
185
+ /**
186
+ * SEC filings are asked for unless the listing is known to be outside the US:
187
+ * by the saved ticker, the requested venue, the quote, or the listing the
188
+ * source still describes when it has no current quote. A symbol nothing is
189
+ * known about yet is looked up as a US ticker.
190
+ */
191
+ function shouldFetchSecFilings(
192
+ symbol: string,
193
+ exchange: string,
194
+ tickerFile: TickerRecord | null,
195
+ financials: TickerFinancials,
196
+ ): boolean {
197
+ const saved = tickerFile?.metadata;
198
+ const { quote, quoteMetadata } = financials;
199
+ return !isKnownNonUsListing({
200
+ metadata: {
201
+ ticker: saved?.ticker ?? symbol,
202
+ exchange: saved?.exchange || exchange || quote?.listingExchangeName || quote?.exchangeName
203
+ || quoteMetadata?.listingExchangeName || "",
204
+ currency: saved?.currency || quote?.currency || quoteMetadata?.currency || "",
205
+ name: saved?.name ?? symbol,
206
+ broker_contracts: saved?.broker_contracts,
207
+ portfolios: [],
208
+ watchlists: [],
209
+ positions: [],
210
+ custom: {},
211
+ tags: [],
212
+ },
213
+ });
182
214
  }
183
215
 
184
216
  async function appendTickerPositions(lines: string[], tickerFile: TickerRecord | null, quote: TickerFinancials["quote"],
@@ -241,60 +273,103 @@ function enterpriseValueCurrency(
241
273
  || undefined;
242
274
  }
243
275
 
276
+ /** A fundamentals line: the text the report prints, and for CSV the figure behind it in `unit`. */
277
+ interface FundamentalsMetric {
278
+ label: string;
279
+ text: string;
280
+ value?: number | string | null;
281
+ unit?: string;
282
+ }
283
+
284
+ type MetricFigure = Omit<FundamentalsMetric, "label">;
285
+
286
+ /** An amount in the currency the source reported it in; `ccy?` when it named none, as the text says. */
287
+ function reportedMoney(value: number | undefined, currency: string | undefined, perShare = false): MetricFigure {
288
+ return { text: formatReportedMoney(value, currency, perShare), value, unit: currency?.trim() || "ccy?" };
289
+ }
290
+
291
+ function percentFigure(fraction: number | null | undefined, format: (value: number) => string): MetricFigure {
292
+ return fraction != null ? { text: format(fraction), value: fraction * 100, unit: "%" } : { text: "—" };
293
+ }
294
+
295
+ function multipleFigure(value: ReturnType<typeof priceEarningsOnEarnings> | number | undefined): MetricFigure {
296
+ const text = formatPriceEarnings(value, 2);
297
+ return { text, value: typeof value === "number" && Number.isFinite(value) && value > 0 ? value : text === "N/M" ? text : null };
298
+ }
299
+
244
300
  function fundamentalsMetrics(
245
301
  quote: TickerFinancials["quote"],
246
302
  fundamentals: TickerFinancials["fundamentals"],
247
303
  profile: TickerFinancials["profile"],
248
- marketCapText: string,
304
+ marketCap: MetricFigure,
249
305
  priceReturns: { return1Y?: number | null; return3Y?: number | null },
250
- enterpriseValueText = formatReportedMoney(fundamentals?.enterpriseValue, enterpriseValueCurrency(quote, fundamentals)),
251
- ): Array<[string, string]> {
306
+ reportingCurrency: string | undefined,
307
+ enterpriseValue = reportedMoney(reportedEnterpriseValue(fundamentals), enterpriseValueCurrency(quote, fundamentals)),
308
+ ): FundamentalsMetric[] {
309
+ const signed = (value: number) => colorBySign(formatPercent(value), value);
310
+ const receipt = fundamentals?.sharesOutstanding != null && sharesOutstandingInReceipts(quote, fundamentals, profile?.description);
252
311
  return [
253
- ["Market Cap", marketCapText],
254
- ["Enterprise Value", enterpriseValueText],
312
+ { label: "Market Cap", ...marketCap },
313
+ { label: "Enterprise Value", ...enterpriseValue },
255
314
  // A multiple over a loss is N/M, even beside a positive one the source served from an older period.
256
- ["P/E (TTM)", formatPriceEarnings(priceEarningsOnEarnings(fundamentals?.trailingPE, fundamentals?.eps), 2)],
257
- ["Forward P/E", formatPriceEarnings(priceEarningsOnEarnings(fundamentals?.forwardPE, fundamentals?.forwardEps), 2)],
258
- ["PEG", formatPriceEarnings(fundamentals?.pegRatio, 2)],
315
+ { label: "P/E (TTM)", ...multipleFigure(priceEarningsOnEarnings(fundamentals?.trailingPE, fundamentals?.eps)) },
316
+ { label: "Forward P/E", ...multipleFigure(priceEarningsOnEarnings(fundamentals?.forwardPE, fundamentals?.forwardEps)) },
317
+ { label: "PEG", ...multipleFigure(fundamentals?.pegRatio) },
259
318
  // The flows and EPS are one trailing-twelve-month block, the same twelve months for each line.
260
- ["EPS (TTM)", formatReportedMoney(fundamentals?.eps, fundamentals?.financialCurrency, true)],
261
- [`Dividend Yield${fundamentals?.dividendYieldBasis ? ` (${fundamentals.dividendYieldBasis})` : ""}`, fundamentals?.dividendYield != null ? formatFractionPercentCell(fundamentals.dividendYield) : "—"],
262
- ["Revenue (TTM)", formatReportedMoney(fundamentals?.revenue, fundamentals?.financialCurrency)],
263
- ["Net Income (TTM)", formatReportedMoney(fundamentals?.netIncome, fundamentals?.financialCurrency)],
264
- ["Operating Cash Flow (TTM)", formatReportedMoney(fundamentals?.operatingCashFlow, fundamentals?.financialCurrency)],
265
- ["Free Cash Flow (TTM)", formatReportedMoney(fundamentals?.freeCashFlow, fundamentals?.financialCurrency)],
319
+ { label: "EPS (TTM)", ...reportedMoney(fundamentals?.eps, reportingCurrency, true) },
320
+ {
321
+ label: `Dividend Yield${fundamentals?.dividendYieldBasis ? ` (${fundamentals.dividendYieldBasis})` : ""}`,
322
+ ...percentFigure(fundamentals?.dividendYield, formatFractionPercentCell),
323
+ },
324
+ { label: "Revenue (TTM)", ...reportedMoney(fundamentals?.revenue, reportingCurrency) },
325
+ { label: "Net Income (TTM)", ...reportedMoney(fundamentals?.netIncome, reportingCurrency) },
326
+ { label: "Operating Cash Flow (TTM)", ...reportedMoney(fundamentals?.operatingCashFlow, reportingCurrency) },
327
+ { label: "Free Cash Flow (TTM)", ...reportedMoney(fundamentals?.freeCashFlow, reportingCurrency) },
266
328
  // Levels, not changes, so they carry no sign.
267
- ["Operating Margin", fundamentals?.operatingMargin != null ? formatFractionPercentCell(fundamentals.operatingMargin) : "—"],
268
- ["Profit Margin", fundamentals?.profitMargin != null ? formatFractionPercentCell(fundamentals.profitMargin) : "—"],
269
- ["Revenue Growth", fundamentals?.revenueGrowth != null ? colorBySign(formatPercent(fundamentals.revenueGrowth), fundamentals.revenueGrowth) : "—"],
270
- ["Last Quarter Growth", fundamentals?.lastQuarterGrowth != null ? colorBySign(formatPercent(fundamentals.lastQuarterGrowth), fundamentals.lastQuarterGrowth) : "—"],
271
- ["1Y Return", priceReturns.return1Y != null ? colorBySign(formatPercent(priceReturns.return1Y), priceReturns.return1Y) : "—"],
272
- ["3Y Return", priceReturns.return3Y != null ? colorBySign(formatPercent(priceReturns.return3Y), priceReturns.return3Y) : "—"],
273
- // A receipt's count is its ordinary shares expressed in receipts, as its market cap is.
274
- [
275
- "Shares Outstanding",
276
- fundamentals?.sharesOutstanding != null && isDepositaryReceipt({ ...quote, description: profile?.description })
277
- ? `${formatCompact(fundamentals.sharesOutstanding)} (ADR equivalent)`
278
- : formatCompact(fundamentals?.sharesOutstanding),
279
- ],
329
+ { label: "Operating Margin", ...percentFigure(fundamentals?.operatingMargin, formatFractionPercentCell) },
330
+ { label: "Profit Margin", ...percentFigure(fundamentals?.profitMargin, formatFractionPercentCell) },
331
+ { label: "Revenue Growth", ...percentFigure(fundamentals?.revenueGrowth, signed) },
332
+ { label: "Last Quarter Growth", ...percentFigure(fundamentals?.lastQuarterGrowth, signed) },
333
+ { label: "1Y Return", ...percentFigure(priceReturns.return1Y, signed) },
334
+ { label: "3Y Return", ...percentFigure(priceReturns.return3Y, signed) },
335
+ {
336
+ label: "Shares Outstanding",
337
+ text: sharesOutstandingText(fundamentals, receipt),
338
+ value: fundamentals?.sharesOutstanding,
339
+ ...(receipt ? { unit: "ADR equivalent" } : {}),
340
+ },
280
341
  ];
281
342
  }
282
343
 
344
+ function metricLines(metrics: readonly FundamentalsMetric[]): Array<[string, string]> {
345
+ return metrics.map((metric) => [metric.label, metric.text]);
346
+ }
347
+
283
348
  const VALUATION_METRICS = new Set(["Market Cap", "Enterprise Value", "P/E (TTM)", "Forward P/E", "PEG", "EPS (TTM)"]);
284
349
 
350
+ type FundamentalsReportData = TickerFinancials & { symbol: string; exchange?: string };
351
+
352
+ /** The lines `fundamentals` or `valuation` reports, the ones with a value. */
353
+ function fundamentalsReportMetrics(financials: FundamentalsReportData, view: "fundamentals" | "valuation"): FundamentalsMetric[] {
354
+ const quote = financials.quote;
355
+ const fundamentals = financials.fundamentals;
356
+ const capitalization = selectMarketCapitalization(quote, fundamentals);
357
+ const marketCap: MetricFigure = capitalization
358
+ ? { text: `${formatCompact(capitalization.value)} ${capitalization.currency}`, value: capitalization.value, unit: capitalization.currency }
359
+ : { text: "—" };
360
+ const metrics = fundamentalsMetrics(quote, fundamentals, financials.profile, marketCap, computeTickerPriceReturns(financials), fundamentalsCurrency(financials));
361
+ return (view === "valuation"
362
+ ? metrics.filter(({ label }) => VALUATION_METRICS.has(label) || label.startsWith("Dividend Yield"))
363
+ : metrics).filter((metric) => metric.text !== "—");
364
+ }
365
+
285
366
  /** Text for `gloomberb fundamentals` and `gloomberb valuation`: the ticker report's fundamentals without the rest. */
286
367
  export function renderFundamentalsReport(
287
- financials: TickerFinancials & { symbol: string; exchange?: string },
368
+ financials: FundamentalsReportData,
288
369
  view: "fundamentals" | "valuation",
289
370
  ): string {
290
371
  const quote = financials.quote;
291
- const fundamentals = financials.fundamentals;
292
372
  const profile = financials.profile;
293
- const capitalization = selectMarketCapitalization(quote, fundamentals);
294
- const marketCapText = capitalization
295
- ? `${formatCompact(capitalization.value)} ${capitalization.currency}`
296
- : "—";
297
- const metrics = fundamentalsMetrics(quote, fundamentals, profile, marketCapText, computeTickerPriceReturns(financials));
298
373
  const symbol = quote?.symbol ?? financials.symbol;
299
374
  const name = quote?.name && quote.name !== symbol ? ` ${cliStyles.bold(quote.name)}` : "";
300
375
  const lines = [`${cliStyles.accent(symbol)}${name}`];
@@ -305,16 +380,49 @@ export function renderFundamentalsReport(
305
380
  ].filter((part): part is string => !!part);
306
381
  if (profileParts.length > 0) lines.push(cliStyles.muted(profileParts.join(METADATA_SEPARATOR)));
307
382
 
308
- const shown = view === "valuation"
309
- ? metrics.filter(([label]) => VALUATION_METRICS.has(label) || label.startsWith("Dividend Yield"))
310
- : metrics;
311
383
  const before = lines.length;
312
- appendMetricSection(lines, view === "valuation" ? "Valuation" : "Fundamentals", shown);
384
+ appendMetricSection(lines, view === "valuation" ? "Valuation" : "Fundamentals", metricLines(fundamentalsReportMetrics(financials, view)));
313
385
  if (lines.length === before) lines.push("", cliStyles.muted(`No ${view} reported for ${financials.symbol}.`));
314
386
  if (view === "fundamentals") appendTextSection(lines, "Description", profile?.description);
315
387
  return lines.join("\n");
316
388
  }
317
389
 
390
+ /**
391
+ * `fundamentals` and `valuation` for `--csv` and `--ndjson`: the metrics as
392
+ * `Metric,Value` with each unit in its label, and for `fundamentals` the
393
+ * company profile the text prints around them.
394
+ */
395
+ export function fundamentalsReportTables(
396
+ financials: FundamentalsReportData,
397
+ view: "fundamentals" | "valuation",
398
+ freshness: ReportFreshness,
399
+ ): CliReportTables {
400
+ const metrics = fundamentalsReportMetrics(financials, view);
401
+ const tables = [exportEntriesTable(
402
+ view === "valuation" ? "Valuation" : "Fundamentals",
403
+ metrics.map((metric) => ({ label: metric.label, value: metric.value, formatted: metric.text, unit: metric.unit })),
404
+ )];
405
+ if (view === "fundamentals") {
406
+ const quote = financials.quote;
407
+ const profile = financials.profile;
408
+ tables.push(exportEntriesTable("Profile", [
409
+ { label: "Symbol", value: quote?.symbol ?? financials.symbol },
410
+ { label: "Name", value: quote?.name },
411
+ { label: "Exchange", value: financials.exchange ? exchangeLabel(financials.exchange) : undefined },
412
+ { label: "Sector", value: profile?.sector },
413
+ { label: "Industry", value: profile?.industry },
414
+ { label: "Description", value: profile?.description?.trim() },
415
+ ].filter((entry) => typeof entry.value === "string" && entry.value.trim().length > 0)));
416
+ }
417
+ return {
418
+ tables,
419
+ footer: reportFooterLines({
420
+ freshness,
421
+ notes: metrics.length === 0 ? [`No ${view} reported for ${financials.symbol}.`] : [],
422
+ }),
423
+ };
424
+ }
425
+
318
426
  /** "Euronext Paris (EPA)": the venue the report is for, named in full when the app knows it. */
319
427
  function listingVenueLabel(
320
428
  listingExchange: string | undefined,
@@ -335,6 +443,7 @@ export async function buildTickerReport({
335
443
  config,
336
444
  toBase,
337
445
  notes,
446
+ quoteNote,
338
447
  recentNews = [],
339
448
  recentSecFilings = [],
340
449
  }: {
@@ -346,6 +455,8 @@ export async function buildTickerReport({
346
455
  config: AppConfig;
347
456
  toBase: (value: number, fromCurrency: string) => Promise<number>;
348
457
  notes?: string;
458
+ /** Why there is no quote, when a source said; "Quote unavailable." otherwise. */
459
+ quoteNote?: string;
349
460
  recentNews?: NewsArticle[];
350
461
  recentSecFilings?: SecFilingItem[];
351
462
  }): Promise<string> {
@@ -360,7 +471,7 @@ export async function buildTickerReport({
360
471
  const lines: string[] = [];
361
472
 
362
473
  lines.push(`${cliStyles.accent(quote?.symbol ?? symbol)} ${cliStyles.bold(name)}`);
363
- if (!quote) lines.push(cliStyles.muted("Quote unavailable."));
474
+ if (!quote) lines.push(cliStyles.muted(quoteNote ?? QUOTE_UNAVAILABLE));
364
475
 
365
476
  const summaryParts = [
366
477
  listingVenueLabel(listingExchange, quote, financials, tickerFile) || undefined,
@@ -407,10 +518,10 @@ export async function buildTickerReport({
407
518
  : `${formatCompact(capitalization.value)} ${capitalization.currency}`
408
519
  : "—";
409
520
  // Shown in the same currency as the market cap, so the two can be compared.
410
- const enterpriseValue = fundamentals?.enterpriseValue;
521
+ const enterpriseValue = reportedEnterpriseValue(fundamentals);
411
522
  const evCurrency = enterpriseValueCurrency(quote, fundamentals);
412
523
  // A minor unit such as GBp stays as reported: the converter would read it as the major currency.
413
- const convertedEnterpriseValue = enterpriseValue != null && Number.isFinite(enterpriseValue) && evCurrency && /^[A-Z]{3}$/.test(evCurrency)
524
+ const convertedEnterpriseValue = enterpriseValue != null && evCurrency && /^[A-Z]{3}$/.test(evCurrency)
414
525
  ? await toBase(enterpriseValue, evCurrency) : Number.NaN;
415
526
  const enterpriseValueText = Number.isFinite(convertedEnterpriseValue)
416
527
  ? `${formatCompact(convertedEnterpriseValue)} ${config.baseCurrency}`
@@ -442,12 +553,12 @@ export async function buildTickerReport({
442
553
  ]);
443
554
 
444
555
  appendMetricSection(lines, "Extended Hours", [
445
- ["Pre-Market", extendedRow("PRE")],
446
- ["After Hours", extendedRow("POST")],
556
+ [EXTENDED_SESSION_LABELS.PRE, extendedRow("PRE")],
557
+ [EXTENDED_SESSION_LABELS.POST, extendedRow("POST")],
447
558
  ]);
448
559
  }
449
560
 
450
- appendMetricSection(lines, "Fundamentals", fundamentalsMetrics(quote, fundamentals, profile, marketCapText, priceReturns, enterpriseValueText));
561
+ appendMetricSection(lines, "Fundamentals", metricLines(fundamentalsMetrics(quote, fundamentals, profile, { text: marketCapText }, priceReturns, fundamentalsCurrency(financials), { text: enterpriseValueText })));
451
562
 
452
563
  if (capitalization?.provenance.kind === "fundamentals") {
453
564
  lines.push(cliStyles.muted(`Market cap: ${describeFundamentalMarketCap(capitalization.provenance)}.`));
@@ -532,10 +643,9 @@ function buildTickerStructuredData({
532
643
  symbol: quote.symbol,
533
644
  instrumentType: quote.instrumentType,
534
645
  name: quote.name,
535
- price: quote.price,
646
+ // Last and Change as the text report reads them, then the extended print from that close.
647
+ ...getQuoteSessionFields(quote),
536
648
  priceBasis: quote.priceBasis ?? null,
537
- change: quote.change,
538
- changePercent: quote.changePercent,
539
649
  currency: quote.currency,
540
650
  marketCap: quote.marketCap ?? null,
541
651
  volume: quote.volume ?? null,
@@ -587,6 +697,18 @@ function buildTickerStructuredData({
587
697
  };
588
698
  }
589
699
 
700
+ const QUOTE_UNAVAILABLE = "Quote unavailable.";
701
+
702
+ /** Asks for the quote the report lacks once more, for the reason the data service gave when it had none. */
703
+ async function quoteUnavailableNote(dataProvider: MarketContext["dataProvider"], symbol: string, exchange: string): Promise<string> {
704
+ try {
705
+ await dataProvider.getQuote(symbol, exchange);
706
+ } catch (error) {
707
+ return providerMissReason(error) ?? QUOTE_UNAVAILABLE;
708
+ }
709
+ return QUOTE_UNAVAILABLE;
710
+ }
711
+
590
712
  export async function ticker(symbol: string, dependencies: TickerCommandDependencies = {}) {
591
713
  const initMarketDataFn = dependencies.initMarketData ?? initMarketData;
592
714
  const failCommand = dependencies.fail ?? fail;
@@ -610,7 +732,10 @@ export async function ticker(symbol: string, dependencies: TickerCommandDependen
610
732
  } catch (error) {
611
733
  // A known exchange the symbol is not listed on: say where it is.
612
734
  await failIfNotTraded(listing, { store, dataProvider }, { fail: failCommand });
613
- failCommand(`Failed to fetch data for ${normalized}.`, error instanceof Error ? error.message : String(error));
735
+ const reason = error instanceof Error ? error.message : String(error);
736
+ // A symbol no listing carries is not a failed fetch, and the message already names it.
737
+ if (isNotATickerMessage(reason)) failCommand(reason);
738
+ failCommand(`Failed to fetch data for ${normalized}.`, reason);
614
739
  }
615
740
 
616
741
  const hasResearchData = financials && (
@@ -647,7 +772,7 @@ export async function ticker(symbol: string, dependencies: TickerCommandDependen
647
772
  }),
648
773
  // Outside the US the lookup checks the SEC registrant against the listing's company,
649
774
  // and refuses another company's filings.
650
- shouldFetchSecFilings(tickerFile, resolvedFinancials) && dataProvider.getSecFilings
775
+ shouldFetchSecFilings(requestSymbol, exchange, tickerFile, resolvedFinancials) && dataProvider.getSecFilings
651
776
  ? dataProvider.getSecFilings(requestSymbol, SEC_FILING_LIMIT, exchange || quote?.exchangeName || "",
652
777
  listingName ? { listingName } : undefined)
653
778
  : Promise.resolve([]),
@@ -659,10 +784,11 @@ export async function ticker(symbol: string, dependencies: TickerCommandDependen
659
784
 
660
785
  // The quote is the feed in this report; without one, the fundamentals date it.
661
786
  const freshness = quote ? quotesFreshness([quote]) : fundamentalsFreshness(resolvedFinancials);
787
+ const quoteNote = quote ? undefined : await quoteUnavailableNote(dataProvider, requestSymbol, exchange);
662
788
  if (dependencies.printResult) {
663
789
  dependencies.printResult({
664
790
  freshness,
665
- warnings: quote ? undefined : ["Quote unavailable."],
791
+ warnings: quote ? undefined : [quoteNote!],
666
792
  data: buildTickerStructuredData({
667
793
  symbol: normalized,
668
794
  listing,
@@ -685,6 +811,7 @@ export async function ticker(symbol: string, dependencies: TickerCommandDependen
685
811
  config,
686
812
  toBase,
687
813
  notes,
814
+ quoteNote,
688
815
  recentNews,
689
816
  recentSecFilings,
690
817
  }));