gloomberb 0.17.6 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (768) hide show
  1. package/README.md +2 -0
  2. package/README.zh-CN.md +2 -0
  3. package/package.json +6 -1
  4. package/patches/electrobun@1.18.1.patch +74 -0
  5. package/src/account/auth-model.ts +3 -2
  6. package/src/account/device-signin-dialog.tsx +38 -13
  7. package/src/account/device-signin.ts +2 -1
  8. package/src/account/upgrade-dialog.tsx +6 -2
  9. package/src/api-client/askg.ts +5 -3
  10. package/src/api-client/bank-figures.ts +73 -0
  11. package/src/api-client/credit-boards.ts +21 -1
  12. package/src/api-client/crypto-markets.ts +88 -1
  13. package/src/api-client/data.ts +104 -4
  14. package/src/api-client/debt-maturities.ts +18 -0
  15. package/src/api-client/equity-screener.ts +3 -0
  16. package/src/api-client/errors.ts +13 -0
  17. package/src/api-client/fund-facts.ts +72 -0
  18. package/src/api-client/futures-curve.ts +26 -3
  19. package/src/api-client/geo.ts +11 -1
  20. package/src/api-client/index.ts +25 -2
  21. package/src/api-client/insider-signals.ts +95 -11
  22. package/src/api-client/normalizers.ts +1 -0
  23. package/src/api-client/paths.ts +20 -1
  24. package/src/api-client/request.ts +11 -3
  25. package/src/api-client/research-activity.ts +15 -8
  26. package/src/api-client/socket.ts +6 -3
  27. package/src/api-client/supply-chain-graph.ts +2 -2
  28. package/src/api-client/supply-chain.ts +8 -0
  29. package/src/api-client/tape.ts +12 -0
  30. package/src/api-client/types.ts +66 -2
  31. package/src/api-client/upgrade-experiment.ts +4 -3
  32. package/src/api-client/wall-experiments.ts +5 -3
  33. package/src/api-client/wall-summary.ts +3 -1
  34. package/src/api-client/web-experiments.ts +5 -2
  35. package/src/api-client/yield-curves.ts +17 -0
  36. package/src/app/command-bar-intro.ts +38 -0
  37. package/src/app/keybindings/actions.ts +1 -1
  38. package/src/app/pane-runtime/pane-template-runtime.ts +35 -7
  39. package/src/app/pane-runtime/plugin-bindings.ts +4 -0
  40. package/src/app/pane-runtime/ticker-open-runtime.ts +4 -14
  41. package/src/app/pane-runtime/ticker-open-target.ts +31 -0
  42. package/src/app/runtime/desktop-deeplink.ts +3 -4
  43. package/src/app/runtime/plugin-bindings.ts +3 -2
  44. package/src/app/runtime/startup.ts +3 -4
  45. package/src/app/runtime/ticker-refresh.ts +13 -12
  46. package/src/app/runtime/update.ts +3 -2
  47. package/src/architecture/core-builtin-allowlist.json +0 -3
  48. package/src/architecture/silent-catch-allowlist.json +3 -0
  49. package/src/architecture/ui-literals-allowlist.json +186 -0
  50. package/src/architecture/ui-tokens-allowlist.json +40 -0
  51. package/src/ask-gloom/pane-context.ts +3 -1
  52. package/src/brokers/signed-in/catalog.ts +2 -1
  53. package/src/brokers/signed-in/client.ts +7 -2
  54. package/src/brokers/signed-in/sign-in-dialog.tsx +120 -26
  55. package/src/brokers/signed-in/sign-in.ts +22 -20
  56. package/src/brokers/sync-broker-instance.ts +2 -1
  57. package/src/capabilities/chart-series.ts +2 -0
  58. package/src/capabilities/registry.ts +1 -3
  59. package/src/cli/bank-section.ts +147 -0
  60. package/src/cli/base-converter.ts +5 -2
  61. package/src/cli/board-coins.ts +70 -0
  62. package/src/cli/commands/fred-series.ts +90 -0
  63. package/src/cli/commands/market.ts +340 -69
  64. package/src/cli/commands/news-search.ts +35 -2
  65. package/src/cli/commands/options-chain.ts +7 -5
  66. package/src/cli/commands/options-leaps.ts +3 -3
  67. package/src/cli/commands/overview.ts +78 -29
  68. package/src/cli/commands/plugins.ts +1 -0
  69. package/src/cli/commands/search.ts +87 -24
  70. package/src/cli/commands/system.ts +5 -2
  71. package/src/cli/commands/ticker.ts +337 -60
  72. package/src/cli/context.ts +2 -1
  73. package/src/cli/desktop-pane-shot.ts +11 -3
  74. package/src/cli/earnings-calendar.ts +2 -1
  75. package/src/cli/errors.ts +10 -0
  76. package/src/cli/export-source.ts +18 -3
  77. package/src/cli/glossary.ts +196 -14
  78. package/src/cli/history-rows.ts +60 -9
  79. package/src/cli/index-roots.ts +26 -0
  80. package/src/cli/index.ts +34 -9
  81. package/src/cli/known-gaps.ts +156 -22
  82. package/src/cli/listing-arg.ts +156 -12
  83. package/src/cli/listing-suggestion.ts +4 -2
  84. package/src/cli/name-entries.ts +76 -0
  85. package/src/cli/not-a-ticker.ts +15 -6
  86. package/src/cli/pane-functions/access-gate.ts +22 -0
  87. package/src/cli/pane-functions/capabilities.ts +62 -4
  88. package/src/cli/pane-functions/catalog.ts +94 -39
  89. package/src/cli/pane-functions/data.ts +6 -5
  90. package/src/cli/pane-functions/discovery.ts +1 -1
  91. package/src/cli/pane-functions/dom.ts +3 -3
  92. package/src/cli/pane-functions/freshness.ts +49 -8
  93. package/src/cli/pane-functions/function-help.ts +13 -10
  94. package/src/cli/pane-functions/headless.ts +177 -42
  95. package/src/cli/pane-functions/index.ts +64 -8
  96. package/src/cli/pane-functions/options.ts +17 -3
  97. package/src/cli/pane-functions/report-notices.ts +17 -3
  98. package/src/cli/pane-functions/resolver.ts +48 -13
  99. package/src/cli/pane-functions/screenshot.ts +124 -23
  100. package/src/cli/pane-functions/shot-options.ts +68 -0
  101. package/src/cli/perpetual-contract.ts +3 -1
  102. package/src/cli/report-tables.ts +10 -2
  103. package/src/cli/staged-tickers.ts +5 -0
  104. package/src/cli/statement-filings.ts +261 -0
  105. package/src/cli/symbol-args.ts +47 -8
  106. package/src/cli/symbol-list.ts +9 -2
  107. package/src/cli/symbol-rows.ts +269 -29
  108. package/src/cli/ticker-resolution.ts +148 -34
  109. package/src/cli/treasury-yields.ts +86 -0
  110. package/src/cli/types.ts +3 -0
  111. package/src/cli/uncovered-instrument.ts +20 -0
  112. package/src/components/chart/composite/axis-overlays.tsx +16 -9
  113. package/src/components/chart/composite/composite-chart.tsx +85 -6
  114. package/src/components/chart/composite/downsample.ts +19 -3
  115. package/src/components/chart/composite/format.ts +3 -0
  116. package/src/components/chart/composite/legend.tsx +155 -76
  117. package/src/components/chart/composite/panel-bitmap.ts +8 -2
  118. package/src/components/chart/composite/panel-surface.tsx +3 -3
  119. package/src/components/chart/composite/toolbar.tsx +12 -7
  120. package/src/components/chart/composite/types.ts +6 -0
  121. package/src/components/chart/composite/use-composite-chart-keyboard.ts +28 -1
  122. package/src/components/chart/curve/curve-surface.tsx +1 -1
  123. package/src/components/chart/static/series.ts +39 -0
  124. package/src/components/chart/static/trail-chart-surface.tsx +2 -1
  125. package/src/components/command-bar/commands/collection-list.ts +45 -15
  126. package/src/components/command-bar/commands/collection.ts +10 -3
  127. package/src/components/command-bar/commands/registry.ts +2 -2
  128. package/src/components/command-bar/list/badge.ts +4 -3
  129. package/src/components/command-bar/list/model.ts +5 -0
  130. package/src/components/command-bar/list/view.tsx +1 -1
  131. package/src/components/command-bar/panel/index.tsx +19 -8
  132. package/src/components/command-bar/panel/native-surface.ts +6 -4
  133. package/src/components/command-bar/panel/prompt-example.ts +22 -0
  134. package/src/components/command-bar/routes/root/provider-search.ts +3 -9
  135. package/src/components/command-bar/routes/root/results.ts +13 -0
  136. package/src/components/command-bar/routes/root/start-here.ts +90 -0
  137. package/src/components/command-bar/routes/ticker-search/results.ts +42 -3
  138. package/src/components/command-bar/routes/ticker-search/route.ts +3 -10
  139. package/src/components/command-bar/theme-picker.tsx +3 -1
  140. package/src/components/command-bar/workflow/builtin.ts +5 -1
  141. package/src/components/command-bar/workflow/collection-actions.ts +21 -12
  142. package/src/components/command-bar/workflow/ops.ts +21 -1
  143. package/src/{plugins/builtin/portfolio-list/command-bar.ts → components/command-bar/workflow/portfolio-position.ts} +42 -9
  144. package/src/components/command-bar/workflow/tickers.ts +6 -4
  145. package/src/components/feedback-dialog.tsx +1 -1
  146. package/src/components/form-modal/broker-step.tsx +7 -63
  147. package/src/components/form-modal/content.tsx +7 -2
  148. package/src/components/form-modal/field-row.tsx +6 -8
  149. package/src/components/form-modal/host.tsx +3 -3
  150. package/src/components/form-modal/model.ts +3 -0
  151. package/src/components/form-modal/routes.ts +17 -2
  152. package/src/components/index.ts +6 -6
  153. package/src/components/input-search-bar.tsx +43 -6
  154. package/src/components/layout/detached-pane-shell.tsx +0 -1
  155. package/src/components/layout/floating-pane.tsx +0 -1
  156. package/src/components/layout/header.tsx +8 -7
  157. package/src/components/layout/pane/footer/index.tsx +7 -4
  158. package/src/components/layout/pane/footer/model.ts +28 -2
  159. package/src/components/layout/pane/header.tsx +9 -19
  160. package/src/components/layout/pane/index.tsx +0 -1
  161. package/src/components/layout/pane/instrument-coverage-gate.tsx +57 -0
  162. package/src/components/layout/pane/pane-tabs.tsx +4 -3
  163. package/src/components/layout/pane/sizing.ts +9 -0
  164. package/src/components/layout/pane/ticker-fate-gate.tsx +8 -2
  165. package/src/components/layout/shell/pane/capture.ts +44 -20
  166. package/src/components/layout/status-bar.tsx +3 -6
  167. package/src/components/markdown-text.tsx +17 -2
  168. package/src/components/market-board/index.tsx +19 -8
  169. package/src/components/metric-treemap/heat-surface.tsx +2 -7
  170. package/src/components/onboarding/account-step/qr-panel.tsx +5 -2
  171. package/src/components/onboarding/onboarding-frame.tsx +24 -21
  172. package/src/components/onboarding/portfolio-step/positions-panel.tsx +20 -10
  173. package/src/components/onboarding/wizard-positions.ts +40 -11
  174. package/src/components/pane-settings-dialog/desktop.tsx +12 -50
  175. package/src/components/pane-settings-dialog/field-dialogs.tsx +1 -1
  176. package/src/components/price-performance.tsx +18 -2
  177. package/src/components/reader/article-reader.tsx +11 -10
  178. package/src/components/reader/detail-reader.tsx +9 -5
  179. package/src/components/reader/reader-text.tsx +51 -24
  180. package/src/components/sign-in-code-panel.tsx +129 -75
  181. package/src/components/ticker/badge/index.tsx +2 -1
  182. package/src/components/ui/action-row.tsx +5 -2
  183. package/src/components/ui/audio-player.tsx +70 -0
  184. package/src/components/ui/card.tsx +75 -0
  185. package/src/components/ui/data-table/index.tsx +4 -2
  186. package/src/components/ui/data-table/types.ts +11 -0
  187. package/src/components/ui/detail-scroll-body.tsx +1 -1
  188. package/src/components/ui/dialog-actions.tsx +1 -21
  189. package/src/components/ui/display.tsx +13 -5
  190. package/src/components/ui/external-link.tsx +4 -2
  191. package/src/components/ui/fields.tsx +12 -0
  192. package/src/components/ui/figure.tsx +5 -3
  193. package/src/components/ui/frame.tsx +40 -6
  194. package/src/components/ui/icon.tsx +4 -0
  195. package/src/components/ui/index.ts +4 -1
  196. package/src/components/ui/list-view.tsx +8 -0
  197. package/src/components/ui/prose.tsx +97 -25
  198. package/src/components/ui/query-bar-keys.tsx +3 -1
  199. package/src/components/ui/query-bar.tsx +6 -0
  200. package/src/components/ui/quote.ts +42 -0
  201. package/src/components/ui/range-track.tsx +15 -2
  202. package/src/components/ui/reveal-in-scroll-box.ts +21 -3
  203. package/src/components/ui/select-button.tsx +38 -3
  204. package/src/components/ui/status.tsx +73 -4
  205. package/src/components/ui/table-layout.ts +20 -0
  206. package/src/components/use-pinned-moment.ts +19 -0
  207. package/src/core/app-runtime.ts +2 -2
  208. package/src/core/state/app/instrument.ts +18 -1
  209. package/src/core/state/app/layout.ts +6 -0
  210. package/src/core/state/app/state.ts +14 -2
  211. package/src/data/cached-query.ts +1 -1
  212. package/src/data/config/chart-settings.ts +3 -1
  213. package/src/data/config/home.ts +4 -1
  214. package/src/data/config/store/node.ts +9 -4
  215. package/src/data/config/store/normalize.ts +9 -0
  216. package/src/data/json-storage.ts +6 -3
  217. package/src/data/json-ticker-repository.ts +3 -1
  218. package/src/data/plugin-cache.ts +5 -1
  219. package/src/data/sqlite/json.ts +3 -1
  220. package/src/data/ticker-repository.ts +5 -2
  221. package/src/feedback/diagnostics.ts +2 -6
  222. package/src/i18n/es.ts +86 -6
  223. package/src/i18n/index.ts +3 -9
  224. package/src/i18n/ja.ts +86 -6
  225. package/src/i18n/ko.ts +86 -6
  226. package/src/i18n/zh-cn.ts +86 -6
  227. package/src/i18n/zh-tw.ts +86 -6
  228. package/src/layout-marketplace/gallery-desktop.tsx +8 -4
  229. package/src/market-data/bars-per-year.ts +43 -0
  230. package/src/market-data/bond-funds.ts +85 -0
  231. package/src/market-data/coordinator/auxiliary.ts +5 -2
  232. package/src/market-data/coordinator/index.ts +6 -5
  233. package/src/market-data/futures-contract.ts +102 -5
  234. package/src/market-data/hooks.tsx +20 -11
  235. package/src/market-data/market/bar-period.ts +36 -0
  236. package/src/market-data/market/format.ts +5 -13
  237. package/src/market-data/market/freshness.ts +1 -3
  238. package/src/market-data/market/index-level.ts +51 -0
  239. package/src/market-data/model-dividend-yield.ts +57 -16
  240. package/src/market-data/quotes/live-valuation.ts +48 -2
  241. package/src/market-data/realized-volatility.ts +16 -7
  242. package/src/market-data/tax-equivalent.ts +344 -0
  243. package/src/news/aggregator.ts +4 -2
  244. package/src/notifications/notification-log.ts +5 -3
  245. package/src/plugins/auto-update-node.ts +1 -0
  246. package/src/plugins/builtin/account-management/footer.ts +1 -1
  247. package/src/plugins/builtin/account-management/keyboard.ts +3 -0
  248. package/src/plugins/builtin/account-management/model.ts +1 -0
  249. package/src/plugins/builtin/account-management/pane.tsx +71 -19
  250. package/src/plugins/builtin/account-management/trial-cancel.ts +40 -0
  251. package/src/plugins/builtin/alerts/cli.ts +7 -18
  252. package/src/plugins/builtin/alerts/constants.ts +8 -0
  253. package/src/plugins/builtin/alerts/event-rows.ts +16 -0
  254. package/src/plugins/builtin/alerts/events-pane.tsx +2 -14
  255. package/src/plugins/builtin/alerts/headless.ts +182 -0
  256. package/src/plugins/builtin/alerts/index.tsx +3 -0
  257. package/src/plugins/builtin/alerts/pane.tsx +1 -7
  258. package/src/plugins/builtin/alerts/storage.ts +17 -1
  259. package/src/plugins/builtin/analytics/index.tsx +6 -1
  260. package/src/plugins/builtin/analytics/metrics.ts +47 -9
  261. package/src/plugins/builtin/analytics/risk-headless.ts +14 -2
  262. package/src/plugins/builtin/analytics/risk-math.ts +83 -0
  263. package/src/plugins/builtin/analytics/risk-model.ts +97 -4
  264. package/src/plugins/builtin/analytics/risk-pane.tsx +11 -6
  265. package/src/plugins/builtin/analytics/sector-model.ts +14 -3
  266. package/src/plugins/builtin/awards/headless.ts +6 -5
  267. package/src/plugins/builtin/awards/index.tsx +1 -1
  268. package/src/plugins/builtin/backtest/client.ts +38 -8
  269. package/src/plugins/builtin/backtest/engine.ts +25 -13
  270. package/src/plugins/builtin/backtest/export.ts +27 -0
  271. package/src/plugins/builtin/backtest/format.ts +19 -3
  272. package/src/plugins/builtin/backtest/headless.ts +42 -28
  273. package/src/plugins/builtin/backtest/index.tsx +3 -0
  274. package/src/plugins/builtin/backtest/pane.tsx +39 -10
  275. package/src/plugins/builtin/backtest/report.ts +160 -0
  276. package/src/plugins/builtin/backtest/rules.ts +2 -0
  277. package/src/plugins/builtin/backtest/window.ts +112 -0
  278. package/src/plugins/builtin/bond-calculator/headless.ts +3 -2
  279. package/src/plugins/builtin/broker-manager/add-flow.tsx +4 -4
  280. package/src/plugins/builtin/catalysts/headless.ts +24 -13
  281. package/src/plugins/builtin/catalysts/index.tsx +4 -2
  282. package/src/plugins/builtin/catalysts/model.ts +18 -1
  283. package/src/plugins/builtin/catalysts/pane.tsx +2 -2
  284. package/src/plugins/builtin/cds/client.ts +28 -5
  285. package/src/plugins/builtin/cds/headless.ts +183 -31
  286. package/src/plugins/builtin/cds/index.tsx +1 -1
  287. package/src/plugins/builtin/cds/model.ts +229 -53
  288. package/src/plugins/builtin/cds/pane.tsx +82 -26
  289. package/src/plugins/builtin/central-bank-rates/headless.ts +1 -1
  290. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +39 -1
  291. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +77 -0
  292. package/src/plugins/builtin/chart-composer/chart-spec.ts +15 -0
  293. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +22 -2
  294. package/src/plugins/builtin/chart-composer/editor/desktop-view.tsx +2 -2
  295. package/src/plugins/builtin/chart-composer/headless-schema.ts +10 -2
  296. package/src/plugins/builtin/chart-composer/headless.ts +99 -21
  297. package/src/plugins/builtin/chart-composer/index.tsx +70 -13
  298. package/src/plugins/builtin/chart-composer/pane.tsx +65 -15
  299. package/src/plugins/builtin/chart-composer/presets.ts +79 -11
  300. package/src/plugins/builtin/chart-composer/series-catalog.ts +50 -14
  301. package/src/plugins/builtin/chart-composer/series-expression.ts +9 -7
  302. package/src/plugins/builtin/chart-composer/series-listings.ts +178 -0
  303. package/src/plugins/builtin/chart-composer/session-range.ts +87 -0
  304. package/src/plugins/builtin/chat/attachments/desktop.tsx +4 -1
  305. package/src/plugins/builtin/chat/content/composer-runtime.ts +49 -14
  306. package/src/plugins/builtin/chat/content/composer.tsx +22 -1
  307. package/src/plugins/builtin/chat/content/index.tsx +35 -5
  308. package/src/plugins/builtin/chat/content/layout-metrics.ts +3 -0
  309. package/src/plugins/builtin/chat/content/shortcuts.ts +32 -13
  310. package/src/plugins/builtin/chat/content/snapshot.ts +29 -6
  311. package/src/plugins/builtin/chat/ghost-user.ts +11 -3
  312. package/src/plugins/builtin/chat/layout.ts +2 -0
  313. package/src/plugins/builtin/chat/message/desktop.tsx +13 -5
  314. package/src/plugins/builtin/chat/message/header.tsx +26 -4
  315. package/src/plugins/builtin/chat/message/pane-chip.tsx +131 -35
  316. package/src/plugins/builtin/chat/message/render-state.ts +28 -1
  317. package/src/plugins/builtin/chat/message/terminal.tsx +9 -3
  318. package/src/plugins/builtin/chat/pane-links/composer.ts +87 -0
  319. package/src/plugins/builtin/chat/pane-links/model.ts +1 -1
  320. package/src/plugins/builtin/chat/share/flow.tsx +9 -73
  321. package/src/plugins/builtin/cloud/askg/controller.ts +5 -3
  322. package/src/plugins/builtin/cloud/askg/executor.ts +3 -1
  323. package/src/plugins/builtin/cloud/askg/lock-note.ts +16 -0
  324. package/src/plugins/builtin/cloud/askg/pane.tsx +6 -2
  325. package/src/plugins/builtin/cloud/auth-actions.tsx +4 -2
  326. package/src/plugins/builtin/cloud/company-picker.tsx +21 -26
  327. package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +5 -3
  328. package/src/plugins/builtin/cloud/plugin.tsx +2 -0
  329. package/src/plugins/builtin/cloud/team/module.tsx +5 -1
  330. package/src/plugins/builtin/cloud/team/pane.tsx +11 -4
  331. package/src/plugins/builtin/cloud/team/views.ts +11 -4
  332. package/src/plugins/builtin/cloud/terminal-relay/engine.ts +9 -4
  333. package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +3 -2
  334. package/src/plugins/builtin/cloud/thesis/detail.tsx +2 -1
  335. package/src/plugins/builtin/cloud/thesis/exposure.ts +3 -0
  336. package/src/plugins/builtin/cloud/thesis/prompts.tsx +3 -2
  337. package/src/plugins/builtin/cloud/thesis/ticker-tab.tsx +2 -1
  338. package/src/plugins/builtin/cloud/trial-offer-status-widget.tsx +2 -1
  339. package/src/plugins/builtin/cloud/verification-status-widget.tsx +2 -1
  340. package/src/plugins/builtin/commodities-energy/index.tsx +8 -5
  341. package/src/plugins/builtin/commodities-energy/view-state.ts +11 -0
  342. package/src/plugins/builtin/company-attention/headless.ts +15 -7
  343. package/src/plugins/builtin/company-attention/index.tsx +1 -1
  344. package/src/plugins/builtin/company-attention/model.ts +49 -4
  345. package/src/plugins/builtin/company-attention/pane.tsx +11 -9
  346. package/src/plugins/builtin/company-kpis/headless.ts +4 -3
  347. package/src/plugins/builtin/company-kpis/index.tsx +2 -2
  348. package/src/plugins/builtin/company-kpis/pane.tsx +9 -3
  349. package/src/plugins/builtin/congress-trades/headless.ts +23 -2
  350. package/src/plugins/builtin/correlation/relationship/pane.tsx +18 -46
  351. package/src/plugins/builtin/cot/headless.ts +5 -2
  352. package/src/plugins/builtin/credit-boards/cdx-pane.tsx +41 -13
  353. package/src/plugins/builtin/credit-boards/client.ts +9 -2
  354. package/src/plugins/builtin/credit-boards/headless.ts +93 -27
  355. package/src/plugins/builtin/credit-boards/index.tsx +15 -4
  356. package/src/plugins/builtin/credit-boards/model.ts +105 -6
  357. package/src/plugins/builtin/credit-boards/sovr-pane.tsx +14 -3
  358. package/src/plugins/builtin/credit-documents/detail.tsx +2 -1
  359. package/src/plugins/builtin/credit-documents/index.tsx +3 -0
  360. package/src/plugins/builtin/credit-documents/model.ts +3 -10
  361. package/src/plugins/builtin/crypto-board/client.ts +152 -2
  362. package/src/plugins/builtin/crypto-board/headless.ts +138 -19
  363. package/src/plugins/builtin/crypto-board/index.tsx +5 -3
  364. package/src/plugins/builtin/crypto-board/model.ts +210 -12
  365. package/src/plugins/builtin/crypto-board/pane.tsx +148 -9
  366. package/src/plugins/builtin/crypto-board/series.ts +52 -1
  367. package/src/plugins/builtin/crypto-board/supply.ts +123 -0
  368. package/src/plugins/builtin/debt-maturities/client.ts +54 -1
  369. package/src/plugins/builtin/debt-maturities/headless.ts +27 -3
  370. package/src/plugins/builtin/debt-maturities/index.tsx +2 -0
  371. package/src/plugins/builtin/debt-maturities/model.ts +58 -13
  372. package/src/plugins/builtin/debt-maturities/pane.tsx +47 -7
  373. package/src/plugins/builtin/dividend-yield/client.ts +42 -36
  374. package/src/plugins/builtin/dividend-yield/headless.ts +113 -18
  375. package/src/plugins/builtin/dividend-yield/index.tsx +5 -2
  376. package/src/plugins/builtin/dividend-yield/pane.tsx +37 -13
  377. package/src/plugins/builtin/dividend-yield/provider-client.ts +7 -3
  378. package/src/plugins/builtin/dividend-yield/ranking.ts +187 -0
  379. package/src/plugins/builtin/dividend-yield/reference-price.ts +28 -5
  380. package/src/plugins/builtin/dividend-yield/types.ts +6 -1
  381. package/src/plugins/builtin/dividend-yield/view.ts +1 -1
  382. package/src/plugins/builtin/docs/blocks.tsx +54 -8
  383. package/src/plugins/builtin/docs/pane.tsx +8 -13
  384. package/src/plugins/builtin/earnings/headless.ts +3 -2
  385. package/src/plugins/builtin/earnings-calls/data.ts +51 -0
  386. package/src/plugins/builtin/earnings-calls/headless.ts +7 -0
  387. package/src/plugins/builtin/earnings-calls/index.tsx +1 -0
  388. package/src/plugins/builtin/earnings-calls/model.ts +97 -0
  389. package/src/plugins/builtin/earnings-calls/pane.tsx +107 -7
  390. package/src/plugins/builtin/earnings-calls/transcript-view.tsx +140 -22
  391. package/src/plugins/builtin/earnings-calls/use-call-playback.ts +194 -0
  392. package/src/plugins/builtin/econ/calendar-model.ts +22 -0
  393. package/src/plugins/builtin/econ/calendar-source.ts +35 -0
  394. package/src/plugins/builtin/econ/index.tsx +40 -8
  395. package/src/plugins/builtin/econ-statistics/defs.ts +7 -0
  396. package/src/plugins/builtin/econ-statistics/detail.tsx +8 -1
  397. package/src/plugins/builtin/econ-statistics/headless.ts +26 -5
  398. package/src/plugins/builtin/econ-statistics/pane.tsx +4 -2
  399. package/src/plugins/builtin/econ-statistics/stats.ts +10 -0
  400. package/src/plugins/builtin/econ-statistics/view.ts +19 -0
  401. package/src/plugins/builtin/equity-screener/client.ts +1 -1
  402. package/src/plugins/builtin/equity-screener/model.ts +46 -4
  403. package/src/plugins/builtin/equity-screener/pane.tsx +3 -0
  404. package/src/plugins/builtin/estimate-revisions/client.ts +32 -22
  405. package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
  406. package/src/plugins/builtin/estimate-revisions/index.tsx +1 -0
  407. package/src/plugins/builtin/estimate-revisions/pane.tsx +5 -3
  408. package/src/plugins/builtin/executives/index.tsx +1 -0
  409. package/src/plugins/builtin/exposure/editor.tsx +3 -3
  410. package/src/plugins/builtin/fear-greed/index.tsx +9 -0
  411. package/src/plugins/builtin/filing-events/index.tsx +1 -0
  412. package/src/plugins/builtin/futures/index.tsx +2 -2
  413. package/src/plugins/builtin/futures/model.ts +34 -21
  414. package/src/plugins/builtin/futures/table.tsx +1 -1
  415. package/src/plugins/builtin/futures/use-board-terms.ts +2 -2
  416. package/src/plugins/builtin/futures-curve/headless.ts +4 -2
  417. package/src/plugins/builtin/futures-curve/model.ts +5 -7
  418. package/src/plugins/builtin/help/index.tsx +55 -8
  419. package/src/plugins/builtin/help/shortcut-table.tsx +15 -2
  420. package/src/plugins/builtin/holders/headless.ts +12 -0
  421. package/src/plugins/builtin/insider/headless.ts +311 -41
  422. package/src/plugins/builtin/insider/index.tsx +280 -106
  423. package/src/plugins/builtin/insider/insiders.tsx +224 -0
  424. package/src/plugins/builtin/insider/signals-cells.tsx +52 -0
  425. package/src/plugins/builtin/insider/signals-client.ts +135 -11
  426. package/src/plugins/builtin/insider/signals-model.ts +628 -56
  427. package/src/plugins/builtin/insider/signals.tsx +283 -83
  428. package/src/plugins/builtin/ipo-calendar/headless.ts +17 -7
  429. package/src/plugins/builtin/ipo-calendar/index.tsx +23 -3
  430. package/src/plugins/builtin/ipo-calendar/model.ts +84 -36
  431. package/src/plugins/builtin/ipo-calendar/pane.tsx +20 -8
  432. package/src/plugins/builtin/iv-history/headless.ts +2 -0
  433. package/src/plugins/builtin/jobs/headless.ts +1 -0
  434. package/src/plugins/builtin/jobs/index.tsx +1 -0
  435. package/src/plugins/builtin/jodi/headless.ts +2 -0
  436. package/src/plugins/builtin/kelly-sizer/pane.tsx +1 -1
  437. package/src/plugins/builtin/kelly-sizer/portfolio.ts +1 -1
  438. package/src/plugins/builtin/market-heatmap/headless.ts +1 -0
  439. package/src/plugins/builtin/market-heatmap/portfolio.ts +3 -1
  440. package/src/plugins/builtin/market-valuation/pane.tsx +1 -1
  441. package/src/plugins/builtin/market-valuation/zone-scale/desktop.tsx +31 -57
  442. package/src/plugins/builtin/mna/distress/headless.ts +2 -1
  443. package/src/plugins/builtin/mna/headless.ts +14 -2
  444. package/src/plugins/builtin/mna/index.tsx +1 -0
  445. package/src/plugins/builtin/news/headless.ts +4 -0
  446. package/src/plugins/builtin/news/wire/news/footer.ts +5 -3
  447. package/src/plugins/builtin/news/wire/news/table.tsx +57 -11
  448. package/src/plugins/builtin/notes/cli.ts +8 -4
  449. package/src/plugins/builtin/notes/files.ts +66 -20
  450. package/src/plugins/builtin/notes/migration.ts +18 -6
  451. package/src/plugins/builtin/notes/owner.tsx +3 -2
  452. package/src/plugins/builtin/notes/quick-notes-pane.tsx +3 -2
  453. package/src/plugins/builtin/options-scenario/client.ts +7 -4
  454. package/src/plugins/builtin/options-scenario/headless.ts +5 -3
  455. package/src/plugins/builtin/pe-band/index.tsx +1 -1
  456. package/src/plugins/builtin/pe-band/model.ts +1 -15
  457. package/src/plugins/builtin/perps/headless.ts +30 -13
  458. package/src/plugins/builtin/perps/model.ts +45 -3
  459. package/src/plugins/builtin/perps/pane.tsx +7 -7
  460. package/src/plugins/builtin/portfolio-list/cell-version.ts +10 -4
  461. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +128 -14
  462. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +108 -46
  463. package/src/plugins/builtin/portfolio-list/cli/render.ts +368 -45
  464. package/src/plugins/builtin/portfolio-list/cli/shared.ts +8 -2
  465. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +24 -34
  466. package/src/plugins/builtin/portfolio-list/grid.tsx +3 -1
  467. package/src/plugins/builtin/portfolio-list/headless.ts +151 -29
  468. package/src/plugins/builtin/portfolio-list/income.ts +296 -0
  469. package/src/plugins/builtin/portfolio-list/metrics.ts +2 -2
  470. package/src/plugins/builtin/portfolio-list/pane/futures-terms.ts +58 -0
  471. package/src/plugins/builtin/portfolio-list/pane/index.tsx +27 -10
  472. package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +47 -28
  473. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +3 -2
  474. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +10 -3
  475. package/src/plugins/builtin/portfolio-list/summary/index.tsx +26 -4
  476. package/src/plugins/builtin/portfolio-list/summary/totals.ts +31 -3
  477. package/src/plugins/builtin/portfolio-list/table.tsx +25 -5
  478. package/src/plugins/builtin/power/prices-headless.ts +2 -1
  479. package/src/plugins/builtin/realized-vol/chart-model.ts +29 -5
  480. package/src/plugins/builtin/realized-vol/charts.tsx +14 -8
  481. package/src/plugins/builtin/realized-vol/evidence.ts +2 -0
  482. package/src/plugins/builtin/realized-vol/headless.ts +6 -4
  483. package/src/plugins/builtin/realized-vol/model.ts +5 -1
  484. package/src/plugins/builtin/realized-vol/pane.tsx +31 -11
  485. package/src/plugins/builtin/realized-vol/settings.ts +1 -1
  486. package/src/plugins/builtin/research/analyst-headless.ts +4 -0
  487. package/src/plugins/builtin/research/corporate-actions-pane.tsx +2 -0
  488. package/src/plugins/builtin/research/event-model.ts +22 -2
  489. package/src/plugins/builtin/research/headless-schema.ts +1 -0
  490. package/src/plugins/builtin/research/headless.ts +3 -0
  491. package/src/plugins/builtin/research/index.tsx +3 -0
  492. package/src/plugins/builtin/research/relative-valuation-columns.ts +27 -5
  493. package/src/plugins/builtin/research/relative-valuation-headless.ts +2 -0
  494. package/src/plugins/builtin/revenue-breakdown/index.tsx +1 -0
  495. package/src/plugins/builtin/reverse-dcf/headless.ts +9 -6
  496. package/src/plugins/builtin/reverse-dcf/index.tsx +2 -2
  497. package/src/plugins/builtin/reverse-dcf/model.ts +51 -4
  498. package/src/plugins/builtin/reverse-dcf/pane.tsx +23 -10
  499. package/src/plugins/builtin/risk-factors/headless.ts +7 -0
  500. package/src/plugins/builtin/risk-factors/index.tsx +1 -0
  501. package/src/plugins/builtin/scanner/feed.ts +5 -3
  502. package/src/plugins/builtin/scanner/headless.ts +9 -57
  503. package/src/plugins/builtin/scanner/index.ts +1 -2
  504. package/src/plugins/builtin/sec/forms.ts +2 -6
  505. package/src/plugins/builtin/sec/fund-facts-view.tsx +53 -0
  506. package/src/plugins/builtin/sec/fund-facts.ts +328 -0
  507. package/src/plugins/builtin/sec/headless.ts +140 -44
  508. package/src/plugins/builtin/sec/index.tsx +95 -30
  509. package/src/plugins/builtin/sec/model.ts +2 -44
  510. package/src/plugins/builtin/shared/headless-options.ts +10 -0
  511. package/src/plugins/builtin/shared/locked-rows.tsx +3 -1
  512. package/src/plugins/builtin/shared/move-rank.ts +108 -0
  513. package/src/plugins/builtin/shared/report-freshness.ts +25 -9
  514. package/src/plugins/builtin/shared/scanner-capture.ts +95 -0
  515. package/src/plugins/builtin/shared/treasury-cutoffs.ts +15 -0
  516. package/src/plugins/builtin/shared/use-quote-board.ts +1 -0
  517. package/src/plugins/builtin/shared/volatility/live-session.ts +34 -0
  518. package/src/plugins/builtin/shared/volatility-indices.ts +32 -0
  519. package/src/plugins/builtin/short-interest/headless.ts +3 -0
  520. package/src/plugins/builtin/short-interest/watch-model.ts +2 -2
  521. package/src/plugins/builtin/social-mentions/client.ts +8 -1
  522. package/src/plugins/builtin/social-mentions/pane.tsx +8 -6
  523. package/src/plugins/builtin/supply-chain/client.ts +12 -3
  524. package/src/plugins/builtin/supply-chain/disclosure-quote.tsx +9 -5
  525. package/src/plugins/builtin/supply-chain/evidence.ts +3 -1
  526. package/src/plugins/builtin/supply-chain/flow-layout.ts +2 -1
  527. package/src/plugins/builtin/supply-chain/flow.tsx +23 -16
  528. package/src/plugins/builtin/supply-chain/graph-client.ts +8 -5
  529. package/src/plugins/builtin/supply-chain/graph-evidence.ts +1 -1
  530. package/src/plugins/builtin/supply-chain/graph-model.ts +10 -2
  531. package/src/plugins/builtin/supply-chain/graph-pane.tsx +9 -7
  532. package/src/plugins/builtin/supply-chain/graph.tsx +8 -6
  533. package/src/plugins/builtin/supply-chain/headless.ts +69 -27
  534. package/src/plugins/builtin/supply-chain/index.tsx +1 -1
  535. package/src/plugins/builtin/supply-chain/model.ts +76 -15
  536. package/src/plugins/builtin/supply-chain/pane.tsx +29 -15
  537. package/src/plugins/builtin/supply-chain/row-evidence.tsx +5 -4
  538. package/src/plugins/builtin/themes/model.ts +2 -5
  539. package/src/plugins/builtin/thirteenf/api.ts +50 -2
  540. package/src/plugins/builtin/thirteenf/data.ts +250 -11
  541. package/src/plugins/builtin/thirteenf/headless.ts +311 -28
  542. package/src/plugins/builtin/thirteenf/index.tsx +4 -1
  543. package/src/plugins/builtin/thirteenf/model.ts +244 -19
  544. package/src/plugins/builtin/thirteenf/overlap-pane.tsx +133 -33
  545. package/src/plugins/builtin/thirteenf/overlap.ts +1 -1
  546. package/src/plugins/builtin/thirteenf/pane.tsx +24 -5
  547. package/src/plugins/builtin/thirteenf/report-notes.ts +78 -0
  548. package/src/plugins/builtin/thirteenf/types.ts +49 -0
  549. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +22 -8
  550. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +17 -1
  551. package/src/plugins/builtin/ticker-detail/financials/model.ts +2 -42
  552. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +1 -1
  553. package/src/plugins/builtin/ticker-detail/headless.ts +23 -10
  554. package/src/plugins/builtin/ticker-detail/overview/components.tsx +27 -3
  555. package/src/plugins/builtin/ticker-detail/overview/dividend.ts +60 -0
  556. package/src/plugins/builtin/ticker-detail/overview/model.ts +46 -9
  557. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +3 -0
  558. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +36 -3
  559. package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +18 -19
  560. package/src/plugins/builtin/time-sales/client.ts +7 -4
  561. package/src/plugins/builtin/time-sales/headless.ts +71 -22
  562. package/src/plugins/builtin/time-sales/model.ts +12 -0
  563. package/src/plugins/builtin/time-sales/pane.tsx +31 -7
  564. package/src/plugins/builtin/time-sales/window.ts +128 -0
  565. package/src/plugins/builtin/trace-bonds/client.ts +351 -33
  566. package/src/plugins/builtin/trace-bonds/headless.ts +60 -22
  567. package/src/plugins/builtin/trace-bonds/index.tsx +4 -2
  568. package/src/plugins/builtin/trace-bonds/model.ts +27 -25
  569. package/src/plugins/builtin/trace-bonds/pane.tsx +63 -45
  570. package/src/plugins/builtin/treasury-auctions/cache.ts +61 -15
  571. package/src/plugins/builtin/treasury-auctions/client.ts +45 -10
  572. package/src/plugins/builtin/treasury-auctions/headless.ts +35 -13
  573. package/src/plugins/builtin/treasury-auctions/index.tsx +5 -2
  574. package/src/plugins/builtin/treasury-auctions/model.ts +20 -16
  575. package/src/plugins/builtin/treasury-auctions/pane.tsx +29 -12
  576. package/src/plugins/builtin/vol-surface/charts.tsx +2 -1
  577. package/src/plugins/builtin/vol-surface/headless.ts +3 -2
  578. package/src/plugins/builtin/vol-surface/pane.tsx +2 -1
  579. package/src/plugins/builtin/vol-surface/stored.ts +4 -7
  580. package/src/plugins/builtin/volatility/chart-model.ts +16 -15
  581. package/src/plugins/builtin/volatility/charts.tsx +5 -5
  582. package/src/plugins/builtin/volatility/client.ts +73 -2
  583. package/src/plugins/builtin/volatility/evidence.ts +13 -14
  584. package/src/plugins/builtin/volatility/headless.ts +13 -7
  585. package/src/plugins/builtin/volatility/index.tsx +1 -1
  586. package/src/plugins/builtin/volatility/model.ts +104 -38
  587. package/src/plugins/builtin/volatility/pane.tsx +42 -24
  588. package/src/plugins/builtin/volatility/series.ts +22 -13
  589. package/src/plugins/builtin/world-venue-map/geo-series.ts +9 -0
  590. package/src/plugins/builtin/world-venue-map/headless.ts +8 -5
  591. package/src/plugins/builtin/world-venue-map/index.ts +16 -2
  592. package/src/plugins/builtin/world-venue-map/map.tsx +13 -17
  593. package/src/plugins/builtin/yield-curve/curves.ts +29 -5
  594. package/src/plugins/builtin/yield-curve/headless.ts +41 -8
  595. package/src/plugins/builtin/yield-curve/history.ts +5 -5
  596. package/src/plugins/builtin/yield-curve/index.tsx +30 -13
  597. package/src/plugins/compat.ts +3 -1
  598. package/src/plugins/dependencies.ts +8 -2
  599. package/src/plugins/host-link.ts +12 -5
  600. package/src/plugins/installer.ts +16 -7
  601. package/src/plugins/loader.ts +9 -2
  602. package/src/plugins/marketplace/activation.ts +10 -4
  603. package/src/plugins/registry/host-actions.ts +3 -0
  604. package/src/plugins/registry/index.ts +3 -1
  605. package/src/{plugins/builtin/portfolio-list → portfolio}/allocation.ts +74 -12
  606. package/src/{plugins/builtin/portfolio-list → portfolio}/column-values.ts +140 -53
  607. package/src/portfolio/futures-positions.ts +213 -0
  608. package/src/portfolio/futures-terms.ts +75 -0
  609. package/src/portfolio/manual-lots.ts +78 -0
  610. package/src/portfolio/mutations.ts +54 -10
  611. package/src/portfolio/position-metrics.ts +44 -10
  612. package/src/portfolio/valuation-basis.ts +31 -4
  613. package/src/public/__snapshots__/public-api.test.ts.snap +4 -0
  614. package/src/public/time-series.ts +2 -1
  615. package/src/remote/confirm-change.tsx +2 -1
  616. package/src/remote/server.ts +1 -1
  617. package/src/remote/watchlist.ts +9 -1
  618. package/src/renderers/dom/data-table/row.tsx +1 -1
  619. package/src/renderers/dom/desktop/audio-player.tsx +312 -0
  620. package/src/renderers/dom/desktop/control-styles.ts +17 -82
  621. package/src/renderers/dom/desktop/controls.tsx +39 -63
  622. package/src/renderers/dom/desktop/dialog-actions.tsx +13 -53
  623. package/src/renderers/dom/desktop/icons.tsx +8 -0
  624. package/src/renderers/dom/desktop/list-view.tsx +6 -6
  625. package/src/renderers/dom/desktop/popover.tsx +0 -3
  626. package/src/renderers/dom/desktop/query-bar.tsx +6 -4
  627. package/src/renderers/dom/desktop/select-field.tsx +9 -8
  628. package/src/renderers/dom/desktop/stack-header.ts +3 -0
  629. package/src/renderers/dom/dom-ui-host.tsx +3 -2
  630. package/src/renderers/dom/host/chart-surface.tsx +3 -3
  631. package/src/renderers/dom/host/size-observer.ts +33 -4
  632. package/src/renderers/dom/host/surface-3d.tsx +3 -2
  633. package/src/renderers/dom/host/surface-fit.ts +4 -1
  634. package/src/renderers/dom/host/tabs.tsx +22 -132
  635. package/src/renderers/dom/styles.css +358 -160
  636. package/src/renderers/electrobun/bun/core-capabilities.ts +1 -1
  637. package/src/renderers/electrobun/bun/desktop/backend.ts +1 -1
  638. package/src/renderers/electrobun/bun/desktop/initialization.ts +1 -0
  639. package/src/renderers/electrobun/bun/desktop/state-broadcaster.ts +43 -1
  640. package/src/renderers/electrobun/bun/desktop/workspace/requests.ts +5 -1
  641. package/src/renderers/electrobun/shared/rpc-codec.ts +7 -0
  642. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +21 -17
  643. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +3 -3
  644. package/src/renderers/electrobun/view/desktop/window/bridge.ts +6 -8
  645. package/src/renderers/electrobun/view/desktop/window/snapshot.ts +18 -0
  646. package/src/series/capability.ts +1 -0
  647. package/src/series/files.ts +9 -3
  648. package/src/series/registry.ts +40 -14
  649. package/src/series/resolve.ts +121 -18
  650. package/src/series/standalone.ts +3 -2
  651. package/src/series/types.ts +55 -1
  652. package/src/series/validate.ts +39 -0
  653. package/src/shares/api.ts +26 -7
  654. package/src/shares/bug-report-dialog.tsx +2 -2
  655. package/src/shares/bug-report-flow.tsx +4 -7
  656. package/src/shares/capture-flow.ts +5 -4
  657. package/src/shares/capture-preview.tsx +2 -2
  658. package/src/shares/chat.ts +7 -27
  659. package/src/shares/flow.tsx +86 -40
  660. package/src/shares/location.ts +1 -3
  661. package/src/shares/pane-image.ts +11 -9
  662. package/src/shares/pane.ts +5 -2
  663. package/src/shares/payload.ts +1 -1
  664. package/src/shares/personal-pane.ts +3 -3
  665. package/src/shares/portable-layout.ts +9 -2
  666. package/src/shares/ready.ts +42 -0
  667. package/src/shares/test-harness.ts +62 -0
  668. package/src/sources/gloomberb-cloud/batched-lookups.ts +73 -0
  669. package/src/sources/gloomberb-cloud/index.ts +64 -12
  670. package/src/sources/gloomberb-cloud/normalizers.ts +31 -2
  671. package/src/sources/gloomberb-cloud/perpetuals.ts +20 -1
  672. package/src/sources/history-omitted.ts +34 -0
  673. package/src/sources/history-result.ts +3 -0
  674. package/src/sources/history-retention.ts +1 -1
  675. package/src/sources/provider-errors.ts +43 -1
  676. package/src/sources/provider-router/batches.ts +3 -2
  677. package/src/sources/provider-router/cache.ts +2 -1
  678. package/src/sources/provider-router/cached-routes.ts +9 -3
  679. package/src/sources/provider-router/history.ts +9 -8
  680. package/src/sources/provider-router/index.ts +18 -3
  681. package/src/sources/provider-router/primary.ts +5 -4
  682. package/src/sources/provider-router/quote-route.ts +3 -1
  683. package/src/sources/provider-router/routing.ts +2 -1
  684. package/src/sources/provider-router/search.ts +47 -13
  685. package/src/sources/provider-router/streaming.ts +7 -4
  686. package/src/sources/sec-edgar.ts +1 -3
  687. package/src/state/app/context/index.tsx +9 -13
  688. package/src/state/app/tab-cursor.ts +149 -12
  689. package/src/state/hooks/quote-streaming.ts +3 -2
  690. package/src/state/hooks/session-snapshot.ts +3 -2
  691. package/src/state/persist-scheduler.ts +12 -4
  692. package/src/sync/controller.ts +22 -1
  693. package/src/sync/core-contributors.ts +58 -15
  694. package/src/team/collections-sync.ts +14 -4
  695. package/src/team/collections.ts +40 -11
  696. package/src/team/store.ts +5 -4
  697. package/src/telemetry/attention-counts.ts +8 -2
  698. package/src/telemetry/crash-reports-dom.ts +3 -0
  699. package/src/telemetry/crash-reports-node.ts +7 -4
  700. package/src/telemetry/crash-reports.ts +11 -11
  701. package/src/telemetry/usage-counts.ts +16 -12
  702. package/src/theme/colors.ts +2 -0
  703. package/src/theme/font-scale.ts +2 -0
  704. package/src/theme/ui-tokens.ts +71 -0
  705. package/src/tickers/batched-lookups.ts +186 -0
  706. package/src/tickers/company-name-listing.ts +97 -0
  707. package/src/tickers/company-name.ts +13 -0
  708. package/src/tickers/instrument-coverage.ts +112 -0
  709. package/src/tickers/listing-fate.ts +49 -9
  710. package/src/tickers/listing-venues.ts +24 -5
  711. package/src/tickers/open-target.ts +13 -5
  712. package/src/tickers/search/index.ts +112 -35
  713. package/src/tickers/search/ranking.ts +49 -1
  714. package/src/tickers/terminal-codes.ts +79 -0
  715. package/src/tickers/ticker-changes.ts +74 -3
  716. package/src/tickers/us-listing.ts +2 -1
  717. package/src/time-series/chart-data.ts +79 -8
  718. package/src/time-series/fundamentals.ts +55 -7
  719. package/src/time-series/ice-credit.ts +17 -2
  720. package/src/time-series/live-bars.ts +21 -8
  721. package/src/time-series/live-quotes.ts +2 -3
  722. package/src/time-series/price-comparison.ts +6 -1
  723. package/src/time-series/resolve.ts +65 -10
  724. package/src/time-series/spec.ts +2 -1
  725. package/src/time-series/studies.ts +3 -3
  726. package/src/time-series/types.ts +22 -0
  727. package/src/time-series/use-chart-resolution.ts +2 -1
  728. package/src/types/config.ts +7 -0
  729. package/src/types/data-provider.ts +20 -0
  730. package/src/types/headless.ts +142 -1
  731. package/src/types/instrument.ts +6 -0
  732. package/src/types/plugin.ts +32 -9
  733. package/src/types/price-history.ts +5 -0
  734. package/src/types/ticker-changes.ts +19 -0
  735. package/src/types/ticker.ts +10 -2
  736. package/src/ui/context-menu.tsx +2 -0
  737. package/src/ui/host.tsx +40 -4
  738. package/src/ui/measured-cells.ts +13 -7
  739. package/src/ui/qr.ts +7 -5
  740. package/src/updater/index.ts +5 -5
  741. package/src/utils/calendar-date.ts +86 -27
  742. package/src/utils/currency-units.ts +17 -0
  743. package/src/utils/debug-log.ts +1 -1
  744. package/src/utils/dividend-cash.ts +48 -0
  745. package/src/utils/dom-screenshot-rasters.ts +3 -1
  746. package/src/utils/dom-screenshot.ts +14 -10
  747. package/src/utils/exchange-rate-snapshot.ts +9 -4
  748. package/src/utils/external-url.ts +1 -0
  749. package/src/utils/fiscal-period.ts +47 -0
  750. package/src/utils/format.ts +5 -2
  751. package/src/utils/forward-dividend.ts +160 -11
  752. package/src/utils/futures-generic.ts +34 -8
  753. package/src/utils/http-proxy-response.ts +2 -1
  754. package/src/utils/local-utc-offset.ts +2 -0
  755. package/src/utils/log-failure.ts +31 -0
  756. package/src/utils/option-expiry.ts +12 -12
  757. package/src/utils/price-history-integrity.ts +56 -0
  758. package/src/utils/price-history.ts +13 -1
  759. package/src/utils/sec-filings.ts +245 -0
  760. package/src/utils/selection-clipboard.ts +5 -2
  761. package/src/utils/throttled-fetch.ts +1 -0
  762. package/src/{plugins/builtin/dividend-yield/trailing-cash.ts → utils/trailing-dividend.ts} +55 -8
  763. package/src/utils/url.ts +1 -0
  764. package/src/utils/utc-time.ts +11 -0
  765. package/src/plugins/builtin/chat/share/targets.ts +0 -27
  766. package/src/renderers/dom/host/top-surface.ts +0 -119
  767. package/src/shares/dialog.tsx +0 -221
  768. package/src/shares/live.ts +0 -19
@@ -4,16 +4,15 @@ import { dryRunNote } from "../../../cli/helpers";
4
4
  import { requireArg, takeOption } from "../../../cli/commands/command-utils";
5
5
  import { EXCHANGE_OPTION, listingReadNotes, requireListingArg, type ListingArg } from "../../../cli/listing-arg";
6
6
  import { saveConfig } from "../../../data/config/store";
7
- import type { AppConfig } from "../../../types/config";
8
7
  import type { CliCommandContext, CliCommandDef } from "../../../types/plugin";
9
8
  import { getActiveQuoteDisplay } from "../../../market-data/market/status";
10
9
  import { settleWithin } from "../../../utils/async-deadline";
11
10
  import { cliStyles } from "../../../utils/cli-output";
12
11
  import { ambiguousNumberMessage, meantThousandsDot, parsePastedNumber, thousandsDotReadings, type ThousandsDotReadings } from "../../../utils/decimal-comma";
13
12
  import { newYorkToday } from "../earnings/board-model";
14
- import { createAlert, deserializeAlerts, rearmAlert, serializeAlerts } from "./alert-engine";
15
- import { ALERTS_KEY } from "./constants";
16
- import { EVENT_ALERTS_KEY, MAX_EVENT_ALERTS, eventAlertTarget, readEventAlerts, toggleEventAlert, type EventAlertRule } from "./events";
13
+ import { createAlert, rearmAlert, serializeAlerts } from "./alert-engine";
14
+ import { ALERTS_KEY, ALERTS_PLUGIN_ID } from "./constants";
15
+ import { EVENT_ALERTS_KEY, MAX_EVENT_ALERTS, eventAlertTarget, toggleEventAlert, type EventAlertRule } from "./events";
17
16
  import { alertKindLabel } from "./history";
18
17
  import { MAX_LEAD_DAYS, type MacroAlertEvent } from "./research-rules";
19
18
  import {
@@ -36,10 +35,9 @@ import {
36
35
  type ScheduledEventTarget,
37
36
  } from "./scheduled";
38
37
  import { scheduledEventSources } from "./scheduled-sources";
38
+ import { readAlertStores } from "./storage";
39
39
  import type { AlertCondition, AlertRule } from "./types";
40
40
 
41
- const ALERTS_PLUGIN_ID = "alerts";
42
-
43
41
  const ADD_USAGE = "Usage: gloomberb alerts add <symbol> <above|below|crosses> <price>, alerts add <symbol> earnings [--days <n>], or alerts add <CPI|FOMC> [--days <n>]";
44
42
  const DAYS_RULE = `--days takes a whole number of days from 1 to ${MAX_LEAD_DAYS}; without it the alert goes off 1 day before.`;
45
43
 
@@ -230,17 +228,6 @@ async function requireEventDate(
230
228
  return lookup.date;
231
229
  }
232
230
 
233
- function readAlertStores(config: AppConfig) {
234
- const pluginState = config.pluginConfig[ALERTS_PLUGIN_ID] ?? {};
235
- const rawPrice = pluginState[ALERTS_KEY];
236
- const rawEvents = pluginState[EVENT_ALERTS_KEY];
237
- return {
238
- pluginState,
239
- alerts: deserializeAlerts(typeof rawPrice === "string" ? rawPrice : "[]"),
240
- events: readEventAlerts(typeof rawEvents === "string" ? rawEvents : "[]"),
241
- };
242
- }
243
-
244
231
  export const alertsCliCommand: CliCommandDef = {
245
232
  name: "alerts",
246
233
  aliases: ["alert"],
@@ -385,10 +372,12 @@ export const alertsCliCommand: CliCommandDef = {
385
372
  await save({ events: [...rules, rule] });
386
373
  const eventDate = rule.eventDate!;
387
374
  const due = scheduledPhase(eventDate, scheduled.leadDays, undefined, today) === "due";
375
+ const delivery = scheduled.target.kind === "macro" ? ", only while it is running" : " while it is running, or on your phone with Cloud sync";
388
376
  ctx.printResult({ data: { changed: !ctx.cliOptions.dryRun, dryRun: ctx.cliOptions.dryRun, alert: rule }, ...(read.length > 0 ? { warnings: read } : {}) }, {
377
+ // Delivery, as docs/usage.md states it: CPI and FOMC notify in the running app only; earnings also reach the phone.
389
378
  text: (data) => `Added alert ${data.alert.id}: ${name} on ${eventDate}, ${plural(scheduled.leadDays, "day")} before (${due
390
379
  ? "already reached, so the app alerts at its next check"
391
- : `the app alerts on ${leadStartDate(eventDate, scheduled.leadDays)}`}).${dryRunNote(data.dryRun)}`,
380
+ : `the app alerts on ${leadStartDate(eventDate, scheduled.leadDays)}`}${delivery}).${dryRunNote(data.dryRun)}`,
392
381
  });
393
382
  return;
394
383
  }
@@ -1,4 +1,12 @@
1
+ export const ALERTS_PLUGIN_ID = "alerts";
1
2
  export const ALERTS_KEY = "alerts";
3
+
4
+ /** The Alerts pane's tabs: what `ALRT --tab` takes, and the pane state `tab` holds. */
5
+ export const ALERT_TABS = [
6
+ { label: "Prices", value: "prices" },
7
+ { label: "Events", value: "events" },
8
+ { label: "History", value: "history" },
9
+ ];
2
10
  /** Fallback cadence when the pane's Check interval setting is unset. */
3
11
  export const POLL_INTERVAL_MS = 30_000;
4
12
  export const POLL_SECONDS_KEY = "pollSeconds";
@@ -0,0 +1,16 @@
1
+ import { eventAlertTarget, type EventAlertRule } from "./events";
2
+ import { readScheduledRule, scheduledAlertStatus } from "./scheduled";
3
+
4
+ /** Earnings and macro event rules name the event day they wait for; the rest name what they follow. */
5
+ export function ruleTarget(rule: EventAlertRule): string {
6
+ const target = eventAlertTarget(rule);
7
+ if (!readScheduledRule(rule)) return target;
8
+ return `${target} · ${rule.eventDate ?? "date not known yet"}`;
9
+ }
10
+
11
+ /** The state word the Events tab shows: a scheduled rule is Alerted once it has gone off for its coming event. */
12
+ export function ruleState(rule: EventAlertRule, today: string): "Active" | "Paused" | "Alerted" {
13
+ const scheduled = readScheduledRule(rule);
14
+ const status = scheduled ? scheduledAlertStatus(rule, scheduled.leadDays, today) : rule.status;
15
+ return status === "paused" ? "Paused" : status === "triggered" ? "Alerted" : "Active";
16
+ }
@@ -21,6 +21,7 @@ import {
21
21
  toggleEventAlert,
22
22
  type EventAlertRule,
23
23
  } from "./events";
24
+ import { ruleState, ruleTarget } from "./event-rows";
24
25
  import { relativeTime } from "./format";
25
26
  import { alertKindLabel, fetchAlertHistory, ruleStateText } from "./history";
26
27
  import { isResearchAlertKind } from "./research-rules";
@@ -28,23 +29,10 @@ import { useAsyncResource } from "../../../public/react";
28
29
  import { usePlanAccess } from "../../../api-client/plan-access";
29
30
  import { useResearchCloudSession } from "../shared/research-cloud-session";
30
31
  import { newYorkToday } from "../earnings/board-model";
31
- import { readScheduledRule, rearmScheduledAlert, scheduledAlertStatus } from "./scheduled";
32
+ import { rearmScheduledAlert } from "./scheduled";
32
33
  import { checkScheduledEventAlertsNow } from "./scheduled-check";
33
34
  import { alertTarget, alertViewHints, eventRuleSubject, useOpenAlertTarget } from "./targets";
34
35
 
35
- /** Earnings and macro event rules name the event day they wait for; the rest name what they follow. */
36
- function ruleTarget(rule: EventAlertRule): string {
37
- const target = eventAlertTarget(rule);
38
- if (!readScheduledRule(rule)) return target;
39
- return `${target} · ${rule.eventDate ?? "date not known yet"}`;
40
- }
41
-
42
- function ruleState(rule: EventAlertRule, today: string): "Active" | "Paused" | "Alerted" {
43
- const scheduled = readScheduledRule(rule);
44
- const status = scheduled ? scheduledAlertStatus(rule, scheduled.leadDays, today) : rule.status;
45
- return status === "paused" ? "Paused" : status === "triggered" ? "Alerted" : "Active";
46
- }
47
-
48
36
  const columnsFor = (width: number, lastCheck: boolean): DataTableColumn[] => [
49
37
  { id: "kind", label: "Event", width: 15, align: "left" },
50
38
  { id: "target", label: "Following", width: 28, flexGrow: 1, align: "left" },
@@ -0,0 +1,182 @@
1
+ /**
2
+ * `gloomberb fn ALRT`: the Alerts pane's three tabs as reports. Prices lists
3
+ * the price alerts as the pane's table does, Events the event alerts (earnings,
4
+ * CPI and FOMC with their dates, filings, news, market moves), History the
5
+ * alerts delivered to the account over the last 90 days.
6
+ */
7
+ import type { HeadlessPaneColumn, HeadlessPaneContext, HeadlessPaneDefinition, HeadlessPaneRow, HeadlessRowsResult } from "../../../types/headless";
8
+ import type { PaneLock } from "../../../types/plugin";
9
+ import { newYorkToday } from "../earnings/board-model";
10
+ import { explainRefusal } from "../shared/cloud-denied";
11
+ import { ALERT_TABS, ALERTS_PLUGIN_ID } from "./constants";
12
+ import { ruleState } from "./event-rows";
13
+ import { eventAlertTarget, type EventAlertRule } from "./events";
14
+ import {
15
+ conditionLabel,
16
+ formatAlertDistance,
17
+ formatAlertTargetPrice,
18
+ formatCurrentPrice,
19
+ formatQuoteChecked,
20
+ relativeTime,
21
+ } from "./format";
22
+ import { alertKindLabel, validateAlertHistory, type AlertHistory, type AlertHistoryItem } from "./history";
23
+ import { readScheduledRule, scheduledEventName } from "./scheduled";
24
+ import { readAlertStores } from "./storage";
25
+ import type { AlertRule } from "./types";
26
+
27
+ type AlertsTab = "prices" | "events" | "history";
28
+
29
+ /** Pages of history one report reads; the pane reads more as it is scrolled. */
30
+ const HISTORY_PAGES = 5;
31
+
32
+ const plural = (count: number, word: string) => `${count} ${word}${count === 1 ? "" : "s"}`;
33
+ const asAlert = (row: HeadlessPaneRow) => row as unknown as AlertRule;
34
+ const text = (value: unknown) => (typeof value === "string" && value ? value : "");
35
+
36
+ /** The text report words each cell as the pane does; CSV and JSON keep the stored numbers and times. */
37
+ const PRICE_COLUMNS: HeadlessPaneColumn[] = [
38
+ { key: "status", header: "State", format: (value) => (value === "triggered" ? "Triggered" : "Active") },
39
+ { key: "symbol", header: "Symbol", format: (value, row) => (row.exchange ? `${text(value)}:${text(row.exchange)}` : text(value)) },
40
+ { key: "lastCheckedPrice", header: "Current", align: "right", textFormat: (_value, row) => formatCurrentPrice(asAlert(row), 14) },
41
+ { key: "targetPrice", header: "Target", align: "right", textFormat: (_value, row) => formatAlertTargetPrice(asAlert(row), 14) },
42
+ { key: "awayPercent", header: "Away", align: "right", textFormat: (_value, row) => formatAlertDistance(asAlert(row)) },
43
+ { key: "condition", header: "Trigger", format: (value) => conditionLabel(value as AlertRule["condition"]) },
44
+ { key: "lastCheckedAt", header: "Quote", textFormat: (_value, row) => formatQuoteChecked(asAlert(row)) },
45
+ { key: "triggeredAt", header: "Alerted", textFormat: (value) => (typeof value === "number" ? relativeTime(value) : "-") },
46
+ ];
47
+
48
+ const EVENT_COLUMNS: HeadlessPaneColumn[] = [
49
+ { key: "event", header: "Event" },
50
+ { key: "following", header: "Following" },
51
+ { key: "eventDate", header: "Event date", textFormat: (value, row) => text(value) || (row.leadDays == null ? "" : "not known yet") },
52
+ { key: "leadDays", header: "Days before", align: "right" },
53
+ { key: "state", header: "State" },
54
+ { key: "since", header: "Since" },
55
+ ];
56
+
57
+ const HISTORY_COLUMNS: HeadlessPaneColumn[] = [
58
+ { key: "deliveredAt", header: "Sent (UTC)", format: (value) => text(value).slice(0, 16).replace("T", " ") },
59
+ { key: "event", header: "Event" },
60
+ { key: "title", header: "Alert" },
61
+ { key: "body", header: "Detail" },
62
+ ];
63
+
64
+ /** A price alert as the Prices table lists it: the stored fields, without the quote's provider id, and the distance to target. */
65
+ function priceRow(alert: AlertRule): HeadlessPaneRow {
66
+ const { lastQuoteProviderId: _provider, ...stored } = alert;
67
+ const price = alert.lastCheckError ? null : alert.lastCheckedPrice;
68
+ const away = price == null || !Number.isFinite(price) || price === 0 ? null : ((alert.targetPrice - price) / price) * 100;
69
+ return { ...stored, awayPercent: away != null && Number.isFinite(away) ? away : null };
70
+ }
71
+
72
+ /** Active alerts first, then the ones that went off, latest first, as the pane orders them. */
73
+ function pricesResult(alerts: readonly AlertRule[], error: string | null, events: number): HeadlessRowsResult {
74
+ const active = alerts.filter((alert) => alert.status === "active");
75
+ const triggered = alerts.filter((alert) => alert.status === "triggered").sort((a, b) => (b.triggeredAt ?? 0) - (a.triggeredAt ?? 0));
76
+ return {
77
+ columns: PRICE_COLUMNS,
78
+ rows: [...active, ...triggered].map(priceRow),
79
+ empty: "No price alerts. Add one with gloomberb alerts add AAPL above 250.",
80
+ ...(error ? { errors: [error], complete: false } : {}),
81
+ ...(events > 0 ? { notes: [`${plural(events, "event alert")} not listed here: gloomberb fn ALRT --tab events`] } : {}),
82
+ };
83
+ }
84
+
85
+ /** An event alert as the Events table lists it: a scheduled one with its event date and lead time apart. */
86
+ function eventRow(rule: EventAlertRule, today: string): HeadlessPaneRow {
87
+ const scheduled = readScheduledRule(rule);
88
+ return {
89
+ id: rule.id,
90
+ kind: rule.kind,
91
+ event: alertKindLabel(rule.kind),
92
+ following: scheduled ? scheduledEventName(scheduled.target) : eventAlertTarget(rule),
93
+ eventDate: scheduled ? rule.eventDate ?? null : null,
94
+ leadDays: scheduled?.leadDays ?? null,
95
+ state: ruleState(rule, today),
96
+ since: new Date(rule.createdAt).toISOString().slice(0, 10),
97
+ };
98
+ }
99
+
100
+ function eventsResult(rules: readonly EventAlertRule[], error: string | null): HeadlessRowsResult {
101
+ const today = newYorkToday();
102
+ return {
103
+ columns: EVENT_COLUMNS,
104
+ rows: [...rules].sort((a, b) => b.createdAt - a.createdAt).map((rule) => eventRow(rule, today)),
105
+ empty: "No event alerts. Add one with gloomberb alerts add CRWV earnings --days 3 or gloomberb alerts add CPI --days 1.",
106
+ ...(error ? { errors: [error], complete: false } : {}),
107
+ };
108
+ }
109
+
110
+ function historyRow(item: AlertHistoryItem): HeadlessPaneRow {
111
+ return { id: item.id, deliveredAt: item.deliveredAt, kind: item.kind, event: alertKindLabel(item.kind), title: item.title, body: item.body };
112
+ }
113
+
114
+ /** What a signed-out read of History says: the tab is the account's own list of delivered alerts. */
115
+ export function alertHistoryLockNote({ verifyEmail }: PaneLock): string {
116
+ const account = verifyEmail
117
+ ? "verify your email (Ctrl+P, Resend Verification Email)"
118
+ : "log in or sign up free from the command bar (Ctrl+P, Log In or Sign Up)";
119
+ return [
120
+ `ALRT History needs a free Gloom sign-in: it lists the alerts Gloom delivered to your account over the last 90 days. ${verifyEmail ? "Until the email is verified" : "Signed out"} it shows none of them.`,
121
+ `To read it, open the app (gloomberb), ${account}; gloomberb fn ALRT --tab history then reads with that session.`,
122
+ ].join("\n");
123
+ }
124
+
125
+ async function historyResult(ctx: HeadlessPaneContext): Promise<HeadlessRowsResult> {
126
+ const items: AlertHistoryItem[] = [];
127
+ let first: AlertHistory | null = null;
128
+ let more = false;
129
+ try {
130
+ for (let offset: number | null = 0, page = 0; offset != null; page += 1) {
131
+ if (page === HISTORY_PAGES) {
132
+ more = true;
133
+ break;
134
+ }
135
+ const history: AlertHistory = validateAlertHistory(await ctx.apiClient.getMobileAlertHistory<unknown>(offset));
136
+ first ??= history;
137
+ if (history.status === "unavailable") break;
138
+ items.push(...history.items);
139
+ offset = history.hasMore ? history.nextOffset : null;
140
+ }
141
+ } catch (error) {
142
+ throw explainRefusal(error, alertHistoryLockNote, { symbol: null, token: "ALRT" });
143
+ }
144
+ const unavailable = first?.status === "unavailable";
145
+ return {
146
+ columns: HISTORY_COLUMNS,
147
+ rows: items.map(historyRow),
148
+ empty: "No alerts delivered in the last 90 days.",
149
+ freshness: { source: "Gloom Cloud", status: "not-a-feed", basis: "delivered alerts", ...(first ? { asOf: first.asOf } : {}) },
150
+ ...(unavailable ? { errors: [first?.warning ?? "Alert history is unavailable."], complete: false } : {}),
151
+ ...(more ? { notes: [`Showing the latest ${items.length} delivered alerts; the pane loads older ones as you scroll.`] } : {}),
152
+ metadata: { deviceEnabled: first?.deviceEnabled ?? null },
153
+ };
154
+ }
155
+
156
+ export const alertsHeadless: HeadlessPaneDefinition<"rows"> = {
157
+ shape: "rows",
158
+ description: "Your alerts: price alerts with current price and distance to target, event alerts (earnings, CPI and FOMC dates, filings, news, market moves) or the alerts delivered to your account.",
159
+ freshness: { source: "Your alerts", status: "not-a-feed", basis: "your alert rules" },
160
+ argument: { kind: "none" },
161
+ options: [{
162
+ key: "tab",
163
+ description: "Alerts tab: prices, events or history (delivered alerts, signed in).",
164
+ type: "enum",
165
+ values: ALERT_TABS.map(({ value }) => ({ value })),
166
+ defaultValue: "prices",
167
+ example: "--tab events",
168
+ pluginState: { pluginId: ALERTS_PLUGIN_ID, key: "tab" },
169
+ }],
170
+ discovery: {
171
+ screenshotReadiness: "live-dom",
172
+ dataRequirements: ["Your saved alerts; the History tab needs a Gloom sign-in"],
173
+ limitations: ["Current price and quote time are what the app saved at its last check, blank until it has checked the alert."],
174
+ },
175
+ describe: (args) => `Alerts | ${String(args.options.tab ?? "prices")}`,
176
+ async load(args, ctx) {
177
+ const tab = (args.options.tab ?? "prices") as AlertsTab;
178
+ if (tab === "history") return historyResult(ctx);
179
+ const { alerts, alertsError, events } = readAlertStores(ctx.config);
180
+ return tab === "events" ? eventsResult(events.rules, events.error) : pricesResult(alerts, alertsError, events.rules.length);
181
+ },
182
+ };
@@ -27,6 +27,7 @@ import {
27
27
  parseAlertShortcutValues,
28
28
  } from "./command";
29
29
  import { POLL_INTERVAL_MS, POLL_SECONDS_KEY } from "./constants";
30
+ import { alertHistoryLockNote, alertsHeadless } from "./headless";
30
31
  import { AlertsPane } from "./pane";
31
32
  import { alertsCliCommand } from "./cli";
32
33
  import {
@@ -317,6 +318,7 @@ export const alertsPlugin: GloomPlugin = {
317
318
  ctx.registerPane({
318
319
  id: "alerts",
319
320
  reportFreshness: { source: "Your alerts", status: "not-a-feed", basis: "your alert rules" },
321
+ reportLockNote: alertHistoryLockNote,
320
322
  name: "Alerts",
321
323
  icon: "A",
322
324
  component: AlertsPane,
@@ -349,6 +351,7 @@ export const alertsPlugin: GloomPlugin = {
349
351
  description: "Price, market and filing event alerts",
350
352
  keywords: ["alerts", "price", "trigger", "alarm", "watch", "notify"],
351
353
  shortcut: { prefix: "ALRT" },
354
+ headless: alertsHeadless,
352
355
  });
353
356
  },
354
357
 
@@ -28,7 +28,7 @@ import {
28
28
  serializeAlerts,
29
29
  } from "./alert-engine";
30
30
  import { parseAlertCommandValues } from "./command";
31
- import { ALERTS_KEY } from "./constants";
31
+ import { ALERT_TABS, ALERTS_KEY } from "./constants";
32
32
  import {
33
33
  conditionLabel,
34
34
  formatAlertDistance,
@@ -73,12 +73,6 @@ const ALERT_TABLE_CONTENT_WIDTH = ALERT_COLUMNS.reduce(
73
73
  2,
74
74
  );
75
75
 
76
- const ALERT_TABS = [
77
- { label: "Prices", value: "prices" },
78
- { label: "Events", value: "events" },
79
- { label: "History", value: "history" },
80
- ];
81
-
82
76
  export function AlertsPane(props: PaneProps) {
83
77
  const [tab, setTab] = usePluginPaneState<string>("tab", "prices");
84
78
  // A missed price alert opened from the Unread list selects its rule on Prices.
@@ -1,9 +1,12 @@
1
+ import type { AppConfig } from "../../../types/config";
1
2
  import type { GloomPluginContext } from "../../../types/plugin";
2
3
  import {
3
4
  deserializeAlerts,
5
+ readAlertsStoreError,
4
6
  serializeAlerts,
5
7
  } from "./alert-engine";
6
- import { ALERTS_KEY } from "./constants";
8
+ import { ALERTS_KEY, ALERTS_PLUGIN_ID } from "./constants";
9
+ import { EVENT_ALERTS_KEY, readEventAlerts } from "./events";
7
10
  import type { AlertRule } from "./types";
8
11
 
9
12
  export function loadAlerts(ctx: GloomPluginContext): AlertRule[] {
@@ -18,3 +21,16 @@ export function saveAlerts(
18
21
  ): void {
19
22
  ctx.configState.set(ALERTS_KEY, serializeAlerts(alerts));
20
23
  }
24
+
25
+ /** Both alert stores as the saved config holds them, for the CLI and the reports, which have no plugin context. */
26
+ export function readAlertStores(config: AppConfig) {
27
+ const pluginState = config.pluginConfig[ALERTS_PLUGIN_ID] ?? {};
28
+ const rawPrice = pluginState[ALERTS_KEY];
29
+ const rawEvents = pluginState[EVENT_ALERTS_KEY];
30
+ return {
31
+ pluginState,
32
+ alerts: deserializeAlerts(typeof rawPrice === "string" ? rawPrice : "[]"),
33
+ alertsError: typeof rawPrice === "string" ? readAlertsStoreError(rawPrice) : null,
34
+ events: readEventAlerts(typeof rawEvents === "string" ? rawEvents : "[]"),
35
+ };
36
+ }
@@ -257,6 +257,10 @@ function LegacyPortfolioAnalyticsPane({ focused, width, height }: PaneProps) {
257
257
  ...(sectorAllocation.unvaluedSymbols.length > 0 ? [{
258
258
  text: `Weights unavailable: missing prices or FX for ${sectorAllocation.unvaluedSymbols.join(", ")}.`, tone: "warning" as const,
259
259
  }] : []),
260
+ // Named once in the pane's notices: its totals and its sectors leave the same futures out.
261
+ ...(sectorAllocation.unsizedSymbols.length > 0 ? [{
262
+ text: `No contract size, so not valued: ${sectorAllocation.unsizedSymbols.join(", ")}.`, tone: "warning" as const,
263
+ }] : []),
260
264
  ];
261
265
  const sectorRows = sectorAllocation.rows;
262
266
  const sortedSectorRows = useMemo(
@@ -453,9 +457,10 @@ export const portfolioAnalyticsModule: PluginModule = {
453
457
  headless: portfolioRiskHeadless,
454
458
  tableExport: true,
455
459
  // The risk window reads as trailing until it is set.
456
- settings: (context) => ({ values: { riskSince: context.settings.riskSince ?? "trailing" }, fields: [
460
+ settings: (context) => ({ values: { riskSince: context.settings.riskSince ?? "trailing", riskWeights: context.settings.riskWeights ?? "13f" }, fields: [
457
461
  { key: "analyticsView", label: "View", type: "select", options: [{ value: "overview", label: "Overview" }, { value: "risk", label: "Risk depth" }] },
458
462
  { key: "riskSince", label: "Risk window", type: "select", options: [{ value: "trailing", label: "Trailing 60 sessions" }, { value: "filed", label: "Since 13F filing" }] },
463
+ { key: "riskWeights", label: "Since-filing weights", type: "select", options: [{ value: "13f", label: "13F weights, bought and held" }, { value: "current", label: "Current weights, held fixed" }] },
459
464
  { key: "riskEvidence", label: "Local evidence JSON", type: "text" },
460
465
  { key: "equityShift", label: "Index shift (%)", type: "text" },
461
466
  { key: "rateShift", label: "10Y shift (bp)", type: "text" },
@@ -138,23 +138,61 @@ function returnIntervalKey(point: DatedReturn): string {
138
138
  return `${point.startDateKey}/${point.dateKey}`;
139
139
  }
140
140
 
141
+ /** The intervals every series covers, and each series' return on them, in the first series' order. */
142
+ interface AlignedSeries {
143
+ series: DatedReturn[][];
144
+ lengths: number[];
145
+ points: DatedReturn[];
146
+ values: Float64Array[];
147
+ }
148
+
149
+ /**
150
+ * Lined-up holdings, kept with their series: weights move with every quote,
151
+ * the series only with their bars, so a portfolio valued again (each Cloud
152
+ * sync values every one, GLO-925) only weighs returns already lined up
153
+ * instead of matching every interval of every holding again. A few lists per
154
+ * first series, since one holding can open more than one portfolio.
155
+ */
156
+ const alignedByFirstSeries = new WeakMap<DatedReturn[], AlignedSeries[]>();
157
+
158
+ function alignSeries(series: DatedReturn[][]): AlignedSeries {
159
+ const kept = alignedByFirstSeries.get(series[0]!) ?? [];
160
+ const cached = kept.find((entry) => entry.series.length === series.length
161
+ && entry.series.every((returns, index) => returns === series[index] && entry.lengths[index] === returns.length));
162
+ if (cached) return cached;
163
+ const samples = series.map((returns) => new Map(returns
164
+ .filter(validReturnInterval)
165
+ .map((point) => [returnIntervalKey(point), point])));
166
+ const points: DatedReturn[] = [];
167
+ const columns: number[][] = series.map(() => []);
168
+ for (const [key, first] of samples[0]!) {
169
+ const row: number[] = [];
170
+ for (const sample of samples) {
171
+ const point = sample.get(key);
172
+ if (!point) break;
173
+ row.push(point.value);
174
+ }
175
+ if (row.length < samples.length) continue;
176
+ points.push(first);
177
+ row.forEach((value, index) => columns[index]!.push(value));
178
+ }
179
+ const aligned = { series: [...series], lengths: series.map((returns) => returns.length), points, values: columns.map((column) => Float64Array.from(column)) };
180
+ alignedByFirstSeries.set(series[0]!, [aligned, ...kept].slice(0, 4));
181
+ return aligned;
182
+ }
183
+
141
184
  export function computeWeightedPortfolioReturns(series: WeightedReturnSeries[]): DatedReturn[] {
142
185
  const holdings = series.filter((entry) => Number.isFinite(entry.weight) && entry.weight > 0);
143
186
  const totalWeight = holdings.reduce((sum, entry) => sum + entry.weight, 0);
144
187
  if (!holdings.length || !Number.isFinite(totalWeight) || totalWeight <= 0) return [];
145
- const samples = holdings.map((entry) => new Map(entry.returns
146
- .filter(validReturnInterval)
147
- .map((point) => [returnIntervalKey(point), point])));
188
+ const { points, values } = alignSeries(holdings.map((entry) => entry.returns));
148
189
  const returns: DatedReturn[] = [];
149
- for (const [key, first] of samples[0]!) {
190
+ for (let row = 0; row < points.length; row++) {
150
191
  let value = 0;
151
- let complete = true;
152
192
  for (let index = 0; index < holdings.length; index++) {
153
- const point = samples[index]!.get(key);
154
- if (!point) { complete = false; break; }
155
- value += point.value * (holdings[index]!.weight / totalWeight);
193
+ value += values[index]![row]! * (holdings[index]!.weight / totalWeight);
156
194
  }
157
- if (complete && Number.isFinite(value)) returns.push({ ...first, value });
195
+ if (Number.isFinite(value)) returns.push({ ...points[row]!, value });
158
196
  }
159
197
  return returns.sort((left, right) => left.dateKey.localeCompare(right.dateKey));
160
198
  }
@@ -17,6 +17,7 @@ import {
17
17
  riskPercentile,
18
18
  riskValue,
19
19
  sinceFallbackNote,
20
+ sinceFiledMethod,
20
21
  type PortfolioRiskModel,
21
22
  type RiskCoverage,
22
23
  type RiskDisplayRow,
@@ -142,6 +143,7 @@ export const portfolioRiskHeadless: HeadlessPaneDefinition<"bundle"> = {
142
143
  ],
143
144
  limitations: [
144
145
  `Fixed-current-weight USD equity basket over the holdings that qualify, largest ${RISK_HISTORY_LIMIT} by value; foreign listings convert to USD at daily FX closes; metadata.coverage states the covered share of market value and each holding left out.`,
146
+ "--since filed buys the 13F's own weights at the filing-date close and holds them (--weights current holds today's weights fixed instead).",
145
147
  "No account performance inferred.",
146
148
  "ETF price-return factor proxies.",
147
149
  "Historical percentiles need 20 rolling samples.",
@@ -163,6 +165,13 @@ export const portfolioRiskHeadless: HeadlessPaneDefinition<"bundle"> = {
163
165
  values: [{ value: "filed" }],
164
166
  description: "Risk rows since the 13F filing date of a portfolio made with portfolio import --13f, instead of the trailing 60 sessions.",
165
167
  },
168
+ {
169
+ key: "weights",
170
+ type: "enum",
171
+ settingKey: "riskWeights",
172
+ values: [{ value: "13f" }, { value: "current" }],
173
+ description: "With --since filed: 13f (when left out) buys the 13F's own weights at the filing-date close and holds them; current holds today's weights fixed over the same sessions.",
174
+ },
166
175
  {
167
176
  key: "evidence",
168
177
  type: "string",
@@ -254,16 +263,19 @@ export const portfolioRiskHeadless: HeadlessPaneDefinition<"bundle"> = {
254
263
  rates: Number(args.options["rate-shift"] ?? 100),
255
264
  volatility: Number(args.options["vol-shift"] ?? 10),
256
265
  },
257
- args.options.since === "filed" ? { since: "filed" } : {},
266
+ args.options.since === "filed"
267
+ ? { since: "filed", weights: args.options.weights === "current" ? "current" : "13f" }
268
+ : {},
258
269
  );
259
270
  // Options for views the report does not print are named, not dropped silently; the fallback from --since opens the report.
260
271
  const fallback = sinceFallbackNote(local.portfolio);
261
272
  const shifted = ["equity-shift", "rate-shift", "vol-shift"].filter((key) => args.options[key] != null);
262
273
  const notices = [
263
- ...(model.window.kind === "since-filed" ? [`Risk rows since the 13F filing on ${model.window.filed}, against ${model.benchmark}`] : []),
274
+ ...(model.window.kind === "since-filed" ? [sinceFiledMethod(model.window, model.benchmark)] : []),
264
275
  ...(args.options.since === "filed" && model.window.kind !== "since-filed" ? [fallback] : []),
265
276
  ...(requestedView && requestedView !== "stress" && shifted.length ? [`${shifted.map((key) => `--${key}`).join(", ")} change${shifted.length === 1 ? "s" : ""} the stress view only, not --view ${requestedView}`] : []),
266
277
  ...(requestedView && args.options.since != null && requestedView !== "risk" ? [`--since changes the risk view only, not --view ${requestedView}`] : []),
278
+ ...(args.options.weights != null && args.options.since !== "filed" ? ["--weights applies with --since filed only"] : []),
267
279
  ];
268
280
  // A basket view is complete only when the basket covers every holding.
269
281
  const covered = model.coverage.leftOut.length === 0;
@@ -340,6 +340,89 @@ export function sinceBasketRisk(
340
340
  });
341
341
  }
342
342
 
343
+ /** A held basket's daily returns, and why it stops or leaves a holding out when it does. */
344
+ export interface HeldBasket {
345
+ returns: DatedReturn[];
346
+ /**
347
+ * Set when the basket ends before the last session: the holding (its index
348
+ * in the input) whose daily closes end first, and the day they end.
349
+ */
350
+ cutShort: { holding: number; date: string } | null;
351
+ /** Holdings with no close on or before `since`, which cannot be bought at it and are left out. */
352
+ unpriced: number[];
353
+ }
354
+
355
+ /**
356
+ * Daily returns of a basket bought at the close on or before `since` (a 13F
357
+ * filing date) at `weights` and held: each holding's share drifts with its
358
+ * price, nothing is rebalanced. The basket is valued at every session of
359
+ * `calendar` (the benchmark's, so the two pair; the holdings' own dates when
360
+ * left out). A holding with no close for a session (a halt, a missing bar)
361
+ * holds its value flat, and its multi-day return lands on the session it
362
+ * arrives. The basket ends where the first holding's closes end, and says
363
+ * which.
364
+ */
365
+ export function buyAndHoldReturns(
366
+ holdings: readonly { weight: number; returns: readonly DatedReturn[] }[],
367
+ since: string,
368
+ calendar?: readonly DatedReturn[],
369
+ ): HeldBasket {
370
+ const unpriced: number[] = [];
371
+ // Each holding's price relative to its start close, by date, along its own unbroken run of closes.
372
+ const paths = holdings.flatMap((row, index) => {
373
+ if (!Number.isFinite(row.weight) || row.weight <= 0) return [];
374
+ const points = row.returns
375
+ .filter((point) => valid(point) && point.dateKey > since)
376
+ .toSorted((left, right) => left.dateKey.localeCompare(right.dateKey));
377
+ if (!points.length || points[0]!.startDateKey > since) {
378
+ unpriced.push(index);
379
+ return [];
380
+ }
381
+ const levels: Array<{ date: string; level: number }> = [];
382
+ let level = 1;
383
+ for (const [at, point] of points.entries()) {
384
+ if (at > 0 && point.startDateKey !== points[at - 1]!.dateKey) break;
385
+ level *= 1 + point.value;
386
+ levels.push({ date: point.dateKey, level });
387
+ }
388
+ return [{ index, weight: row.weight, start: points[0]!.startDateKey, levels }];
389
+ });
390
+ if (!paths.length) return { returns: [], cutShort: null, unpriced };
391
+ const sessions = (calendar
392
+ ? calendar.filter((point) => valid(point) && point.dateKey > since).map((point) => point.dateKey)
393
+ : [...new Set(paths.flatMap((path) => path.levels.map((point) => point.date)))]
394
+ ).toSorted();
395
+ // Known up to the earliest last close: past it a holding's value is unknown, not flat.
396
+ const last = paths.reduce((first, path) => (path.levels.at(-1)!.date < first.levels.at(-1)!.date ? path : first));
397
+ const end = last.levels.at(-1)!.date;
398
+ const total = paths.reduce((sum, path) => sum + path.weight, 0);
399
+ // The close the basket is bought at: the latest start close among the holdings.
400
+ const bought = paths.reduce((latest, path) => (path.start > latest ? path.start : latest), "");
401
+ const cursor = paths.map(() => -1);
402
+ const returns: DatedReturn[] = [];
403
+ let previous = { date: since, value: 1 };
404
+ for (const date of sessions) {
405
+ if (date > end) break;
406
+ let value = 0;
407
+ for (const [at, path] of paths.entries()) {
408
+ let next = cursor[at]!;
409
+ while (next + 1 < path.levels.length && path.levels[next + 1]!.date <= date) next += 1;
410
+ cursor[at] = next;
411
+ value += (path.weight / total) * (next < 0 ? 1 : path.levels[next]!.level);
412
+ }
413
+ const start = returns.length ? previous.date
414
+ : (calendar?.find((point) => point.dateKey === date)?.startDateKey ?? bought);
415
+ returns.push({ startDateKey: start, dateKey: date, value: value / previous.value - 1 });
416
+ previous = { date, value };
417
+ }
418
+ const lastSession = sessions.at(-1);
419
+ return {
420
+ returns,
421
+ cutShort: lastSession && end < lastSession ? { holding: last.index, date: end } : null,
422
+ unpriced,
423
+ };
424
+ }
425
+
343
426
  export function rollingBeta(
344
427
  asset: readonly DatedReturn[],
345
428
  factor: readonly DatedReturn[],