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
@@ -0,0 +1,37 @@
1
+ import { notATickerSymbol } from "../sources/provider-errors";
2
+
3
+ // "Not a ticker: APPLE." as the router words it; the symbol ends at the sentence's own period.
4
+ const NOT_A_TICKER_SENTENCE = /Not a ticker: ((?:(?!\.\s)[^\n`\x1b])+?)\.(?=\s|\x1b|$)(?! Try `gloomberb search)/g;
5
+
6
+ /** The symbol as the user typed it on the command line (`Apple`), not as the router saw it (`APPLE`). */
7
+ function typedSymbol(symbol: string, args: readonly string[]): string {
8
+ const wanted = symbol.toUpperCase();
9
+ for (const arg of args) {
10
+ for (const part of arg.split(",")) {
11
+ const typed = part.trim().replace(/^\$/, "");
12
+ if (typed.toUpperCase() === wanted) return typed;
13
+ }
14
+ }
15
+ return symbol;
16
+ }
17
+
18
+ /** "Try `gloomberb search Apple`." naming what the user typed; a venue (`Apple:NYSE`) is not part of a search. */
19
+ function searchHint(typed: string): string {
20
+ const query = typed.split(":")[0]!.trim() || typed;
21
+ return `Try \`gloomberb search ${/\s/.test(query) ? JSON.stringify(query) : query}\`.`;
22
+ }
23
+
24
+ /**
25
+ * Adds the search hint after each "Not a ticker: APPLE." in text meant for a person. The router
26
+ * only knows the symbol upper-cased, so the hint reads the user's own spelling from `args`.
27
+ */
28
+ export function withSearchHints(text: string, args: readonly string[]): string {
29
+ return text.includes("Not a ticker: ")
30
+ ? text.replace(NOT_A_TICKER_SENTENCE, (sentence, symbol: string) => `${sentence} ${searchHint(typedSymbol(symbol, args))}`)
31
+ : text;
32
+ }
33
+
34
+ /** Whether an error message says the symbol is not a ticker. */
35
+ export function isNotATickerMessage(message: string | null | undefined): boolean {
36
+ return message != null && notATickerSymbol(message) !== null;
37
+ }
@@ -5,6 +5,10 @@ export interface CliGlobalOptions {
5
5
  quiet: boolean;
6
6
  color: boolean | null;
7
7
  limit?: number;
8
+ /** `--tail <n>`: the newest n rows of a dated series, in their printed order. Never set with `limit`. */
9
+ tail?: number;
10
+ /** `--width <n>`: fit tables to n columns. Unset, a terminal's own width fits them and piped output is not fitted. */
11
+ width?: number;
8
12
  refresh: boolean;
9
13
  dryRun: boolean;
10
14
  yes: boolean;
@@ -15,6 +19,8 @@ export interface ParsedCliArgs {
15
19
  options: CliGlobalOptions;
16
20
  /** `--help` or `-h` appeared before `--`. The flag is removed from args. */
17
21
  help: boolean;
22
+ /** Index in `args` where the arguments after a bare `--` begin; they are never options. */
23
+ literalStart: number;
18
24
  }
19
25
 
20
26
  export function isCliHelpFlag(arg: string): boolean {
@@ -30,23 +36,49 @@ export const DEFAULT_CLI_OPTIONS: CliGlobalOptions = {
30
36
  yes: false,
31
37
  };
32
38
 
33
- function parseLimit(value: string | undefined): number {
34
- if (!value) throw new Error("Missing value for --limit.");
39
+ function parseRowCount(flag: "--limit" | "--tail", value: string | undefined): number {
40
+ if (!value) throw new Error(`Missing value for ${flag}.`);
35
41
  const parsed = Number(value);
36
42
  if (!Number.isInteger(parsed) || parsed < 1) {
37
- throw new Error("--limit must be a positive integer.");
43
+ throw new Error(`${flag} must be a positive integer.`);
38
44
  }
39
45
  return parsed;
40
46
  }
41
47
 
48
+ /** Commands whose own `--width` is a size in pixels, so it is not the table width. */
49
+ const PIXEL_WIDTH_COMMANDS = new Set(["shot", "screenshot"]);
50
+ const MIN_TABLE_WIDTH = 20;
51
+
52
+ function parseColumnCount(value: string | undefined): number {
53
+ const parsed = Number(value);
54
+ if (!value || !Number.isInteger(parsed) || parsed < MIN_TABLE_WIDTH) {
55
+ throw new Error(`--width must be a whole number of columns, ${MIN_TABLE_WIDTH} or more, such as --width 80.`);
56
+ }
57
+ return parsed;
58
+ }
59
+
60
+ /** The first word that is not an option or the value of one: the command the arguments are for. */
61
+ function commandWord(rawArgs: readonly string[]): string | undefined {
62
+ for (let index = 0; index < rawArgs.length; index += 1) {
63
+ const arg = rawArgs[index]!;
64
+ if (arg === "--") return rawArgs[index + 1];
65
+ if (arg === "--limit" || arg === "--tail" || arg === "--width") index += 1;
66
+ else if (!arg.startsWith("-")) return arg;
67
+ }
68
+ return undefined;
69
+ }
70
+
42
71
  export function parseCliGlobalArgs(rawArgs: string[]): ParsedCliArgs {
43
72
  const options: CliGlobalOptions = { ...DEFAULT_CLI_OPTIONS };
44
73
  const args: string[] = [];
45
74
  let help = false;
75
+ let literalStart: number | null = null;
76
+ const ownsWidth = PIXEL_WIDTH_COMMANDS.has(commandWord(rawArgs)?.toLowerCase() ?? "");
46
77
 
47
78
  for (let index = 0; index < rawArgs.length; index += 1) {
48
79
  const arg = rawArgs[index]!;
49
80
  if (arg === "--") {
81
+ literalStart = args.length;
50
82
  args.push(...rawArgs.slice(index + 1));
51
83
  break;
52
84
  }
@@ -90,17 +122,33 @@ export function parseCliGlobalArgs(rawArgs: string[]): ParsedCliArgs {
90
122
  options.yes = true;
91
123
  continue;
92
124
  }
93
- if (arg === "--limit") {
125
+ if (!ownsWidth && arg === "--width") {
94
126
  index += 1;
95
- options.limit = parseLimit(rawArgs[index]);
127
+ options.width = parseColumnCount(rawArgs[index]);
128
+ continue;
129
+ }
130
+ if (!ownsWidth && arg.startsWith("--width=")) {
131
+ options.width = parseColumnCount(arg.slice("--width=".length));
132
+ continue;
133
+ }
134
+ if (arg === "--limit" || arg === "--tail") {
135
+ index += 1;
136
+ options[arg === "--limit" ? "limit" : "tail"] = parseRowCount(arg, rawArgs[index]);
96
137
  continue;
97
138
  }
98
139
  if (arg.startsWith("--limit=")) {
99
- options.limit = parseLimit(arg.slice("--limit=".length));
140
+ options.limit = parseRowCount("--limit", arg.slice("--limit=".length));
141
+ continue;
142
+ }
143
+ if (arg.startsWith("--tail=")) {
144
+ options.tail = parseRowCount("--tail", arg.slice("--tail=".length));
100
145
  continue;
101
146
  }
102
147
  args.push(arg);
103
148
  }
149
+ if (options.limit != null && options.tail != null) {
150
+ throw new Error("Use --limit or --tail, not both: --limit keeps the first rows, --tail the newest.");
151
+ }
104
152
 
105
- return { args, options, help };
153
+ return { args, options, help, literalStart: literalStart ?? args.length };
106
154
  }
@@ -9,6 +9,7 @@ import type {
9
9
  export type PaneFunctionReadiness = "ready" | "partial" | "live-dom" | "unsupported";
10
10
  type PaneFunctionScreenshotReadiness = PaneFunctionReadiness;
11
11
  type PaneFunctionTickerCardinality = "none" | "one" | "one-or-more" | "two-or-more" | "one-or-two";
12
+ /** A headless option, or a rendered view's, which may name its value, show an example and check what is typed. */
12
13
  export type PaneFunctionOptionDef = HeadlessPaneOptionDef;
13
14
  export type NormalizedPaneFunctionOptions = Record<string, string | number | boolean>;
14
15
 
@@ -64,7 +65,7 @@ function fallbackCapability(
64
65
  limitations: [dataPane
65
66
  ? RENDERED_VIEW_LIMITATION
66
67
  : "This pane is an interactive surface and does not expose a data report."],
67
- options: [],
68
+ options: [...(pane.reportOptions ?? [])],
68
69
  };
69
70
  }
70
71
 
@@ -134,6 +135,11 @@ function resolveOptionDef(
134
135
  ));
135
136
  }
136
137
 
138
+ /** Whether the function has an option of its own under this name or an alias. */
139
+ export function capabilityHasOption(capability: PaneFunctionCapability, key: string): boolean {
140
+ return resolveOptionDef(capability, key) !== undefined;
141
+ }
142
+
137
143
  function normalizeEnumValue(option: PaneFunctionOptionDef, rawValue: string): string {
138
144
  const token = optionToken(rawValue);
139
145
  const match = option.values?.find((candidate) => (
@@ -154,6 +160,7 @@ function normalizeOptionValue(option: PaneFunctionOptionDef, rawValue: string |
154
160
  throw new Error(`Invalid --${option.key} value "${rawValue}". Use true or false.`);
155
161
  }
156
162
  if (rawValue === true) throw new Error(`--${option.key} requires a value.`);
163
+ if (option.normalize) return option.normalize(rawValue);
157
164
  if (option.type === "enum") return normalizeEnumValue(option, rawValue);
158
165
  if (option.type === "integer") {
159
166
  const value = Number(rawValue);
@@ -175,7 +182,11 @@ export function normalizeCapabilityOptions(
175
182
  settings: { strict?: boolean } = {},
176
183
  ): NormalizedPaneFunctionOptions {
177
184
  if (!capability.botSafe) {
178
- return Object.fromEntries(Object.entries(options).map(([key, value]) => [key, value]));
185
+ // A rendered view takes any pane setting; the options it declares are checked.
186
+ return Object.fromEntries(Object.entries(options).map(([key, value]) => {
187
+ const option = resolveOptionDef(capability, key);
188
+ return option ? [option.key, normalizeOptionValue(option, value)] : [key, value];
189
+ }));
179
190
  }
180
191
 
181
192
  const normalized: Record<string, string | number | boolean> = {};
@@ -259,6 +259,11 @@ function paneCatalogSearchScore(entry: PaneCatalogEntry, query: string): number
259
259
  ].filter((value): value is string => !!value).join(" ").toLowerCase();
260
260
 
261
261
  let score = searchable.includes(query.toLowerCase()) ? 12 : 0;
262
+ // A query that is one of the function's own keywords ("hedge" for OSA) beats one found inside a
263
+ // longer keyword ("hedge funds" for 13F).
264
+ const keywords = [entry.label, ...entry.keywords, ...entry.capability.aliases]
265
+ .filter((value): value is string => !!value).map((value) => value.toLowerCase().replace(/\s+/g, " "));
266
+ if (keywords.includes(terms.join(" "))) score += 4;
262
267
  let matchedTerms = 0;
263
268
  for (const term of terms) {
264
269
  const normalized = normalizeLookupToken(term);
@@ -320,7 +325,8 @@ function optionChoices(option: PaneFunctionOptionDef): string[] {
320
325
 
321
326
  function optionFlags(option: PaneFunctionOptionDef): string {
322
327
  const choices = optionChoices(option).join("|");
323
- return `--${option.key} <${choices && choices.length <= MAX_INLINE_CHOICES ? choices : option.values?.length ? "value" : option.type}>`;
328
+ const value = choices && choices.length <= MAX_INLINE_CHOICES ? choices : option.values?.length ? "value" : option.placeholder ?? option.type;
329
+ return `--${option.key} <${value}>`;
324
330
  }
325
331
 
326
332
  function optionDescription(option: PaneFunctionOptionDef): string {
@@ -365,7 +371,12 @@ function renderCatalogEntry(entry: PaneCatalogEntry): string {
365
371
  }
366
372
 
367
373
  lines.push("", renderSection("Examples"));
368
- if (capability.reportReadiness !== "unsupported") lines.push(...wrapCommandLine(`gloomberb fn ${invocation}`, width));
374
+ if (capability.reportReadiness !== "unsupported") {
375
+ lines.push(...wrapCommandLine(`gloomberb fn ${invocation}`, width));
376
+ for (const option of capability.options) {
377
+ if (option.example) lines.push(...wrapCommandLine(`gloomberb fn ${invocation} ${option.example}`, width));
378
+ }
379
+ }
369
380
  lines.push(...wrapCommandLine(`gloomberb shot ${invocation} --output ${entry.token.toLowerCase()}.png`, width));
370
381
  return lines.join("\n");
371
382
  }
@@ -9,6 +9,7 @@ import { cleanTickerInput } from "./options";
9
9
  import { parsePublicTickerKey, publicTickerKey } from "../../utils/exchanges";
10
10
  import type { ResolvedPaneFunction } from "./resolver";
11
11
  import { toMarketDataContext } from "../../market-data/selectors";
12
+ import { quoteMetadataFromQuote } from "../../market-data/quotes/metadata";
12
13
  import { loadSeasonalityHistory, SEASONALITY_HISTORY_RESOLUTION } from "../../plugins/builtin/seasonality/client";
13
14
  import type { InstrumentRef } from "../../market-data/request-types";
14
15
  import { CORRELATION_HISTORY_RESOLUTION, loadCorrelationHistory } from "../../plugins/builtin/correlation/history";
@@ -22,6 +23,26 @@ const SHOT_PRICE_HISTORY_RANGE = "5Y" as const;
22
23
  const FINANCIAL_ANALYSIS_PANE_ID = "financial-analysis";
23
24
  const FINANCIAL_ANALYSIS_TEMPLATE_ID = "financial-analysis-pane";
24
25
 
26
+ async function loadStoredShotTicker(context: MarketContext, symbol: string): Promise<TickerRecord | null> {
27
+ const normalized = cleanTickerInput(symbol);
28
+ const { symbol: bare } = parsePublicTickerKey(normalized);
29
+ return await context.store.loadTicker(normalized)
30
+ ?? (bare !== normalized ? await context.store.loadTicker(bare) : null);
31
+ }
32
+
33
+ /**
34
+ * A holding the pane can value without a quote: some position carries the
35
+ * broker's own mark or market value. An option contract no quote covers stays
36
+ * at that mark in the pane, so a failed quote lookup for it is not an error.
37
+ */
38
+ export async function loadBrokerMarkedHolding(context: MarketContext, symbol: string): Promise<TickerRecord | null> {
39
+ const ticker = await loadStoredShotTicker(context, symbol);
40
+ const marked = ticker?.metadata.positions.some(({ shares, markPrice, marketValue }) => (
41
+ shares !== 0 && (Number.isFinite(markPrice) || Number.isFinite(marketValue))
42
+ ));
43
+ return marked ? ticker : null;
44
+ }
45
+
25
46
  export async function fetchTickerFinancials(
26
47
  context: MarketContext,
27
48
  symbol: string,
@@ -32,8 +53,7 @@ export async function fetchTickerFinancials(
32
53
  }> {
33
54
  const normalized = cleanTickerInput(symbol);
34
55
  const instrument = parsePublicTickerKey(normalized);
35
- const tickerFile = await context.store.loadTicker(normalized)
36
- ?? (instrument.symbol !== normalized ? await context.store.loadTicker(instrument.symbol) : null);
56
+ const tickerFile = await loadStoredShotTicker(context, symbol);
37
57
  const exchange = instrument.exchange ?? tickerFile?.metadata.exchange ?? "";
38
58
  const financials = await context.dataProvider.getTickerFinancials(instrument.symbol, exchange);
39
59
  return { tickerFile, financials, instrument: { symbol: instrument.symbol, ...(exchange ? { exchange } : {}) } };
@@ -142,14 +162,25 @@ export function isFinancialAnalysisFunction(resolved: ResolvedPaneFunction): boo
142
162
  && resolved.instance.settings?.lockedTabId === "financials";
143
163
  }
144
164
 
145
- export function createFallbackTicker(symbol: string, financials: TickerFinancials | null, context: MarketContext): TickerRecord {
165
+ /**
166
+ * The ticker a shot shows for a symbol that is not saved. Without a usable
167
+ * quote (a thin US listing after the close), the listing comes from the quote
168
+ * metadata kept when the quote was dropped, or else from asking the source
169
+ * for it, so the pane still knows a US stock from a listing abroad. What no
170
+ * source knows stays empty rather than guessed from the base currency.
171
+ */
172
+ export async function createFallbackTicker(symbol: string, financials: TickerFinancials | null, context: MarketContext): Promise<TickerRecord> {
146
173
  const instrument = parsePublicTickerKey(symbol);
147
174
  const quote = financials?.quote;
175
+ const known = quote ? quoteMetadataFromQuote(quote) : financials?.quoteMetadata;
176
+ const listing = instrument.exchange || known?.listingExchangeName
177
+ ? known
178
+ : await context.dataProvider.getQuoteMetadata?.(instrument.symbol, "").catch(() => null) ?? known;
148
179
  return {
149
180
  metadata: {
150
181
  ticker: instrument.symbol,
151
- exchange: instrument.exchange ?? quote?.listingExchangeName ?? quote?.exchangeName ?? "",
152
- currency: quote?.currency ?? context.config.baseCurrency,
182
+ exchange: instrument.exchange ?? listing?.listingExchangeName ?? "",
183
+ currency: listing?.currency ?? "",
153
184
  name: quote?.name ?? instrument.symbol,
154
185
  portfolios: [],
155
186
  watchlists: [],
@@ -7,6 +7,8 @@ import type { ResolvedPaneFunction } from "./resolver";
7
7
  import { collectShotSymbols } from "./data";
8
8
  import { renderDesktopShot, type PaneScreenshotResult } from "./screenshot";
9
9
  import { deriveRenderedFreshness, formatFreshnessLine, type ReportFreshness } from "./freshness";
10
+ import { exportTextTable, reportFooterLines, type CliReportTables } from "../report-tables";
11
+ import { renderedReportFreshness, renderedReportNotices, renderedReportObservations } from "./report-notices";
10
12
 
11
13
  const DOM_REPORT_WIDTH = 1280;
12
14
  const DOM_REPORT_HEIGHT = 720;
@@ -17,12 +19,6 @@ function rowsContainEllipsis(rows: DesktopPaneShotRenderedRow[]): boolean {
17
19
  return rows.some((row) => row.cells.some((cell) => /\u2026|\.\.\./.test(cell.text)));
18
20
  }
19
21
 
20
- function isDomReportTruncated(
21
- render: Pick<PaneScreenshotResult["render"], "rows" | "truncated">,
22
- ): boolean {
23
- return render.truncated || rowsContainEllipsis(render.rows);
24
- }
25
-
26
22
  /** Column identity per cell; a repeated label within one row stays distinct. */
27
23
  function domCellKeys(row: DesktopPaneShotRenderedRow): string[] {
28
24
  const seen = new Map<string, number>();
@@ -42,7 +38,13 @@ function cellText(cell: DesktopPaneShotRenderedRow["cells"][number]): string {
42
38
  return cell.instant ? formatUtcTime(cell.instant) || cell.text : cell.text;
43
39
  }
44
40
 
45
- function renderDomTables(rows: DesktopPaneShotRenderedRow[]): string[] {
41
+ interface DomTable {
42
+ tableIndex: number;
43
+ columns: Array<{ key: string; header: string }>;
44
+ rows: Array<Map<string, DesktopPaneShotRenderedRow["cells"][number]>>;
45
+ }
46
+
47
+ function domTables(rows: DesktopPaneShotRenderedRow[]): DomTable[] {
46
48
  const byTable = new Map<number, DesktopPaneShotRenderedRow[]>();
47
49
  for (const row of rows) {
48
50
  const tableRows = byTable.get(row.tableIndex) ?? [];
@@ -50,7 +52,7 @@ function renderDomTables(rows: DesktopPaneShotRenderedRow[]): string[] {
50
52
  byTable.set(row.tableIndex, tableRows);
51
53
  }
52
54
 
53
- return [...byTable.entries()].flatMap(([tableIndex, tableRows], index) => {
55
+ return [...byTable.entries()].map(([tableIndex, tableRows]) => {
54
56
  // Captured rows omit blank cells, so a cell's position is not its column.
55
57
  const columns: Array<{ key: string; header: string }> = [];
56
58
  for (const row of tableRows) {
@@ -66,22 +68,55 @@ function renderDomTables(rows: DesktopPaneShotRenderedRow[]): string[] {
66
68
  previous = position;
67
69
  }
68
70
  }
69
- const output = renderTable(
71
+ return {
72
+ tableIndex,
70
73
  columns,
71
- tableRows.map((row) => {
74
+ rows: tableRows.map((row) => {
72
75
  const keys = domCellKeys(row);
73
- const textByKey = new Map(row.cells.map((cell, cellIndex) => [keys[cellIndex]!, cellText(cell)]));
74
- return columns.map((column) => textByKey.get(column.key) ?? "");
76
+ return new Map(row.cells.map((cell, cellIndex) => [keys[cellIndex]!, cell]));
75
77
  }),
76
- );
77
- return [
78
- ...(index > 0 ? [""] : []),
79
- ...(byTable.size > 1 ? [renderSection(`Rendered table ${tableIndex + 1}`)] : []),
80
- output,
81
- ];
78
+ };
82
79
  });
83
80
  }
84
81
 
82
+ function domTableTitle(table: DomTable): string {
83
+ return `Rendered table ${table.tableIndex + 1}`;
84
+ }
85
+
86
+ function renderDomTables(rows: DesktopPaneShotRenderedRow[]): string[] {
87
+ const tables = domTables(rows);
88
+ return tables.flatMap((table, index) => [
89
+ ...(index > 0 ? [""] : []),
90
+ ...(tables.length > 1 ? [renderSection(domTableTitle(table))] : []),
91
+ renderTable(
92
+ table.columns,
93
+ table.rows.map((cells) => table.columns.map((column) => {
94
+ const cell = cells.get(column.key);
95
+ return cell ? cellText(cell) : "";
96
+ })),
97
+ ),
98
+ ]);
99
+ }
100
+
101
+ /** The rendered tables as `--csv` writes them, with the instant behind a shortened time. */
102
+ function domReportTables(
103
+ rows: DesktopPaneShotRenderedRow[],
104
+ title: string,
105
+ freshness: ReportFreshness,
106
+ incomplete: boolean | string,
107
+ notices: readonly string[],
108
+ ): CliReportTables {
109
+ const tables = domTables(rows);
110
+ return {
111
+ tables: tables.map((table) => exportTextTable(
112
+ tables.length > 1 ? domTableTitle(table) : title,
113
+ table.columns.map((column) => column.header),
114
+ table.rows.map((cells) => table.columns.map((column) => cells.get(column.key))),
115
+ )),
116
+ footer: reportFooterLines({ freshness, incomplete, notes: notices }),
117
+ };
118
+ }
119
+
85
120
  function renderedFailureReason(
86
121
  result: PaneScreenshotResult,
87
122
  rows: DesktopPaneShotRenderedRow[],
@@ -99,8 +134,10 @@ function renderedFailureReason(
99
134
  return null;
100
135
  }
101
136
 
137
+ /** The rows a report reads: every row of a table that publishes them all, else what the viewport shows. */
102
138
  function reportRows(result: PaneScreenshotResult): DesktopPaneShotRenderedRow[] {
103
- if (result.render.rows.length > 0) return result.render.rows;
139
+ const rows = result.render.reportRows ?? result.render.rows;
140
+ if (rows.length > 0) return rows;
104
141
  if (
105
142
  result.render.loadingStateDetected
106
143
  || result.render.errorStateDetected
@@ -122,15 +159,20 @@ export function buildDomPaneReportFromRender(
122
159
  result: PaneScreenshotResult,
123
160
  ): PaneFunctionReport {
124
161
  const rows = reportRows(result);
125
- const hasStructuredRows = result.render.rows.length > 0;
126
- const truncated = isDomReportTruncated({ ...result.render, rows });
127
- const truncationReasons = [...result.render.truncationReasons];
162
+ const hasStructuredRows = (result.render.reportRows ?? result.render.rows).length > 0;
163
+ // A table that reported every row is whole, whatever the viewport cut from the capture.
164
+ const truncationReasons = [...(result.render.reportTruncationReasons ?? result.render.truncationReasons)];
128
165
  if (rowsContainEllipsis(rows) && !truncationReasons.includes("one or more cells are visibly clipped")) {
129
166
  truncationReasons.push("one or more cells are visibly clipped");
130
167
  }
168
+ const truncated = truncationReasons.length > 0
169
+ || (result.render.reportTruncationReasons ? false : result.render.truncated);
131
170
  const failureReason = renderedFailureReason(result, rows);
132
171
  const unavailableSymbols = failureReason && result.symbols.length > 0 ? result.symbols : [];
133
- const textLines = [resolved.label, ""];
172
+ // What the view leaves out and how to see more: FXC's other currencies, OMON's strikes outside its window.
173
+ const rendered = renderedReportNotices(result.render.semanticUi ?? []);
174
+ const notices = [...(resolved.pane.reportNotices?.(resolved.instance.settings ?? {}) ?? []), ...rendered.notices];
175
+ const textLines = [resolved.label, "", ...notices, ...(notices.length > 0 ? [""] : [])];
134
176
  if (hasStructuredRows) {
135
177
  textLines.push(...renderDomTables(rows));
136
178
  } else if (result.render.visibleText) {
@@ -139,11 +181,15 @@ export function buildDomPaneReportFromRender(
139
181
  textLines.push(failureReason ?? "No rendered values were available.");
140
182
  }
141
183
  if (failureReason && rows.length > 0) textLines.push("", failureReason);
142
- const freshness = deriveRenderedFreshness(resolved.pane.reportFreshness, {
184
+ // A pane that knows its feed dates the report; the footer and cell times fill in the rest.
185
+ const declared = { ...resolved.pane.reportFreshness, ...renderedReportFreshness(result.render.semanticUi ?? []) };
186
+ const freshness = deriveRenderedFreshness(declared, {
143
187
  footerText: result.render.footerText ?? "",
144
188
  cellTimes: rows.flatMap((row) => row.cells.flatMap((cell) => cell.instant ?? [])),
189
+ observed: renderedReportObservations(result.render.semanticUi ?? []),
145
190
  });
146
191
 
192
+ const complete = failureReason === null && !truncated;
147
193
  return {
148
194
  data: {
149
195
  kind: "rendered-view",
@@ -153,7 +199,7 @@ export function buildDomPaneReportFromRender(
153
199
  options: resolved.options,
154
200
  rowCount: rows.length,
155
201
  empty: rows.length === 0,
156
- complete: failureReason === null && !truncated,
202
+ complete,
157
203
  unavailableSymbols,
158
204
  rows,
159
205
  visibleText: result.render.visibleText,
@@ -161,9 +207,17 @@ export function buildDomPaneReportFromRender(
161
207
  truncationReasons,
162
208
  limitation: DOM_LIMITATION,
163
209
  ...(failureReason ? { reason: failureReason } : {}),
210
+ ...(notices.length > 0 ? { metadata: { ...rendered.facts, notices } } : {}),
164
211
  freshness,
165
212
  },
166
213
  text: textLines.join("\n").trimEnd(),
214
+ tables: domReportTables(
215
+ rows,
216
+ resolved.label,
217
+ freshness,
218
+ !complete && (failureReason ?? (truncationReasons.length > 0 ? truncationReasons.join("; ") : true)),
219
+ notices,
220
+ ),
167
221
  };
168
222
  }
169
223
 
@@ -173,15 +227,20 @@ export function appendDomReportFooter(
173
227
  truncated: boolean,
174
228
  freshness: ReportFreshness,
175
229
  ): string {
176
- const clipping = truncated ? "The rendered view is clipped." : "The rendered view may be clipped.";
177
230
  return [
178
231
  text,
179
232
  "",
180
- `Rendered view: values come from the visible pane. ${clipping} Render time: ${elapsedMs} ms.`,
233
+ domReportNote(elapsedMs, truncated),
181
234
  cliStyles.muted(formatFreshnessLine(freshness)),
182
235
  ].join("\n");
183
236
  }
184
237
 
238
+ /** What a rendered-view report says about where its values come from. */
239
+ export function domReportNote(elapsedMs: number, truncated: boolean): string {
240
+ const clipping = truncated ? "The rendered view is clipped." : "The rendered view may be clipped.";
241
+ return `Rendered view: values come from the visible pane. ${clipping} Render time: ${elapsedMs} ms.`;
242
+ }
243
+
185
244
  function failedDomReport(
186
245
  resolved: ResolvedPaneFunction,
187
246
  rawArg: string,
@@ -193,6 +252,7 @@ function failedDomReport(
193
252
  .trim();
194
253
  const reason = `The rendered view could not be read: ${message || "unknown renderer error"}`;
195
254
  const symbols = collectShotSymbols(resolved, rawArg);
255
+ const freshness = deriveRenderedFreshness(resolved.pane.reportFreshness, { footerText: "", cellTimes: [] });
196
256
  return {
197
257
  data: {
198
258
  kind: "rendered-view",
@@ -210,9 +270,10 @@ function failedDomReport(
210
270
  truncationReasons: [],
211
271
  limitation: DOM_LIMITATION,
212
272
  reason,
213
- freshness: deriveRenderedFreshness(resolved.pane.reportFreshness, { footerText: "", cellTimes: [] }),
273
+ freshness,
214
274
  },
215
275
  text: [resolved.label, "", reason].join("\n"),
276
+ tables: { tables: [], footer: reportFooterLines({ freshness, incomplete: reason }) },
216
277
  };
217
278
  }
218
279