gloomberb 0.18.2 → 0.18.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (954) hide show
  1. package/README.md +8 -8
  2. package/README.zh-CN.md +11 -11
  3. package/bin/{gloomberb → gloom} +3 -1
  4. package/package.json +6 -2
  5. package/patches/electrobun@1.18.1.patch +106 -5
  6. package/src/account/checkout-handoff.tsx +225 -0
  7. package/src/account/device-signin-dialog.tsx +2 -2
  8. package/src/account/device-signin.ts +2 -2
  9. package/src/account/upgrade-dialog.tsx +1 -1
  10. package/src/api-client/askg.ts +2 -2
  11. package/src/api-client/auth.ts +2 -2
  12. package/src/api-client/central-bank-rates.ts +6 -0
  13. package/src/api-client/collections.ts +5 -1
  14. package/src/api-client/cot.ts +2 -0
  15. package/src/api-client/crypto-etf-flows.ts +37 -0
  16. package/src/api-client/crypto-markets.ts +60 -0
  17. package/src/api-client/data.ts +99 -5
  18. package/src/api-client/doe.ts +15 -0
  19. package/src/api-client/equity-screener.ts +28 -0
  20. package/src/api-client/exchange-announcements.ts +38 -0
  21. package/src/api-client/fund-facts.ts +39 -0
  22. package/src/api-client/futures-curve.ts +9 -1
  23. package/src/api-client/hiring.ts +301 -0
  24. package/src/api-client/index.ts +24 -5
  25. package/src/api-client/market-discovery.ts +14 -0
  26. package/src/api-client/members.ts +6 -0
  27. package/src/api-client/mna.ts +6 -0
  28. package/src/api-client/paths.ts +18 -1
  29. package/src/api-client/request.ts +26 -7
  30. package/src/api-client/short-side-publications.ts +37 -0
  31. package/src/api-client/socket.ts +64 -4
  32. package/src/api-client/swap-curve.ts +35 -0
  33. package/src/api-client/telemetry.ts +17 -0
  34. package/src/api-client/themes.ts +7 -1
  35. package/src/api-client/types.ts +90 -2
  36. package/src/app/global-shortcuts.ts +1 -16
  37. package/src/app/pane-runtime/plugin-bindings.ts +9 -2
  38. package/src/app/runtime/desktop-deeplink.ts +5 -5
  39. package/src/app/runtime/plugin-bindings.ts +2 -2
  40. package/src/app/runtime/startup.ts +13 -0
  41. package/src/app/runtime/update.ts +28 -8
  42. package/src/app/star-prompt/status-line.tsx +2 -2
  43. package/src/architecture/core-builtin-allowlist.json +5 -2
  44. package/src/architecture/pane-tabs-allowlist.json +65 -0
  45. package/src/architecture/ui-literals-allowlist.json +3 -3
  46. package/src/architecture/ui-tokens-allowlist.json +1 -1
  47. package/src/brokers/broker-portfolio-sync.ts +37 -0
  48. package/src/brokers/directory.ts +11 -0
  49. package/src/brokers/logos.ts +3 -1
  50. package/src/brokers/signed-in/adapter.ts +304 -26
  51. package/src/brokers/signed-in/client.ts +14 -2
  52. package/src/brokers/signed-in/connect.ts +10 -2
  53. package/src/brokers/sync-broker-instance.ts +9 -1
  54. package/src/capabilities/chart-series.ts +22 -6
  55. package/src/cli/bank-section.ts +1 -1
  56. package/src/cli/base-converter.ts +23 -14
  57. package/src/cli/central-bank-events.ts +1 -1
  58. package/src/cli/command-options.ts +59 -4
  59. package/src/cli/commands/api.ts +9 -6
  60. package/src/cli/commands/broker.ts +2 -2
  61. package/src/cli/commands/command-utils.ts +2 -2
  62. package/src/cli/commands/crypto-hints.ts +7 -20
  63. package/src/cli/commands/fred-series.ts +4 -2
  64. package/src/cli/commands/keybindings.ts +2 -2
  65. package/src/cli/commands/market.ts +1189 -296
  66. package/src/cli/commands/news-hints.ts +2 -2
  67. package/src/cli/commands/news-search.ts +59 -6
  68. package/src/cli/commands/options-leaps.ts +41 -26
  69. package/src/cli/commands/overview.ts +121 -48
  70. package/src/cli/commands/plugins.ts +9 -9
  71. package/src/cli/commands/remote.ts +13 -10
  72. package/src/cli/commands/search.ts +64 -44
  73. package/src/cli/commands/system.ts +27 -19
  74. package/src/cli/commands/themes.ts +1 -1
  75. package/src/cli/commands/ticker.ts +272 -70
  76. package/src/cli/context.ts +3 -2
  77. package/src/cli/desktop-pane-shot-view.ts +2 -2
  78. package/src/cli/desktop-pane-shot.ts +1 -1
  79. package/src/cli/earnings-calendar.ts +4 -4
  80. package/src/cli/entry.ts +18 -1
  81. package/src/cli/errors.ts +20 -2
  82. package/src/cli/exit-codes.ts +1 -1
  83. package/src/cli/export-source.ts +10 -4
  84. package/src/cli/freshness.ts +2 -8
  85. package/src/cli/fx-forward.ts +130 -0
  86. package/src/cli/fx-pair.ts +10 -9
  87. package/src/cli/glossary.ts +64 -20
  88. package/src/cli/help.ts +20 -14
  89. package/src/cli/history-export.ts +126 -0
  90. package/src/cli/history-rows.ts +196 -43
  91. package/src/cli/index-roots.ts +5 -45
  92. package/src/cli/index.ts +32 -18
  93. package/src/cli/issuer-membership.ts +103 -0
  94. package/src/cli/known-gaps.ts +118 -25
  95. package/src/cli/listing-arg.ts +315 -43
  96. package/src/cli/name-entries.ts +73 -22
  97. package/src/cli/native-smoke.ts +2 -0
  98. package/src/cli/not-a-ticker.ts +19 -9
  99. package/src/cli/opentui-libc.ts +5 -0
  100. package/src/cli/options.ts +12 -0
  101. package/src/cli/pane-functions/capabilities.ts +77 -20
  102. package/src/cli/pane-functions/catalog.ts +40 -23
  103. package/src/cli/pane-functions/discovery.ts +1 -1
  104. package/src/cli/pane-functions/dom.ts +12 -8
  105. package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
  106. package/src/cli/pane-functions/freshness.ts +174 -23
  107. package/src/cli/pane-functions/function-help.ts +66 -27
  108. package/src/cli/pane-functions/headless.ts +48 -16
  109. package/src/cli/pane-functions/index.ts +82 -21
  110. package/src/cli/pane-functions/options.ts +22 -2
  111. package/src/cli/pane-functions/report-notices.ts +12 -4
  112. package/src/cli/pane-functions/report.ts +5 -5
  113. package/src/cli/pane-functions/resolver.ts +65 -14
  114. package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
  115. package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
  116. package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
  117. package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
  118. package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
  119. package/src/cli/pane-functions/screenshot-payload.ts +453 -0
  120. package/src/cli/pane-functions/screenshot-render.ts +316 -0
  121. package/src/cli/pane-functions/screenshot-types.ts +162 -0
  122. package/src/cli/pane-functions/shot-options.ts +8 -3
  123. package/src/cli/peso-dollar-rates.ts +79 -0
  124. package/src/cli/quote-answer.ts +38 -3
  125. package/src/cli/report-tables.ts +190 -27
  126. package/src/cli/restore-plugins.ts +29 -14
  127. package/src/cli/result.ts +122 -25
  128. package/src/cli/series-search.ts +5 -5
  129. package/src/cli/statement-filings.ts +19 -0
  130. package/src/cli/suffixed-listing-rows.ts +49 -0
  131. package/src/cli/symbol-args.ts +50 -15
  132. package/src/cli/symbol-cells.ts +120 -0
  133. package/src/cli/symbol-list.ts +226 -60
  134. package/src/cli/symbol-rows.ts +131 -25
  135. package/src/cli/ticker-resolution.ts +108 -11
  136. package/src/cli/treasury-yields.ts +5 -5
  137. package/src/cli/types.ts +2 -0
  138. package/src/cli/uncovered-instrument.ts +3 -3
  139. package/src/cli/unknown-command.ts +6 -6
  140. package/src/components/chart/composite/chart-layout.ts +131 -0
  141. package/src/components/chart/composite/composite-chart.tsx +387 -21
  142. package/src/components/chart/composite/drawing-store.ts +26 -6
  143. package/src/components/chart/composite/interactions.ts +9 -3
  144. package/src/components/chart/composite/legend.tsx +75 -3
  145. package/src/components/chart/composite/levels.ts +5 -0
  146. package/src/components/chart/composite/panel-gestures.ts +41 -0
  147. package/src/components/chart/composite/panel-labels.ts +2 -1
  148. package/src/components/chart/composite/panel-surface.tsx +316 -11
  149. package/src/components/chart/composite/price-axis-labels.tsx +27 -3
  150. package/src/components/chart/composite/rasterizer.ts +44 -19
  151. package/src/components/chart/composite/scene.ts +16 -4
  152. package/src/components/chart/composite/text-renderer.ts +48 -21
  153. package/src/components/chart/composite/toolbar.tsx +52 -5
  154. package/src/components/chart/composite/types.ts +19 -0
  155. package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
  156. package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
  157. package/src/components/chart/composite/use-composite-viewport.ts +12 -3
  158. package/src/components/chart/composite/value-scale.ts +149 -0
  159. package/src/components/chart/composite/volume-profile-paint.ts +6 -3
  160. package/src/components/chart/core/pointer.ts +2 -0
  161. package/src/components/chart-table/index.ts +2 -0
  162. package/src/components/chart-table/read.tsx +74 -0
  163. package/src/components/command-bar/commands/collection-list.ts +41 -19
  164. package/src/components/command-bar/commands/collection.ts +9 -3
  165. package/src/components/command-bar/commands/direct/index.ts +1 -1
  166. package/src/components/command-bar/commands/direct/runtime.ts +3 -2
  167. package/src/components/command-bar/pane-templates/items.ts +59 -6
  168. package/src/components/command-bar/pane-templates/workflow.ts +10 -1
  169. package/src/components/command-bar/routes/root/command-items.ts +32 -6
  170. package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
  171. package/src/components/command-bar/routes/root/provider-search.ts +42 -11
  172. package/src/components/command-bar/routes/root/results.ts +18 -4
  173. package/src/components/command-bar/routes/root/runtime.ts +15 -3
  174. package/src/components/command-bar/routes/root/search-providers.ts +25 -2
  175. package/src/components/command-bar/routes/root/selection.ts +6 -1
  176. package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
  177. package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
  178. package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
  179. package/src/components/command-bar/selection-runtime.ts +50 -10
  180. package/src/components/command-bar/surface/index.tsx +24 -2
  181. package/src/components/command-bar/view-model.ts +7 -0
  182. package/src/components/command-bar/workflow/broker.ts +2 -2
  183. package/src/components/command-bar/workflow/collection-actions.ts +46 -7
  184. package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
  185. package/src/components/command-bar/workflow/fields.ts +8 -2
  186. package/src/components/command-bar/workflow/ops.ts +18 -4
  187. package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
  188. package/src/components/command-bar/workflow/submit.ts +3 -2
  189. package/src/components/command-bar/workflow/tickers.ts +5 -1
  190. package/src/components/company-logo.tsx +39 -0
  191. package/src/components/data-table/sections.ts +4 -2
  192. package/src/components/data-table/view.tsx +23 -3
  193. package/src/components/form-modal/confirm.tsx +2 -1
  194. package/src/components/form-modal/request.ts +5 -0
  195. package/src/components/form-modal/routes.ts +4 -1
  196. package/src/components/index.ts +13 -6
  197. package/src/components/layout/detached-pane-shell.tsx +1 -0
  198. package/src/components/layout/floating-pane.tsx +1 -0
  199. package/src/components/layout/header.tsx +234 -60
  200. package/src/components/layout/market-summary.ts +9 -6
  201. package/src/components/layout/pane/capture-status.ts +1 -1
  202. package/src/components/layout/pane/footer/model.ts +11 -5
  203. package/src/components/layout/pane/header.tsx +10 -3
  204. package/src/components/layout/pane/index.tsx +1 -0
  205. package/src/components/layout/pane/pane-tabs.tsx +9 -1
  206. package/src/components/layout/shell/chrome.ts +19 -6
  207. package/src/components/layout/shell/index.tsx +2 -1
  208. package/src/components/layout/shell/pane/layers.tsx +19 -1
  209. package/src/components/layout/status-bar.tsx +2 -2
  210. package/src/components/market-board/index.tsx +11 -3
  211. package/src/components/onboarding/onboarding-wizard.tsx +1 -0
  212. package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
  213. package/src/components/onboarding/wizard-broker-sync.ts +4 -1
  214. package/src/components/pane-settings-dialog/desktop.tsx +20 -7
  215. package/src/components/pane-settings-dialog/tui.tsx +17 -9
  216. package/src/components/pane-settings-dialog/value.ts +8 -1
  217. package/src/components/pane-settings-dialog.tsx +44 -13
  218. package/src/components/sign-in-code-panel.tsx +27 -19
  219. package/src/components/ui/column-grid.tsx +48 -4
  220. package/src/components/ui/country-flag-art.tsx +180 -0
  221. package/src/components/ui/country-flag.tsx +118 -12
  222. package/src/components/ui/data-table/opentui/index.tsx +61 -2
  223. package/src/components/ui/data-table/opentui/model.ts +109 -2
  224. package/src/components/ui/data-table/types.ts +1 -1
  225. package/src/components/ui/display.tsx +5 -1
  226. package/src/components/ui/index.ts +3 -1
  227. package/src/components/ui/logo-mark.tsx +11 -2
  228. package/src/components/ui/query-bar.tsx +1 -1
  229. package/src/components/ui/row-notes.ts +79 -0
  230. package/src/components/ui/stat-grid.tsx +28 -3
  231. package/src/components/ui/status.tsx +3 -1
  232. package/src/core/app-services.ts +4 -0
  233. package/src/core/state/app/layout.ts +4 -4
  234. package/src/data/cached-query.ts +8 -1
  235. package/src/data/config/chart-settings.ts +3 -3
  236. package/src/data/config/home.ts +10 -2
  237. package/src/data/config/layout.ts +4 -1
  238. package/src/data/config/store/node.ts +4 -0
  239. package/src/data/config/store/normalize.ts +13 -3
  240. package/src/data/config/store/portfolio-as-of-column.ts +2 -2
  241. package/src/data/json-storage.ts +2 -0
  242. package/src/data/saved-copies.ts +84 -0
  243. package/src/docs/snapshot.json +65 -32
  244. package/src/i18n/es.ts +51 -12
  245. package/src/i18n/ja.ts +51 -12
  246. package/src/i18n/ko.ts +51 -12
  247. package/src/i18n/zh-cn.ts +51 -12
  248. package/src/i18n/zh-tw.ts +51 -12
  249. package/src/layout/desks.ts +1 -1
  250. package/src/layout/launch-layout.ts +1 -1
  251. package/src/layout/pane-manager/floating-actions.ts +5 -3
  252. package/src/layout/pane-manager/floating.ts +43 -1
  253. package/src/layout/pane-manager/index.ts +2 -0
  254. package/src/layout/selected-ticker.ts +74 -0
  255. package/src/market-data/depositary-pair.ts +251 -0
  256. package/src/market-data/futures-board.ts +1 -1
  257. package/src/market-data/futures-contract.ts +124 -40
  258. package/src/market-data/fx-closes.ts +17 -2
  259. package/src/market-data/hooks.tsx +19 -11
  260. package/src/market-data/market/change-basis.ts +49 -7
  261. package/src/market-data/market/freshness.ts +34 -5
  262. package/src/market-data/market/period-return.ts +163 -0
  263. package/src/market-data/market/trading-sessions.ts +13 -0
  264. package/src/market-data/market/year-to-date.ts +8 -13
  265. package/src/market-data/performance.ts +20 -14
  266. package/src/market-data/perpetual-premium.ts +32 -0
  267. package/src/market-data/published-apac-sessions.ts +2 -1
  268. package/src/market-data/published-futures-sessions.ts +69 -0
  269. package/src/market-data/quotes/contributions.ts +5 -1
  270. package/src/market-data/quotes/freshness.ts +42 -0
  271. package/src/market-data/quotes/intraday-bar.ts +37 -0
  272. package/src/market-data/quotes/regular-session-valuation.ts +13 -8
  273. package/src/market-data/quotes/resolution.ts +4 -2
  274. package/src/market-data/tax-equivalent.ts +1 -1
  275. package/src/market-data/ticker-price-returns.ts +3 -1
  276. package/src/news/aggregator.ts +5 -1
  277. package/src/news/news-model.ts +4 -0
  278. package/src/news/types.ts +11 -0
  279. package/src/notifications/app-notifier.ts +1 -1
  280. package/src/plugins/auto-update.ts +2 -2
  281. package/src/plugins/builtin/account-management/index.tsx +1 -0
  282. package/src/plugins/builtin/account-management/pane.tsx +9 -8
  283. package/src/plugins/builtin/alerts/alert-engine.ts +30 -18
  284. package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
  285. package/src/plugins/builtin/alerts/cli.ts +485 -76
  286. package/src/plugins/builtin/alerts/command.ts +5 -10
  287. package/src/plugins/builtin/alerts/event-rows.ts +9 -5
  288. package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
  289. package/src/plugins/builtin/alerts/events.ts +108 -5
  290. package/src/plugins/builtin/alerts/fired-log.ts +78 -0
  291. package/src/plugins/builtin/alerts/format.ts +2 -1
  292. package/src/plugins/builtin/alerts/headless.ts +100 -39
  293. package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
  294. package/src/plugins/builtin/alerts/history-rows.ts +89 -0
  295. package/src/plugins/builtin/alerts/index.tsx +45 -18
  296. package/src/plugins/builtin/alerts/iv-level.ts +365 -0
  297. package/src/plugins/builtin/alerts/levels.ts +3 -3
  298. package/src/plugins/builtin/alerts/pane.tsx +97 -29
  299. package/src/plugins/builtin/alerts/price.ts +35 -0
  300. package/src/plugins/builtin/alerts/quotes.ts +24 -0
  301. package/src/plugins/builtin/alerts/research-builder.ts +84 -11
  302. package/src/plugins/builtin/alerts/research-rules.ts +77 -3
  303. package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
  304. package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
  305. package/src/plugins/builtin/alerts/scheduled.ts +188 -29
  306. package/src/plugins/builtin/alerts/storage.ts +13 -10
  307. package/src/plugins/builtin/alerts/targets.ts +12 -3
  308. package/src/plugins/builtin/analytics/index.tsx +8 -2
  309. package/src/plugins/builtin/analytics/metrics.ts +1 -1
  310. package/src/plugins/builtin/analytics/risk-book.ts +215 -0
  311. package/src/plugins/builtin/analytics/risk-client.ts +13 -6
  312. package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
  313. package/src/plugins/builtin/analytics/risk-math.ts +6 -3
  314. package/src/plugins/builtin/analytics/risk-model.ts +297 -104
  315. package/src/plugins/builtin/analytics/risk-options.ts +17 -2
  316. package/src/plugins/builtin/analytics/risk-pane.tsx +107 -43
  317. package/src/plugins/builtin/attention/pane.tsx +22 -16
  318. package/src/plugins/builtin/awards/headless.ts +7 -3
  319. package/src/plugins/builtin/awards/model.ts +18 -0
  320. package/src/plugins/builtin/awards/pane.tsx +12 -9
  321. package/src/plugins/builtin/backtest/export.ts +1 -1
  322. package/src/plugins/builtin/backtest/headless.ts +3 -3
  323. package/src/plugins/builtin/backtest/rules.ts +41 -5
  324. package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
  325. package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
  326. package/src/plugins/builtin/broker-manager/footer.ts +27 -11
  327. package/src/plugins/builtin/broker-manager/index.tsx +21 -12
  328. package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
  329. package/src/plugins/builtin/broker-manager/model.ts +12 -2
  330. package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
  331. package/src/plugins/builtin/broker-manager/table.ts +28 -12
  332. package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
  333. package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
  334. package/src/plugins/builtin/broker-trading/controller.ts +45 -13
  335. package/src/plugins/builtin/broker-trading/dock.tsx +24 -4
  336. package/src/plugins/builtin/broker-trading/headless.ts +2 -1
  337. package/src/plugins/builtin/broker-trading/index.tsx +7 -1
  338. package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
  339. package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
  340. package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
  341. package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
  342. package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
  343. package/src/plugins/builtin/broker-trading/pane.tsx +115 -26
  344. package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
  345. package/src/plugins/builtin/broker-trading/ticket.tsx +122 -36
  346. package/src/plugins/builtin/buildout/cells.tsx +4 -0
  347. package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
  348. package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
  349. package/src/plugins/builtin/buildout/pane/index.tsx +34 -18
  350. package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
  351. package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
  352. package/src/plugins/builtin/catalysts/client.ts +2 -2
  353. package/src/plugins/builtin/catalysts/detail.tsx +3 -2
  354. package/src/plugins/builtin/catalysts/index.tsx +1 -1
  355. package/src/plugins/builtin/catalysts/model.ts +49 -4
  356. package/src/plugins/builtin/catalysts/pane.tsx +9 -11
  357. package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
  358. package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
  359. package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
  360. package/src/plugins/builtin/changelog/index.tsx +1 -0
  361. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
  362. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
  363. package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
  364. package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
  365. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
  366. package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
  367. package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
  368. package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
  369. package/src/plugins/builtin/chart-composer/headless.ts +253 -35
  370. package/src/plugins/builtin/chart-composer/index.tsx +12 -2
  371. package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
  372. package/src/plugins/builtin/chart-composer/pane.tsx +128 -28
  373. package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
  374. package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
  375. package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
  376. package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
  377. package/src/plugins/builtin/chart-composer/settings.ts +31 -19
  378. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
  379. package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
  380. package/src/plugins/builtin/chat/attachments/model.ts +3 -1
  381. package/src/plugins/builtin/chat/content/index.tsx +1 -1
  382. package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
  383. package/src/plugins/builtin/chat/people.ts +1 -1
  384. package/src/plugins/builtin/clinical-trials/client.ts +5 -2
  385. package/src/plugins/builtin/clinical-trials/model.ts +13 -4
  386. package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
  387. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
  388. package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
  389. package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
  390. package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
  391. package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
  392. package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
  393. package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
  394. package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
  395. package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
  396. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  397. package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
  398. package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
  399. package/src/plugins/builtin/commodity-balances/pane.tsx +14 -8
  400. package/src/plugins/builtin/company-attention/app-rank.tsx +11 -10
  401. package/src/plugins/builtin/company-attention/building-model.ts +222 -0
  402. package/src/plugins/builtin/company-attention/building.tsx +172 -0
  403. package/src/plugins/builtin/company-attention/client.ts +117 -1
  404. package/src/plugins/builtin/company-attention/evidence.ts +16 -3
  405. package/src/plugins/builtin/company-attention/headless.ts +101 -5
  406. package/src/plugins/builtin/company-attention/index.tsx +6 -3
  407. package/src/plugins/builtin/company-attention/model.ts +33 -7
  408. package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
  409. package/src/plugins/builtin/company-attention/moves.tsx +159 -0
  410. package/src/plugins/builtin/company-attention/pane.tsx +89 -31
  411. package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
  412. package/src/plugins/builtin/company-attention/signals.tsx +160 -0
  413. package/src/plugins/builtin/company-kpis/headless.ts +3 -2
  414. package/src/plugins/builtin/company-kpis/model.ts +2 -2
  415. package/src/plugins/builtin/company-kpis/pane.tsx +5 -4
  416. package/src/plugins/builtin/composite-plugins.ts +2 -1
  417. package/src/plugins/builtin/congress-trades/headless.ts +1 -1
  418. package/src/plugins/builtin/connections/index.ts +1 -0
  419. package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
  420. package/src/plugins/builtin/correlation/headless.ts +7 -4
  421. package/src/plugins/builtin/correlation/relationship/model.ts +1 -0
  422. package/src/plugins/builtin/correlation/settings.ts +1 -0
  423. package/src/plugins/builtin/cot/headless.ts +28 -6
  424. package/src/plugins/builtin/cot/model.ts +12 -0
  425. package/src/plugins/builtin/cot/pane.tsx +7 -5
  426. package/src/plugins/builtin/cpi/headless.ts +5 -1
  427. package/src/plugins/builtin/cpi/pane.tsx +11 -9
  428. package/src/plugins/builtin/credit-boards/model.ts +2 -0
  429. package/src/plugins/builtin/credit-documents/headless.ts +1 -1
  430. package/src/plugins/builtin/credit-documents/pane.tsx +8 -7
  431. package/src/plugins/builtin/crypto-board/client.ts +86 -0
  432. package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
  433. package/src/plugins/builtin/crypto-board/defi.ts +239 -0
  434. package/src/plugins/builtin/crypto-board/headless.ts +117 -6
  435. package/src/plugins/builtin/crypto-board/index.tsx +8 -3
  436. package/src/plugins/builtin/crypto-board/model.ts +40 -8
  437. package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
  438. package/src/plugins/builtin/crypto-board/series.ts +19 -1
  439. package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
  440. package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
  441. package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
  442. package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
  443. package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
  444. package/src/plugins/builtin/debt-maturities/pane.tsx +4 -3
  445. package/src/plugins/builtin/debug/index.tsx +1 -0
  446. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  447. package/src/plugins/builtin/docs/index.tsx +1 -1
  448. package/src/plugins/builtin/docs/pane.tsx +2 -2
  449. package/src/plugins/builtin/docs/targets.ts +1 -1
  450. package/src/plugins/builtin/doe/client.ts +5 -1
  451. package/src/plugins/builtin/doe/headless.ts +12 -6
  452. package/src/plugins/builtin/doe/model.ts +43 -6
  453. package/src/plugins/builtin/doe/pane.tsx +19 -12
  454. package/src/plugins/builtin/earnings/board-model.ts +13 -6
  455. package/src/plugins/builtin/earnings/board-table.ts +4 -1
  456. package/src/plugins/builtin/earnings/board.tsx +253 -50
  457. package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
  458. package/src/plugins/builtin/earnings/calendar.tsx +338 -0
  459. package/src/plugins/builtin/earnings/client.ts +4 -3
  460. package/src/plugins/builtin/earnings/headless.ts +53 -15
  461. package/src/plugins/builtin/earnings/history-model.ts +53 -36
  462. package/src/plugins/builtin/earnings/index.tsx +15 -22
  463. package/src/plugins/builtin/earnings/model.ts +17 -12
  464. package/src/plugins/builtin/earnings/scope.ts +89 -0
  465. package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
  466. package/src/plugins/builtin/earnings-calls/data.ts +146 -2
  467. package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
  468. package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
  469. package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
  470. package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
  471. package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
  472. package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
  473. package/src/plugins/builtin/econ/calendar-model.ts +132 -20
  474. package/src/plugins/builtin/econ/detail-view.tsx +48 -10
  475. package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
  476. package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
  477. package/src/plugins/builtin/econ/index.tsx +112 -25
  478. package/src/plugins/builtin/econ/print-watch.ts +2 -1
  479. package/src/plugins/builtin/econ/types.ts +32 -1
  480. package/src/plugins/builtin/econ-statistics/client.ts +16 -3
  481. package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
  482. package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
  483. package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
  484. package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
  485. package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
  486. package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
  487. package/src/plugins/builtin/econ-statistics/view.ts +16 -1
  488. package/src/plugins/builtin/equity-screener/client.ts +21 -3
  489. package/src/plugins/builtin/equity-screener/headless.ts +77 -5
  490. package/src/plugins/builtin/equity-screener/live.ts +1 -1
  491. package/src/plugins/builtin/equity-screener/model.ts +34 -0
  492. package/src/plugins/builtin/equity-screener/pane.tsx +148 -106
  493. package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
  494. package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
  495. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
  496. package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
  497. package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
  498. package/src/plugins/builtin/exposure/headless.ts +51 -6
  499. package/src/plugins/builtin/exposure/index.tsx +28 -2
  500. package/src/plugins/builtin/exposure/model.ts +7 -0
  501. package/src/plugins/builtin/exposure/pane.tsx +16 -10
  502. package/src/plugins/builtin/fear-greed/index.tsx +1 -1
  503. package/src/plugins/builtin/filing-events/index.tsx +1 -1
  504. package/src/plugins/builtin/futures/model.ts +10 -9
  505. package/src/plugins/builtin/futures/returns.ts +8 -36
  506. package/src/plugins/builtin/futures/table.tsx +1 -1
  507. package/src/plugins/builtin/futures-curve/client.ts +40 -9
  508. package/src/plugins/builtin/futures-curve/headless.ts +39 -17
  509. package/src/plugins/builtin/futures-curve/model.ts +258 -69
  510. package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
  511. package/src/plugins/builtin/fx-matrix/client.ts +15 -8
  512. package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
  513. package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
  514. package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
  515. package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
  516. package/src/plugins/builtin/gpu/board.tsx +4 -1
  517. package/src/plugins/builtin/gpu/changes.tsx +10 -10
  518. package/src/plugins/builtin/gpu/equities.tsx +4 -1
  519. package/src/plugins/builtin/gpu/headless.ts +9 -4
  520. package/src/plugins/builtin/gpu/history.tsx +4 -2
  521. package/src/plugins/builtin/gpu/pane.tsx +5 -3
  522. package/src/plugins/builtin/help/index.tsx +13 -3
  523. package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
  524. package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
  525. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  526. package/src/plugins/builtin/holders/client.ts +15 -2
  527. package/src/plugins/builtin/holders/format.ts +28 -17
  528. package/src/plugins/builtin/holders/headless.ts +48 -8
  529. package/src/plugins/builtin/holders/index-holders.ts +264 -0
  530. package/src/plugins/builtin/holders/pane.tsx +79 -15
  531. package/src/plugins/builtin/holders/report-rows.ts +35 -7
  532. package/src/plugins/builtin/holders/table-model.ts +2 -1
  533. package/src/plugins/builtin/holders/thirteenf-match.ts +3 -1
  534. package/src/plugins/builtin/holders/treemap.tsx +2 -2
  535. package/src/plugins/builtin/insider/base-values.ts +11 -7
  536. package/src/plugins/builtin/insider/client.ts +3 -0
  537. package/src/plugins/builtin/insider/headless.ts +20 -7
  538. package/src/plugins/builtin/insider/index.tsx +17 -8
  539. package/src/plugins/builtin/insider/issuer.ts +34 -4
  540. package/src/plugins/builtin/insider/signals-client.ts +3 -3
  541. package/src/plugins/builtin/insider/signals.tsx +1 -1
  542. package/src/plugins/builtin/insider/table-model.ts +35 -13
  543. package/src/plugins/builtin/insider/table.tsx +5 -2
  544. package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
  545. package/src/plugins/builtin/iv-history/client.ts +20 -0
  546. package/src/plugins/builtin/iv-history/events.ts +145 -0
  547. package/src/plugins/builtin/iv-history/format.ts +3 -0
  548. package/src/plugins/builtin/iv-history/headless.ts +91 -7
  549. package/src/plugins/builtin/iv-history/index.tsx +1 -1
  550. package/src/plugins/builtin/iv-history/model.ts +13 -4
  551. package/src/plugins/builtin/iv-history/series.ts +3 -1
  552. package/src/plugins/builtin/jobs/lock-note.ts +1 -1
  553. package/src/plugins/builtin/jobs/model.ts +4 -15
  554. package/src/plugins/builtin/jobs/pane.tsx +7 -5
  555. package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
  556. package/src/plugins/builtin/jodi/pane.tsx +14 -8
  557. package/src/plugins/builtin/layout-manager/index.tsx +1 -0
  558. package/src/plugins/builtin/macro-day/headless.ts +20 -7
  559. package/src/plugins/builtin/macro-day/index.tsx +3 -2
  560. package/src/plugins/builtin/macro-day/model.ts +29 -8
  561. package/src/plugins/builtin/macro-day/pane.tsx +46 -10
  562. package/src/plugins/builtin/macro-day/releases.ts +55 -13
  563. package/src/plugins/builtin/market-heatmap/data.ts +9 -2
  564. package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
  565. package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
  566. package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
  567. package/src/plugins/builtin/market-heatmap/model.ts +10 -7
  568. package/src/plugins/builtin/market-movers/client.ts +36 -21
  569. package/src/plugins/builtin/market-movers/headless.ts +8 -2
  570. package/src/plugins/builtin/market-movers/index.tsx +16 -10
  571. package/src/plugins/builtin/market-movers/screener.ts +33 -11
  572. package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
  573. package/src/plugins/builtin/market-movers/session-table.ts +4 -2
  574. package/src/plugins/builtin/market-movers/table.ts +4 -1
  575. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  576. package/src/plugins/builtin/market-valuation/view.ts +5 -0
  577. package/src/plugins/builtin/members/headless.ts +6 -5
  578. package/src/plugins/builtin/members/pane.tsx +11 -4
  579. package/src/plugins/builtin/mna/client.ts +1 -0
  580. package/src/plugins/builtin/mna/detail.tsx +20 -32
  581. package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
  582. package/src/plugins/builtin/mna/distress/model.ts +3 -2
  583. package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
  584. package/src/plugins/builtin/mna/headless.ts +6 -13
  585. package/src/plugins/builtin/mna/model.ts +93 -15
  586. package/src/plugins/builtin/mna/pane.tsx +5 -4
  587. package/src/plugins/builtin/news/headless.ts +12 -6
  588. package/src/plugins/builtin/news/index.tsx +10 -1
  589. package/src/plugins/builtin/news/wire/index.tsx +3 -2
  590. package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
  591. package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
  592. package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
  593. package/src/plugins/builtin/notes/cli.ts +50 -15
  594. package/src/plugins/builtin/notes/export.ts +17 -6
  595. package/src/plugins/builtin/notes/files.ts +16 -5
  596. package/src/plugins/builtin/openfda/pane.tsx +1 -1
  597. package/src/plugins/builtin/options/carry.ts +2 -2
  598. package/src/plugins/builtin/options/enrichment-model.ts +10 -9
  599. package/src/plugins/builtin/options/index.tsx +1 -1
  600. package/src/plugins/builtin/options/model-spot.ts +70 -4
  601. package/src/plugins/builtin/options/view.tsx +51 -23
  602. package/src/plugins/builtin/options-calculator/headless.ts +46 -7
  603. package/src/plugins/builtin/options-calculator/pane.tsx +3 -2
  604. package/src/plugins/builtin/options-positioning/headless.ts +11 -3
  605. package/src/plugins/builtin/options-positioning/model.ts +24 -0
  606. package/src/plugins/builtin/options-positioning/pane.tsx +10 -12
  607. package/src/plugins/builtin/options-scenario/client.ts +142 -29
  608. package/src/plugins/builtin/options-scenario/collar.ts +8 -6
  609. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
  610. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
  611. package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
  612. package/src/plugins/builtin/options-scenario/csp.ts +101 -21
  613. package/src/plugins/builtin/options-scenario/headless.ts +49 -21
  614. package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
  615. package/src/plugins/builtin/options-scenario/index.tsx +28 -3
  616. package/src/plugins/builtin/options-scenario/model.ts +13 -0
  617. package/src/plugins/builtin/options-scenario/pane.tsx +22 -10
  618. package/src/plugins/builtin/perps/equity-row.tsx +11 -3
  619. package/src/plugins/builtin/perps/freshness.ts +8 -5
  620. package/src/plugins/builtin/perps/headless.ts +3 -1
  621. package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
  622. package/src/plugins/builtin/perps/live-rows.ts +161 -0
  623. package/src/plugins/builtin/perps/markets-section.tsx +154 -0
  624. package/src/plugins/builtin/perps/pane.tsx +36 -17
  625. package/src/plugins/builtin/perps/venue-markets.ts +96 -0
  626. package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
  627. package/src/plugins/builtin/plugin-marketplace/pane.tsx +145 -60
  628. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +78 -27
  629. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
  630. package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
  631. package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
  632. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
  633. package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
  634. package/src/plugins/builtin/portfolio-list/income.ts +13 -2
  635. package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
  636. package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
  637. package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
  638. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
  639. package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
  640. package/src/plugins/builtin/power/client.ts +6 -3
  641. package/src/plugins/builtin/power/evidence.ts +22 -7
  642. package/src/plugins/builtin/power/gas.tsx +5 -1
  643. package/src/plugins/builtin/power/pane.tsx +44 -32
  644. package/src/plugins/builtin/power/prices.tsx +10 -3
  645. package/src/plugins/builtin/research/analyst-headless.ts +25 -8
  646. package/src/plugins/builtin/research/analyst-model.ts +68 -3
  647. package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
  648. package/src/plugins/builtin/research/event-model.ts +3 -1
  649. package/src/plugins/builtin/research/event-sources.ts +12 -4
  650. package/src/plugins/builtin/research/index.tsx +2 -1
  651. package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
  652. package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
  653. package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
  654. package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
  655. package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
  656. package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
  657. package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
  658. package/src/plugins/builtin/reverse-dcf/client.ts +2 -1
  659. package/src/plugins/builtin/reverse-dcf/model.ts +10 -5
  660. package/src/plugins/builtin/risk-factors/index.tsx +2 -2
  661. package/src/plugins/builtin/scanner/lock-note.ts +1 -1
  662. package/src/plugins/builtin/seasonality/client.ts +2 -1
  663. package/src/plugins/builtin/sec/forms.ts +13 -0
  664. package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
  665. package/src/plugins/builtin/sec/fund-facts.ts +68 -8
  666. package/src/plugins/builtin/sec/headless.ts +85 -8
  667. package/src/plugins/builtin/sec/index.tsx +58 -12
  668. package/src/plugins/builtin/sectors/client.ts +6 -4
  669. package/src/plugins/builtin/sectors/sector-model.ts +11 -15
  670. package/src/plugins/builtin/series-inventory.ts +2 -0
  671. package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
  672. package/src/plugins/builtin/shared/cloud-resource.ts +15 -2
  673. package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
  674. package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
  675. package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
  676. package/src/plugins/builtin/shared/earnings-report.ts +3 -3
  677. package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
  678. package/src/plugins/builtin/shared/job-posting.ts +129 -0
  679. package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
  680. package/src/plugins/builtin/shared/report-freshness.ts +3 -0
  681. package/src/plugins/builtin/shared/research-trading.tsx +23 -0
  682. package/src/plugins/builtin/shared/series-cache.ts +2 -0
  683. package/src/plugins/builtin/shared/series-list-detail.tsx +3 -1
  684. package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
  685. package/src/plugins/builtin/shared/volatility/options.ts +2 -1
  686. package/src/plugins/builtin/short-interest/client.ts +2 -0
  687. package/src/plugins/builtin/short-interest/headless.ts +41 -12
  688. package/src/plugins/builtin/short-interest/index.tsx +23 -1
  689. package/src/plugins/builtin/short-interest/model.ts +70 -19
  690. package/src/plugins/builtin/short-interest/pane.tsx +19 -2
  691. package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
  692. package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
  693. package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
  694. package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
  695. package/src/plugins/builtin/short-interest/schedule.ts +35 -2
  696. package/src/plugins/builtin/short-interest/surface.tsx +11 -4
  697. package/src/plugins/builtin/short-interest/types.ts +9 -0
  698. package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
  699. package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
  700. package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
  701. package/src/plugins/builtin/social-mentions/client.ts +2 -1
  702. package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
  703. package/src/plugins/builtin/supply-chain/model.ts +51 -3
  704. package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
  705. package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
  706. package/src/plugins/builtin/themes/headless.ts +8 -5
  707. package/src/plugins/builtin/themes/model.ts +14 -4
  708. package/src/plugins/builtin/themes/pane.tsx +24 -5
  709. package/src/plugins/builtin/thirteenf/headless.ts +5 -5
  710. package/src/plugins/builtin/thirteenf/signals.ts +3 -1
  711. package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
  712. package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
  713. package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
  714. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
  715. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
  716. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
  717. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
  718. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
  719. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
  720. package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
  721. package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
  722. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
  723. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
  724. package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
  725. package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
  726. package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
  727. package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
  728. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
  729. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
  730. package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
  731. package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
  732. package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
  733. package/src/plugins/builtin/vol-surface/client.ts +28 -7
  734. package/src/plugins/builtin/vol-surface/headless.ts +43 -15
  735. package/src/plugins/builtin/vol-surface/model.ts +34 -12
  736. package/src/plugins/builtin/vol-surface/pane.tsx +33 -13
  737. package/src/plugins/builtin/vol-surface/stored.ts +34 -3
  738. package/src/plugins/builtin/vol-surface/tables.ts +14 -0
  739. package/src/plugins/builtin/volatility/model.ts +5 -10
  740. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
  741. package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
  742. package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
  743. package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
  744. package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
  745. package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
  746. package/src/plugins/builtin/world-venue-map/index.ts +3 -26
  747. package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
  748. package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
  749. package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
  750. package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
  751. package/src/plugins/builtin/yield-curve/client.ts +25 -0
  752. package/src/plugins/builtin/yield-curve/curves.ts +7 -4
  753. package/src/plugins/builtin/yield-curve/headless.ts +38 -4
  754. package/src/plugins/builtin/yield-curve/history.ts +4 -3
  755. package/src/plugins/builtin/yield-curve/index.tsx +12 -6
  756. package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
  757. package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
  758. package/src/plugins/bundle.ts +1 -1
  759. package/src/plugins/catalog-browser.ts +2 -1
  760. package/src/plugins/compat.ts +3 -3
  761. package/src/plugins/dependencies.ts +75 -14
  762. package/src/plugins/extracted-plugins.ts +132 -34
  763. package/src/plugins/host-link.ts +149 -34
  764. package/src/plugins/installer.ts +35 -10
  765. package/src/plugins/loader.ts +206 -38
  766. package/src/plugins/manager-node.ts +2 -2
  767. package/src/plugins/marketplace/deactivation.ts +22 -0
  768. package/src/plugins/marketplace/model.ts +2 -2
  769. package/src/plugins/marketplace/packs.ts +1 -1
  770. package/src/plugins/ownership.ts +1 -1
  771. package/src/plugins/peer-retry.ts +155 -0
  772. package/src/plugins/registry/contributions.ts +3 -1
  773. package/src/plugins/registry/index.ts +4 -3
  774. package/src/plugins/registry/plugin-state.ts +3 -0
  775. package/src/plugins/seed-notice.ts +20 -0
  776. package/src/plugins/shortcut-argument.ts +39 -0
  777. package/src/portfolio/allocation.ts +1 -1
  778. package/src/portfolio/collection-name.ts +31 -0
  779. package/src/portfolio/column-values.ts +10 -8
  780. package/src/portfolio/cost-fx.ts +296 -19
  781. package/src/portfolio/manual-lots.ts +75 -0
  782. package/src/portfolio/mutations.ts +60 -22
  783. package/src/portfolio/suffixed-listings.ts +209 -0
  784. package/src/portfolio/totals-currency.ts +24 -0
  785. package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
  786. package/src/public/time-series.ts +11 -8
  787. package/src/remote/schema.ts +1 -1
  788. package/src/renderers/browser/config-host.ts +3 -0
  789. package/src/renderers/browser/main.tsx +23 -3
  790. package/src/renderers/dom/boot-frame-page.ts +187 -0
  791. package/src/renderers/dom/boot-frame.ts +237 -0
  792. package/src/renderers/dom/build-assets.ts +46 -8
  793. package/src/renderers/dom/desktop/controls.tsx +1 -1
  794. package/src/renderers/dom/desktop/query-bar.tsx +2 -0
  795. package/src/renderers/dom/dom-ui-host.tsx +4 -29
  796. package/src/renderers/dom/host/ascii-text.ts +16 -2
  797. package/src/renderers/dom/host/box.tsx +43 -2
  798. package/src/renderers/dom/host/chart-surface.tsx +2 -0
  799. package/src/renderers/dom/host/hls.chunk.ts +3 -0
  800. package/src/renderers/dom/host/image-surface.tsx +49 -0
  801. package/src/renderers/dom/host/media-surface.tsx +24 -18
  802. package/src/renderers/dom/host/mouse.ts +30 -0
  803. package/src/renderers/dom/host/size-observer.ts +1 -1
  804. package/src/renderers/dom/host/style.ts +1 -1
  805. package/src/renderers/dom/host/tabs.tsx +16 -5
  806. package/src/renderers/dom/host/top-surface.ts +127 -0
  807. package/src/renderers/dom/styles.css +115 -0
  808. package/src/renderers/dom/test-utils.tsx +2 -1
  809. package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
  810. package/src/renderers/electrobun/bun/core-capabilities.ts +9 -1
  811. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
  812. package/src/renderers/electrobun/bun/desktop/backend.ts +56 -3
  813. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
  814. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
  815. package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
  816. package/src/renderers/electrobun/bun/desktop/update.ts +210 -30
  817. package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
  818. package/src/renderers/electrobun/bun/index.ts +11 -1
  819. package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
  820. package/src/renderers/electrobun/bun/window/create.ts +4 -1
  821. package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
  822. package/src/renderers/electrobun/shared/protocol.ts +6 -1
  823. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
  824. package/src/renderers/electrobun/view/config-host.ts +3 -0
  825. package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
  826. package/src/renderers/electrobun/view/main.tsx +30 -4
  827. package/src/renderers/electrobun/view/news-source.ts +9 -7
  828. package/src/renderers/electrobun/view/remote/asset-data-client.ts +9 -2
  829. package/src/renderers/electrobun/view/ui-host.tsx +1 -1
  830. package/src/renderers/opentui/browser-open.ts +88 -0
  831. package/src/renderers/opentui/host.tsx +5 -14
  832. package/src/renderers/opentui/image/loader.ts +3 -2
  833. package/src/renderers/opentui/native-smoke.ts +10 -1
  834. package/src/renderers/opentui/pane-image/index.ts +2 -1
  835. package/src/renderers/opentui/render-lib.ts +253 -0
  836. package/src/renderers/opentui/render-timing-smoke.ts +1 -1
  837. package/src/renderers/opentui/start.tsx +8 -1
  838. package/src/renderers/share/layout-view.tsx +2 -2
  839. package/src/renderers/share/main.tsx +4 -4
  840. package/src/renderers/share/view.tsx +1 -1
  841. package/src/series/resolve.ts +22 -6
  842. package/src/series/standalone.ts +30 -2
  843. package/src/series/types.ts +8 -1
  844. package/src/shares/api.ts +4 -1
  845. package/src/shares/pane.ts +1 -1
  846. package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
  847. package/src/sources/gloomberb-cloud/index.ts +39 -16
  848. package/src/sources/gloomberb-cloud/news.ts +39 -0
  849. package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
  850. package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
  851. package/src/sources/listing-symbols.ts +37 -0
  852. package/src/sources/provider-errors.ts +16 -2
  853. package/src/sources/provider-router/financial-routes.ts +21 -3
  854. package/src/sources/provider-router/financials.ts +15 -2
  855. package/src/sources/provider-router/history.ts +30 -8
  856. package/src/sources/provider-router/index.ts +16 -0
  857. package/src/sources/provider-router/primary.ts +1 -1
  858. package/src/state/app/bootstrap.ts +23 -0
  859. package/src/state/hooks/inline-tickers.ts +30 -5
  860. package/src/sync/controller.ts +1 -1
  861. package/src/sync/core-contributors.ts +46 -14
  862. package/src/team/collections-sync.ts +2 -1
  863. package/src/team/collections.ts +178 -17
  864. package/src/telemetry/crash-reports.ts +21 -4
  865. package/src/telemetry/update-failures-node.ts +59 -0
  866. package/src/telemetry/update-failures.ts +307 -0
  867. package/src/test-support/builtin-panes.ts +1 -1
  868. package/src/theme/colors.ts +3 -30
  869. package/src/theme/ui-tokens.ts +37 -1
  870. package/src/tickers/company-name-listing.ts +215 -36
  871. package/src/tickers/company-name.ts +43 -0
  872. package/src/tickers/index-roots.ts +47 -0
  873. package/src/tickers/instrument-label.ts +5 -1
  874. package/src/tickers/listing-fate.ts +30 -0
  875. package/src/tickers/metadata.ts +10 -0
  876. package/src/tickers/perpetual-listing.ts +5 -2
  877. package/src/tickers/search/home-listing.ts +75 -0
  878. package/src/tickers/search/index.ts +76 -27
  879. package/src/tickers/search/ranking.ts +54 -4
  880. package/src/tickers/search/upsert.ts +29 -0
  881. package/src/tickers/terminal-codes.ts +416 -40
  882. package/src/time-series/bar-aggregation.ts +243 -0
  883. package/src/time-series/base-series.ts +307 -0
  884. package/src/time-series/chart-bounds.ts +349 -0
  885. package/src/time-series/chart-seed.ts +142 -0
  886. package/src/time-series/economic.ts +5 -0
  887. package/src/time-series/fundamentals.ts +18 -3
  888. package/src/time-series/history-acquisition.ts +499 -0
  889. package/src/time-series/leverage.ts +100 -0
  890. package/src/time-series/market-resolution.ts +4 -2
  891. package/src/time-series/market.ts +2 -1
  892. package/src/time-series/price-comparison.ts +175 -30
  893. package/src/time-series/range.ts +9 -1
  894. package/src/time-series/resolution.ts +174 -16
  895. package/src/time-series/resolve-context.ts +157 -0
  896. package/src/time-series/resolve.ts +126 -1577
  897. package/src/time-series/series-name.ts +38 -0
  898. package/src/time-series/series-presentation.ts +208 -0
  899. package/src/time-series/spec.ts +11 -6
  900. package/src/time-series/studies.ts +109 -12
  901. package/src/time-series/tail-reconcile.ts +121 -0
  902. package/src/time-series/types.ts +29 -2
  903. package/src/time-series/use-chart-resolution.ts +4 -5
  904. package/src/types/broker.ts +10 -0
  905. package/src/types/config.ts +14 -0
  906. package/src/types/data-provider.ts +20 -0
  907. package/src/types/exchange-rate.ts +6 -0
  908. package/src/types/financials.ts +104 -7
  909. package/src/types/headless.ts +83 -6
  910. package/src/types/instrument.ts +3 -0
  911. package/src/types/issuer-listings.ts +28 -0
  912. package/src/types/plugin.ts +65 -8
  913. package/src/types/price-history.ts +2 -0
  914. package/src/types/ticker.ts +13 -0
  915. package/src/types/trading.ts +59 -1
  916. package/src/ui/ascii-font.ts +13 -1
  917. package/src/ui/host.tsx +6 -1
  918. package/src/updater/command-names.ts +175 -0
  919. package/src/updater/failure.ts +163 -0
  920. package/src/updater/index.ts +97 -28
  921. package/src/utils/calendar-date.ts +32 -15
  922. package/src/utils/cash-runway.ts +241 -0
  923. package/src/utils/central-banks.ts +42 -0
  924. package/src/utils/cli-output.ts +259 -80
  925. package/src/utils/contract-month.ts +16 -0
  926. package/src/utils/crypto-pair.ts +61 -3
  927. package/src/utils/currency-pair.ts +26 -0
  928. package/src/utils/currency-units.ts +29 -0
  929. package/src/utils/datetime-format.ts +10 -0
  930. package/src/utils/debug-log.ts +1 -1
  931. package/src/utils/decimal-comma.ts +39 -6
  932. package/src/utils/exchange-announcements.ts +71 -0
  933. package/src/utils/exchange-rate-snapshot.ts +10 -0
  934. package/src/utils/financial-statements.ts +83 -4
  935. package/src/utils/format.ts +34 -16
  936. package/src/utils/fundamentals.ts +150 -34
  937. package/src/utils/fx-market-hours.ts +10 -1
  938. package/src/utils/latest-financial-period.ts +8 -0
  939. package/src/utils/linux-libc.ts +54 -0
  940. package/src/utils/market-capitalization.ts +111 -15
  941. package/src/utils/max-drawdown.ts +64 -0
  942. package/src/utils/network-failure.ts +83 -0
  943. package/src/utils/option-expiry.ts +139 -7
  944. package/src/utils/price-earnings.ts +11 -5
  945. package/src/utils/price-history.ts +18 -8
  946. package/src/utils/price-window.ts +131 -0
  947. package/src/utils/release-date.ts +47 -0
  948. package/src/utils/sec.ts +71 -0
  949. package/src/utils/throttled-fetch.ts +11 -4
  950. package/src/utils/trailing-eps.ts +67 -0
  951. package/src/utils/typed-text.ts +21 -0
  952. package/src/utils/utc-time.ts +24 -1
  953. package/src/version.ts +6 -0
  954. package/src/cli/pane-functions/screenshot.ts +0 -2122
@@ -1,5 +1,15 @@
1
1
  import type { UpdateChannel } from "../types/config";
2
+ import { reportUpdateFailure, type UpdateInstallKind } from "../telemetry/update-failures";
3
+ import { detectLinuxLibc, type LinuxLibc } from "../utils/linux-libc";
2
4
  import { compareSemver, isPrereleaseVersion } from "../utils/semver";
5
+ import { PACKAGE_NAME } from "../version";
6
+ import {
7
+ classifyUpdateError,
8
+ httpStatusFailureCode,
9
+ type UpdateFailure,
10
+ type UpdateFailureCode,
11
+ type UpdateFailurePhase,
12
+ } from "./failure";
3
13
  import {
4
14
  GITHUB_LATEST_RELEASE_API_URL,
5
15
  GITHUB_RELEASES_API_URL,
@@ -49,6 +59,8 @@ export interface UpdateProgress {
49
59
  message?: string;
50
60
  /** With `ready`: this host can apply the update and relaunch on request. */
51
61
  canRestart?: boolean;
62
+ /** With `error`: the step that failed and why, which the header says in a few words. */
63
+ failure?: UpdateFailure;
52
64
  }
53
65
 
54
66
  export type UpdateAction =
@@ -68,7 +80,7 @@ export type UpdateCheckResult =
68
80
  /** `notice`: why a newer-looking state is not an update, such as a nightly build waiting for a stable release. */
69
81
  | { kind: "current"; notice?: string }
70
82
  | { kind: "disabled" }
71
- | { kind: "error"; error: string };
83
+ | { kind: "error"; error: string; failure?: UpdateFailure };
72
84
 
73
85
  /**
74
86
  * On the stable channel a nightly build is never replaced by an older stable
@@ -101,6 +113,7 @@ export function setUpdateHost(host: UpdateHost | null): void {
101
113
 
102
114
  export function getAssetBaseNameForRuntime(
103
115
  runtimeProcess: Pick<NodeJS.Process, "platform" | "arch"> | null = getRuntimeProcess(),
116
+ libc: LinuxLibc | null = detectLinuxLibc(),
104
117
  ): string {
105
118
  const os = runtimeProcess?.platform === "darwin"
106
119
  ? "darwin"
@@ -111,8 +124,10 @@ export function getAssetBaseNameForRuntime(
111
124
  // only publishes arm64 today, so an x64 macOS runtime resolves no asset and
112
125
  // reports that instead of overwriting itself with an unrunnable binary.
113
126
  const arch = runtimeProcess?.arch === "arm64" ? "arm64" : "x64";
127
+ // A musl system keeps the musl build: the glibc one cannot start there.
128
+ const variant = os === "linux" && libc === "musl" ? "-musl" : "";
114
129
  const extension = os === "windows" ? ".exe" : "";
115
- return `gloomberb-${os}-${arch}${extension}`;
130
+ return `gloomberb-${os}-${arch}${variant}${extension}`;
116
131
  }
117
132
 
118
133
  function getAssetBaseName(): string {
@@ -269,7 +284,7 @@ export function detectUpdateAction(
269
284
  || entrypoint.includes("/.bun/install/")
270
285
  || entrypoint.includes("/install/global/")
271
286
  ) {
272
- return { kind: "manual", command: "bun install -g gloomberb@latest" };
287
+ return { kind: "manual", command: `bun install -g ${PACKAGE_NAME}@latest` };
273
288
  }
274
289
 
275
290
  if (
@@ -292,7 +307,7 @@ export function detectUpdateAction(
292
307
  || entrypoint.includes("/lib/node_modules/")
293
308
  || entrypoint.includes("/node_modules/")
294
309
  ) {
295
- return { kind: "manual", command: "npm install -g gloomberb@latest" };
310
+ return { kind: "manual", command: `npm install -g ${PACKAGE_NAME}@latest` };
296
311
  }
297
312
 
298
313
  return null;
@@ -302,6 +317,23 @@ export function canSelfUpdate(release: Pick<ReleaseInfo, "updateAction"> | null
302
317
  return release?.updateAction.kind === "self" || release?.updateAction.kind === "desktop";
303
318
  }
304
319
 
320
+ /**
321
+ * Whether the install-update key has something to retry: a release this build
322
+ * can install itself whose last attempt failed. A fresh one downloads on its
323
+ * own, and a manual or managed one names its own command. (A downloaded
324
+ * desktop update has its own use of the key: restarting into it.)
325
+ */
326
+ export function canRetryUpdate(state: {
327
+ updateAvailable: ReleaseInfo | null;
328
+ updateProgress: UpdateProgress | null;
329
+ updateCheckInProgress: boolean;
330
+ }): boolean {
331
+ return !!state.updateAvailable
332
+ && state.updateProgress?.phase === "error"
333
+ && !state.updateCheckInProgress
334
+ && canSelfUpdate(state.updateAvailable);
335
+ }
336
+
305
337
  /** A downloaded update this host can install and relaunch into when the user asks. */
306
338
  export function canRestartToApply(progress: UpdateProgress | null | undefined): boolean {
307
339
  return progress?.phase === "ready" && progress.canRestart === true;
@@ -344,6 +376,11 @@ export async function checkForUpdateDetailed(
344
376
  return { kind: "disabled" };
345
377
  }
346
378
  const nightly = channel === "nightly" && updateAction.kind === "self";
379
+ const failed = (error: string, code: UpdateFailureCode, targetVersion?: string): UpdateCheckResult => {
380
+ const failure: UpdateFailure = { phase: "check", code };
381
+ reportUpdateFailure(failure, { targetVersion, channel: nightly ? "nightly" : "stable" });
382
+ return { kind: "error", error, failure };
383
+ };
347
384
 
348
385
  let timeout: ReturnType<typeof setTimeout> | undefined;
349
386
  try {
@@ -356,7 +393,7 @@ export async function checkForUpdateDetailed(
356
393
  });
357
394
 
358
395
  if (!res.ok) {
359
- return { kind: "error", error: `GitHub returned ${res.status}` };
396
+ return failed(`GitHub returned ${res.status}`, httpStatusFailureCode(res.status));
360
397
  }
361
398
 
362
399
  const payload = await res.json();
@@ -379,16 +416,10 @@ export async function checkForUpdateDetailed(
379
416
 
380
417
  const asset = resolveReleaseAsset(data.assets);
381
418
  if (!asset) {
382
- return {
383
- kind: "error",
384
- error: `No compatible release asset found for ${getAssetBaseName()}`,
385
- };
419
+ return failed(`No compatible release asset found for ${getAssetBaseName()}`, "no_build", version);
386
420
  }
387
421
  if (!asset.checksum) {
388
- return {
389
- kind: "error",
390
- error: `Release asset ${asset.name} is missing a valid SHA-256 digest`,
391
- };
422
+ return failed(`Release asset ${asset.name} is missing a valid SHA-256 digest`, "no_build", version);
392
423
  }
393
424
 
394
425
  return {
@@ -406,12 +437,10 @@ export async function checkForUpdateDetailed(
406
437
  };
407
438
  } catch (error: unknown) {
408
439
  if (error instanceof Error && error.name === "AbortError") {
409
- return { kind: "error", error: "Update check timed out" };
440
+ return failed("Update check timed out", "timeout");
410
441
  }
411
- return {
412
- kind: "error",
413
- error: error instanceof Error ? error.message : "Update check failed",
414
- };
442
+ const code = classifyUpdateError(error);
443
+ return failed(error instanceof Error ? error.message : "Update check failed", code === "unknown" && error instanceof SyntaxError ? "bad_response" : code);
415
444
  } finally {
416
445
  if (timeout) clearTimeout(timeout);
417
446
  }
@@ -483,7 +512,7 @@ export async function performUpdate(
483
512
  error: action.kind === "manual"
484
513
  ? `Run ${action.command}`
485
514
  : action.kind === "managed"
486
- ? `Update through the package manager that installed Gloomberb: ${action.reason}.`
515
+ ? `Update through the package manager that installed Gloom: ${action.reason}.`
487
516
  : "This update type is unavailable in the current runtime.",
488
517
  });
489
518
  return;
@@ -501,20 +530,26 @@ export async function performUpdate(
501
530
  if (!execPath) {
502
531
  onProgress({
503
532
  phase: "error",
504
- error: "Self-update is unavailable when running from source or via Bun/Node. Relaunch the packaged gloomberb binary to update.",
533
+ error: "Self-update is unavailable when running from source or via Bun/Node. Relaunch the packaged gloom binary to update.",
505
534
  });
506
535
  return;
507
536
  }
508
537
 
509
538
  const checksum = /^[a-f\d]{64}$/i.exec(release.checksum ?? "")?.[0].toLowerCase();
539
+ const fail = (failure: UpdateFailure, error: string) => {
540
+ reportUpdateFailure(failure, { targetVersion: release.version, channel: release.channel });
541
+ onProgress({ phase: "error", error, failure });
542
+ };
510
543
  if (!checksum) {
511
- onProgress({ phase: "error", error: "Self-update requires a valid SHA-256 checksum." });
544
+ fail({ phase: "verify", code: "no_build" }, "Self-update requires a valid SHA-256 checksum.");
512
545
  return;
513
546
  }
514
547
 
515
548
  const updatePath = execPath + ".update";
516
549
  const oldPath = execPath + ".old";
517
550
  let unlinkUpdatePath: ((path: string) => void) | null = null;
551
+ /** The step under way, which a thrown error is reported against. */
552
+ let phase: UpdateFailurePhase = "download";
518
553
 
519
554
  try {
520
555
  // Not import(): Bun folds even a specifier held in a variable and bundles
@@ -531,7 +566,7 @@ export async function performUpdate(
531
566
 
532
567
  const res = await fetch(release.downloadUrl);
533
568
  if (!res.ok || !res.body) {
534
- throw new Error(`Download failed: ${res.status}`);
569
+ throw new UpdateStepError({ phase: "download", code: httpStatusFailureCode(res.status) }, `Download failed: ${res.status}`);
535
570
  }
536
571
 
537
572
  const contentLength = Number(res.headers.get("content-length") || 0);
@@ -540,7 +575,18 @@ export async function performUpdate(
540
575
  let received = 0;
541
576
 
542
577
  while (true) {
543
- const { done, value } = await reader.read();
578
+ let chunk: Awaited<ReturnType<typeof reader.read>>;
579
+ try {
580
+ chunk = await reader.read();
581
+ } catch (error) {
582
+ // The connection broke partway: whatever it says, the file is incomplete.
583
+ const code = classifyUpdateError(error);
584
+ throw new UpdateStepError(
585
+ { phase: "download", code: code === "timeout" ? code : "interrupted" },
586
+ error instanceof Error ? error.message : "Download interrupted",
587
+ );
588
+ }
589
+ const { done, value } = chunk;
544
590
  if (done) break;
545
591
  chunks.push(value);
546
592
  received += value.length;
@@ -551,7 +597,14 @@ export async function performUpdate(
551
597
  });
552
598
  }
553
599
  }
600
+ if (contentLength > 0 && received < contentLength) {
601
+ throw new UpdateStepError(
602
+ { phase: "download", code: "interrupted" },
603
+ `Download stopped at ${received} of ${contentLength} bytes`,
604
+ );
605
+ }
554
606
 
607
+ phase = "verify";
555
608
  const downloaded = new Uint8Array(received);
556
609
  let offset = 0;
557
610
  for (const chunk of chunks) {
@@ -560,11 +613,12 @@ export async function performUpdate(
560
613
  }
561
614
  const actual = createHash("sha256").update(downloaded).digest("hex");
562
615
  if (actual !== checksum) {
563
- throw new Error(`Checksum mismatch: expected ${checksum}, got ${actual}`);
616
+ throw new UpdateStepError({ phase: "verify", code: "corrupt" }, `Checksum mismatch: expected ${checksum}, got ${actual}`);
564
617
  }
565
618
  const nextBinary = release.compressed
566
619
  ? new Uint8Array(gunzipSync(downloaded))
567
620
  : downloaded;
621
+ phase = "apply";
568
622
  await Bun.write(updatePath, nextBinary);
569
623
  chmodSync(updatePath, 0o755);
570
624
 
@@ -600,9 +654,24 @@ export async function performUpdate(
600
654
  try {
601
655
  unlinkUpdatePath?.(updatePath);
602
656
  } catch { /* Intentional ignore: Remove a partial update download while the original failure is reported through update progress. */ }
603
- onProgress({
604
- phase: "error",
605
- error: err instanceof Error ? err.message : "Update failed",
606
- });
657
+ const failure = err instanceof UpdateStepError ? err.failure : { phase, code: classifyUpdateError(err) };
658
+ fail(failure, err instanceof Error ? err.message : "Update failed");
607
659
  }
608
660
  }
661
+
662
+ /** A failed step whose code is known where it is thrown. */
663
+ class UpdateStepError extends Error {
664
+ constructor(readonly failure: UpdateFailure, message: string) {
665
+ super(message);
666
+ this.name = "UpdateStepError";
667
+ }
668
+ }
669
+
670
+ /** How the running terminal app was installed, as update failure reports name it. */
671
+ export function terminalInstallKind(action: UpdateAction | null = detectUpdateAction()): UpdateInstallKind {
672
+ if (!action) return "terminal-source";
673
+ if (action.kind === "self") return "terminal-binary";
674
+ if (action.kind === "managed") return "terminal-managed";
675
+ if (action.kind === "manual") return "terminal-package-manager";
676
+ return "unknown";
677
+ }
@@ -43,6 +43,8 @@ const ISO_DATE = /^(\d{4})-(\d{2})-(\d{2})$/;
43
43
  const YEAR_LAST = /^(\d{1,2})([/.-])(\d{1,2})\2(\d{4})$/;
44
44
  /** A four-digit year first, written another way than YYYY-MM-DD: 2026/10/14, 2026.10.14, 2026-10-4. */
45
45
  const YEAR_FIRST = /^(\d{4})([/.-])(\d{1,2})\2(\d{1,2})$/;
46
+ /** The year, month and day marked as Japanese and Chinese write them (2026年10月14日), and Korean (2026년 10월 14일). */
47
+ const MARKED = /^(\d{4})\s*[年년]\s*(\d{1,2})\s*[月월]\s*(\d{1,2})\s*[日일]$/;
46
48
  /** The day written day first with dots, as most of Europe writes it: 14.10.2026, 1.10.2026. */
47
49
  const DOTTED = /^(\d{1,2})\.(\d{1,2})\.(\d{4})$/;
48
50
  /** The month named before the day: Oct 14 2026, October 14, 2026, Sept. 1st 2026. */
@@ -58,6 +60,11 @@ export const DATE_OPTION_EXAMPLES = '2026-10-01, 1.10.2026 or "Oct 1 2026"';
58
60
  /** The same for a form's date field, typed without quotes. */
59
61
  export const DATE_FIELD_EXAMPLES = "2026-10-01, 1.10.2026 or Oct 1 2026";
60
62
 
63
+ /** The formats a date option takes, with one more word it reads besides (`latest`): a date, or that word. */
64
+ export function dateOptionFormatsOr(word: string): string {
65
+ return `${DATE_OPTION_FORMATS.replace(" or ", ", ")} or ${word}`;
66
+ }
67
+
61
68
  /** 1 to 12 for a month's name or its first three letters (Sept too); null for any other word. */
62
69
  function monthNumber(name: string): number | null {
63
70
  const word = name.toLowerCase();
@@ -66,16 +73,22 @@ function monthNumber(name: string): number | null {
66
73
  }
67
74
 
68
75
  /**
69
- * A date as people type it, as YYYY-MM-DD: YYYY-MM-DD itself, DD.MM.YYYY
70
- * (dots are written day first), and the month named on either side of the
71
- * day (Oct 14 2026, 14 October 2026). Null for anything else, and for a day
72
- * the calendar does not have. A slash is written both ways round (10/14 in
73
- * the US, 14/10 in Europe), so a slashed date is never read as one.
76
+ * A date as people type it, as YYYY-MM-DD: YYYY-MM-DD itself, the year first
77
+ * with other separators (2026/10/14, 2026.10.14), the year, month and day
78
+ * marked (2026年10月14日), DD.MM.YYYY (dots after the day are written day
79
+ * first), and the month named on either side of the day (Oct 14 2026, 14
80
+ * October 2026). Null for anything else, and for a day the calendar does not
81
+ * have. A slash after the day or the month is written both ways round (10/14
82
+ * in the US, 14/10 in Europe), so 10/14/2026 is never read as a date.
74
83
  */
75
84
  export function readCalendarDate(value: string): string | null {
76
85
  const text = value.trim().replace(/\s+/g, " ");
77
86
  const iso = ISO_DATE.exec(text);
78
87
  if (iso) return calendarDay(Number(iso[1]), Number(iso[2]), Number(iso[3]));
88
+ const yearFirst = YEAR_FIRST.exec(text);
89
+ if (yearFirst) return calendarDay(Number(yearFirst[1]), Number(yearFirst[3]), Number(yearFirst[4]));
90
+ const marked = MARKED.exec(text);
91
+ if (marked) return calendarDay(Number(marked[1]), Number(marked[2]), Number(marked[3]));
79
92
  const dotted = DOTTED.exec(text);
80
93
  if (dotted) return calendarDay(Number(dotted[3]), Number(dotted[2]), Number(dotted[1]));
81
94
  const monthFirst = MONTH_FIRST.exec(text);
@@ -94,14 +107,11 @@ export function readCalendarDate(value: string): string | null {
94
107
  /**
95
108
  * The YYYY-MM-DD date that a date written another way plainly names, to
96
109
  * offer as the one to type: 14/10/2026 and 10/14/2026 are 2026-10-14, since a
97
- * part over 12 can only be the day, and 2026/10/14 is too. Null when both
98
- * parts could be the month (03/04/2026), and for text that is not a date of
99
- * the calendar.
110
+ * part over 12 can only be the day. Null when both parts could be the month
111
+ * (03/04/2026), and for text that is not a date of the calendar.
100
112
  */
101
113
  function isoDateReading(value: string): string | null {
102
114
  const text = value.trim();
103
- const yearFirst = YEAR_FIRST.exec(text);
104
- if (yearFirst) return calendarDay(Number(yearFirst[1]), Number(yearFirst[3]), Number(yearFirst[4]));
105
115
  const yearLast = YEAR_LAST.exec(text);
106
116
  if (!yearLast) return null;
107
117
  const [first, second, year] = [Number(yearLast[1]), Number(yearLast[3]), Number(yearLast[4])];
@@ -109,6 +119,16 @@ function isoDateReading(value: string): string | null {
109
119
  return first <= 12 && second > 12 ? calendarDay(year, first, second) : calendarDay(year, second, first);
110
120
  }
111
121
 
122
+ /**
123
+ * What to type instead of a date written another way that plainly names one:
124
+ * `type --from 2026-10-14 for 14/10/2026`. Null for anything else. `option` is
125
+ * how the option is typed (`--from`), or empty for a form's field.
126
+ */
127
+ export function dateOptionHint(value: string, option: string): string | null {
128
+ const reading = isoDateReading(value);
129
+ return reading ? `type ${option ? `${option} ` : ""}${reading} for ${value.trim()}` : null;
130
+ }
131
+
112
132
  /**
113
133
  * Why a date option's value is no date, naming the formats it takes: with
114
134
  * the date to type for one written another way that plainly names it
@@ -125,11 +145,8 @@ export function dateOptionError(
125
145
  } = {},
126
146
  ): string {
127
147
  const format = `Use ${subject} as ${formats}`;
128
- const typed = option ? `${option} ` : "";
129
- const reading = isoDateReading(value);
130
- return reading
131
- ? `${format}: type ${typed}${reading} for ${value.trim()}.`
132
- : `${format}, such as ${typed}${example ?? isoDateToday(now)}.`;
148
+ const hint = dateOptionHint(value, option);
149
+ return hint ? `${format}: ${hint}.` : `${format}, such as ${option ? `${option} ` : ""}${example ?? isoDateToday(now)}.`;
133
150
  }
134
151
 
135
152
  /**
@@ -0,0 +1,241 @@
1
+ import type { CompanyProfile, FinancialStatement } from "../types/financials";
2
+ import { formatNumber } from "./format";
3
+ import { latestFinancialPeriod } from "./latest-financial-period";
4
+
5
+ /**
6
+ * Months of cash: cash and short-term investments at the latest balance sheet
7
+ * over the cash the operations used per month. One computation behind
8
+ * `ticker`, the Overview and FA's Liquidity tab.
9
+ *
10
+ * The burn is operating cash flow, the line a 10-Q reports for the quarter:
11
+ * a quarter's over 3 months, the trailing year's over 12. Both are given
12
+ * because a quarter swings for a company paid in lumps (a collaboration's
13
+ * upfront payment one quarter, none the next), and the year smooths that.
14
+ * Positive operating cash flow is no burn. Capital expenditure and financing
15
+ * are left out: a raise is cash in, not less burn.
16
+ */
17
+
18
+ export const QUARTER_MONTHS = 3;
19
+ export const YEAR_MONTHS = 12;
20
+ const MAX_DISPLAY_MONTHS = 120;
21
+ export const SHORT_RUNWAY_HISTORY = "< 4 quarters";
22
+
23
+ /** Financial firms' operating cash flow includes their financing business, not operating burn. */
24
+ export function excludesCashRunway(profile?: Pick<CompanyProfile, "sector" | "industry">): boolean {
25
+ return /financ|bank|broker|insur|capital markets/i.test(`${profile?.sector ?? ""} ${profile?.industry ?? ""}`);
26
+ }
27
+
28
+ /** The method, as the reports state it under the figures; cash alone when no short-term investments are reported. */
29
+ export function runwayMethod(includesShortTerm = true): string {
30
+ const cash = includesShortTerm ? "cash + ST investments" : "cash (no ST investments reported)";
31
+ return `Runway: ${cash} over operating cash burn per month (the quarter's operating cash flow ÷ 3, the trailing year's ÷ 12). Values over ${MAX_DISPLAY_MONTHS} months are shown as > ${MAX_DISPLAY_MONTHS} mo.`;
32
+ }
33
+
34
+ const DAY_MS = 86_400_000;
35
+ /** A fiscal year ending within this many days of a quarter is that quarter's trailing year, as FA reads it. */
36
+ const SAME_PERIOD_END_DAYS = 7;
37
+
38
+ const finite = (value: unknown): value is number => typeof value === "number" && Number.isFinite(value);
39
+
40
+ export interface RunwayLiquidity {
41
+ amount: number;
42
+ /** False when the filer reports no total with short-term investments and the amount is cash alone. */
43
+ includesShortTerm: boolean;
44
+ }
45
+
46
+ /** Whether the filer reports cash and short-term investments as a total in any period on file. */
47
+ export function reportsShortTermTotal(statements: Iterable<FinancialStatement>): boolean {
48
+ for (const statement of statements) if (finite(statement.cashCashEquivalentsAndShortTermInvestments)) return true;
49
+ return false;
50
+ }
51
+
52
+ /**
53
+ * Cash, cash equivalents and short-term investments as reported; cash alone
54
+ * when the filer reports no such total. A filer that reports it in other
55
+ * periods (`totalOnFile`) holds short-term investments, so a period without
56
+ * the total is a missing line: Viking's March 2025 quarter has only its 37.9M
57
+ * of cash on file, the quarter after 807.7M with its investments.
58
+ */
59
+ export function cashAndShortTermInvestments(statement: FinancialStatement, totalOnFile = false): RunwayLiquidity | null {
60
+ if (finite(statement.cashCashEquivalentsAndShortTermInvestments)) {
61
+ return { amount: statement.cashCashEquivalentsAndShortTermInvestments, includesShortTerm: true };
62
+ }
63
+ if (totalOnFile) return null;
64
+ return finite(statement.cashAndCashEquivalents) ? { amount: statement.cashAndCashEquivalents, includesShortTerm: false } : null;
65
+ }
66
+
67
+ /** Cash used by operations per month over a period of `months`, or "no-burn" when they brought cash in. */
68
+ export function monthlyOperatingBurn(operatingCashFlow: number | undefined, months: number): number | "no-burn" | undefined {
69
+ if (!finite(operatingCashFlow)) return undefined;
70
+ return operatingCashFlow >= 0 ? "no-burn" : -operatingCashFlow / months;
71
+ }
72
+
73
+ /** Months the cash lasts at a monthly burn above zero; none left is zero months. */
74
+ export function runwayMonths(liquidity: number, monthlyBurn: number): number {
75
+ return Math.max(0, liquidity) / monthlyBurn;
76
+ }
77
+
78
+ export type RunwayEstimate =
79
+ | { kind: "months"; months: number; monthlyBurn: number; operatingCashFlow: number }
80
+ | { kind: "no-burn"; operatingCashFlow: number };
81
+
82
+ function estimate(liquidity: number, operatingCashFlow: number | undefined, months: number): RunwayEstimate | null {
83
+ const burn = monthlyOperatingBurn(operatingCashFlow, months);
84
+ if (burn === undefined) return null;
85
+ return burn === "no-burn"
86
+ ? { kind: "no-burn", operatingCashFlow: operatingCashFlow! }
87
+ : { kind: "months", months: runwayMonths(liquidity, burn), monthlyBurn: burn, operatingCashFlow: operatingCashFlow! };
88
+ }
89
+
90
+ const days = (from: string, to: string) => (Date.parse(to) - Date.parse(from)) / DAY_MS;
91
+
92
+ /**
93
+ * Operating cash flow over the year to a quarter, as FA's quarterly columns
94
+ * read a trailing flow: the fiscal year when one ends with the quarter,
95
+ * otherwise the four consecutive quarters to it summed. Distinguishes a short
96
+ * history from a missing operating cash flow line.
97
+ */
98
+ function trailingOperatingCashFlowValue(
99
+ quarter: FinancialStatement,
100
+ quarterlyStatements: readonly FinancialStatement[],
101
+ annualStatements: readonly FinancialStatement[],
102
+ ): number | "short-history" | "not-reported" {
103
+ const year = annualStatements.find((candidate) => (
104
+ Math.abs(days(quarter.date, candidate.date)) <= SAME_PERIOD_END_DAYS
105
+ && (!candidate.currency || !quarter.currency || candidate.currency === quarter.currency)
106
+ ));
107
+ if (year) return finite(year.operatingCashFlow) ? year.operatingCashFlow : "not-reported";
108
+ const sorted = [...quarterlyStatements].sort((a, b) => a.date.localeCompare(b.date));
109
+ const index = sorted.findIndex((statement) => statement.date === quarter.date);
110
+ if (index < 3) return "short-history";
111
+ const four = sorted.slice(index - 3, index + 1);
112
+ // Four rows need not cover twelve months: a skipped quarter or a half-year report is not a year.
113
+ for (let at = 1; at < four.length; at += 1) {
114
+ const gap = days(four[at - 1]!.date, four[at]!.date);
115
+ if (!Number.isFinite(gap) || gap < 60 || gap > 120) return "short-history";
116
+ }
117
+ if (new Set(four.map((statement) => statement.currency)).size > 1) return "short-history";
118
+ const flows = four.map((statement) => statement.operatingCashFlow);
119
+ return flows.every(finite) ? flows.reduce((sum, value) => sum + value, 0) : "not-reported";
120
+ }
121
+
122
+ export function trailingOperatingCashFlow(
123
+ quarter: FinancialStatement,
124
+ quarterlyStatements: readonly FinancialStatement[],
125
+ annualStatements: readonly FinancialStatement[],
126
+ ): number | null {
127
+ const flow = trailingOperatingCashFlowValue(quarter, quarterlyStatements, annualStatements);
128
+ return typeof flow === "number" ? flow : null;
129
+ }
130
+
131
+ export interface CashRunway {
132
+ /** The balance sheet's date: the latest quarter's end. */
133
+ periodEnd: string;
134
+ currency?: string;
135
+ liquidity: number;
136
+ includesShortTerm: boolean;
137
+ /** At the latest quarter's burn. */
138
+ quarter: RunwayEstimate | null;
139
+ /** At the trailing year's burn. */
140
+ trailing: RunwayEstimate | null;
141
+ trailingGap?: "short-history" | "not-reported";
142
+ }
143
+
144
+ /**
145
+ * Runway at the latest quarter's balance sheet. Null without a quarter, its
146
+ * cash (or its total with short-term investments, for a filer that reports
147
+ * one elsewhere), or any operating cash flow to measure a burn by.
148
+ */
149
+ export function cashRunway({ quarterlyStatements, annualStatements, profile }: {
150
+ quarterlyStatements: readonly FinancialStatement[];
151
+ annualStatements: readonly FinancialStatement[];
152
+ profile?: Pick<CompanyProfile, "sector" | "industry">;
153
+ }): CashRunway | null {
154
+ if (excludesCashRunway(profile)) return null;
155
+ const quarter = latestFinancialPeriod(quarterlyStatements, (row) => row.date);
156
+ if (!quarter) return null;
157
+ const liquidity = cashAndShortTermInvestments(quarter, reportsShortTermTotal([...quarterlyStatements, ...annualStatements]));
158
+ if (!liquidity) return null;
159
+ const quarterly = estimate(liquidity.amount, quarter.operatingCashFlow, QUARTER_MONTHS);
160
+ const trailingFlow = trailingOperatingCashFlowValue(quarter, quarterlyStatements, annualStatements);
161
+ const trailing = estimate(liquidity.amount, typeof trailingFlow === "number" ? trailingFlow : undefined, YEAR_MONTHS);
162
+ if (!quarterly && !trailing) return null;
163
+ return {
164
+ periodEnd: quarter.date,
165
+ ...(quarter.currency ? { currency: quarter.currency } : {}),
166
+ liquidity: liquidity.amount,
167
+ includesShortTerm: liquidity.includesShortTerm,
168
+ quarter: quarterly,
169
+ trailing,
170
+ ...(typeof trailingFlow === "string" ? { trailingGap: trailingFlow } : {}),
171
+ };
172
+ }
173
+
174
+ /** "12.0 months", to the tenth FA's runway rows show. */
175
+ export function formatRunwayMonths(months: number, unit = "months"): string {
176
+ return months > MAX_DISPLAY_MONTHS ? `> ${MAX_DISPLAY_MONTHS} mo` : `${formatNumber(months, 1)}${unit ? ` ${unit}` : ""}`;
177
+ }
178
+
179
+ /** Whether either burn measure finds the company using cash. */
180
+ export function burnsCash(runway: CashRunway | null | undefined): runway is CashRunway {
181
+ return runway?.quarter?.kind === "months" || runway?.trailing?.kind === "months";
182
+ }
183
+
184
+ /** A prospectus for an offering that raises cash: a shelf takedown (424B5) or an underwritten offering (424B4). */
185
+ const OFFERING_FORMS = ["424B5", "424B4"] as const;
186
+
187
+ export interface OfferingFiling {
188
+ form: string;
189
+ /** YYYY-MM-DD */
190
+ filed: string;
191
+ /** Two prospectuses on one day are two offerings (shares and convertible notes). */
192
+ accessionNumber?: string;
193
+ }
194
+
195
+ /**
196
+ * Offering prospectuses filed on or after a balance sheet's date, oldest first:
197
+ * cash the balance sheet, and a runway on it, do not include yet.
198
+ */
199
+ export function offeringsAfter(filings: readonly OfferingFiling[], periodEnd: string): OfferingFiling[] {
200
+ return filings
201
+ .map((filing) => ({ ...filing, form: filing.form.trim().toUpperCase().replace(/\/A$/, ""), filed: filing.filed.slice(0, 10) }))
202
+ .filter((filing) => (OFFERING_FORMS as readonly string[]).includes(filing.form) && filing.filed >= periodEnd)
203
+ .sort((a, b) => a.filed.localeCompare(b.filed));
204
+ }
205
+
206
+ const MAX_NOTED_DATES = 3;
207
+
208
+ /** "424B5 offering filed 2026-09-23 and 2026-09-25, after the 2026-06-30 balance sheet; cash and runway predate it." */
209
+ export function offeringNote(offerings: readonly OfferingFiling[], periodEnd: string): string | null {
210
+ if (offerings.length === 0) return null;
211
+ const forms = [...new Set(offerings.map((filing) => filing.form))].join("/");
212
+ const allDates = [...new Set(offerings.map((filing) => filing.filed))].sort();
213
+ const dates = allDates.slice(-MAX_NOTED_DATES);
214
+ const omitted = allDates.length - dates.length;
215
+ const earlier = omitted ? ` (${omitted} earlier ${omitted === 1 ? "date" : "dates"} omitted)` : "";
216
+ const relation = allDates.includes(periodEnd) ? "on or after" : "after";
217
+ const when = dates.length === 1 ? dates[0] : `${dates.slice(0, -1).join(", ")} and ${dates.at(-1)}`;
218
+ return `${forms} offering filed ${when}${earlier}, ${relation} the ${periodEnd} balance sheet; cash and runway predate it.`;
219
+ }
220
+
221
+ interface OfferingFilingsClient {
222
+ getCloudSecFilings(params: { ticker: string; forms?: readonly string[]; limit?: number }, options?: { signal?: AbortSignal }): Promise<{
223
+ filings: Array<{ form: string; filingDate: string; accessionNumber?: string }>;
224
+ }>;
225
+ }
226
+
227
+ const OFFERING_FILING_LIMIT = 10;
228
+
229
+ /** A US company's latest offering prospectuses, newest first. */
230
+ export async function fetchOfferingFilings(client: OfferingFilingsClient, ticker: string, signal?: AbortSignal): Promise<OfferingFiling[]> {
231
+ const { filings } = await client.getCloudSecFilings({ ticker, forms: OFFERING_FORMS, limit: OFFERING_FILING_LIMIT }, signal ? { signal } : undefined);
232
+ // A server that predates the form filter sends every form: offeringsAfter keeps the offerings.
233
+ return filings.flatMap((filing) => {
234
+ if (!filing || typeof filing.form !== "string" || typeof filing.filingDate !== "string"
235
+ || !/^\d{4}-\d{2}-\d{2}(?:$|T)/.test(filing.filingDate)) return [];
236
+ const filed = filing.filingDate.slice(0, 10);
237
+ const parsed = new Date(filed);
238
+ if (!Number.isFinite(parsed.getTime()) || parsed.toISOString().slice(0, 10) !== filed) return [];
239
+ return [{ form: filing.form, filed, ...(typeof filing.accessionNumber === "string" ? { accessionNumber: filing.accessionNumber } : {}) }];
240
+ });
241
+ }
@@ -69,6 +69,48 @@ export function centralBankNamed(query: string): CentralBank | null {
69
69
  return CENTRAL_BANKS.find((bank) => centralBankNames(bank).some((name) => nameKey(name) === wanted)) ?? null;
70
70
  }
71
71
 
72
+ /** Words a query puts beside a bank's name when it asks for its policy rate: "Bank of Japan rate", "ECB rate decision", "Fed funds rate". */
73
+ const POLICY_RATE_WORDS = new Set([
74
+ "rate", "rates", "policy", "interest", "decision", "decisions", "meeting", "meetings", "target", "funds",
75
+ "cash", "repo", "key", "base", "deposit", "benchmark", "official", "overnight", "hike", "hikes", "cut", "cuts",
76
+ "monetary", "current", "latest", "today",
77
+ ]);
78
+
79
+ /** Where `name` sits in `words` as whole words, or -1. */
80
+ function wordsIndex(words: readonly string[], name: readonly string[]): number {
81
+ for (let start = 0; start + name.length <= words.length; start += 1) {
82
+ if (name.every((word, offset) => words[start + offset] === word)) return start;
83
+ }
84
+ return -1;
85
+ }
86
+
87
+ /**
88
+ * The bank a query asks about: named on its own (`centralBankNamed`), or by
89
+ * a name with words that ask for its policy rate around it ("bank of japan
90
+ * rate", "Federal Reserve rate", "BOE base rate"), or its jurisdiction with
91
+ * "policy rate" or "interest rate" ("Japan policy rate"). Null for anything
92
+ * else, a name inside a longer phrase ("Bank of Japan bonds").
93
+ */
94
+ export function centralBankAskedAbout(query: string): CentralBank | null {
95
+ const named = centralBankNamed(query);
96
+ if (named) return named;
97
+ const words = nameKey(query).split(" ").filter(Boolean);
98
+ let found: { bank: CentralBank; length: number } | null = null;
99
+ for (const bank of CENTRAL_BANKS) {
100
+ const names = centralBankNames(bank).map((name) => ({ words: nameKey(name).split(" "), place: false }));
101
+ for (const name of [...names, { words: nameKey(bank.place).split(" "), place: true }]) {
102
+ const start = wordsIndex(words, name.words);
103
+ if (start < 0 || (found && found.length >= name.words.length)) continue;
104
+ const rest = [...words.slice(0, start), ...words.slice(start + name.words.length)];
105
+ if (rest.length === 0 || !rest.every((word) => POLICY_RATE_WORDS.has(word))) continue;
106
+ // A country with a rate ("Japan rate") may be its currency or bonds; a policy or interest rate is the bank's.
107
+ if (name.place && !rest.includes("policy") && !rest.includes("interest")) continue;
108
+ found = { bank, length: name.words.length };
109
+ }
110
+ }
111
+ return found?.bank ?? null;
112
+ }
113
+
72
114
  /** The bank whose board row reads a FRED series (DFEDTARU is the Fed's), else null. */
73
115
  export function centralBankCiting(fredSeriesId: string): CentralBank | null {
74
116
  const wanted = fredSeriesId.trim().toUpperCase();