gloomberb 0.16.1 → 0.16.2

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 (574) hide show
  1. package/README.md +2 -1
  2. package/package.json +2 -1
  3. package/src/api-client/beneficial-owners.ts +92 -0
  4. package/src/api-client/data.ts +26 -8
  5. package/src/api-client/errors.ts +12 -0
  6. package/src/api-client/geo.ts +363 -0
  7. package/src/api-client/index.ts +2 -0
  8. package/src/api-client/market-discovery.ts +10 -0
  9. package/src/api-client/paths.ts +30 -1
  10. package/src/api-client/perps.ts +37 -0
  11. package/src/api-client/request.ts +5 -2
  12. package/src/api-client/types.ts +2 -0
  13. package/src/brokers/account-cache.ts +24 -0
  14. package/src/cli/commands/command-utils.ts +8 -0
  15. package/src/cli/commands/crypto-hints.ts +75 -0
  16. package/src/cli/commands/market.ts +414 -106
  17. package/src/cli/commands/overview.ts +77 -32
  18. package/src/cli/commands/ticker.ts +101 -43
  19. package/src/cli/desktop-pane-shot.ts +34 -4
  20. package/src/cli/freshness.ts +61 -0
  21. package/src/cli/help.ts +1 -0
  22. package/src/cli/helpers.ts +4 -8
  23. package/src/cli/index.ts +12 -2
  24. package/src/cli/listing-arg.ts +321 -0
  25. package/src/cli/pane-functions/access-gate.ts +42 -0
  26. package/src/cli/pane-functions/catalog.ts +28 -1
  27. package/src/cli/pane-functions/data.ts +3 -1
  28. package/src/cli/pane-functions/dom.ts +20 -2
  29. package/src/cli/pane-functions/freshness.ts +400 -0
  30. package/src/cli/pane-functions/function-help.ts +27 -20
  31. package/src/cli/pane-functions/headless.ts +39 -11
  32. package/src/cli/pane-functions/index.ts +15 -4
  33. package/src/cli/pane-functions/options.ts +3 -0
  34. package/src/cli/pane-functions/report.ts +4 -0
  35. package/src/cli/pane-functions/resolver.ts +35 -7
  36. package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
  37. package/src/cli/pane-functions/screenshot.ts +7 -3
  38. package/src/cli/result.ts +41 -27
  39. package/src/cli/ticker-resolution.ts +7 -5
  40. package/src/components/chart/composite/composite-chart.tsx +88 -2536
  41. package/src/components/chart/composite/drawing-store.ts +59 -0
  42. package/src/components/chart/composite/legend.tsx +319 -0
  43. package/src/components/chart/composite/panel-bitmap.ts +139 -0
  44. package/src/components/chart/composite/panel-gestures.ts +59 -0
  45. package/src/components/chart/composite/panel-labels.ts +107 -0
  46. package/src/components/chart/composite/panel-surface.tsx +876 -0
  47. package/src/components/chart/composite/tool-catalog.ts +98 -0
  48. package/src/components/chart/composite/toolbar.tsx +186 -0
  49. package/src/components/chart/composite/tools.ts +8 -0
  50. package/src/components/chart/composite/use-composite-chart-keyboard.ts +703 -0
  51. package/src/components/chart/composite/use-composite-viewport.ts +143 -0
  52. package/src/components/command-bar/list/model.ts +5 -0
  53. package/src/components/command-bar/list/view.tsx +16 -3
  54. package/src/components/command-bar/pane-templates/workflow.ts +1 -0
  55. package/src/components/command-bar/routes/ticker-search/actions.ts +5 -0
  56. package/src/components/command-bar/workflow/ops.ts +1 -1
  57. package/src/components/command-bar/workflow/tickers.ts +6 -0
  58. package/src/components/data-table/view.tsx +29 -10
  59. package/src/components/feedback-dialog.tsx +2 -1
  60. package/src/components/form-modal/field-row.tsx +2 -2
  61. package/src/components/layout/detached-pane-shell.tsx +6 -3
  62. package/src/components/layout/pane/content.tsx +23 -10
  63. package/src/components/layout/pane/error-boundary.tsx +103 -0
  64. package/src/components/layout/pane/footer/registration.tsx +68 -23
  65. package/src/components/layout/pane/header.tsx +11 -11
  66. package/src/components/layout/shell/menu.ts +2 -1
  67. package/src/components/layout/shell/pane/actions.ts +2 -1
  68. package/src/components/layout/shell/pane/layers.tsx +14 -3
  69. package/src/components/metric-treemap/heat-surface.tsx +43 -16
  70. package/src/components/metric-treemap/heat-tiles.ts +18 -0
  71. package/src/components/metric-treemap/layout.ts +2 -0
  72. package/src/components/onboarding/onboarding-keyboard.ts +311 -0
  73. package/src/components/onboarding/onboarding-wizard.tsx +101 -788
  74. package/src/components/onboarding/use-onboarding-broker-form.ts +263 -0
  75. package/src/components/onboarding/use-onboarding-progress.ts +298 -0
  76. package/src/components/onboarding/use-onboarding-upgrade.ts +83 -0
  77. package/src/components/ticker/list-table-view.tsx +13 -1
  78. package/src/components/ui/fields.tsx +8 -0
  79. package/src/components/ui/range-track.tsx +10 -3
  80. package/src/components/ui/status.tsx +8 -2
  81. package/src/components/ui/tabs.tsx +7 -4
  82. package/src/components/ui/text-prompt-dialog.tsx +4 -2
  83. package/src/data/config/store/normalize.ts +17 -1
  84. package/src/i18n/es.ts +19 -1
  85. package/src/i18n/ja.ts +19 -1
  86. package/src/i18n/ko.ts +19 -1
  87. package/src/i18n/zh-cn.ts +19 -1
  88. package/src/i18n/zh-tw.ts +19 -1
  89. package/src/market-data/coordinator/chart.ts +1 -1
  90. package/src/market-data/coordinator/quotes.ts +23 -4
  91. package/src/market-data/fx-closes.ts +72 -0
  92. package/src/market-data/market/freshness.ts +78 -6
  93. package/src/market-data/market/session-close-note.ts +57 -0
  94. package/src/market-data/market/status.ts +151 -0
  95. package/src/market-data/published-apac-sessions.ts +66 -0
  96. package/src/market-data/quotes/contributions.ts +2 -0
  97. package/src/market-data/quotes/resolution.ts +2 -0
  98. package/src/market-data/quotes/screener-live-quotes.ts +49 -4
  99. package/src/plugins/builtin/account-management/pane.tsx +4 -0
  100. package/src/plugins/builtin/alerts/cli.ts +10 -5
  101. package/src/plugins/builtin/alerts/index.tsx +1 -0
  102. package/src/plugins/builtin/analytics/metrics.ts +8 -3
  103. package/src/plugins/builtin/analytics/risk-client.ts +191 -66
  104. package/src/plugins/builtin/analytics/risk-fx.ts +102 -0
  105. package/src/plugins/builtin/analytics/risk-headless.ts +19 -13
  106. package/src/plugins/builtin/analytics/risk-model.ts +45 -17
  107. package/src/plugins/builtin/analytics/risk-pane.tsx +1 -0
  108. package/src/plugins/builtin/analytics/risk-test-data.ts +25 -1
  109. package/src/plugins/builtin/attention/headless.ts +6 -4
  110. package/src/plugins/builtin/attention/index.tsx +1 -1
  111. package/src/plugins/builtin/attention/pane.tsx +1 -1
  112. package/src/plugins/builtin/awards/headless.ts +1 -0
  113. package/src/plugins/builtin/awards/pane.tsx +1 -1
  114. package/src/plugins/builtin/backtest/headless.ts +1 -0
  115. package/src/plugins/builtin/bond-calculator/headless.ts +1 -0
  116. package/src/plugins/builtin/buildout/index.tsx +1 -0
  117. package/src/plugins/builtin/catalysts/headless.ts +3 -1
  118. package/src/plugins/builtin/cds/headless.ts +2 -0
  119. package/src/plugins/builtin/central-bank-rates/headless.ts +1 -0
  120. package/src/plugins/builtin/chart-composer/headless.ts +38 -3
  121. package/src/plugins/builtin/chart-composer/index.tsx +3 -1
  122. package/src/plugins/builtin/chart-composer/series-expression.ts +18 -2
  123. package/src/plugins/builtin/chat/channels.ts +19 -3
  124. package/src/plugins/builtin/chat/content/composer-runtime.ts +28 -13
  125. package/src/plugins/builtin/chat/content/footer.tsx +15 -6
  126. package/src/plugins/builtin/chat/content/index.tsx +120 -21
  127. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +261 -113
  128. package/src/plugins/builtin/chat/content/transcript.tsx +20 -2
  129. package/src/plugins/builtin/chat/direct-messages.ts +200 -0
  130. package/src/plugins/builtin/chat/index.tsx +1 -0
  131. package/src/plugins/builtin/chat/message/desktop.tsx +3 -0
  132. package/src/plugins/builtin/chat/message/header.tsx +16 -6
  133. package/src/plugins/builtin/chat/message/inline-tokens.tsx +72 -32
  134. package/src/plugins/builtin/chat/message/profile-popover.tsx +96 -12
  135. package/src/plugins/builtin/chat/message/terminal.tsx +3 -0
  136. package/src/plugins/builtin/chat/message/types.ts +14 -2
  137. package/src/plugins/builtin/chat/profile-popover.ts +18 -13
  138. package/src/plugins/builtin/clinical-trials/index.tsx +1 -0
  139. package/src/plugins/builtin/cloud/askg/executor.ts +2 -1
  140. package/src/plugins/builtin/cloud/plugin.tsx +1 -0
  141. package/src/plugins/builtin/cloud/team/module.tsx +1 -0
  142. package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
  143. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  144. package/src/plugins/builtin/comment-letters/index.tsx +1 -0
  145. package/src/plugins/builtin/company-attention/headless.ts +5 -1
  146. package/src/plugins/builtin/company-attention/pane.tsx +1 -1
  147. package/src/plugins/builtin/company-kpis/headless.ts +1 -0
  148. package/src/plugins/builtin/congress-trades/headless.ts +1 -0
  149. package/src/plugins/builtin/correlation/compute.ts +59 -16
  150. package/src/plugins/builtin/correlation/geo.ts +34 -0
  151. package/src/plugins/builtin/correlation/headless-schema.ts +4 -1
  152. package/src/plugins/builtin/correlation/headless.ts +42 -8
  153. package/src/plugins/builtin/correlation/history.ts +2 -0
  154. package/src/plugins/builtin/correlation/index.tsx +68 -14
  155. package/src/plugins/builtin/correlation/matrix/model.ts +17 -2
  156. package/src/plugins/builtin/correlation/matrix/selection.ts +5 -3
  157. package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
  158. package/src/plugins/builtin/correlation/relationship/pane.tsx +4 -2
  159. package/src/plugins/builtin/correlation/relationship/view-model.ts +16 -1
  160. package/src/plugins/builtin/correlation/settings.ts +1 -1
  161. package/src/plugins/builtin/cot/headless.ts +6 -3
  162. package/src/plugins/builtin/cot/index.tsx +3 -3
  163. package/src/plugins/builtin/cot/model.ts +36 -3
  164. package/src/plugins/builtin/cpi/headless.ts +4 -0
  165. package/src/plugins/builtin/credit-boards/headless.ts +2 -0
  166. package/src/plugins/builtin/credit-conditions/headless.ts +1 -0
  167. package/src/plugins/builtin/credit-documents/gauge.tsx +5 -8
  168. package/src/plugins/builtin/credit-documents/headless.ts +2 -0
  169. package/src/plugins/builtin/crypto-board/headless.ts +3 -0
  170. package/src/plugins/builtin/custom-view/loader.ts +1 -1
  171. package/src/plugins/builtin/debt-maturities/headless.ts +4 -0
  172. package/src/plugins/builtin/dividend-yield/headless.ts +1 -0
  173. package/src/plugins/builtin/doe/headless.ts +7 -0
  174. package/src/plugins/builtin/doe/range-bar.tsx +7 -37
  175. package/src/plugins/builtin/earnings/headless.ts +5 -0
  176. package/src/plugins/builtin/earnings-calls/headless.ts +1 -0
  177. package/src/plugins/builtin/earnings-ripple/client.ts +91 -18
  178. package/src/plugins/builtin/earnings-ripple/headless.ts +28 -8
  179. package/src/plugins/builtin/earnings-ripple/index.tsx +2 -2
  180. package/src/plugins/builtin/earnings-ripple/model.ts +97 -7
  181. package/src/plugins/builtin/earnings-ripple/pane.tsx +148 -23
  182. package/src/plugins/builtin/econ/index.tsx +1 -0
  183. package/src/plugins/builtin/econ-statistics/headless.ts +2 -0
  184. package/src/plugins/builtin/equity-screener/headless.ts +2 -0
  185. package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
  186. package/src/plugins/builtin/executives/index.tsx +1 -0
  187. package/src/plugins/builtin/exposure/headless.ts +3 -1
  188. package/src/plugins/builtin/fear-greed/headless.ts +2 -0
  189. package/src/plugins/builtin/filing-events/index.tsx +1 -0
  190. package/src/plugins/builtin/futures-curve/client.ts +12 -3
  191. package/src/plugins/builtin/futures-curve/headless.ts +39 -10
  192. package/src/plugins/builtin/futures-curve/index.tsx +3 -3
  193. package/src/plugins/builtin/futures-curve/model.ts +188 -4
  194. package/src/plugins/builtin/futures-curve/pane.tsx +51 -9
  195. package/src/plugins/builtin/gpu/headless.ts +7 -3
  196. package/src/plugins/builtin/gpu/ladder.tsx +26 -30
  197. package/src/plugins/builtin/gpu/model.ts +27 -1
  198. package/src/plugins/builtin/holders/beneficial-client.ts +209 -0
  199. package/src/plugins/builtin/holders/beneficial-model.ts +279 -0
  200. package/src/plugins/builtin/holders/beneficial-report.ts +126 -0
  201. package/src/plugins/builtin/holders/beneficial-view.tsx +241 -0
  202. package/src/plugins/builtin/holders/headless.ts +139 -5
  203. package/src/plugins/builtin/holders/index.tsx +10 -3
  204. package/src/plugins/builtin/holders/pane.tsx +20 -3
  205. package/src/plugins/builtin/holders/report-header.ts +95 -0
  206. package/src/plugins/builtin/holders/table-model.ts +20 -5
  207. package/src/plugins/builtin/holders/thirteenf-match.ts +29 -1
  208. package/src/plugins/builtin/holders/types.ts +2 -1
  209. package/src/plugins/builtin/insider/headless.ts +2 -0
  210. package/src/plugins/builtin/ipo-calendar/headless.ts +1 -0
  211. package/src/plugins/builtin/iv-history/headless.ts +4 -1
  212. package/src/plugins/builtin/jobs/headless.ts +1 -0
  213. package/src/plugins/builtin/kelly-sizer/index.tsx +1 -0
  214. package/src/plugins/builtin/macro-day/headless.ts +2 -0
  215. package/src/plugins/builtin/market-halts/index.tsx +1 -0
  216. package/src/plugins/builtin/market-heatmap/data.ts +2 -0
  217. package/src/plugins/builtin/market-heatmap/headless.ts +135 -0
  218. package/src/plugins/builtin/market-heatmap/index.tsx +39 -46
  219. package/src/plugins/builtin/market-heatmap/model.ts +146 -0
  220. package/src/plugins/builtin/market-heatmap/portfolio.ts +23 -4
  221. package/src/plugins/builtin/market-movers/headless.ts +2 -0
  222. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  223. package/src/plugins/builtin/members/client.ts +20 -3
  224. package/src/plugins/builtin/members/headless.ts +5 -3
  225. package/src/plugins/builtin/members/model.ts +10 -2
  226. package/src/plugins/builtin/members/pane.tsx +13 -6
  227. package/src/plugins/builtin/mna/distress/headless.ts +1 -0
  228. package/src/plugins/builtin/mna/headless.ts +1 -0
  229. package/src/plugins/builtin/money-markets/headless.ts +1 -0
  230. package/src/plugins/builtin/news/headless.ts +2 -0
  231. package/src/plugins/builtin/news/wire/index.tsx +8 -1
  232. package/src/plugins/builtin/notes/cli.ts +14 -6
  233. package/src/plugins/builtin/notes/index.tsx +1 -0
  234. package/src/plugins/builtin/openfda/index.tsx +1 -0
  235. package/src/plugins/builtin/options-calculator/headless.ts +2 -0
  236. package/src/plugins/builtin/options-positioning/headless.ts +3 -0
  237. package/src/plugins/builtin/options-scenario/headless.ts +5 -0
  238. package/src/plugins/builtin/pe-band/client.ts +48 -3
  239. package/src/plugins/builtin/pe-band/headless.ts +25 -7
  240. package/src/plugins/builtin/pe-band/model.ts +92 -16
  241. package/src/plugins/builtin/pe-band/pane.tsx +33 -16
  242. package/src/plugins/builtin/perps/client.ts +50 -3
  243. package/src/plugins/builtin/perps/headless.ts +144 -16
  244. package/src/plugins/builtin/perps/index.tsx +6 -6
  245. package/src/plugins/builtin/perps/model.ts +189 -12
  246. package/src/plugins/builtin/perps/pane.tsx +248 -47
  247. package/src/plugins/builtin/portfolio-list/allocation.ts +245 -0
  248. package/src/plugins/builtin/portfolio-list/cached-account.ts +33 -0
  249. package/src/plugins/builtin/portfolio-list/cell-version.ts +19 -1
  250. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +328 -29
  251. package/src/plugins/builtin/portfolio-list/cli/render.ts +230 -39
  252. package/src/plugins/builtin/portfolio-list/cli/shared.ts +67 -2
  253. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +35 -31
  254. package/src/plugins/builtin/portfolio-list/column-values.ts +124 -47
  255. package/src/plugins/builtin/portfolio-list/headless.ts +98 -16
  256. package/src/plugins/builtin/portfolio-list/index.tsx +14 -3
  257. package/src/plugins/builtin/portfolio-list/live-valuation.ts +7 -5
  258. package/src/plugins/builtin/portfolio-list/mutations.ts +55 -1
  259. package/src/plugins/builtin/portfolio-list/pane/data.ts +6 -0
  260. package/src/plugins/builtin/portfolio-list/pane/index.tsx +47 -13
  261. package/src/plugins/builtin/portfolio-list/settings.ts +33 -2
  262. package/src/plugins/builtin/portfolio-list/summary/index.tsx +24 -1
  263. package/src/plugins/builtin/portfolio-list/summary/totals.ts +26 -7
  264. package/src/plugins/builtin/power/headless.ts +3 -1
  265. package/src/plugins/builtin/rate-path/headless.ts +2 -0
  266. package/src/plugins/builtin/realized-vol/headless.ts +2 -0
  267. package/src/plugins/builtin/relative-rotation/headless.ts +2 -0
  268. package/src/plugins/builtin/research/analyst-headless.ts +3 -0
  269. package/src/plugins/builtin/research/events-headless.ts +2 -0
  270. package/src/plugins/builtin/research/headless.ts +2 -0
  271. package/src/plugins/builtin/research/index.tsx +1 -0
  272. package/src/plugins/builtin/research/relative-valuation-headless.ts +10 -5
  273. package/src/plugins/builtin/research/relative-valuation-model.ts +11 -3
  274. package/src/plugins/builtin/research/relative-valuation-pane.tsx +3 -3
  275. package/src/plugins/builtin/research-search/index.tsx +1 -0
  276. package/src/plugins/builtin/revenue-breakdown/headless.ts +2 -0
  277. package/src/plugins/builtin/reverse-dcf/headless.ts +2 -0
  278. package/src/plugins/builtin/risk-factors/headless.ts +2 -0
  279. package/src/plugins/builtin/scanner/flow-history.ts +2 -13
  280. package/src/plugins/builtin/scanner/headless.ts +14 -0
  281. package/src/plugins/builtin/seasonality/headless.ts +2 -0
  282. package/src/plugins/builtin/sec/command-bar-search.ts +14 -4
  283. package/src/plugins/builtin/sec/filing-content.ts +42 -17
  284. package/src/plugins/builtin/sec/forms.ts +12 -0
  285. package/src/plugins/builtin/sec/headless.ts +2 -0
  286. package/src/plugins/builtin/sectors/client.ts +1 -0
  287. package/src/plugins/builtin/sectors/headless.ts +9 -1
  288. package/src/plugins/builtin/sectors/sector-model.ts +2 -0
  289. package/src/plugins/builtin/shared/crypto-pair.ts +14 -0
  290. package/src/plugins/builtin/shared/locked-rows.tsx +1 -1
  291. package/src/plugins/builtin/shared/report-freshness.ts +57 -0
  292. package/src/plugins/builtin/shared/research-cells.tsx +4 -9
  293. package/src/plugins/builtin/short-interest/headless.ts +2 -0
  294. package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
  295. package/src/plugins/builtin/short-volume/headless.ts +1 -0
  296. package/src/plugins/builtin/social-mentions/headless.ts +1 -0
  297. package/src/plugins/builtin/supply-chain/headless.ts +7 -1
  298. package/src/plugins/builtin/supply-chain/index.tsx +10 -1
  299. package/src/plugins/builtin/supply-chain/model.ts +27 -2
  300. package/src/plugins/builtin/supply-chain/pane.tsx +71 -32
  301. package/src/plugins/builtin/themes/headless.ts +3 -0
  302. package/src/plugins/builtin/thirteenf/headless.ts +110 -25
  303. package/src/plugins/builtin/thirteenf/report-notes.ts +149 -0
  304. package/src/plugins/builtin/ticker-detail/headless.ts +7 -1
  305. package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
  306. package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -2
  307. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +26 -26
  308. package/src/plugins/builtin/time-sales/headless.ts +5 -1
  309. package/src/plugins/builtin/treasury-auctions/headless.ts +1 -0
  310. package/src/plugins/builtin/volatility/headless.ts +6 -1
  311. package/src/plugins/builtin/world-indices/headless.ts +2 -0
  312. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +157 -0
  313. package/src/plugins/builtin/world-venue-map/basemap.ts +214 -0
  314. package/src/plugins/builtin/world-venue-map/client.ts +45 -0
  315. package/src/plugins/builtin/world-venue-map/entity-detail.tsx +147 -0
  316. package/src/plugins/builtin/world-venue-map/entity-table.ts +59 -0
  317. package/src/plugins/builtin/world-venue-map/evidence.ts +77 -0
  318. package/src/plugins/builtin/world-venue-map/feed.ts +293 -0
  319. package/src/plugins/builtin/world-venue-map/geo-draw.tsx +248 -0
  320. package/src/plugins/builtin/world-venue-map/geo-series.ts +142 -0
  321. package/src/plugins/builtin/world-venue-map/geo-svg.tsx +447 -0
  322. package/src/plugins/builtin/world-venue-map/headless.ts +146 -0
  323. package/src/plugins/builtin/world-venue-map/ids.ts +1 -0
  324. package/src/plugins/builtin/world-venue-map/index.ts +67 -4
  325. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +552 -0
  326. package/src/plugins/builtin/world-venue-map/layers.ts +348 -0
  327. package/src/plugins/builtin/world-venue-map/map-symbols.ts +220 -0
  328. package/src/plugins/builtin/world-venue-map/map.tsx +381 -45
  329. package/src/plugins/builtin/world-venue-map/model.ts +7 -4
  330. package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +199 -0
  331. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n00.chunk.ts +4 -0
  332. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n15.chunk.ts +4 -0
  333. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n30.chunk.ts +4 -0
  334. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n45.chunk.ts +4 -0
  335. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n60.chunk.ts +4 -0
  336. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n75.chunk.ts +4 -0
  337. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s15.chunk.ts +4 -0
  338. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s30.chunk.ts +4 -0
  339. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s60.chunk.ts +4 -0
  340. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n00.chunk.ts +4 -0
  341. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n15.chunk.ts +4 -0
  342. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n30.chunk.ts +4 -0
  343. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n45.chunk.ts +4 -0
  344. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n60.chunk.ts +4 -0
  345. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n75.chunk.ts +4 -0
  346. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s15.chunk.ts +4 -0
  347. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s30.chunk.ts +4 -0
  348. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s45.chunk.ts +4 -0
  349. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n00.chunk.ts +4 -0
  350. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n15.chunk.ts +4 -0
  351. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n30.chunk.ts +4 -0
  352. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n45.chunk.ts +4 -0
  353. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n60.chunk.ts +4 -0
  354. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n75.chunk.ts +4 -0
  355. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s15.chunk.ts +4 -0
  356. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s30.chunk.ts +4 -0
  357. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s45.chunk.ts +4 -0
  358. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s60.chunk.ts +4 -0
  359. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n00.chunk.ts +4 -0
  360. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n15.chunk.ts +4 -0
  361. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n30.chunk.ts +4 -0
  362. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n45.chunk.ts +4 -0
  363. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n60.chunk.ts +4 -0
  364. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n75.chunk.ts +4 -0
  365. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s15.chunk.ts +4 -0
  366. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s30.chunk.ts +4 -0
  367. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s60.chunk.ts +4 -0
  368. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n00.chunk.ts +4 -0
  369. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n15.chunk.ts +4 -0
  370. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n30.chunk.ts +4 -0
  371. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n45.chunk.ts +4 -0
  372. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n60.chunk.ts +4 -0
  373. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n75.chunk.ts +4 -0
  374. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s15.chunk.ts +4 -0
  375. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s30.chunk.ts +4 -0
  376. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s60.chunk.ts +4 -0
  377. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n00.chunk.ts +4 -0
  378. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n15.chunk.ts +4 -0
  379. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n30.chunk.ts +4 -0
  380. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n45.chunk.ts +4 -0
  381. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n60.chunk.ts +4 -0
  382. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n75.chunk.ts +4 -0
  383. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075s45.chunk.ts +4 -0
  384. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n00.chunk.ts +4 -0
  385. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n15.chunk.ts +4 -0
  386. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n30.chunk.ts +4 -0
  387. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n45.chunk.ts +4 -0
  388. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n60.chunk.ts +4 -0
  389. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n75.chunk.ts +4 -0
  390. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090s15.chunk.ts +4 -0
  391. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n00.chunk.ts +4 -0
  392. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n15.chunk.ts +4 -0
  393. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n30.chunk.ts +4 -0
  394. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n45.chunk.ts +4 -0
  395. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n60.chunk.ts +4 -0
  396. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n75.chunk.ts +4 -0
  397. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s15.chunk.ts +4 -0
  398. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s30.chunk.ts +4 -0
  399. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s45.chunk.ts +4 -0
  400. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n00.chunk.ts +4 -0
  401. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n15.chunk.ts +4 -0
  402. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n30.chunk.ts +4 -0
  403. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n45.chunk.ts +4 -0
  404. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n60.chunk.ts +4 -0
  405. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s15.chunk.ts +4 -0
  406. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s30.chunk.ts +4 -0
  407. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s45.chunk.ts +4 -0
  408. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n00.chunk.ts +4 -0
  409. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n15.chunk.ts +4 -0
  410. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n30.chunk.ts +4 -0
  411. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n45.chunk.ts +4 -0
  412. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n60.chunk.ts +4 -0
  413. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n75.chunk.ts +4 -0
  414. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s15.chunk.ts +4 -0
  415. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s30.chunk.ts +4 -0
  416. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s45.chunk.ts +4 -0
  417. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n00.chunk.ts +4 -0
  418. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n15.chunk.ts +4 -0
  419. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n45.chunk.ts +4 -0
  420. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n60.chunk.ts +4 -0
  421. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n75.chunk.ts +4 -0
  422. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s15.chunk.ts +4 -0
  423. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s30.chunk.ts +4 -0
  424. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s45.chunk.ts +4 -0
  425. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s60.chunk.ts +4 -0
  426. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n00.chunk.ts +4 -0
  427. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n15.chunk.ts +4 -0
  428. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n45.chunk.ts +4 -0
  429. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n60.chunk.ts +4 -0
  430. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s15.chunk.ts +4 -0
  431. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s30.chunk.ts +4 -0
  432. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s45.chunk.ts +4 -0
  433. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s60.chunk.ts +4 -0
  434. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n00.chunk.ts +4 -0
  435. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n15.chunk.ts +4 -0
  436. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n30.chunk.ts +4 -0
  437. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n45.chunk.ts +4 -0
  438. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n60.chunk.ts +4 -0
  439. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n75.chunk.ts +4 -0
  440. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s15.chunk.ts +4 -0
  441. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s30.chunk.ts +4 -0
  442. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s45.chunk.ts +4 -0
  443. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n00.chunk.ts +4 -0
  444. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n15.chunk.ts +4 -0
  445. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n30.chunk.ts +4 -0
  446. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n60.chunk.ts +4 -0
  447. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n75.chunk.ts +4 -0
  448. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s30.chunk.ts +4 -0
  449. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s60.chunk.ts +4 -0
  450. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n30.chunk.ts +4 -0
  451. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n45.chunk.ts +4 -0
  452. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n60.chunk.ts +4 -0
  453. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n75.chunk.ts +4 -0
  454. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s15.chunk.ts +4 -0
  455. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s30.chunk.ts +4 -0
  456. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s60.chunk.ts +4 -0
  457. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n00.chunk.ts +4 -0
  458. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n30.chunk.ts +4 -0
  459. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n45.chunk.ts +4 -0
  460. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n60.chunk.ts +4 -0
  461. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n75.chunk.ts +4 -0
  462. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s15.chunk.ts +4 -0
  463. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s30.chunk.ts +4 -0
  464. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s45.chunk.ts +4 -0
  465. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s60.chunk.ts +4 -0
  466. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n00.chunk.ts +4 -0
  467. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n15.chunk.ts +4 -0
  468. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n30.chunk.ts +4 -0
  469. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n45.chunk.ts +4 -0
  470. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n60.chunk.ts +4 -0
  471. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n75.chunk.ts +4 -0
  472. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s15.chunk.ts +4 -0
  473. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s30.chunk.ts +4 -0
  474. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s45.chunk.ts +4 -0
  475. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s60.chunk.ts +4 -0
  476. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n00.chunk.ts +4 -0
  477. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n15.chunk.ts +4 -0
  478. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n30.chunk.ts +4 -0
  479. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n45.chunk.ts +4 -0
  480. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n60.chunk.ts +4 -0
  481. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n75.chunk.ts +4 -0
  482. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s15.chunk.ts +4 -0
  483. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s30.chunk.ts +4 -0
  484. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s45.chunk.ts +4 -0
  485. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s60.chunk.ts +4 -0
  486. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n00.chunk.ts +4 -0
  487. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n15.chunk.ts +4 -0
  488. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n30.chunk.ts +4 -0
  489. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n45.chunk.ts +4 -0
  490. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n60.chunk.ts +4 -0
  491. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n75.chunk.ts +4 -0
  492. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105s15.chunk.ts +4 -0
  493. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n00.chunk.ts +4 -0
  494. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n15.chunk.ts +4 -0
  495. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n30.chunk.ts +4 -0
  496. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n45.chunk.ts +4 -0
  497. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n60.chunk.ts +4 -0
  498. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n75.chunk.ts +4 -0
  499. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120s30.chunk.ts +4 -0
  500. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n30.chunk.ts +4 -0
  501. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n45.chunk.ts +4 -0
  502. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n60.chunk.ts +4 -0
  503. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n75.chunk.ts +4 -0
  504. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135s30.chunk.ts +4 -0
  505. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n45.chunk.ts +4 -0
  506. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n60.chunk.ts +4 -0
  507. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s15.chunk.ts +4 -0
  508. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s30.chunk.ts +4 -0
  509. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n00.chunk.ts +4 -0
  510. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n15.chunk.ts +4 -0
  511. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n45.chunk.ts +4 -0
  512. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n60.chunk.ts +4 -0
  513. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s15.chunk.ts +4 -0
  514. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s30.chunk.ts +4 -0
  515. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n00.chunk.ts +4 -0
  516. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n15.chunk.ts +4 -0
  517. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n45.chunk.ts +4 -0
  518. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n60.chunk.ts +4 -0
  519. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s15.chunk.ts +4 -0
  520. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s30.chunk.ts +4 -0
  521. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s45.chunk.ts +4 -0
  522. package/src/plugins/builtin/world-venue-map/natural-earth/world-50m.chunk.ts +4 -0
  523. package/src/plugins/builtin/world-venue-map/pane.tsx +28 -43
  524. package/src/plugins/builtin/world-venue-map/use-geo.ts +55 -0
  525. package/src/plugins/builtin/world-venue-map/venue-header.tsx +32 -0
  526. package/src/plugins/builtin/yield-curve/headless.ts +16 -0
  527. package/src/plugins/loader.ts +13 -1
  528. package/src/plugins/registry/pane-settings.ts +1 -0
  529. package/src/renderers/dom/build-assets.ts +81 -3
  530. package/src/renderers/dom/data-table/row.tsx +2 -0
  531. package/src/renderers/dom/desktop/controls.tsx +7 -3
  532. package/src/renderers/dom/desktop/list-view.tsx +35 -10
  533. package/src/renderers/dom/desktop/popover.tsx +73 -14
  534. package/src/renderers/dom/host/input.tsx +14 -3
  535. package/src/renderers/dom/styles.css +6 -7
  536. package/src/renderers/electrobun/view/backend-rpc.ts +10 -4
  537. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -0
  538. package/src/renderers/electrobun/view/rpc-timeout.ts +14 -3
  539. package/src/renderers/opentui/host.tsx +5 -0
  540. package/src/sources/gloomberb-cloud/index.ts +25 -4
  541. package/src/sources/gloomberb-cloud/normalizers.ts +27 -3
  542. package/src/sources/provider-router/cached-routes.ts +4 -1
  543. package/src/sources/provider-router/financials.ts +8 -7
  544. package/src/sources/provider-router/history.ts +15 -10
  545. package/src/sources/sec-registrant.ts +75 -0
  546. package/src/state/app/context/index.tsx +24 -8
  547. package/src/state/hooks/quote-streaming.ts +41 -26
  548. package/src/sync/core-contributors.ts +4 -0
  549. package/src/telemetry/crash-reports.ts +4 -1
  550. package/src/test-support/cli-context.ts +10 -2
  551. package/src/theme/heat-colors.ts +266 -84
  552. package/src/time-series/resolve.ts +1 -1
  553. package/src/time-series/use-chart-resolution.ts +1 -1
  554. package/src/types/context-menu.ts +6 -0
  555. package/src/types/data-provider.ts +2 -0
  556. package/src/types/financials.ts +3 -0
  557. package/src/types/headless.ts +79 -2
  558. package/src/types/plugin.ts +20 -1
  559. package/src/types/ticker.ts +15 -0
  560. package/src/ui/host.tsx +14 -0
  561. package/src/updater/index.ts +9 -11
  562. package/src/utils/async-deadline.ts +21 -0
  563. package/src/utils/cli-output.ts +5 -1
  564. package/src/utils/crypto-pair.ts +41 -0
  565. package/src/utils/currency-units.ts +14 -0
  566. package/src/utils/depositary-receipt.ts +26 -0
  567. package/src/utils/exchanges.ts +72 -0
  568. package/src/utils/fire-and-forget.ts +24 -0
  569. package/src/utils/format.ts +13 -0
  570. package/src/utils/price-earnings.ts +70 -3
  571. package/src/utils/price-history.ts +58 -13
  572. package/src/utils/rpc-timeout-error.ts +27 -0
  573. package/src/utils/sec.ts +13 -1
  574. package/src/utils/utc-time.ts +79 -0
@@ -46,6 +46,8 @@ interface PortfolioRiskHolding {
46
46
  priceAsOf: string | null;
47
47
  /** "close" when no current quote arrived and the latest completed close marks the holding. */
48
48
  markSource?: "quote" | "close" | null;
49
+ /** The listing currency its closes were converted from at daily FX closes; null for a USD listing. */
50
+ convertedFrom: string | null;
49
51
  historyAsOf: string | null;
50
52
  returns: DatedReturn[];
51
53
  error: string | null;
@@ -71,6 +73,8 @@ export interface RiskCoverage {
71
73
  holdings: number;
72
74
  /** Holdings that qualify for the basket. */
73
75
  covered: number;
76
+ /** Covered holdings whose returns were converted to USD from their listing currency. */
77
+ converted: number;
74
78
  unvalued: number;
75
79
  minimumShare: number;
76
80
  /** The basket views estimate only when qualifying holdings reach the minimum share. */
@@ -223,24 +227,28 @@ const coveragePercent = (share: number) => Math.floor(share * 100);
223
227
  const holdingCount = (count: number) => `${count} holding${count === 1 ? "" : "s"}`;
224
228
  const shareText = (share: number) =>
225
229
  share < 0.001 ? "under 0.1%" : `${(share * 100).toFixed(1)}%`;
226
- /** "covers 78% of market value · 9 holdings left out", or null when nothing is left out. */
230
+ /**
231
+ * "covers 78% of market value · 9 holdings left out · 2 converted from local
232
+ * currency", or null when every holding is in the basket in its own USD listing.
233
+ */
227
234
  export function riskCoverageText(coverage: RiskCoverage | undefined): string | null {
228
- if (!coverage?.leftOut.length) return null;
235
+ if (!coverage) return null;
236
+ const converted = coverage.converted ? `${holdingCount(coverage.converted)} converted from local currency` : null;
237
+ if (!coverage.leftOut.length) return converted;
229
238
  const covers = coverage.share == null
230
239
  ? "covers an unknown share of market value"
231
240
  : `covers ${coverage.unvalued ? "at most " : ""}${coveragePercent(coverage.share)}% of market value`;
232
- return `${covers} · ${holdingCount(coverage.leftOut.length)} left out`;
241
+ return [covers, `${holdingCount(coverage.leftOut.length)} left out`, ...(converted ? [converted] : [])].join(" · ");
233
242
  }
234
- /** One notice per left-out holding, largest first, after a lead line. */
243
+ /** A reason reads as the tail of a sentence, so its first word loses its capital unless it is an acronym ("FX", "USD"). */
244
+ const lowerFirst = (text: string) => (/^[A-Z][a-z]/.test(text) ? text[0]!.toLowerCase() + text.slice(1) : text);
245
+ /** One sentence per left-out holding, largest first, naming the holding and why it is out. */
235
246
  export function riskCoverageNotices(coverage: RiskCoverage | undefined): string[] {
236
247
  if (!coverage?.leftOut.length) return [];
237
- return [
238
- `${holdingCount(coverage.leftOut.length)} left out of the basket, largest first:`,
239
- ...coverage.leftOut.map(
240
- (row) =>
241
- `${row.symbol} (${row.share == null ? "value unknown" : `${shareText(row.share)} of market value`}): ${row.reason}`,
242
- ),
243
- ];
248
+ return coverage.leftOut.map(
249
+ (row) =>
250
+ `${row.symbol} (${row.share == null ? "value unknown" : `${shareText(row.share)} of market value`}) is excluded from the risk estimate: ${lowerFirst(row.reason.replace(/\.$/, ""))}.`,
251
+ );
244
252
  }
245
253
  /** Why the basket views show no estimate, when too little of the account qualifies. */
246
254
  export function riskCoverageShortfall(
@@ -321,10 +329,13 @@ export function buildPortfolioRisk(
321
329
  ? { price: quote.price, currency: quote.currency, stale: !!quote.stale }
322
330
  : null;
323
331
  const quantity = signedQuantity(lots);
332
+ // A converted listing is marked and returned in USD; its own currency is what the holding records.
333
+ const convertedFrom = history?.converted?.currency ?? null;
324
334
  const listingCurrency =
325
335
  quote?.currency ?? close?.currency ?? history?.listing?.currency ?? ticker.metadata.currency;
336
+ const foreign = !convertedFrom && listingCurrency !== "USD";
326
337
  const error =
327
- syntheticPositionUnsupportedReason(ticker, listingCurrency, portfolio.id) ??
338
+ syntheticPositionUnsupportedReason(ticker, "USD", portfolio.id) ??
328
339
  (lots.some((row) => !Number.isFinite(row.shares))
329
340
  ? "Invalid position quantity"
330
341
  : null) ??
@@ -332,10 +343,14 @@ export function buildPortfolioRisk(
332
343
  ? "Historical account-currency FX is required"
333
344
  : null) ??
334
345
  (ticker.metadata.currency &&
335
- mark?.currency &&
336
- ticker.metadata.currency !== mark.currency
346
+ (convertedFrom ?? mark?.currency) &&
347
+ ticker.metadata.currency !== (convertedFrom ?? mark?.currency)
337
348
  ? "Holding and quote currencies differ"
338
349
  : null) ??
350
+ // A foreign listing that did not convert says why: no pair, stale or gapped FX.
351
+ (foreign
352
+ ? (history?.error ?? syntheticPositionUnsupportedReason(ticker, listingCurrency, portfolio.id))
353
+ : null) ??
339
354
  history?.error ??
340
355
  (!history ? "Daily history unavailable" : null);
341
356
  const priceDate = close ? close.date : quoteDate(quote?.lastUpdated);
@@ -376,6 +391,7 @@ export function buildPortfolioRisk(
376
391
  : outsideValue(ticker, portfolio, quote ?? history?.listing ?? null, rates),
377
392
  priceAsOf: priceDate,
378
393
  markSource: close ? "close" : quote ? "quote" : null,
394
+ convertedFrom,
379
395
  historyAsOf: history?.asOf ?? null,
380
396
  returns,
381
397
  error,
@@ -395,6 +411,7 @@ export function buildPortfolioRisk(
395
411
  share,
396
412
  holdings: holdings.length,
397
413
  covered: qualifying.length,
414
+ converted: qualifying.filter((row) => row.convertedFrom != null).length,
398
415
  unvalued: holdings.length - valued.length,
399
416
  minimumShare: RISK_MIN_COVERAGE,
400
417
  sufficient,
@@ -416,14 +433,24 @@ export function buildPortfolioRisk(
416
433
  holding.weight =
417
434
  book?.rows.find((row) => row.id === holding.id)?.weight ?? null;
418
435
  const closeMarked = members.filter((row) => row.markSource === "close").length;
436
+ const converted = members.filter((row) => row.convertedFrom != null).length;
419
437
  const held = new Set(holdings.map((row) => row.id));
420
- const warnings = [
421
- ...market.warnings,
438
+ // Caveats about an estimate that was made; the warnings are what failed.
439
+ const notes = [
422
440
  ...(closeMarked
423
441
  ? [
424
442
  `${closeMarked} holding${closeMarked === 1 ? "" : "s"} had no current quote; weighted at the latest completed close.`,
425
443
  ]
426
444
  : []),
445
+ // Daily closes pair by date, so a market that closes before or after the US session is not synchronous with it.
446
+ ...(converted
447
+ ? [
448
+ "Converted holdings are matched to the US close of the same date; where their market closes at another time, correlations and betas to US holdings read lower than they are.",
449
+ ]
450
+ : []),
451
+ ];
452
+ const warnings = [
453
+ ...market.warnings,
427
454
  // A held instrument's failure is its left-out reason; factor proxies report here.
428
455
  ...market.histories.flatMap((row) =>
429
456
  row.error && !held.has(riskInstrumentId(row.instrument))
@@ -561,7 +588,7 @@ export function buildPortfolioRisk(
561
588
  asOf: row.priceAsOf,
562
589
  detail: row.leftOut
563
590
  ? row.leftOut
564
- : `${row.quantity} shares; ${formatNumber(row.value ?? undefined)} ${row.currency}${row.markSource === "close" ? ` at ${row.priceAsOf} close` : ""}; history ${row.historyAsOf}`,
591
+ : `${row.quantity} shares; ${formatNumber(row.value ?? undefined)} ${row.currency}${row.markSource === "close" ? ` at ${row.priceAsOf} close` : ""}${row.convertedFrom ? ` from ${row.convertedFrom} at daily FX` : ""}; history ${row.historyAsOf}`,
565
592
  ...(row.leftOut ? { leftOut: row.leftOut } : {}),
566
593
  })),
567
594
  correlation: correlation.map((row) => ({
@@ -733,6 +760,7 @@ export function buildPortfolioRisk(
733
760
  coverage.leftOut.length === 0 &&
734
761
  metrics.some((row) => row.value != null),
735
762
  warnings: [...new Set(warnings)],
763
+ notes,
736
764
  fetchedAt: market.fetchedAt,
737
765
  };
738
766
  }
@@ -444,6 +444,7 @@ export function PortfolioRiskPane({ focused, width, height }: PaneProps) {
444
444
  // views say what they need in the body, with the import action.
445
445
  const notices = [
446
446
  ...riskCoverageNotices(model?.coverage),
447
+ ...(model?.notes ?? []),
447
448
  ...(model?.warnings ?? []),
448
449
  ...(derived.error ? [derived.error] : []),
449
450
  ...(resource.error ? [resource.error] : []),
@@ -178,14 +178,35 @@ function fredSeries(id: string, asOf: Date): CloudFredSeriesPayload {
178
178
  };
179
179
  }
180
180
 
181
+ /**
182
+ * Daily closes of the pair that prices `currency` against the dollar, every
183
+ * weekday as FX trades, wobbling around the rate the endpoint reports.
184
+ */
185
+ function fxPairHistory(symbol: string, asOf: Date): CloudMarketResponse<CloudPricePointPayload[]> | null {
186
+ const currency = symbol.replace(/(USD)?=X$/, "");
187
+ const rate = BROKER_FX_RATES[currency];
188
+ if (rate == null) return null;
189
+ const usdQuoted = symbol.endsWith("USD=X");
190
+ const data: CloudPricePointPayload[] = [];
191
+ const today = Date.parse(asOf.toISOString().slice(0, 10));
192
+ for (let day = today - 240 * 86_400_000; day < today; day += 86_400_000) {
193
+ if ([0, 6].includes(new Date(day).getUTCDay())) continue;
194
+ const usdPerUnit = rate * (1 + Math.sin(data.length / 5) / 100);
195
+ const close = usdQuoted ? usdPerUnit : 1 / usdPerUnit;
196
+ data.push({ date: new Date(day).toISOString(), open: close, high: close, low: close, close });
197
+ }
198
+ return { status: "success", data, providerMeta: { servedResolution: "1d", normalizedSymbol: symbol } };
199
+ }
200
+
181
201
  /**
182
202
  * Cloud responses for the broker account: US listings and the factor proxies
183
203
  * quote and keep daily history, foreign listings quote in their own currency,
184
- * the uncovered holdings have neither.
204
+ * the uncovered holdings have neither. Daily FX history exists only with `fx`.
185
205
  */
186
206
  export function brokerRiskClient(
187
207
  asOf: Date = now,
188
208
  holdings: readonly BrokerFixtureHolding[] = brokerFixtureHoldings(),
209
+ { fx = false }: { fx?: boolean } = {},
189
210
  ) {
190
211
  const bySymbol = new Map(holdings.map((holding) => [normalizeSymbol(holding.symbol), holding]));
191
212
  const find = (symbol: string) => bySymbol.get(normalizeSymbol(symbol));
@@ -217,6 +238,9 @@ export function brokerRiskClient(
217
238
  },
218
239
  getCloudHistory: async (symbol: string, exchange: string) => {
219
240
  calls.histories.push(symbol);
241
+ if (symbol.endsWith("=X"))
242
+ return (fx && fxPairHistory(symbol, asOf)) ||
243
+ { status: "empty" as const, data: null, reasonCode: "Daily history unavailable" };
220
244
  const holding = find(symbol);
221
245
  if (holding && holding.price == null)
222
246
  return { status: "empty" as const, data: null, reasonCode: "Daily history unavailable" };
@@ -15,16 +15,18 @@ export const attentionHeadless: HeadlessPaneDefinition<"bundle"> = {
15
15
  const metadata = { asOf: data.asOf, stale: data.stale, complete: data.status === "ready" && !data.truncated,
16
16
  status: data.status, periodStart: data.periodStart, periodEnd: data.periodEnd, entitlement: data.entitlement,
17
17
  privacy: data.privacy, coverage: data.coverage, methodologyUrl: data.methodologyUrl, selectedListing: data.selectedListing ?? null, historyEvidence: data.historyEvidence ?? null, unit: "rounded researcher-hours" };
18
- if (tab === "sectors" || tab === "countries") return { metadata, sections: [{ title: tab === "sectors" ? "Sector attention" : "Country attention",
18
+ // Published hour by hour, so not a feed, but the service says when publication has fallen behind.
19
+ const freshness = { status: data.stale ? "stale" as const : "not-a-feed" as const, basis: "hourly publication" };
20
+ if (tab === "sectors" || tab === "countries") return { metadata, freshness, sections: [{ title: tab === "sectors" ? "Sector attention" : "Country attention",
19
21
  columns: [{ key: "name", header: "Group" }, { key: "researchUnits", header: "Research hours" }, { key: "sharePct", header: "Share %" }, { key: "tickers", header: "Tickers" }], rows: data[tab].map((row) => ({ ...row })) }] };
20
- if (tab === "history") return { metadata, sections: [{ title: "Published hourly history", columns: [{ key: "symbol", header: "Ticker" },
22
+ if (tab === "history") return { metadata, freshness, sections: [{ title: "Published hourly history", columns: [{ key: "symbol", header: "Ticker" },
21
23
  { key: "bucketStart", header: "Hour (UTC)" }, { key: "researchUnits", header: "Research hours" }],
22
24
  rows: data.history && data.selectedListing ? data.history.map((point) => ({ symbol: data.selectedListing!.symbol, ...point })) : data.rows.flatMap((row) => row.history.map((point) => ({ symbol: row.symbol, ...point }))) }] };
23
- if (tab === "evidence") return { metadata, sections: [{ title: "Publication evidence", columns: [{ key: "symbol", header: "Ticker" },
25
+ if (tab === "evidence") return { metadata, freshness, sections: [{ title: "Publication evidence", columns: [{ key: "symbol", header: "Ticker" },
24
26
  { key: "periodStart", header: "Period start" }, { key: "periodEnd", header: "Period end" }, { key: "asOf", header: "Published" },
25
27
  { key: "confidence", header: "Quality" }, { key: "marketAsOf", header: "Market as of" }],
26
28
  rows: data.rows.map((row) => ({ symbol: row.symbol, ...row.evidence, baselinePeriods: row.baselinePeriods, marketAsOf: row.marketAsOf, news: row.news })) }] };
27
- return { metadata, sections: [{ title: tab === "abnormal" ? "Abnormal attention" : "Research ranking", columns: [
29
+ return { metadata, freshness, sections: [{ title: tab === "abnormal" ? "Abnormal attention" : "Research ranking", columns: [
28
30
  { key: "rank", header: "Rank" }, { key: "symbol", header: "Ticker" }, { key: "name", header: "Name" }, { key: "researchUnits", header: "Research hours" },
29
31
  { key: "sharePct", header: "Share %" }, { key: "zScore", header: "Latest-hour Z-score" }, { key: "priceChangePct", header: "Price %" },
30
32
  { key: "relativeVolume", header: "Relative volume" }, { key: "sector", header: "Sector" }, { key: "country", header: "Country" },
@@ -7,7 +7,7 @@ import { AttentionPane } from "./pane";
7
7
  export const attentionModule: PluginModule = {
8
8
  panes: [{ id: "attention", name: "Research Attention", icon: "A", component: AttentionPane, defaultPosition: "right", defaultMode: "floating",
9
9
  defaultFloatingSize: { width: 126, height: 32 }, tableExport: true, headless: attentionHeadless },
10
- { id: "attention-trending", name: "Gloom Trending", icon: "A", component: TrendingPane, defaultPosition: "right", defaultMode: "floating", defaultFloatingSize: { width: 58, height: 12 } }],
10
+ { id: "attention-trending", reportFreshness: { status: "not-a-feed", basis: "hourly publication" }, name: "Gloom Trending", icon: "A", component: TrendingPane, defaultPosition: "right", defaultMode: "floating", defaultFloatingSize: { width: 58, height: 12 } }],
11
11
  paneTemplates: [{ id: "attention-pane", paneId: "attention", label: "Research Attention",
12
12
  description: "Pro research attention: rankings, abnormal activity, sectors, countries and privacy-qualified hourly history.",
13
13
  keywords: ["attention", "trending", "research", "activity"], shortcut: { prefix: "ATTN", argKind: "text", argPlaceholder: "TICKER", argOptional: true },
@@ -159,7 +159,7 @@ export function AttentionPane({ width, height, focused }: PaneProps) {
159
159
  const cell = (row: AttentionRow | AttentionGroup | Locked, column: DataTableColumn, _index: number, state: { selected: boolean }): DataTableCell => {
160
160
  if (isLocked(row)) return desktop ? { text: "", content: <Blurred><Text fg={colors.textDim}>{column.id === "name" ? "Additional research" : "Hidden"}</Text></Blurred> }
161
161
  : { text: column.id === columns[0]!.id && row.id === "locked:0" ? "Pro" : "░░░", color: colors.textDim };
162
- if (column.id === "sharePct") return { ...shareCell(number(row.sharePct, 1), maxShare ? row.sharePct / maxShare : null, column.width, colors, state.selected, desktop), value: row.sharePct };
162
+ if (column.id === "sharePct") return { ...shareCell(number(row.sharePct, 1), maxShare ? row.sharePct / maxShare : null, column.width, colors, state.selected), value: row.sharePct };
163
163
  if ("symbol" in row) {
164
164
  const numeric = typeof row[column.id as keyof AttentionRow] === "number" ? row[column.id as keyof AttentionRow] as number : undefined;
165
165
  switch (column.id) {
@@ -15,6 +15,7 @@ const awardRecord = (row: AwardRow) => ({ id: row.id, date: row.awardDate, dateB
15
15
 
16
16
  export const awardsHeadless: HeadlessPaneDefinition<"bundle"> = {
17
17
  shape: "bundle", argument: { kind: "free-text", optional: true, placeholder: "ticker", description: "Optional verified listed-company ticker, including exchange suffix." },
18
+ freshness: { source: "Public procurement records", status: "not-a-feed", basis: "published awards" },
18
19
  discovery: { aliases: ["AWARDS"], dataRequirements: ["Verified Gloom Cloud account"],
19
20
  limitations: ["Pro dataset; free accounts receive a limited preview", "Published procurement records; source coverage varies by jurisdiction",
20
21
  "Currencies and prime awards, subawards and notices are separate", "Award obligations are not revenue or remaining backlog", "Unresolved recipients retain their legal names"] },
@@ -240,7 +240,7 @@ function AwardsView({ width, height, focused, symbol }: PaneProps & { symbol: st
240
240
  if (column.id === "contracts") return { text: item.row.count.toLocaleString("en-US"), value: item.row.count, color: colors.textDim };
241
241
  if (column.id === "scope") return { text: awardScope(item.row.source), color: colors.textDim };
242
242
  return item.row.sharePercent === null ? missingCell(colors)
243
- : { ...shareCell(`${item.row.sharePercent.toFixed(1)}%`, maxShare ? item.row.sharePercent / maxShare : null, column.width, colors, state.selected, desktop), value: item.row.sharePercent };
243
+ : { ...shareCell(`${item.row.sharePercent.toFixed(1)}%`, maxShare ? item.row.sharePercent / maxShare : null, column.width, colors, state.selected), value: item.row.sharePercent };
244
244
  }
245
245
  const award = item.row;
246
246
  if (column.id === "date") return { text: award.awardDate, value: award.awardDate };
@@ -8,6 +8,7 @@ import { parseRule } from "./rules";
8
8
 
9
9
  export const backtestHeadless: HeadlessPaneDefinition<"bundle"> = {
10
10
  shape: "bundle",
11
+ freshness: { status: "not-a-feed", basis: "backtest on daily closes", cadence: "daily", observedKey: "date", oldest: null },
11
12
  argument: { kind: "ticker", description: "Instrument to test" },
12
13
  describe: (args) => `BT ${args.symbols[0] ?? ""}`,
13
14
  discovery: {
@@ -32,6 +32,7 @@ export const bondCalculatorHeadless: HeadlessPaneDefinition<"bundle"> = {
32
32
  return {
33
33
  complete: errors.length === 0,
34
34
  errors,
35
+ freshness: { source: "Your inputs, US Treasury", status: "not-a-feed", basis: "calculator", asOf: result.spread?.asOf ?? null },
35
36
  metadata: { settlement: draft.settlement, terms: result.terms, source: "Manual bond inputs; Treasury par yields via Gloom Cloud / FRED",
36
37
  treasuryAsOf: result.spread?.asOf ?? null, percentile: null, percentileReason: "Hypothetical bond has no historical sample", units: "Prices and DV01 per 100 face", mode: draft.mode },
37
38
  sections: [
@@ -4,6 +4,7 @@ import type { PluginModule } from "../plugin-module";
4
4
  export const buildoutModule: PluginModule = {
5
5
  panes: [{
6
6
  id: "buildout",
7
+ reportFreshness: { status: "not-a-feed", basis: "infrastructure research" },
7
8
  name: "TheBuildout",
8
9
  icon: "T",
9
10
  component: BuildoutPane,
@@ -5,7 +5,9 @@ import { catalystCell, catalystChangeText, catalystDate, catalystQuery, catalyst
5
5
 
6
6
  function definition(litigation: boolean): HeadlessPaneDefinition<"bundle"> {
7
7
  return {
8
- shape: "bundle", argument: { kind: "ticker", optional: !litigation, description: litigation ? "Company ticker, including exchange-qualified international listings." : "Optional ticker; omit for market-wide events." },
8
+ shape: "bundle",
9
+ freshness: { source: litigation ? "Court and agency dockets" : "Regulator, court and trade records", status: "not-a-feed", basis: "published records" },
10
+ argument: { kind: "ticker", optional: !litigation, description: litigation ? "Company ticker, including exchange-qualified international listings." : "Optional ticker; omit for market-wide events." },
9
11
  options: [
10
12
  { key: "tab", type: "enum", values: [{ value: "calendar" }, { value: "changes" }], defaultValue: "calendar", description: "Dated events or observed revisions." },
11
13
  { key: "type", type: "enum", values: CATALYST_TYPES.map((value) => ({ value })), description: "Event type." },
@@ -89,6 +89,8 @@ export function createCdsHeadless(
89
89
  ): HeadlessPaneDefinition<"rows"> {
90
90
  return {
91
91
  shape: "rows",
92
+ // Public dissemination of swap trades, held back by rule for some trades.
93
+ freshness: { source: "DTCC", status: "delayed" },
92
94
  argument: {
93
95
  kind: "free-text",
94
96
  placeholder: "ticker or issuer",
@@ -6,6 +6,7 @@ export const centralBankRatesHeadless: HeadlessPaneDefinition<"bundle"> = {
6
6
  discovery: { aliases: ["CBR", "CBRT"], dataRequirements: ["Gloom Cloud central-bank-rates endpoint"],
7
7
  limitations: ["Published policy observations with individual dates", "Policy instruments differ", "Only US meeting dates are maintained"] },
8
8
  shape: "bundle", options: [], argument: { kind: "none" }, describe: "G20 central bank policy rates",
9
+ freshness: { source: "Central banks and BIS", status: "not-a-feed", basis: "published policy rates" },
9
10
  async load(_args, ctx) {
10
11
  const data = await fetchCentralBankRates(ctx.apiClient);
11
12
  const errors = policyNotices(data);
@@ -2,8 +2,10 @@ import { financialPeriodCoverage } from "../../../time-series/financial-period-c
2
2
  import { FINANCIAL_VINTAGE_NOTICE, SEC_EPS_BASIS_NOTICE } from "../../../utils/financial-statements";
3
3
  import { graphRowsForFinancials, summarizeResolvedSeries } from "../../../time-series/reporting";
4
4
  import { priceHistoryIntegrityNotices, chartPriceHistoryIntegrityNotices } from "../../../time-series/market";
5
- import type { HeadlessPaneContext, HeadlessPaneDefinition, HeadlessSeriesResult } from "../../../types/headless";
6
- import type { ChartResolutionResult, ChartSeriesSpec, ChartSpec } from "../../../time-series/types";
5
+ import type { HeadlessPaneContext, HeadlessPaneDefinition, HeadlessPaneFreshness, HeadlessSeries, HeadlessSeriesResult } from "../../../types/headless";
6
+ import type { CapabilitySeriesSource, ChartResolutionResult, ChartSeriesSpec, ChartSpec, ChartViewportSpec } from "../../../time-series/types";
7
+ import { resolveGeoChartSeries } from "../world-venue-map/geo-series";
8
+ import { GEO_SERIES_CAPABILITY_ID } from "./series-expression";
7
9
  import { mergePriceHistoryWindows, priceHistoryAcquisitionIdentity, priceHistoryTailAcquisition, resolveChartSpecData } from "../../../time-series/resolve";
8
10
  import { intersectChartResolutionSupport, isIntradayResolution, normalizeChartResolutionSupport, type ManualChartResolution } from "../../../time-series/resolution";
9
11
  import { intradaySessionDates, loadIntradayWindow, resolveIntradayRequest, type IntradayRequest, type IntradayWindow, type LoadedIntradayWindow } from "./session-history";
@@ -16,6 +18,7 @@ import { createChartSeriesResolver } from "../../../capabilities";
16
18
  import { parsePublicTickerKey, publicTickerKey, resolveExchangeTimeZone } from "../../../utils/exchanges";
17
19
  import { parseChartSpec } from "./chart-spec";
18
20
  import { paneSchemas } from "./headless-schema";
21
+ import { barHistoryFreshness, REPORTED_DATA } from "../shared/report-freshness";
19
22
 
20
23
  export interface ChartPaneModel extends HeadlessSeriesResult {
21
24
  /** The renderer consumes the full model; generic reports project series and metadata. */
@@ -37,6 +40,23 @@ export interface ChartPaneModel extends HeadlessSeriesResult {
37
40
  };
38
41
  }
39
42
 
43
+ /**
44
+ * Map series read straight from the Cloud client, so a report or screenshot
45
+ * charts them where plugin capability handlers are not running; every other
46
+ * capability series goes through the registry as before.
47
+ */
48
+ function headlessCapabilityResolver(context: HeadlessPaneContext) {
49
+ const registry = context.capabilities ? createChartSeriesResolver(context.capabilities) : null;
50
+ return async (source: CapabilitySeriesSource, viewport: ChartViewportSpec, spec: ChartSeriesSpec) => {
51
+ if (source.capabilityId === GEO_SERIES_CAPABILITY_ID) {
52
+ const request = <T,>(path: string, init?: RequestInit) => context.apiClient.geo<T>(path, { ...init, signal: init?.signal ?? context.signal });
53
+ return resolveGeoChartSeries(request, source.seriesId, viewport, context.signal);
54
+ }
55
+ if (!registry) throw new Error(`Chart series capability "${source.capabilityId}" is unavailable. Enable its plugin or provider.`);
56
+ return registry(source, viewport, spec);
57
+ };
58
+ }
59
+
40
60
  export async function loadChartPaneModel(
41
61
  spec: ChartSpec,
42
62
  context: HeadlessPaneContext,
@@ -101,7 +121,7 @@ export async function loadChartPaneModel(
101
121
  if (!primary || rank < primary.rank) primaryHistories.set(key, { key: variantKey, rank });
102
122
  }
103
123
  },
104
- ...(context.capabilities ? { resolveCapabilitySeries: createChartSeriesResolver(context.capabilities) } : {}),
124
+ resolveCapabilitySeries: headlessCapabilityResolver(context),
105
125
  loadFredSeries: async (request) => ({
106
126
  data: await context.apiClient.getCloudFredSeries(request.seriesId, {
107
127
  startDate: request.startDate,
@@ -189,6 +209,20 @@ export async function loadChartPaneModel(
189
209
  };
190
210
  }
191
211
 
212
+ /**
213
+ * Price series are bar histories, stale once bars of the coarsest size stop
214
+ * arriving; fundamentals, valuations and economic series are reported data.
215
+ */
216
+ function chartFreshness(series: readonly HeadlessSeries[]): HeadlessPaneFreshness {
217
+ const order = ["1wk", "1mo"];
218
+ const resolutions = series.map((entry) => (entry as HeadlessSeries & { historyResolution?: string }).historyResolution);
219
+ if (!series.length || resolutions.some((resolution) => !resolution)) return { ...REPORTED_DATA, basis: "reported and published data" };
220
+ const coarsest = resolutions.reduce((worst, resolution) => (
221
+ order.indexOf(resolution!) > order.indexOf(worst!) ? resolution : worst
222
+ ), resolutions[0]);
223
+ return barHistoryFreshness(coarsest);
224
+ }
225
+
192
226
  export function chartHeadless(template: keyof typeof paneSchemas): HeadlessPaneDefinition<"series"> {
193
227
  return {
194
228
  ...paneSchemas[template],
@@ -262,6 +296,7 @@ export function chartHeadless(template: keyof typeof paneSchemas): HeadlessPaneD
262
296
  }
263
297
  }
264
298
  model.snapshot.intradayHistories = intradayHistories;
299
+ model.freshness = chartFreshness(model.series);
265
300
  const priceDomainFailures = intradayHistories.flatMap(({ symbol, exchange, priceDomainFailure }) =>
266
301
  priceDomainFailure ? [{ symbol, exchange, ...priceDomainFailure }] : []);
267
302
  if (priceDomainFailures.length) {
@@ -253,7 +253,9 @@ const chartComposerTemplates: PaneTemplateDef[] = [
253
253
  label: "Chart Series",
254
254
  placeholder: "AAPL:price, MSFT:revenue, FRED:CPIAUCSL",
255
255
  type: "text",
256
- body: ["Enter comma-separated SYMBOL:field or FRED:series expressions."],
256
+ // Empty falls back to the active ticker in createInstance, as `G` with no argument does.
257
+ required: false,
258
+ body: ["Enter comma-separated SYMBOL:field or FRED:series expressions, or leave empty to chart the active ticker."],
257
259
  }],
258
260
  canCreate: () => true,
259
261
  createInstance: (context, options) => {
@@ -33,6 +33,14 @@ export const CHART_FIELD_IDS = {
33
33
  evEbitda: "valuation.evEbitda",
34
34
  } as const;
35
35
 
36
+ /** Series of things with a place (chokepoint transits, port calls), served with the map's layers. */
37
+ export const GEO_SERIES_CAPABILITY_ID = "geo-series";
38
+
39
+ /** `GEO:<series id or short alias>`, e.g. `GEO:SUEZ`. */
40
+ export function formatGeoSeriesExpression(seriesId: string): string {
41
+ return `GEO:${seriesId}`;
42
+ }
43
+
36
44
  export type ParsedSeriesExpression =
37
45
  | { kind: "security"; symbol: string; exchange?: string; fieldId: string; label?: string }
38
46
  | { kind: "economic"; provider: "fred"; seriesId: string; label?: string }
@@ -96,6 +104,12 @@ export function parseSeriesExpression(value: string): ParsedSeriesExpression | n
96
104
  ? { kind: "capability", capabilityId, seriesId }
97
105
  : null;
98
106
  }
107
+ if (parts[0]?.trim().toUpperCase() === "GEO") {
108
+ const seriesId = trimmed.slice(trimmed.indexOf(":") + 1).trim();
109
+ return parts.length >= 2 && isValidChartSeriesId(seriesId)
110
+ ? { kind: "capability", capabilityId: GEO_SERIES_CAPABILITY_ID, seriesId }
111
+ : null;
112
+ }
99
113
  if (parts[0]?.trim().toUpperCase() === "FRED") {
100
114
  const seriesId = parts.length === 2 ? parts[1]?.trim().toUpperCase() ?? "" : "";
101
115
  return /^[A-Z0-9._-]{1,80}$/.test(seriesId)
@@ -160,7 +174,7 @@ export function parseChartExpression(value: string): ParsedSeriesExpression[] {
160
174
  if (parsed) return parsed;
161
175
  const display = leg.trim() || "empty series";
162
176
  throw new Error(
163
- `Invalid chart series "${display}". Use SYMBOL, SYMBOL:field, FUT:code, UST:maturity, FRED:series, or CAP:capability-id:series-id.`,
177
+ `Invalid chart series "${display}". Use SYMBOL, SYMBOL:field, FUT:code, UST:maturity, FRED:series, GEO:series, or CAP:capability-id:series-id.`,
164
178
  );
165
179
  });
166
180
  }
@@ -168,7 +182,9 @@ export function parseChartExpression(value: string): ParsedSeriesExpression[] {
168
182
  export function formatSeriesExpression(series: ChartSeriesSpec): string {
169
183
  if (series.source.kind === "economic") return `FRED:${series.source.seriesId}`;
170
184
  if (series.source.kind === "capability") {
171
- return `CAP:${series.source.capabilityId}:${series.source.seriesId}`;
185
+ return series.source.capabilityId === GEO_SERIES_CAPABILITY_ID
186
+ ? formatGeoSeriesExpression(series.source.seriesId)
187
+ : `CAP:${series.source.capabilityId}:${series.source.seriesId}`;
172
188
  }
173
189
  return `${publicTickerKey(series.source.instrument.symbol, series.source.instrument.exchange)}:${series.source.fieldId}`;
174
190
  }
@@ -4,6 +4,8 @@ import type { AppConfig } from "../../../types/config";
4
4
  import { t } from "../../../i18n";
5
5
  import { chatController } from "./controller";
6
6
  import { formatChannelLabel } from "./channel-labels";
7
+ import { describeConversationStartError, knownConversationRefusal } from "./direct-messages";
8
+ import { buildChatUserByUsername } from "./content/user-map";
7
9
 
8
10
  export const DEFAULT_CHAT_CHANNEL_ID = "everyone";
9
11
  export const LAST_VISITED_CHAT_CHANNEL_KEY = "lastChatChannelId";
@@ -87,9 +89,23 @@ export async function openDmTargetFromCommand(ctx: GloomPluginContext, usernames
87
89
  openDefaultChatPane(ctx);
88
90
  return;
89
91
  }
90
- const channel = usernames.length === 1
91
- ? await chatController.openDirectChannel({ username: usernames[0] })
92
- : await chatController.openGroupChannel({ usernames });
92
+ // The command bar shows a thrown message as it is, so it says why.
93
+ const snapshot = chatController.getSnapshot();
94
+ const userByUsername = buildChatUserByUsername(snapshot.channels, snapshot.messages);
95
+ const refusal = knownConversationRefusal(usernames, {
96
+ userByUsername,
97
+ currentUserId: snapshot.user?.id,
98
+ channels: snapshot.channels,
99
+ });
100
+ if (refusal) throw new Error(refusal);
101
+ let channel: ChatChannel;
102
+ try {
103
+ channel = usernames.length === 1
104
+ ? await chatController.openDirectChannel({ username: usernames[0] })
105
+ : await chatController.openGroupChannel({ usernames });
106
+ } catch (error) {
107
+ throw new Error(describeConversationStartError(error, usernames, userByUsername));
108
+ }
93
109
  openChatChannelFromCommand(ctx, channel.id);
94
110
  }
95
111
 
@@ -1,4 +1,4 @@
1
- import { useCallback, useEffect, useRef, type Dispatch, type SetStateAction } from "react";
1
+ import { useCallback, useEffect, useLayoutEffect, useRef, type Dispatch, type SetStateAction } from "react";
2
2
  import type { TextareaRenderable } from "../../../../ui";
3
3
  import type { ChatMessage } from "../../../../api-client";
4
4
  import {
@@ -44,6 +44,7 @@ export function useChatComposerRuntime({
44
44
  useDefaultControllerChannel,
45
45
  draftAttachmentCount = 0,
46
46
  onPastedImagePaths,
47
+ onConversationStartError,
47
48
  }: {
48
49
  applyingExternalDraftRef: MutableRef<boolean>;
49
50
  blurInput: () => void;
@@ -74,6 +75,8 @@ export function useChatComposerRuntime({
74
75
  draftAttachmentCount?: number;
75
76
  /** Set where pasted file paths can attach (the terminal): the paths, and the text that named them. */
76
77
  onPastedImagePaths?: (paths: string[], pasted: string) => void;
78
+ /** A `/dm` or `/group` command the server refused, with the names it asked for. */
79
+ onConversationStartError?: (error: unknown, usernames: string[]) => void;
77
80
  }) {
78
81
  const replyToRef = useRef(replyTo);
79
82
  const draftAttachmentCountRef = useRef(draftAttachmentCount);
@@ -256,7 +259,7 @@ export function useChatComposerRuntime({
256
259
  if (composerCommand.draft) {
257
260
  controller.setChannelDraft(channel.id, composerCommand.draft);
258
261
  }
259
- }).catch(() => {});
262
+ }).catch((error: unknown) => onConversationStartError?.(error, [composerCommand.username]));
260
263
  return;
261
264
  }
262
265
  if (composerCommand?.kind === "group") {
@@ -268,7 +271,7 @@ export function useChatComposerRuntime({
268
271
  channelIdRef.current = channel.id;
269
272
  onChannelChange?.(channel.id);
270
273
  clearLocalComposer();
271
- }).catch(() => {});
274
+ }).catch((error: unknown) => onConversationStartError?.(error, composerCommand.usernames));
272
275
  return;
273
276
  }
274
277
  const sendChannelId = useDefaultControllerChannel ? channelId : channelIdRef.current;
@@ -289,6 +292,7 @@ export function useChatComposerRuntime({
289
292
  controller,
290
293
  inputValueRef,
291
294
  onChannelChange,
295
+ onConversationStartError,
292
296
  expandDirectSection,
293
297
  persistDraft,
294
298
  setEditingMessage,
@@ -345,20 +349,31 @@ export function useChatComposerRuntime({
345
349
  }
346
350
  }, [focused, inputFocused, inputRef]);
347
351
 
348
- useEffect(() => {
352
+ // The terminal textarea reports edits only through `onContentChange`. It
353
+ // mounts with the composer, which can come after this hook first runs (the
354
+ // saved session landing after the first render on a cold launch, sign-in or
355
+ // email verification finishing, a narrow pane going back to the thread), and
356
+ // a ref change rerenders nothing. So after every render, bind whichever
357
+ // textarea is there now, and let go of the one it replaced.
358
+ const commitLocalDraftRef = useRef(commitLocalDraft);
359
+ commitLocalDraftRef.current = commitLocalDraft;
360
+ const boundTextareaRef = useRef<TextareaRenderable | null>(null);
361
+ useLayoutEffect(() => {
349
362
  const textarea = inputRef.current;
363
+ const bound = boundTextareaRef.current;
364
+ if (textarea === bound) return;
365
+ if (bound) bound.onContentChange = undefined;
366
+ boundTextareaRef.current = textarea;
350
367
  if (!textarea) return;
351
-
352
368
  textarea.onContentChange = () => {
353
- commitLocalDraft(textarea.editBuffer.getText());
354
- };
355
-
356
- return () => {
357
- if (textarea) {
358
- textarea.onContentChange = undefined;
359
- }
369
+ commitLocalDraftRef.current(textarea.editBuffer.getText());
360
370
  };
361
- }, [commitLocalDraft, inputRef]);
371
+ });
372
+ useLayoutEffect(() => () => {
373
+ const bound = boundTextareaRef.current;
374
+ boundTextareaRef.current = null;
375
+ if (bound) bound.onContentChange = undefined;
376
+ }, []);
362
377
 
363
378
  useEffect(() => {
364
379
  if (canSend || !replyTo) return;