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,11 +1,11 @@
1
1
  import type { AppConfig } from "../types/config";
2
2
  import type { Portfolio, PortfolioCash, TickerPosition, TickerRecord, Watchlist } from "../types/ticker";
3
- import { resolveCurrencyUnit, US_CENTS } from "../utils/currency-units";
3
+ import { normalizeHeldCurrencyCode, resolveCurrencyUnit, US_CENTS } from "../utils/currency-units";
4
4
  import { slugifyName } from "../utils/slugify";
5
5
  import { parseCollectionRef } from "../team/collections";
6
6
  import { findNamedCollection } from "./collection-name";
7
7
  import { isFuturesTicker } from "./futures-positions";
8
- import { manualPortfolioLots } from "./manual-lots";
8
+ import { manualPortfolioLots, mergeLotCostTerms, type LotCostFxConflict } from "./manual-lots";
9
9
 
10
10
  export interface DeleteWatchlistResult {
11
11
  config: AppConfig;
@@ -39,15 +39,41 @@ export interface SetManualPortfolioPositionInput {
39
39
  * read does not unsize it.
40
40
  */
41
41
  multiplier?: number;
42
- /** The purchase date, YYYY-MM-DD. Left out, a single manual lot keeps the one it had. */
43
- dateAcquired?: string;
42
+ /**
43
+ * The purchase date, YYYY-MM-DD. Null clears it; left out, the lots keep
44
+ * theirs (several, their earliest: mergeLotCostTerms).
45
+ */
46
+ dateAcquired?: string | null;
44
47
  /**
45
48
  * The rate the cost was bought at: one unit of `currency` in `costFx.currency`.
46
- * Null clears it; left out, a single manual lot in the same currency keeps the one it had.
49
+ * Null clears it; left out, manual lots in the same currency keep theirs
50
+ * (several, weighted by cost), and lots whose rates cannot become one
51
+ * refuse the set (LotCostFxMergeError).
47
52
  */
48
53
  costFx?: { rate: number; currency: string } | null;
49
54
  }
50
55
 
56
+ /**
57
+ * Several lots replaced by one position whose cost FX rate would be inferred
58
+ * from theirs, when theirs cannot honestly become one (mergeLotCostTerms):
59
+ * the set is refused until the position's own rate is given or cleared.
60
+ */
61
+ export class LotCostFxMergeError extends Error {
62
+ constructor(readonly lotCount: number, readonly conflict: LotCostFxConflict, ratedCount: number) {
63
+ super(lotCostFxMergeMessage(lotCount, conflict, ratedCount));
64
+ this.name = "LotCostFxMergeError";
65
+ }
66
+ }
67
+
68
+ function lotCostFxMergeMessage(lotCount: number, conflict: LotCostFxConflict, ratedCount: number): string {
69
+ if (conflict === "lot-currencies") return `The ${lotCount} lots are in different currencies, so one position cannot keep the FX rate their costs were bought at.`;
70
+ if (conflict === "rate-currencies") return `The ${lotCount} lots' costs were converted into different currencies, so one position cannot keep their FX rates.`;
71
+ const rated = ratedCount === 1
72
+ ? "1 converts its cost at the FX rate it was bought at"
73
+ : `${ratedCount} convert their cost at the FX rate they were bought at`;
74
+ return `Of the ${lotCount} lots, ${rated} and ${lotCount - ratedCount} at today's, so one position cannot keep their rates.`;
75
+ }
76
+
51
77
  /** What a position's size counts, as its field and messages name it. */
52
78
  export type PositionQuantityLabel = "Contracts" | "Shares";
53
79
 
@@ -112,7 +138,11 @@ export function resolveManualPositionCurrency(
112
138
  baseCurrency: string | undefined,
113
139
  contractCurrency?: string | null,
114
140
  ): string {
115
- return (rawCurrency?.trim() || contractCurrency?.trim() || ticker.metadata.currency || portfolio.currency || baseCurrency || "USD").toUpperCase();
141
+ // Pence typed as GBp stay pence: upper-cased they would read as pounds. A listing's own GBp is
142
+ // what its quote is shown in once converted, pounds, so a blank currency still saves GBP.
143
+ const typed = rawCurrency?.trim();
144
+ if (typed) return normalizeHeldCurrencyCode(typed);
145
+ return (contractCurrency?.trim() || ticker.metadata.currency || portfolio.currency || baseCurrency || "USD").toUpperCase();
116
146
  }
117
147
 
118
148
  /** A plain ISO code in major units (AUD), else null: pence-type units, US cents and free text never total a portfolio. */
@@ -140,10 +170,11 @@ export function hasOpenPortfolioPositions(portfolioId: string, tickers: Iterable
140
170
  /**
141
171
  * Whether a manual portfolio's currency follows its holdings. Only with the
142
172
  * default USD base: a base currency the user chose is what manual portfolios
143
- * total in. Team portfolios keep the currency the team gave them.
173
+ * total in. Team portfolios keep the currency the team gave them, and one
174
+ * created in a currency keeps that.
144
175
  */
145
176
  function takesHoldingsCurrency(config: AppConfig, portfolio: Portfolio): boolean {
146
- return isManualPortfolio(portfolio) && !portfolio.teamId && config.baseCurrency.trim().toUpperCase() === "USD";
177
+ return isManualPortfolio(portfolio) && !portfolio.teamId && !portfolio.fixedCurrency && config.baseCurrency.trim().toUpperCase() === "USD";
147
178
  }
148
179
 
149
180
  function withPortfolioCurrency(config: AppConfig, portfolioId: string, currency: string): AppConfig {
@@ -239,10 +270,15 @@ export function clearPortfolioTargetWeights(
239
270
  };
240
271
  }
241
272
 
273
+ /**
274
+ * A new manual portfolio in `baseCurrency`, or, with `fixedCurrency`, in
275
+ * `currency` for good (Portfolio.fixedCurrency).
276
+ */
242
277
  export function createManualPortfolio(
243
278
  config: AppConfig,
244
279
  name: string,
245
280
  baseCurrency: string,
281
+ { fixedCurrency }: { fixedCurrency?: string } = {},
246
282
  ): { config: AppConfig; portfolio: Portfolio } {
247
283
  const trimmedName = name.trim();
248
284
  if (!trimmedName) {
@@ -258,11 +294,9 @@ export function createManualPortfolio(
258
294
  throw new Error(`Portfolio "${trimmedName}" already exists.`);
259
295
  }
260
296
 
261
- const portfolio: Portfolio = {
262
- id,
263
- name: trimmedName,
264
- currency: (baseCurrency || config.baseCurrency || "USD").toUpperCase(),
265
- };
297
+ const portfolio: Portfolio = fixedCurrency
298
+ ? { id, name: trimmedName, currency: fixedCurrency.toUpperCase(), fixedCurrency: true }
299
+ : { id, name: trimmedName, currency: (baseCurrency || config.baseCurrency || "USD").toUpperCase() };
266
300
 
267
301
  return {
268
302
  config: {
@@ -399,7 +433,7 @@ export function setManualPortfolioPosition(
399
433
  portfolioId: string,
400
434
  input: SetManualPortfolioPositionInput,
401
435
  ): SetManualPortfolioPositionResult {
402
- const nextCurrency = input.currency.trim().toUpperCase();
436
+ const nextCurrency = normalizeHeldCurrencyCode(input.currency);
403
437
  const sharesError = validatePositionShares(input.shares, positionQuantityLabel(ticker));
404
438
  if (sharesError) throw new Error(sharesError);
405
439
  if (!Number.isFinite(input.avgCost)) {
@@ -411,14 +445,18 @@ export function setManualPortfolioPosition(
411
445
 
412
446
  const replacedPositions = ticker.metadata.positions.filter((position) => position.portfolio === portfolioId);
413
447
  const replacedPositionCount = replacedPositions.length;
414
- // Editing a single snapshot (for example after a split) does not change its
415
- // acquisition date. A consolidated replacement of several lots has no one date.
416
- const single = replacedPositions.length === 1 && replacedPositions[0]?.broker === "manual" ? replacedPositions[0] : null;
417
- const dateAcquired = input.dateAcquired ?? single?.dateAcquired;
418
- // The rate the cost was bought at goes with its cost: a lot kept in its currency keeps it unless it is replaced or cleared.
419
- const keptCostFx = single && single.currency?.trim().toUpperCase() === nextCurrency
420
- && typeof single.costFxRate === "number" && single.costFxCurrency
421
- ? { rate: single.costFxRate, currency: single.costFxCurrency } : null;
448
+ // Editing a snapshot (for example after a split) changes neither its purchase date nor, while its
449
+ // currency stays, the rate its cost was bought at. Several manual lots keep theirs merged.
450
+ const manual = replacedPositions.length > 0 && replacedPositions.every((position) => position.broker === "manual");
451
+ const kept = manual ? mergeLotCostTerms(replacedPositions) : {};
452
+ const dateAcquired = input.dateAcquired === undefined ? kept.dateAcquired : input.dateAcquired;
453
+ const keptCostFx = kept.costFx && kept.currency === nextCurrency ? kept.costFx : null;
454
+ // Lots in this currency with a rate that cannot become the position's: refused rather than dropped or guessed.
455
+ const ratedHere = replacedPositions.filter((position) =>
456
+ normalizeHeldCurrencyCode(position.currency) === nextCurrency && position.costFxRate != null && position.costFxCurrency);
457
+ if (input.costFx === undefined && kept.costFxConflict && ratedHere.length > 0) {
458
+ throw new LotCostFxMergeError(replacedPositions.length, kept.costFxConflict, replacedPositions.filter((position) => position.costFxRate != null && position.costFxCurrency).length);
459
+ }
422
460
  const costFx = input.costFx === undefined ? keptCostFx : input.costFx;
423
461
  if (costFx && !(Number.isFinite(costFx.rate) && costFx.rate > 0)) throw new Error("The cost FX rate must be a positive number.");
424
462
  // A contract's size does not change with the count held; one the lots agree on carries over.
@@ -0,0 +1,209 @@
1
+ import type { AppConfig } from "../types/config";
2
+ import type { TickerMetadata, TickerPosition, TickerRecord } from "../types/ticker";
3
+ import { listingSuffixVenue, tickerHasListingSuffix } from "../sources/listing-symbols";
4
+ import { canonicalExchange, parsePublicTickerKey, publicTickerKey } from "../utils/exchanges";
5
+
6
+ /**
7
+ * A lot as the fields sync keeps of it (`sanitizePosition`), so a copy that
8
+ * went through sync, or through an older build, reads as the same lot.
9
+ */
10
+ function lotFingerprint(lot: TickerPosition): string {
11
+ const costFx = lot.costFxRate != null && lot.costFxCurrency ? [lot.costFxRate, lot.costFxCurrency] : [null, null];
12
+ return JSON.stringify([
13
+ lot.portfolio, lot.shares, lot.avgCost ?? null, lot.currency ?? null, lot.dateAcquired ?? null, ...costFx,
14
+ lot.broker, lot.side ?? null, lot.multiplier ?? null,
15
+ ]);
16
+ }
17
+
18
+ interface SuffixedListingMerge {
19
+ /** The rows to save: each listing's row with what its suffixed rows held, then those rows emptied. */
20
+ saves: TickerRecord[];
21
+ /**
22
+ * Each suffixed row's key to its listing row's key: the rows merged now,
23
+ * and ones merged before, whose targets an older copy of the config may
24
+ * still name.
25
+ */
26
+ moved: Map<string, string>;
27
+ /** Custom fields a suffixed row held another value for than its listing's row did: kept on the suffixed row. */
28
+ keptCustom: Array<{ from: string; into: string; fields: string[] }>;
29
+ }
30
+
31
+ function isFiled(metadata: TickerMetadata): boolean {
32
+ return metadata.portfolios.length > 0 || metadata.watchlists.length > 0 || metadata.positions.length > 0;
33
+ }
34
+
35
+ /** A broker's row: the broker keys what it reports, and its next sync writes there again. */
36
+ function isBrokerRow(metadata: TickerMetadata): boolean {
37
+ return (metadata.broker_contracts ?? []).length > 0 || metadata.positions.some((position) => position.broker !== "manual");
38
+ }
39
+
40
+ function union(left: readonly string[], right: readonly string[]): string[] {
41
+ return [...new Set([...left, ...right])];
42
+ }
43
+
44
+ function isEmptyValue(value: unknown): boolean {
45
+ return value == null || (typeof value === "string" && value.trim() === "");
46
+ }
47
+
48
+ /**
49
+ * The listing's custom fields with the suffixed row's: the listing's value
50
+ * where it has one, else the suffixed row's. A field both hold with other
51
+ * values keeps the listing's, and the suffixed row's value stays with it.
52
+ */
53
+ function mergeCustom(listing: Record<string, unknown>, suffixed: Record<string, unknown>) {
54
+ const custom = { ...listing };
55
+ const kept: Record<string, unknown> = {};
56
+ for (const [field, value] of Object.entries(suffixed)) {
57
+ if (isEmptyValue(value)) continue;
58
+ if (isEmptyValue(custom[field])) custom[field] = value;
59
+ else if (JSON.stringify(custom[field]) !== JSON.stringify(value)) kept[field] = value;
60
+ }
61
+ return { custom, kept };
62
+ }
63
+
64
+ /**
65
+ * The key of a listing's row (SYMBOL on VENUE): the row saved there already,
66
+ * under the bare symbol or a venue key, else, when `create`, the venue's key
67
+ * (GARAN:BIST, SHOP:XTSE). A merge never takes the bare key, so typing SHOP
68
+ * still means the US listing. Null when there is none to take, or the
69
+ * venue's key holds another venue's row.
70
+ */
71
+ function listingKey(
72
+ symbol: string,
73
+ exchange: string,
74
+ rows: ReadonlyMap<string, TickerRecord>,
75
+ keysBySymbol: ReadonlyMap<string, readonly string[]>,
76
+ create: boolean,
77
+ ): string | null {
78
+ const onVenue = (key: string) => canonicalExchange(rows.get(key)?.metadata.exchange) === exchange;
79
+ const venueKey = publicTickerKey(symbol, exchange);
80
+ if (onVenue(symbol)) return symbol;
81
+ if (onVenue(venueKey)) return venueKey;
82
+ const named = keysBySymbol.get(symbol)?.find((key) => !!parsePublicTickerKey(key).exchange && onVenue(key));
83
+ if (named) return named;
84
+ return create && !rows.has(venueKey) ? venueKey : null;
85
+ }
86
+
87
+ /**
88
+ * Rows a portfolio or watchlist holds under a vendor's suffixed key (GARAN.IS
89
+ * on BIST) merged into their listing's own row (GARAN on BIST), which is made
90
+ * when there is none (`listingKey`): memberships, tags and custom fields
91
+ * (`mergeCustom`) join, and lots are added, each once: the listing's row
92
+ * records what it took (`mergedLots`), so a copy sync brings back is not
93
+ * counted twice. The suffixed row stays, emptied, for a link or a layout that
94
+ * names it. A broker's row is the broker's to key and stays as it is, and so
95
+ * does a suffix no saved venue confirms (`listingSuffixVenue`: MKC.V on NYSE
96
+ * is a share class). Null when no suffixed row has a listing's row.
97
+ */
98
+ export function mergeSuffixedListings(tickers: readonly TickerRecord[]): SuffixedListingMerge | null {
99
+ const rows = new Map(tickers.map((ticker) => [ticker.metadata.ticker, ticker] as const));
100
+ const keysBySymbol = new Map<string, string[]>();
101
+ const index = (key: string) => {
102
+ const { symbol } = parsePublicTickerKey(key);
103
+ keysBySymbol.set(symbol, [...keysBySymbol.get(symbol) ?? [], key]);
104
+ };
105
+ for (const key of rows.keys()) index(key);
106
+ const listings = new Set<string>();
107
+ const emptied = new Set<string>();
108
+ const moved = new Map<string, string>();
109
+ const keptCustom: SuffixedListingMerge["keptCustom"] = [];
110
+ for (const { metadata: suffixed } of tickers) {
111
+ if (isBrokerRow(suffixed)) continue;
112
+ const parsed = parsePublicTickerKey(suffixed.ticker);
113
+ if (!tickerHasListingSuffix(parsed.symbol)) continue;
114
+ const venue = listingSuffixVenue(parsed.symbol, parsed.exchange ?? suffixed.exchange);
115
+ if (!venue) continue;
116
+ const filed = isFiled(suffixed);
117
+ const key = listingKey(venue.symbol, venue.exchange, rows, keysBySymbol, filed);
118
+ if (!key) continue;
119
+ moved.set(suffixed.ticker, key);
120
+ if (!filed) continue;
121
+ const existing = rows.get(key)?.metadata;
122
+ if (!existing) index(key);
123
+ const { mergedLots: _lots, broker_contracts: _contracts, ...rest } = suffixed;
124
+ const listing: TickerMetadata = existing ?? {
125
+ ...rest, ticker: key, exchange: venue.exchange, portfolios: [], watchlists: [], positions: [], tags: [], custom: {},
126
+ };
127
+ // Lots the listing's row took from this key before count once: a copy brought back is not added again.
128
+ const taken = [...listing.mergedLots?.[suffixed.ticker] ?? []];
129
+ const unseen = [...taken];
130
+ const added: TickerPosition[] = [];
131
+ for (const lot of suffixed.positions) {
132
+ const fingerprint = lotFingerprint(lot);
133
+ const seen = unseen.indexOf(fingerprint);
134
+ if (seen >= 0) {
135
+ unseen.splice(seen, 1);
136
+ continue;
137
+ }
138
+ added.push(lot);
139
+ taken.push(fingerprint);
140
+ }
141
+ const { custom, kept } = mergeCustom(listing.custom, suffixed.custom);
142
+ if (Object.keys(kept).length > 0) keptCustom.push({ from: suffixed.ticker, into: key, fields: Object.keys(kept) });
143
+ rows.set(key, {
144
+ metadata: {
145
+ ...listing,
146
+ name: listing.name || suffixed.name,
147
+ currency: listing.currency || suffixed.currency,
148
+ portfolios: union(listing.portfolios, [...suffixed.portfolios, ...added.map((lot) => lot.portfolio)]),
149
+ watchlists: union(listing.watchlists, suffixed.watchlists),
150
+ positions: [...listing.positions, ...added],
151
+ tags: union(listing.tags, suffixed.tags),
152
+ custom,
153
+ ...taken.length > 0 ? { mergedLots: { ...listing.mergedLots, [suffixed.ticker]: taken } } : {},
154
+ },
155
+ });
156
+ rows.set(suffixed.ticker, { metadata: { ...suffixed, portfolios: [], watchlists: [], positions: [], tags: [], custom: kept } });
157
+ listings.add(key);
158
+ emptied.add(suffixed.ticker);
159
+ }
160
+ if (moved.size === 0) return null;
161
+ // The listings' rows first: saved in this order, a stop between them loses nothing.
162
+ return { saves: [...listings, ...emptied].map((key) => rows.get(key)!), moved, keptCustom };
163
+ }
164
+
165
+ /**
166
+ * The config with each portfolio's target for a suffixed key moved to its
167
+ * listing's row, added to any target that row had: the two rows' share of
168
+ * the portfolio is one listing's. The same config when no target moved.
169
+ */
170
+ export function moveTargetWeights(config: AppConfig, moved: ReadonlyMap<string, string>): AppConfig {
171
+ let changed = false;
172
+ const portfolios = config.portfolios.map((portfolio) => {
173
+ const targets = portfolio.targetWeights;
174
+ if (!targets || ![...moved.keys()].some((key) => key in targets)) return portfolio;
175
+ const next = { ...targets };
176
+ for (const [from, to] of moved) {
177
+ if (!(from in next)) continue;
178
+ next[to] = (next[to] ?? 0) + next[from]!;
179
+ delete next[from];
180
+ }
181
+ changed = true;
182
+ return { ...portfolio, targetWeights: next };
183
+ });
184
+ return changed ? { ...config, portfolios } : config;
185
+ }
186
+
187
+ /**
188
+ * `mergeSuffixedListings` for a saved profile: the config with its targets
189
+ * moved is saved first, then the rows, the listings' before the ones they
190
+ * took from, so a stop at any point leaves nothing a second run does not
191
+ * finish. The profile comes back as it now is; null when nothing changed.
192
+ */
193
+ export async function mergeSavedSuffixedListings(
194
+ tickers: readonly TickerRecord[],
195
+ config: AppConfig,
196
+ save: { config: (config: AppConfig) => Promise<void>; tickers: (rows: TickerRecord[]) => Promise<void> },
197
+ ): Promise<{ tickers: TickerRecord[]; config: AppConfig; keptCustom: SuffixedListingMerge["keptCustom"] } | null> {
198
+ const merge = mergeSuffixedListings(tickers);
199
+ if (!merge) return null;
200
+ const nextConfig = moveTargetWeights(config, merge.moved);
201
+ if (merge.saves.length === 0 && nextConfig === config) return null;
202
+ if (nextConfig !== config) await save.config(nextConfig);
203
+ if (merge.saves.length > 0) await save.tickers(merge.saves);
204
+ const saved = new Map(merge.saves.map((row) => [row.metadata.ticker, row] as const));
205
+ const kept = tickers.map((ticker) => saved.get(ticker.metadata.ticker) ?? ticker);
206
+ const keys = new Set(tickers.map((ticker) => ticker.metadata.ticker));
207
+ const added = merge.saves.filter((row) => !keys.has(row.metadata.ticker));
208
+ return { tickers: [...kept, ...added], config: nextConfig, keptCustom: merge.keptCustom };
209
+ }
@@ -0,0 +1,24 @@
1
+ import type { Portfolio } from "../types/ticker";
2
+ import { isManualPortfolio } from "./mutations";
3
+
4
+ const CURRENCY_CODE = /^[A-Z]{3}$/;
5
+
6
+ function currencyCode(value: string | undefined): string | null {
7
+ const code = value?.trim().toUpperCase() ?? "";
8
+ return CURRENCY_CODE.test(code) ? code : null;
9
+ }
10
+
11
+ /**
12
+ * The currency a portfolio's totals, market values and P&L are in. A broker
13
+ * portfolio uses its account currency, and a manual one created in a
14
+ * currency that currency. Another manual portfolio uses its stored currency
15
+ * with the default USD base (its first holding sets it, see
16
+ * adoptFirstPositionCurrency); a base currency the user chose is what manual
17
+ * portfolios and watchlists total in.
18
+ */
19
+ export function resolvePortfolioTotalsCurrency(portfolio: Portfolio | null | undefined, baseCurrency: string): string {
20
+ const base = currencyCode(baseCurrency) ?? "USD";
21
+ if (!portfolio) return base;
22
+ if (isManualPortfolio(portfolio) && !portfolio.fixedCurrency && base !== "USD") return base;
23
+ return currencyCode(portfolio.currency) ?? base;
24
+ }
@@ -44,7 +44,9 @@ exports[`the runtime exports of every public subpath are the reviewed ones 1`] =
44
44
  "BulletList",
45
45
  "Button",
46
46
  "ButtonActionScope",
47
+ "COUNTRY_FLAG_CELLS",
47
48
  "Card",
49
+ "ChartRead",
48
50
  "ChartStrip",
49
51
  "ChartTableHeader",
50
52
  "Checkbox",
@@ -53,6 +55,8 @@ exports[`the runtime exports of every public subpath are the reviewed ones 1`] =
53
55
  "ColumnGridPair",
54
56
  "CompositeChart",
55
57
  "ConfirmDialog",
58
+ "CountryFlag",
59
+ "CountryFlagLead",
56
60
  "CurveSurface",
57
61
  "DELAYED_SEGMENT",
58
62
  "DataTable",
@@ -168,6 +172,7 @@ exports[`the runtime exports of every public subpath are the reviewed ones 1`] =
168
172
  "statGridRows",
169
173
  "staticSeries",
170
174
  "unavailableText",
175
+ "useChartReadRows",
171
176
  "useChartTableLayout",
172
177
  "useChartTableSelection",
173
178
  "useExternalLinkFooter",
@@ -183,8 +188,11 @@ exports[`the runtime exports of every public subpath are the reviewed ones 1`] =
183
188
  "usePaneTabs",
184
189
  "usePaneTicker",
185
190
  "useQueryBarSearch",
191
+ "useRowNotes",
186
192
  "useTableLoadMore",
187
193
  "useTickerRowPaneMenu",
194
+ "withCountryFlag",
195
+ "withFlagRoom",
188
196
  ],
189
197
  "./dialog": [
190
198
  "DialogHostProvider",
@@ -383,6 +391,9 @@ exports[`the runtime exports of every public subpath are the reviewed ones 1`] =
383
391
  "SERIES_FREQUENCIES",
384
392
  "TIME_RANGES",
385
393
  "TIME_RANGE_ORDER",
394
+ "aggregatePriceBars",
395
+ "chartBarSizeSource",
396
+ "chartBarSizeStepMs",
386
397
  "clampTimeRangeToMaxRange",
387
398
  "defineSeries",
388
399
  "describeSeriesUnits",
@@ -396,11 +407,14 @@ exports[`the runtime exports of every public subpath are the reviewed ones 1`] =
396
407
  "getSupportedPresetResolution",
397
408
  "inferSeriesFrequency",
398
409
  "intersectChartResolutionSupport",
410
+ "isChartResolution",
399
411
  "isIntradayResolution",
412
+ "isManualChartResolution",
400
413
  "isRangePresetSupported",
401
414
  "isValidSeriesUnit",
402
415
  "normalizeChartResolution",
403
416
  "normalizeChartResolutionSupport",
417
+ "parseChartBarSize",
404
418
  "parseSeriesCsv",
405
419
  "sortChartResolutions",
406
420
  "validateSeriesDefinition",
@@ -11,19 +11,22 @@ export {
11
11
  CHART_RESOLUTIONS, TIME_RANGES,
12
12
  } from "../time-series/range";
13
13
  export type {
14
- ChartDateWindow, ChartResolution, TimeRange,
14
+ ChartBarSizeUnit, ChartDateWindow, ChartResolution, CustomChartResolution, TimeRange,
15
15
  } from "../time-series/range";
16
16
  export {
17
- CHART_RESOLUTION_STEP_MS, clampTimeRangeToMaxRange, DEFAULT_CHART_RESOLUTION_SUPPORT,
18
- getBestSupportedResolutionForVisibleWindow, getChartResolutionLabel, getExpandedBufferRange,
19
- getNextBufferRange, getPresetResolution, getSupportedChartResolutionsForViewport,
20
- getSupportedPresetResolution, getSupportMaxRange, intersectChartResolutionSupport,
21
- isIntradayResolution, isRangePresetSupported, normalizeChartResolution,
22
- normalizeChartResolutionSupport, sortChartResolutions, TIME_RANGE_ORDER,
17
+ CHART_RESOLUTION_STEP_MS, chartBarSizeSource, chartBarSizeStepMs, clampTimeRangeToMaxRange,
18
+ DEFAULT_CHART_RESOLUTION_SUPPORT, getBestSupportedResolutionForVisibleWindow, getChartResolutionLabel,
19
+ getExpandedBufferRange, getNextBufferRange, getPresetResolution, getSupportedChartResolutionsForViewport,
20
+ getSupportedPresetResolution, getSupportMaxRange, intersectChartResolutionSupport, isChartResolution,
21
+ isIntradayResolution, isManualChartResolution, isRangePresetSupported, normalizeChartResolution,
22
+ normalizeChartResolutionSupport, parseChartBarSize, sortChartResolutions, TIME_RANGE_ORDER,
23
23
  } from "../time-series/resolution";
24
24
  export type {
25
- ChartResolutionSupport, ManualChartResolution,
25
+ ChartBarSize, ChartResolutionSupport, ManualChartResolution,
26
26
  } from "../time-series/resolution";
27
+ // Bars of a size the source does not serve, built from its shorter ones the way the chart builds them.
28
+ export { aggregatePriceBars } from "../time-series/bar-aggregation";
29
+ export type { AggregatedPricePoint, BarAggregationListing } from "../time-series/bar-aggregation";
27
30
 
28
31
  // The resolved shape itself: what a chart-series capability returns and what
29
32
  // the composite chart draws. A plugin that answers `chartSeriesProvider`
@@ -375,7 +375,7 @@ export const REMOTE_OPERATIONS: RemoteOperationSchema[] = [
375
375
  ];
376
376
 
377
377
  export const REMOTE_AGENT_HELP = {
378
- title: "Gloomberb remote control guide",
378
+ title: "Gloom remote control guide",
379
379
  quickStart: [
380
380
  "Read app://snapshot once to orient; it includes schema, current layout, panes, command bar state, and semantic UI nodes.",
381
381
  "Prefer app-level operations such as app.search, layout.setGrid, layout.closeFloating, and ticker.pin before falling back to ui.invoke.",
@@ -16,6 +16,7 @@ import {
16
16
  } from "../../types/config";
17
17
  import { researchEntryFromSearch } from "./research-entry";
18
18
  import { BROWSER_STORAGE_KEYS, SafeJsonStorage, type StorageLike } from "../../data/json-storage";
19
+ import { stopBootFrameRecorders } from "../dom/boot-frame";
19
20
 
20
21
  export const BROWSER_DATA_DIR = "browser://local";
21
22
 
@@ -168,6 +169,8 @@ export function createBrowserConfigStore(storage: StorageLike, search = ""): Con
168
169
  return config;
169
170
  },
170
171
  async resetAllData(dataDir) {
172
+ // Before the keys go, or the frame saved as the page closes would bring the old layout back.
173
+ stopBootFrameRecorders();
171
174
  for (const key of Object.values(BROWSER_STORAGE_KEYS)) {
172
175
  try { storage.removeItem(key); } catch {}
173
176
  }
@@ -9,6 +9,8 @@ import { getBrowserPlugins } from "../../plugins/catalog-browser";
9
9
  import { DomErrorBoundary, DomHostProviders } from "../dom/dom-host-providers";
10
10
  import { installFocusScopeRelease } from "../dom/host/focus-scope";
11
11
  import { installDomMarketDataFrames } from "../dom/data-frames";
12
+ import { releaseBootFrameWhenDrawn, startBootFrameRecorder } from "../dom/boot-frame";
13
+ import { BROWSER_STORAGE_KEYS } from "../../data/json-storage";
12
14
  import { createBrowserAppServices } from "./app-services";
13
15
  import {
14
16
  installBrowserFetchTransports,
@@ -69,7 +71,11 @@ if (!rootElement) throw new Error("Missing root element");
69
71
  const appRootElement = rootElement;
70
72
  appRootElement.tabIndex = -1;
71
73
  const root = createRoot(appRootElement);
72
- root.render(<div className="gloom-loading">Starting Gloomberb...</div>);
74
+ // The page drew the last session's layout, or the bare shell, before this
75
+ // script loaded (dom/boot-frame.ts); it stays until the app has drawn its own.
76
+ const releaseBootFrame = releaseBootFrameWhenDrawn(document, appRootElement);
77
+ /** How long after the app mounts the launch frame stays at most. */
78
+ const BOOT_FRAME_RELEASE_FALLBACK_MS = 4_000;
73
79
 
74
80
  async function boot(): Promise<void> {
75
81
  // Read before anything can save a workspace or tidy the address.
@@ -145,7 +151,7 @@ async function boot(): Promise<void> {
145
151
  root.render(
146
152
  <DomErrorBoundary label="Browser renderer crashed" fallback={(error) => (
147
153
  <div className="gloom-fatal">
148
- <h1>Gloomberb crashed</h1>
154
+ <h1>Gloom crashed</h1>
149
155
  <pre>{error instanceof Error ? error.message : String(error)}</pre>
150
156
  <button onClick={() => window.location.reload()}>Reload</button>
151
157
  </div>
@@ -163,10 +169,24 @@ async function boot(): Promise<void> {
163
169
  </DomErrorBoundary>,
164
170
  );
165
171
  appRootElement.focus({ preventScroll: true });
172
+ // A layout with neither panes nor a status bar has nothing to wait for.
173
+ window.setTimeout(releaseBootFrame, BOOT_FRAME_RELEASE_FALLBACK_MS);
174
+ startBootFrameRecorder({
175
+ doc: document,
176
+ root: appRootElement,
177
+ save: (frame) => {
178
+ try {
179
+ localStorage.setItem(BROWSER_STORAGE_KEYS.bootFrame, JSON.stringify(frame));
180
+ } catch {
181
+ // Intentional ignore: storage full or blocked; the next launch draws the bare shell.
182
+ }
183
+ },
184
+ });
166
185
  }
167
186
 
168
187
  void boot().catch((error) => {
169
188
  reportCrash(error, { kind: "uncaught" });
170
189
  const message = error instanceof Error ? error.message : String(error);
171
- root.render(<div className="gloom-fatal"><h1>Gloomberb failed to start</h1><pre>{message}</pre></div>);
190
+ releaseBootFrame();
191
+ root.render(<div className="gloom-fatal"><h1>Gloom failed to start</h1><pre>{message}</pre></div>);
172
192
  });