gloomberb 0.19.1 → 0.19.3

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 (554) hide show
  1. package/README.md +7 -1
  2. package/package.json +2 -1
  3. package/patches/electrobun@1.18.1.patch +108 -1
  4. package/src/account/upgrade-dialog.tsx +4 -23
  5. package/src/api-client/coalesce.ts +118 -0
  6. package/src/api-client/credit-boards.ts +13 -0
  7. package/src/api-client/crypto-etf-flows.ts +6 -0
  8. package/src/api-client/crypto-markets.ts +40 -0
  9. package/src/api-client/data.ts +201 -14
  10. package/src/api-client/equity-screener.ts +10 -0
  11. package/src/api-client/errors.ts +58 -0
  12. package/src/api-client/gpu.ts +29 -0
  13. package/src/api-client/index.ts +5 -2
  14. package/src/api-client/plan-access.ts +10 -1
  15. package/src/api-client/plan-rules.ts +35 -0
  16. package/src/api-client/research-activity.ts +1 -32
  17. package/src/api-client/types.ts +21 -1
  18. package/src/app/attention-notice.tsx +94 -0
  19. package/src/app/runtime/startup.ts +3 -1
  20. package/src/app.tsx +23 -1
  21. package/src/architecture/core-builtin-allowlist.json +2 -1
  22. package/src/capabilities/chart-series.ts +2 -1
  23. package/src/capabilities/factories.ts +1 -0
  24. package/src/cli/ascii-output.ts +42 -0
  25. package/src/cli/base-converter.ts +10 -2
  26. package/src/cli/command-options.ts +16 -1
  27. package/src/cli/commands/crypto-hints.ts +23 -4
  28. package/src/cli/commands/market.ts +101 -27
  29. package/src/cli/commands/news-search.ts +24 -5
  30. package/src/cli/commands/overview.ts +14 -10
  31. package/src/cli/commands/search.ts +84 -25
  32. package/src/cli/commands/system.ts +22 -30
  33. package/src/cli/commands/ticker.ts +49 -9
  34. package/src/cli/commands/version.ts +33 -0
  35. package/src/cli/context.ts +6 -9
  36. package/src/cli/data-dir.ts +7 -0
  37. package/src/cli/desktop-pane-shot-api-policy.ts +85 -0
  38. package/src/cli/desktop-pane-shot-browser.ts +320 -0
  39. package/src/cli/desktop-pane-shot-routes.ts +26 -1
  40. package/src/cli/desktop-pane-shot.ts +196 -256
  41. package/src/cli/early-command.ts +42 -0
  42. package/src/cli/earnings-calendar.ts +9 -0
  43. package/src/cli/entry.ts +19 -13
  44. package/src/cli/errors.ts +12 -2
  45. package/src/cli/glossary.ts +2 -1
  46. package/src/cli/help.ts +1 -1
  47. package/src/cli/history-export.ts +22 -2
  48. package/src/cli/history-rows.ts +189 -11
  49. package/src/cli/index.ts +18 -1
  50. package/src/cli/known-gaps.ts +51 -5
  51. package/src/cli/listing-arg.ts +63 -10
  52. package/src/cli/options.ts +1 -1
  53. package/src/cli/output-file.ts +60 -13
  54. package/src/cli/pane-functions/catalog.ts +14 -3
  55. package/src/cli/pane-functions/data.ts +1 -1
  56. package/src/cli/pane-functions/dom.ts +45 -0
  57. package/src/cli/pane-functions/freshness.ts +46 -9
  58. package/src/cli/pane-functions/function-help.ts +17 -9
  59. package/src/cli/pane-functions/headless.ts +22 -14
  60. package/src/cli/pane-functions/index.ts +6 -2
  61. package/src/cli/pane-functions/options.ts +6 -2
  62. package/src/cli/pane-functions/resolver.ts +27 -5
  63. package/src/cli/pane-functions/screenshot-assessment.ts +33 -0
  64. package/src/cli/pane-functions/screenshot-bridge.ts +94 -13
  65. package/src/cli/pane-functions/screenshot-http.ts +70 -0
  66. package/src/cli/pane-functions/screenshot-render.ts +19 -5
  67. package/src/cli/quote-answer.ts +49 -6
  68. package/src/cli/registry.ts +41 -13
  69. package/src/cli/result.ts +12 -6
  70. package/src/cli/ticker-resolution.ts +2 -1
  71. package/src/cli/types.ts +2 -0
  72. package/src/components/chart/composite/format.ts +3 -0
  73. package/src/components/chart-table/header.tsx +1 -1
  74. package/src/components/chart-table/layout.ts +28 -11
  75. package/src/components/command-bar/action-runtime.ts +4 -0
  76. package/src/components/command-bar/commands/direct/index.ts +18 -33
  77. package/src/components/command-bar/commands/direct/runtime.ts +5 -0
  78. package/src/components/command-bar/commands/registry.ts +10 -1
  79. package/src/components/command-bar/routes/root/command-items.ts +9 -4
  80. package/src/components/command-bar/routes/root/runtime.ts +51 -6
  81. package/src/components/command-bar/selection-runtime.ts +12 -29
  82. package/src/components/command-bar/surface/index.tsx +9 -3
  83. package/src/components/company-logo.tsx +2 -1
  84. package/src/components/layout/detached-pane-shell.tsx +2 -2
  85. package/src/components/layout/header.tsx +10 -5
  86. package/src/components/layout/market-summary.ts +25 -7
  87. package/src/components/layout/pane/footer/index.tsx +8 -2
  88. package/src/components/layout/pane/footer/model.ts +73 -6
  89. package/src/components/layout/pane/header.tsx +2 -2
  90. package/src/components/layout/pane/status-footer.ts +2 -1
  91. package/src/components/market-board/index.tsx +3 -2
  92. package/src/components/onboarding/desks-step.tsx +12 -4
  93. package/src/components/onboarding/first-run-workspace.ts +81 -4
  94. package/src/components/onboarding/onboarding-frame.tsx +4 -2
  95. package/src/components/onboarding/onboarding-keyboard.ts +8 -5
  96. package/src/components/onboarding/onboarding-wizard.tsx +60 -26
  97. package/src/components/onboarding/portfolio-step/positions-panel.tsx +7 -2
  98. package/src/components/onboarding/run-setup-again.ts +24 -0
  99. package/src/components/onboarding/use-onboarding-progress.ts +33 -15
  100. package/src/components/onboarding/use-onboarding-upgrade.ts +2 -6
  101. package/src/components/onboarding/wizard-model.ts +57 -3
  102. package/src/components/onboarding/wizard-positions.ts +1 -1
  103. package/src/components/ui/delayed-mark.tsx +56 -0
  104. package/src/components/ui/display.tsx +16 -5
  105. package/src/components/ui/external-link.tsx +3 -6
  106. package/src/components/ui/icon.tsx +16 -3
  107. package/src/components/ui/logo-mark.tsx +8 -5
  108. package/src/components/ui/stat-grid.tsx +263 -19
  109. package/src/core/app-services.ts +11 -2
  110. package/src/data/app-persistence.ts +9 -7
  111. package/src/data/config/store/node.ts +11 -5
  112. package/src/data/config/store/normalize.ts +16 -3
  113. package/src/data/plugin-cache.ts +15 -0
  114. package/src/data/plugin-state-store.ts +81 -24
  115. package/src/data/profile-permissions.ts +47 -0
  116. package/src/data/resource-store.ts +165 -90
  117. package/src/data/session-store.ts +31 -8
  118. package/src/data/sqlite/access.ts +324 -0
  119. package/src/data/sqlite/checkpointer.ts +285 -0
  120. package/src/data/sqlite/database.ts +80 -4
  121. package/src/data/sqlite/retry.ts +50 -9
  122. package/src/data/ticker-store.ts +57 -23
  123. package/src/docs/snapshot.json +191 -78
  124. package/src/i18n/es.ts +18 -2
  125. package/src/i18n/ja.ts +18 -2
  126. package/src/i18n/ko.ts +18 -2
  127. package/src/i18n/zh-cn.ts +18 -2
  128. package/src/i18n/zh-tw.ts +18 -2
  129. package/src/layout/desk-keys.ts +4 -1
  130. package/src/layout/desks.ts +38 -5
  131. package/src/layout-marketplace/gallery-desktop.tsx +45 -16
  132. package/src/market-data/batched-reads.ts +16 -0
  133. package/src/market-data/coordinator/auxiliary.ts +4 -2
  134. package/src/market-data/coordinator/index.ts +11 -2
  135. package/src/market-data/futures-board.ts +1 -1
  136. package/src/market-data/futures-contract.ts +3 -1
  137. package/src/market-data/market/index-level.ts +6 -4
  138. package/src/market-data/published-apac-sessions.ts +6 -0
  139. package/src/market-data/realized-volatility.ts +4 -2
  140. package/src/news/aggregator.ts +7 -4
  141. package/src/news/news-model.ts +11 -0
  142. package/src/news/story-id.ts +22 -0
  143. package/src/news/ticker-symbols.ts +17 -1
  144. package/src/notifications/app-notifier.ts +35 -14
  145. package/src/plugins/auto-update-node.ts +10 -6
  146. package/src/plugins/builtin/account-management/form-components.tsx +1 -1
  147. package/src/plugins/builtin/account-management/index.tsx +2 -3
  148. package/src/plugins/builtin/account-management/model.ts +1 -1
  149. package/src/plugins/builtin/alerts/cli-forms.ts +15 -1
  150. package/src/plugins/builtin/alerts/events-pane.tsx +7 -5
  151. package/src/plugins/builtin/alerts/events.ts +10 -2
  152. package/src/plugins/builtin/alerts/index.tsx +5 -5
  153. package/src/plugins/builtin/alerts/research-builder.ts +5 -1
  154. package/src/plugins/builtin/alerts/research-rules.ts +18 -0
  155. package/src/plugins/builtin/alerts/targets.ts +4 -1
  156. package/src/plugins/builtin/attention/headless.ts +1 -1
  157. package/src/plugins/builtin/attention/index.tsx +2 -4
  158. package/src/plugins/builtin/attention/listing.ts +1 -1
  159. package/src/plugins/builtin/attention/series.ts +1 -1
  160. package/src/plugins/builtin/awards/index.tsx +1 -2
  161. package/src/plugins/builtin/backtest/client.ts +1 -0
  162. package/src/plugins/builtin/backtest/index.tsx +1 -2
  163. package/src/plugins/builtin/backtest/rules.ts +3 -1
  164. package/src/plugins/builtin/backtest/window.ts +8 -7
  165. package/src/plugins/builtin/broker-manager/detail.tsx +16 -3
  166. package/src/plugins/builtin/broker-manager/index.tsx +1 -1
  167. package/src/plugins/builtin/buildout/cells.tsx +5 -0
  168. package/src/plugins/builtin/buildout/company/flow.tsx +367 -0
  169. package/src/plugins/builtin/buildout/company/id.ts +2 -0
  170. package/src/plugins/builtin/buildout/company/model.ts +247 -0
  171. package/src/plugins/builtin/buildout/company/pane.tsx +317 -0
  172. package/src/plugins/builtin/buildout/data-runtime.ts +31 -10
  173. package/src/plugins/builtin/buildout/facilities.ts +309 -0
  174. package/src/plugins/builtin/buildout/format.ts +9 -0
  175. package/src/plugins/builtin/buildout/index.tsx +51 -5
  176. package/src/plugins/builtin/buildout/model/index.ts +62 -10
  177. package/src/plugins/builtin/buildout/model/normalizers.ts +5 -0
  178. package/src/plugins/builtin/buildout/model/types.ts +11 -2
  179. package/src/plugins/builtin/buildout/pane/index.tsx +91 -20
  180. package/src/plugins/builtin/buildout/pane/status.tsx +1 -1
  181. package/src/plugins/builtin/buildout/pane/themes.tsx +110 -0
  182. package/src/plugins/builtin/buildout/table-model.ts +26 -2
  183. package/src/plugins/builtin/builtin-plugin-meta.ts +16 -0
  184. package/src/plugins/builtin/cds/headless.ts +10 -2
  185. package/src/plugins/builtin/cds/model.ts +7 -3
  186. package/src/plugins/builtin/central-bank-rates/index.tsx +1 -2
  187. package/src/plugins/builtin/central-bank-rates/pane.tsx +2 -1
  188. package/src/plugins/builtin/central-bank-rates/series.ts +2 -3
  189. package/src/plugins/builtin/changelog/index.tsx +3 -2
  190. package/src/plugins/builtin/chart-composer/cli-options.ts +16 -0
  191. package/src/plugins/builtin/chart-composer/headless-schema.ts +10 -0
  192. package/src/plugins/builtin/chart-composer/headless.ts +88 -21
  193. package/src/plugins/builtin/chart-composer/index.tsx +2 -3
  194. package/src/plugins/builtin/chart-composer/pane.tsx +30 -2
  195. package/src/plugins/builtin/chart-composer/series-expression.ts +3 -2
  196. package/src/plugins/builtin/chart-composer/session-range.ts +5 -2
  197. package/src/plugins/builtin/chart-composer/studies.ts +1 -1
  198. package/src/plugins/builtin/chat/controller/index.ts +1 -1
  199. package/src/plugins/builtin/chat/controller/messages.ts +15 -4
  200. package/src/plugins/builtin/chat/ghost-user.ts +8 -0
  201. package/src/plugins/builtin/chat/index.tsx +5 -5
  202. package/src/plugins/builtin/clinical-trials/index.tsx +1 -2
  203. package/src/plugins/builtin/cloud/company-picker.tsx +1 -1
  204. package/src/plugins/builtin/cloud/index.tsx +1 -2
  205. package/src/plugins/builtin/cloud/plugin.tsx +6 -4
  206. package/src/plugins/builtin/cloud/team/module.tsx +1 -1
  207. package/src/plugins/builtin/cloud/thesis/module.tsx +1 -1
  208. package/src/plugins/builtin/cloud/trial-offer-status-widget.tsx +24 -1
  209. package/src/plugins/builtin/cloud/upgrade-status-widget.tsx +39 -15
  210. package/src/plugins/builtin/comment-letters/index.tsx +1 -2
  211. package/src/plugins/builtin/commodity-balances/client.ts +4 -1
  212. package/src/plugins/builtin/commodity-balances/index.tsx +3 -3
  213. package/src/plugins/builtin/commodity-balances/pane.tsx +2 -2
  214. package/src/plugins/builtin/congress-trades/aggregates.ts +13 -2
  215. package/src/plugins/builtin/congress-trades/detail.tsx +20 -4
  216. package/src/plugins/builtin/congress-trades/headless.ts +2 -0
  217. package/src/plugins/builtin/congress-trades/model.ts +92 -64
  218. package/src/plugins/builtin/congress-trades/table.tsx +14 -2
  219. package/src/plugins/builtin/connections/index.ts +2 -3
  220. package/src/plugins/builtin/cot/client.ts +28 -2
  221. package/src/plugins/builtin/cot/headless.ts +4 -1
  222. package/src/plugins/builtin/cot/index.tsx +5 -4
  223. package/src/plugins/builtin/cot/model.ts +58 -7
  224. package/src/plugins/builtin/cot/pane.tsx +6 -2
  225. package/src/plugins/builtin/cpi/client.ts +6 -5
  226. package/src/plugins/builtin/cpi/index.tsx +1 -2
  227. package/src/plugins/builtin/credit-boards/cdx-pane.tsx +2 -1
  228. package/src/plugins/builtin/credit-boards/client.ts +7 -2
  229. package/src/plugins/builtin/credit-boards/headless.ts +25 -12
  230. package/src/plugins/builtin/credit-boards/model.ts +29 -0
  231. package/src/plugins/builtin/credit-boards/series.ts +3 -4
  232. package/src/plugins/builtin/credit-boards/sovr-pane.tsx +9 -4
  233. package/src/plugins/builtin/credit-conditions/client.ts +22 -14
  234. package/src/plugins/builtin/crypto-board/bitcoin-network.ts +143 -0
  235. package/src/plugins/builtin/crypto-board/client.ts +5 -5
  236. package/src/plugins/builtin/crypto-board/headless.ts +4 -3
  237. package/src/plugins/builtin/crypto-board/index.tsx +4 -2
  238. package/src/plugins/builtin/crypto-board/series.ts +6 -4
  239. package/src/plugins/builtin/crypto-etf-flows/client.ts +9 -2
  240. package/src/plugins/builtin/crypto-etf-flows/headless.ts +61 -6
  241. package/src/plugins/builtin/crypto-etf-flows/index.tsx +1 -2
  242. package/src/plugins/builtin/crypto-etf-flows/model.ts +14 -1
  243. package/src/plugins/builtin/crypto-etf-flows/pane.tsx +8 -5
  244. package/src/plugins/builtin/debt-maturities/headless.ts +4 -3
  245. package/src/plugins/builtin/debt-maturities/model.ts +17 -1
  246. package/src/plugins/builtin/debt-maturities/pane.tsx +18 -4
  247. package/src/plugins/builtin/debt-maturities/series.ts +3 -3
  248. package/src/plugins/builtin/debug/index.tsx +1 -1
  249. package/src/plugins/builtin/dividend-yield/client.ts +32 -2
  250. package/src/plugins/builtin/dividend-yield/headless.ts +58 -33
  251. package/src/plugins/builtin/dividend-yield/index.tsx +37 -2
  252. package/src/plugins/builtin/dividend-yield/pane.tsx +32 -13
  253. package/src/plugins/builtin/dividend-yield/ranking-reads.ts +73 -0
  254. package/src/plugins/builtin/dividend-yield/ranking-view.tsx +163 -0
  255. package/src/plugins/builtin/dividend-yield/ranking.ts +1 -1
  256. package/src/plugins/builtin/dividend-yield/view.ts +21 -0
  257. package/src/plugins/builtin/docs/index.tsx +2 -3
  258. package/src/plugins/builtin/doe/client.ts +6 -5
  259. package/src/plugins/builtin/doe/headless.ts +16 -3
  260. package/src/plugins/builtin/doe/index.tsx +5 -4
  261. package/src/plugins/builtin/doe/prices.ts +2 -3
  262. package/src/plugins/builtin/doe/series.ts +4 -4
  263. package/src/plugins/builtin/earnings/board.tsx +2 -1
  264. package/src/plugins/builtin/earnings/history.tsx +2 -1
  265. package/src/plugins/builtin/earnings-calls/calendar.tsx +10 -2
  266. package/src/plugins/builtin/earnings-calls/data.ts +19 -11
  267. package/src/plugins/builtin/earnings-calls/pane.tsx +27 -14
  268. package/src/plugins/builtin/earnings-ripple/client.ts +32 -7
  269. package/src/plugins/builtin/earnings-ripple/index.tsx +1 -2
  270. package/src/plugins/builtin/econ/calendar-model.ts +29 -6
  271. package/src/plugins/builtin/econ/detail-view.tsx +16 -2
  272. package/src/plugins/builtin/econ-statistics/index.tsx +1 -2
  273. package/src/plugins/builtin/equity-screener/client.ts +1 -1
  274. package/src/plugins/builtin/equity-screener/headless.ts +1 -0
  275. package/src/plugins/builtin/equity-screener/ideas.ts +30 -1
  276. package/src/plugins/builtin/equity-screener/index.tsx +1 -2
  277. package/src/plugins/builtin/equity-screener/model.ts +28 -4
  278. package/src/plugins/builtin/equity-screener/pane.tsx +5 -0
  279. package/src/plugins/builtin/equity-screener/screen-check.ts +23 -1
  280. package/src/plugins/builtin/estimate-revisions/index.tsx +1 -2
  281. package/src/plugins/builtin/executives/data.ts +6 -1
  282. package/src/plugins/builtin/executives/pane.tsx +9 -21
  283. package/src/plugins/builtin/exposure/holdings.ts +35 -13
  284. package/src/plugins/builtin/exposure/index.tsx +1 -2
  285. package/src/plugins/builtin/fear-greed/cache.ts +4 -0
  286. package/src/plugins/builtin/fear-greed/cli.ts +44 -0
  287. package/src/plugins/builtin/fear-greed/index.tsx +5 -53
  288. package/src/plugins/builtin/fear-greed/pane.tsx +2 -1
  289. package/src/plugins/builtin/fear-greed/series.ts +6 -4
  290. package/src/plugins/builtin/fixed-income/index.tsx +1 -2
  291. package/src/plugins/builtin/futures/board-reads.ts +25 -0
  292. package/src/plugins/builtin/futures/coalesced-bump.ts +44 -0
  293. package/src/plugins/builtin/futures/index.tsx +15 -0
  294. package/src/plugins/builtin/futures/model.ts +14 -0
  295. package/src/plugins/builtin/futures/use-board-terms.ts +22 -15
  296. package/src/plugins/builtin/futures/use-front-returns.ts +20 -14
  297. package/src/plugins/builtin/futures-curve/headless.ts +6 -1
  298. package/src/plugins/builtin/futures-curve/index.tsx +1 -2
  299. package/src/plugins/builtin/fx-matrix/index.tsx +2 -2
  300. package/src/plugins/builtin/gpu/board.tsx +51 -12
  301. package/src/plugins/builtin/gpu/client.ts +19 -3
  302. package/src/plugins/builtin/gpu/equities.tsx +5 -2
  303. package/src/plugins/builtin/gpu/headless.ts +14 -2
  304. package/src/plugins/builtin/gpu/index.tsx +1 -2
  305. package/src/plugins/builtin/gpu/model.ts +20 -2
  306. package/src/plugins/builtin/gpu/pane.tsx +1 -1
  307. package/src/plugins/builtin/gpu/series.ts +2 -3
  308. package/src/plugins/builtin/help/index.tsx +1 -1
  309. package/src/plugins/builtin/holders/beneficial-view.tsx +1 -2
  310. package/src/plugins/builtin/holders/index-holders.ts +24 -12
  311. package/src/plugins/builtin/holders/index.tsx +2 -3
  312. package/src/plugins/builtin/ipo-calendar/index.tsx +1 -2
  313. package/src/plugins/builtin/iv-history/index.tsx +1 -2
  314. package/src/plugins/builtin/jodi/client.ts +4 -1
  315. package/src/plugins/builtin/jodi/index.tsx +1 -2
  316. package/src/plugins/builtin/kelly-sizer/index.tsx +1 -2
  317. package/src/plugins/builtin/layout-manager/index.tsx +9 -8
  318. package/src/plugins/builtin/macro-day/pane.tsx +4 -2
  319. package/src/plugins/builtin/market-halts/index.tsx +1 -2
  320. package/src/plugins/builtin/market-heatmap/index.tsx +11 -2
  321. package/src/plugins/builtin/market-movers/client.ts +1 -0
  322. package/src/plugins/builtin/market-movers/index.tsx +16 -5
  323. package/src/plugins/builtin/market-movers/screener.ts +23 -6
  324. package/src/plugins/builtin/market-movers/session-body.tsx +6 -2
  325. package/src/plugins/builtin/market-valuation/index.tsx +1 -2
  326. package/src/plugins/builtin/members/index.tsx +1 -2
  327. package/src/plugins/builtin/money-markets/index.tsx +1 -2
  328. package/src/plugins/builtin/money-markets/pane.tsx +2 -1
  329. package/src/plugins/builtin/money-markets/series.ts +3 -5
  330. package/src/plugins/builtin/news/headless.ts +7 -0
  331. package/src/plugins/builtin/news/wire/index.tsx +1 -1
  332. package/src/plugins/builtin/news/wire/news/pop-out.tsx +9 -3
  333. package/src/plugins/builtin/notes/index.tsx +3 -6
  334. package/src/plugins/builtin/openfda/index.tsx +1 -2
  335. package/src/plugins/builtin/options/view.tsx +6 -5
  336. package/src/plugins/builtin/options-calculator/index.tsx +1 -2
  337. package/src/plugins/builtin/options-positioning/index.tsx +1 -2
  338. package/src/plugins/builtin/options-scenario/index.tsx +2 -4
  339. package/src/plugins/builtin/perps/index.tsx +1 -2
  340. package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -3
  341. package/src/plugins/builtin/plugin-marketplace/pane.tsx +2 -1
  342. package/src/plugins/builtin/plugin-module.ts +16 -2
  343. package/src/plugins/builtin/portfolio-list/cli/render.ts +53 -3
  344. package/src/plugins/builtin/portfolio-list/index.tsx +1 -2
  345. package/src/plugins/builtin/portfolio-list/pane/index.tsx +11 -0
  346. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +2 -2
  347. package/src/plugins/builtin/power/gas-client.ts +2 -1
  348. package/src/plugins/builtin/power/index.tsx +1 -2
  349. package/src/plugins/builtin/power/prices-client.ts +3 -2
  350. package/src/plugins/builtin/rate-path/index.tsx +1 -2
  351. package/src/plugins/builtin/realized-vol/headless.ts +2 -0
  352. package/src/plugins/builtin/realized-vol/index.tsx +1 -2
  353. package/src/plugins/builtin/realized-vol/model.ts +16 -2
  354. package/src/plugins/builtin/realized-vol/pane.tsx +3 -3
  355. package/src/plugins/builtin/relative-rotation/index.tsx +1 -2
  356. package/src/plugins/builtin/research/analyst-headless.ts +33 -6
  357. package/src/plugins/builtin/research/analyst-model.ts +37 -2
  358. package/src/plugins/builtin/research/analyst-pane.tsx +25 -5
  359. package/src/plugins/builtin/research/index.tsx +5 -8
  360. package/src/plugins/builtin/research-search/index.tsx +1 -2
  361. package/src/plugins/builtin/revenue-breakdown/headless.ts +22 -8
  362. package/src/plugins/builtin/revenue-breakdown/model.ts +23 -0
  363. package/src/plugins/builtin/reverse-dcf/pane.tsx +4 -2
  364. package/src/plugins/builtin/risk-factors/data.ts +8 -4
  365. package/src/plugins/builtin/risk-factors/index.tsx +3 -1
  366. package/src/plugins/builtin/risk-factors/pane.tsx +5 -8
  367. package/src/plugins/builtin/roadmap/index.tsx +2 -3
  368. package/src/plugins/builtin/roadmap/pane.tsx +49 -2
  369. package/src/plugins/builtin/scanner/hilo-model.ts +18 -1
  370. package/src/plugins/builtin/scanner/hilo-pane.tsx +12 -2
  371. package/src/plugins/builtin/scanner/live-pane.tsx +7 -4
  372. package/src/plugins/builtin/scanner/lock-note.ts +26 -3
  373. package/src/plugins/builtin/sec/filing-content.ts +38 -6
  374. package/src/plugins/builtin/sec/headless.ts +5 -1
  375. package/src/plugins/builtin/sec/index.tsx +4 -2
  376. package/src/plugins/builtin/sec/model.ts +2 -0
  377. package/src/plugins/builtin/sectors/index.tsx +11 -5
  378. package/src/plugins/builtin/series-inventory.ts +2 -0
  379. package/src/plugins/builtin/shared/cloud-resource.ts +73 -8
  380. package/src/plugins/builtin/shared/cloud-upgrade.ts +24 -1
  381. package/src/plugins/builtin/shared/forming-bars.ts +29 -0
  382. package/src/plugins/builtin/shared/fred-points.ts +6 -1
  383. package/src/plugins/builtin/shared/fx-rate-freshness.ts +17 -0
  384. package/src/plugins/builtin/shared/pro-lock-note.ts +23 -8
  385. package/src/plugins/builtin/shared/series-detail-chart.tsx +4 -2
  386. package/src/plugins/builtin/shared/series-warning.ts +13 -4
  387. package/src/plugins/builtin/shared/use-quote-board.ts +5 -0
  388. package/src/plugins/builtin/short-interest/publications-pane.tsx +2 -1
  389. package/src/plugins/builtin/short-volume/pane.tsx +2 -1
  390. package/src/plugins/builtin/short-volume/series.ts +2 -3
  391. package/src/plugins/builtin/social-mentions/client.ts +15 -10
  392. package/src/plugins/builtin/social-mentions/index.tsx +1 -2
  393. package/src/plugins/builtin/social-mentions/pane.tsx +2 -1
  394. package/src/plugins/builtin/social-mentions/series.ts +2 -3
  395. package/src/plugins/builtin/supply-chain/client.ts +22 -1
  396. package/src/plugins/builtin/supply-chain/graph-client.ts +22 -1
  397. package/src/plugins/builtin/supply-chain/index.tsx +1 -2
  398. package/src/plugins/builtin/thirteenf/api.ts +127 -29
  399. package/src/plugins/builtin/thirteenf/data.ts +165 -35
  400. package/src/plugins/builtin/thirteenf/index.tsx +2 -4
  401. package/src/plugins/builtin/thirteenf/model.ts +2 -0
  402. package/src/plugins/builtin/thirteenf/overlap-pane.tsx +5 -1
  403. package/src/plugins/builtin/thirteenf/pane.tsx +41 -16
  404. package/src/plugins/builtin/thirteenf/types.ts +14 -0
  405. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +22 -6
  406. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +81 -11
  407. package/src/plugins/builtin/ticker-detail/financials/model.ts +35 -2
  408. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +53 -18
  409. package/src/plugins/builtin/ticker-detail/headless.ts +70 -11
  410. package/src/plugins/builtin/ticker-detail/index.tsx +5 -10
  411. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +16 -6
  412. package/src/plugins/builtin/time-sales/index.tsx +1 -2
  413. package/src/plugins/builtin/time-sales/pane.tsx +3 -1
  414. package/src/plugins/builtin/trace-bonds/headless.ts +11 -2
  415. package/src/plugins/builtin/trace-bonds/model.ts +44 -10
  416. package/src/plugins/builtin/trace-bonds/pane.tsx +12 -7
  417. package/src/plugins/builtin/treasury-auctions/cache.ts +20 -8
  418. package/src/plugins/builtin/treasury-auctions/client.ts +3 -3
  419. package/src/plugins/builtin/treasury-auctions/headless.ts +3 -1
  420. package/src/plugins/builtin/treasury-auctions/pane.tsx +10 -4
  421. package/src/plugins/builtin/vol-surface/client.ts +18 -3
  422. package/src/plugins/builtin/vol-surface/index.tsx +1 -2
  423. package/src/plugins/builtin/volatility/client.ts +43 -16
  424. package/src/plugins/builtin/volatility/headless.ts +5 -2
  425. package/src/plugins/builtin/volatility/index.tsx +1 -2
  426. package/src/plugins/builtin/volatility/model.ts +17 -6
  427. package/src/plugins/builtin/volatility/pane.tsx +6 -2
  428. package/src/plugins/builtin/volatility/series.ts +2 -1
  429. package/src/plugins/builtin/world-indices/footer.ts +6 -1
  430. package/src/plugins/builtin/world-venue-map/client.ts +10 -1
  431. package/src/plugins/builtin/world-venue-map/index.ts +6 -2
  432. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +48 -7
  433. package/src/plugins/builtin/world-venue-map/layers.ts +17 -0
  434. package/src/plugins/builtin/world-venue-map/local-layers.ts +141 -0
  435. package/src/plugins/builtin/world-venue-map/map-symbols.ts +18 -0
  436. package/src/plugins/builtin/world-venue-map/map.tsx +4 -2
  437. package/src/plugins/builtin/world-venue-map/scope.ts +63 -0
  438. package/src/plugins/builtin/yield-curve/client.ts +4 -6
  439. package/src/plugins/builtin/yield-curve/curves.ts +16 -2
  440. package/src/plugins/builtin/yield-curve/headless.ts +3 -3
  441. package/src/plugins/bundle.ts +52 -2
  442. package/src/plugins/catalog-browser.ts +2 -2
  443. package/src/plugins/catalog-cli.ts +20 -0
  444. package/src/plugins/host-link.ts +13 -1
  445. package/src/plugins/installer.ts +64 -42
  446. package/src/plugins/loader.ts +43 -11
  447. package/src/plugins/peer-imports.ts +201 -0
  448. package/src/plugins/peer-retry.ts +26 -29
  449. package/src/plugins/plugin-process.ts +128 -0
  450. package/src/plugins/redirection-guard.ts +45 -0
  451. package/src/remote/endpoint.ts +16 -3
  452. package/src/renderers/browser/main.tsx +3 -2
  453. package/src/renderers/cloudflare/http-proxy.ts +7 -123
  454. package/src/renderers/dom/desktop/icons.tsx +5 -2
  455. package/src/renderers/dom/host/image-surface.tsx +46 -21
  456. package/src/renderers/dom/styles.css +7 -0
  457. package/src/renderers/dom/toast-host.tsx +2 -0
  458. package/src/renderers/electrobun/bun/desktop/backend.ts +7 -1
  459. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +23 -1
  460. package/src/renderers/electrobun/bun/desktop/initialization.ts +12 -3
  461. package/src/renderers/electrobun/bun/desktop/rpc-timing.ts +88 -0
  462. package/src/renderers/electrobun/bun/desktop/update.ts +20 -4
  463. package/src/renderers/electrobun/bun/desktop/view-ids.ts +8 -4
  464. package/src/renderers/electrobun/bun/external-plugins.ts +4 -0
  465. package/src/renderers/electrobun/bun/window/attention.ts +54 -0
  466. package/src/renderers/electrobun/bun/window/create.ts +6 -2
  467. package/src/renderers/electrobun/bun/window/native-timing.ts +48 -0
  468. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +82 -4
  469. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +13 -5
  470. package/src/renderers/electrobun/view/desktop/window/snapshot.ts +3 -0
  471. package/src/renderers/electrobun/view/main.tsx +7 -2
  472. package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -0
  473. package/src/renderers/electrobun/view/ui-host.tsx +9 -2
  474. package/src/renderers/opentui/browser-open.ts +10 -4
  475. package/src/renderers/opentui/image/surface.tsx +1 -1
  476. package/src/renderers/opentui/start.tsx +12 -6
  477. package/src/renderers/opentui/toast-host.tsx +2 -1
  478. package/src/series/registry.ts +18 -0
  479. package/src/series/resolve.ts +2 -1
  480. package/src/series/standalone.ts +10 -1
  481. package/src/series/types.ts +12 -0
  482. package/src/series/validate.ts +11 -2
  483. package/src/sources/gloomberb-cloud/fred-series.ts +5 -3
  484. package/src/sources/gloomberb-cloud/index.ts +28 -5
  485. package/src/sources/gloomberb-cloud/news.ts +24 -3
  486. package/src/sources/gloomberb-cloud/normalizers.ts +17 -2
  487. package/src/sources/provider-errors.ts +26 -3
  488. package/src/sources/provider-router/history.ts +5 -0
  489. package/src/sources/provider-router/index.ts +13 -0
  490. package/src/sync/core-contributors.ts +32 -0
  491. package/src/telemetry/attention-counts.ts +64 -6
  492. package/src/telemetry/attention-setting.ts +33 -0
  493. package/src/telemetry/crash-reports-node.ts +3 -1
  494. package/src/telemetry/stall-clocks.ts +93 -0
  495. package/src/telemetry/stall-reports-node.ts +25 -9
  496. package/src/telemetry/stall-reports.ts +218 -13
  497. package/src/test-support/outage.ts +8 -0
  498. package/src/test-support/preload.ts +9 -0
  499. package/src/tickers/company-name-listing.ts +59 -29
  500. package/src/tickers/company-name.ts +84 -1
  501. package/src/tickers/listing-fate.ts +14 -3
  502. package/src/tickers/saved-instrument.ts +17 -0
  503. package/src/tickers/search/home-listing.ts +104 -8
  504. package/src/tickers/search/index.ts +5 -2
  505. package/src/tickers/search/types.ts +6 -1
  506. package/src/time-series/bar-aggregation.ts +7 -1
  507. package/src/time-series/base-series.ts +3 -3
  508. package/src/time-series/chart-bounds.ts +1 -1
  509. package/src/time-series/chart-data.ts +5 -2
  510. package/src/time-series/chart-seed.ts +1 -1
  511. package/src/time-series/coin-session-close.ts +211 -0
  512. package/src/time-series/live-bars.ts +13 -2
  513. package/src/time-series/live-quotes.ts +1 -1
  514. package/src/time-series/market.ts +5 -3
  515. package/src/time-series/official-close.ts +159 -0
  516. package/src/time-series/price-comparison.ts +75 -8
  517. package/src/time-series/resolve.ts +32 -4
  518. package/src/time-series/series-presentation.ts +1 -1
  519. package/src/time-series/studies/formula.ts +205 -0
  520. package/src/time-series/studies/indicators.ts +299 -0
  521. package/src/time-series/studies/leverage.ts +75 -0
  522. package/src/time-series/studies/pair.ts +138 -0
  523. package/src/time-series/studies/resolve.ts +333 -0
  524. package/src/time-series/studies/shared.ts +141 -0
  525. package/src/time-series/studies/units.ts +243 -0
  526. package/src/time-series/studies/vwap.ts +274 -0
  527. package/src/time-series/types.ts +7 -0
  528. package/src/types/config.ts +18 -2
  529. package/src/types/data-provider.ts +23 -0
  530. package/src/types/financials.ts +40 -3
  531. package/src/types/headless.ts +42 -3
  532. package/src/types/plugin.ts +32 -3
  533. package/src/ui/host.tsx +17 -1
  534. package/src/ui/toast.tsx +26 -1
  535. package/src/utils/ascii-text.ts +140 -0
  536. package/src/utils/cli-output.ts +91 -18
  537. package/src/utils/concurrency.ts +24 -0
  538. package/src/utils/exchanges.ts +6 -0
  539. package/src/utils/external-url.ts +20 -7
  540. package/src/utils/financial-statements.ts +73 -16
  541. package/src/utils/fundamentals.ts +17 -5
  542. package/src/utils/futures-generic.ts +4 -4
  543. package/src/utils/http-proxy-upstream.ts +124 -0
  544. package/src/utils/lease-liabilities.ts +54 -0
  545. package/src/utils/main-thread-stall.ts +122 -5
  546. package/src/utils/perf-marks.ts +58 -12
  547. package/src/utils/price-history-integrity.ts +47 -1
  548. package/src/utils/private-files.ts +141 -0
  549. package/src/utils/public-address.ts +99 -0
  550. package/src/account/upgrade-personalization.ts +0 -57
  551. package/src/account/upgrade-tickers.ts +0 -124
  552. package/src/api-client/upgrade-experiment.ts +0 -91
  553. package/src/plugins/builtin/cloud/browser.tsx +0 -3
  554. package/src/time-series/studies.ts +0 -1628
@@ -11,6 +11,7 @@ import type {
11
11
  } from "../types/financials";
12
12
  import type { SyncSettings, SyncSnapshot } from "../sync/types";
13
13
  import type { ChatPaneLink } from "./chat-pane-link";
14
+ import type { CreditLevelKind } from "./credit-boards";
14
15
 
15
16
  /**
16
17
  * What stands behind a chat account. `discord` is a person on the Gloom
@@ -249,7 +250,7 @@ export interface AccountProfile {
249
250
  showLocalTime?: boolean;
250
251
  /** The desks chat shows beside your name; empty shows none. */
251
252
  chatDesks?: string[];
252
- /** Your answer to "What do you trade?" at the first run: private, it pre-fills `chatDesks`. */
253
+ /** Your answer to "What do you trade most?" at the first run: private, it pre-fills `chatDesks`. */
253
254
  onboardingDesks?: string[];
254
255
  syncEnabled: boolean;
255
256
  weeklyRoundupEnabled: boolean;
@@ -486,12 +487,16 @@ export interface CloudPricePointPayload {
486
487
  * alone), served in place of `volume`.
487
488
  */
488
489
  venueVolume?: { venue: string; volume: number };
490
+ /** What a coin bar's volume counts: `aggregate` across venues, or `3 spot venues` summed. */
491
+ volumeBasis?: string;
489
492
  /** A daily bar still forming when served: a coin's UTC day, or the trade date a future is trading. */
490
493
  partial?: boolean;
491
494
  /** A coin's daily bar whose prices were rebuilt from hourly bars; a day the source left empty has no volume. */
492
495
  filled?: boolean;
493
496
  /** A future's closed session whose settlement is not confirmed yet: it closes on the last trade. */
494
497
  unsettled?: boolean;
498
+ /** A continuous future's calendar bar: the contract it closes on (NGZ26), where the server knows it. */
499
+ contract?: string;
495
500
  }
496
501
 
497
502
  type CloudEconImpact = "high" | "medium" | "low";
@@ -689,6 +694,8 @@ export interface CloudCdsHistoryPointPayload {
689
694
  maturity: string;
690
695
  /** For a line quoted upfront: that day's level in points on the line's coupon. */
691
696
  upfrontPts?: number;
697
+ /** The day's trades, or the settlement price on a day without enough of them (`prints` 0). */
698
+ kind?: CreditLevelKind;
692
699
  }
693
700
 
694
701
  /**
@@ -735,6 +742,8 @@ export interface CloudCdsLevelPayload extends CloudCdsUpfrontQuote {
735
742
  issuer: string;
736
743
  spreadBp: number;
737
744
  date: string;
745
+ /** As the history response's last point. */
746
+ kind?: CreditLevelKind;
738
747
  /** As the history response's moves for the same name. */
739
748
  change1W?: number | null;
740
749
  change1M?: number | null;
@@ -810,6 +819,12 @@ export interface CloudCongressTradePayload {
810
819
  sourceUrl: string;
811
820
  returnSinceTx?: number | null;
812
821
  returnSinceFiling?: number | null;
822
+ /** SPY's return over the same days as returnSinceTx, percent. */
823
+ spyReturnSinceTx?: number | null;
824
+ spyReturnSinceFiling?: number | null;
825
+ /** returnSinceTx less spyReturnSinceTx, percentage points. */
826
+ excessSinceTx?: number | null;
827
+ excessSinceFiling?: number | null;
813
828
  returnAsOf?: string | null;
814
829
  party?: string | null;
815
830
  committees?: string[];
@@ -829,9 +844,12 @@ export interface CloudCongressMemberPayload {
829
844
  lastFilingDate: string | null;
830
845
  avgLagDays: number | null;
831
846
  medianReturn?: number | null;
847
+ /** Median of the trades' excessSinceFiling. */
848
+ medianExcessSinceFiling?: number | null;
832
849
  buyHitRate?: number | null;
833
850
  pricedTradeCount?: number;
834
851
  pricedBuyCount?: number;
852
+ excessTradeCount?: number;
835
853
  party?: string | null;
836
854
  committees?: string[];
837
855
  }
@@ -1504,6 +1522,8 @@ interface CloudNewsTickerLinkPayload {
1504
1522
  confidence: number;
1505
1523
  relevanceScore: number;
1506
1524
  impactScore?: number;
1525
+ /** The company's market cap, stated on its home listing and not on a cross-listing. */
1526
+ marketCap?: number | null;
1507
1527
  sentiment?: "positive" | "neutral" | "negative" | null;
1508
1528
  }
1509
1529
 
@@ -0,0 +1,94 @@
1
+ import { useEffect, useRef, useSyncExternalStore } from "react";
2
+ import { apiClient } from "../api-client";
3
+ import { t } from "../i18n";
4
+ import { useAppActive } from "../state/app/activity";
5
+ import { useAppDispatch, useAppGetState, useAppSelector } from "../state/app/context";
6
+ import { scheduleConfigSave } from "../state/config-save-scheduler";
7
+ import { cloudSyncController } from "../sync/controller";
8
+ import { attentionCollectionAvailable } from "../telemetry/attention-counts";
9
+ import { ATTENTION_OFF_MESSAGE, attentionNoticeDue, withAttentionNoticeShown } from "../telemetry/attention-setting";
10
+ import { reportTelemetryConfig } from "../telemetry/live-config";
11
+ import type { TelemetryConfig } from "../types/config";
12
+ import type { AppNotificationRequest } from "../types/plugin";
13
+
14
+ /**
15
+ * The whole notice, with no title: the terminal draws none, and it has to
16
+ * name the setting its Turn off acts on and say plainly what leaves the app.
17
+ */
18
+ const ATTENTION_NOTICE_TEXT = "Attention Counts is now on. Tickers you open are sent to Gloom with your account; only hourly totals of 20+ people are published.";
19
+
20
+ /** The signed-in account with a verified email, or null; the same account the collector counts for. */
21
+ function verifiedAccount(): string | null {
22
+ return apiClient.getVerifiedSessionIdentity() ? apiClient.getCurrentUser()?.id ?? null : null;
23
+ }
24
+
25
+ /** Where the account's synced settings come from; whether they were pulled this session. */
26
+ export interface AccountSettingsSource {
27
+ subscribe(listener: () => void): () => void;
28
+ getStatus(): { lastPullAt: string | null };
29
+ }
30
+
31
+ /**
32
+ * The one-time notice that Attention Counts is on by default: a toast that
33
+ * stays until dismissed, with Turn off. It shows once per account on this
34
+ * installation, while the app is in front, to a verified account whose
35
+ * setting is untouched, and only after this session has pulled the
36
+ * account's synced settings, so an off made on another device arrives
37
+ * before it. Nothing is counted under the default until the toast has been
38
+ * drawn for that account; an explicit on or off never sees it.
39
+ */
40
+ export function AttentionCountsNotice({
41
+ notify,
42
+ accountSettings = cloudSyncController,
43
+ }: {
44
+ notify(request: AppNotificationRequest): void;
45
+ accountSettings?: AccountSettingsSource;
46
+ }) {
47
+ const dispatch = useAppDispatch();
48
+ const getState = useAppGetState();
49
+ const telemetry = useAppSelector((state) => state.config.telemetry);
50
+ const account = useSyncExternalStore((onChange) => apiClient.subscribeCurrentUser(onChange), verifiedAccount, verifiedAccount);
51
+ const pulled = useSyncExternalStore(
52
+ (onChange) => accountSettings.subscribe(onChange),
53
+ () => accountSettings.getStatus().lastPullAt !== null,
54
+ () => accountSettings.getStatus().lastPullAt !== null,
55
+ );
56
+ const onScreen = useAppActive();
57
+ /** Accounts this session already showed it to, so a re-render never stacks a second toast. */
58
+ const asked = useRef(new Set<string>());
59
+ const due = pulled && attentionNoticeDue(telemetry, account) && attentionCollectionAvailable();
60
+
61
+ useEffect(() => {
62
+ if (!due || !onScreen || !account || asked.current.has(account)) return;
63
+ asked.current.add(account);
64
+ const save = (change: (telemetry: TelemetryConfig | undefined) => TelemetryConfig | undefined) => {
65
+ const current = getState().config;
66
+ const next = change(current.telemetry);
67
+ if (next === current.telemetry) return;
68
+ // Reported first, so turning off drops unsent counts before React commits.
69
+ reportTelemetryConfig(next);
70
+ dispatch({ type: "SET_CONFIG", config: { ...current, telemetry: next } });
71
+ scheduleConfigSave(() => {
72
+ const state = getState();
73
+ return { ...state.config, recentTickers: state.recentTickers };
74
+ });
75
+ };
76
+ notify({
77
+ body: t(ATTENTION_NOTICE_TEXT),
78
+ type: "info",
79
+ persistent: true,
80
+ action: {
81
+ label: t("Turn off"),
82
+ onClick: () => {
83
+ save((current) => ({ ...current, attention: false }));
84
+ notify({ body: t(ATTENTION_OFF_MESSAGE), type: "success" });
85
+ },
86
+ },
87
+ onShown: () => {
88
+ if (verifiedAccount() === account) save((current) => withAttentionNoticeShown(current, account));
89
+ },
90
+ });
91
+ }, [account, dispatch, due, getState, notify, onScreen]);
92
+
93
+ return null;
94
+ }
@@ -32,7 +32,7 @@ import {
32
32
  type UsageFunction,
33
33
  } from "../../telemetry/usage-counts";
34
34
  import { debugLog } from "../../utils/debug-log";
35
- import { startMainThreadStallMonitor } from "../../utils/main-thread-stall";
35
+ import { markStartupComplete, startMainThreadStallMonitor } from "../../utils/main-thread-stall";
36
36
  import { measurePerfAsync } from "../../utils/perf-marks";
37
37
 
38
38
  const appLog = debugLog.createLogger("app");
@@ -161,6 +161,8 @@ export function useAppStartupRuntime({
161
161
  } catch (err) {
162
162
  logFailure("app.runtime.startup", "Workspace startup hydration failed")(err);
163
163
  }
164
+ // The workspace has its data (or gave up on it): stalls from here on are not startup ones.
165
+ markStartupComplete();
164
166
  })();
165
167
  }, [
166
168
  autoImportBrokerPositions,
package/src/app.tsx CHANGED
@@ -20,6 +20,7 @@ import { DetachedPaneShell } from "./components/layout/detached-pane-shell";
20
20
  import { TransientLayoutProvider } from "./components/layout/transient-layout";
21
21
  import { CommandBar } from "./components/command-bar/surface";
22
22
  import { OnboardingWizard } from "./components/onboarding/onboarding-wizard";
23
+ import { useRunSetupAgain } from "./components/onboarding/run-setup-again";
23
24
  import { CompanyPickerHost } from "./plugins/builtin/cloud/company-picker";
24
25
  import { TerminalRelayHost } from "./plugins/builtin/cloud/terminal-relay/host";
25
26
  import { SignInGate } from "./components/sign-in-gate";
@@ -30,7 +31,7 @@ import type { AppServicesFactory, AppTickerRepositoryPort } from "./core/app-ser
30
31
  import { useThemeColors } from "./theme/theme-context";
31
32
  import type { AppConfig } from "./types/config";
32
33
  import type { DesktopDeepLinkBridge } from "./types/desktop-deeplink";
33
- import type { CliLaunchRequest, GloomPlugin } from "./types/plugin";
34
+ import type { AppNotificationRequest, CliLaunchRequest, GloomPlugin } from "./types/plugin";
34
35
  import type { DataProvider } from "./types/data-provider";
35
36
  import type { DesktopDockPreviewState, DesktopSharedStateSnapshot, DesktopThemePreviewState, DesktopWindowBridge } from "./types/desktop-window";
36
37
  import type { DesktopApplicationMenuBridge } from "./types/desktop-menu";
@@ -69,6 +70,7 @@ import { AppLanguageConfigObserver } from "./app/language-observer";
69
70
  import { isPaneShareHandoff } from "./shares/location";
70
71
  import { apiClient } from "./api-client";
71
72
  import { reportTelemetryConfig } from "./telemetry/live-config";
73
+ import { AttentionCountsNotice } from "./app/attention-notice";
72
74
  import { recordFunctionOpen } from "./telemetry/usage-counts";
73
75
 
74
76
  const EMPTY_EXTERNAL_PLUGINS: LoadedExternalPlugin[] = [];
@@ -87,6 +89,8 @@ interface AppInnerProps {
87
89
  updatesEnabled?: boolean;
88
90
  onboardingActive?: boolean;
89
91
  onOnboardingComplete?: (config: AppConfig) => void | Promise<void>;
92
+ /** Shows setup again once Run Setup Again has saved its progress; absent where setup cannot run. */
93
+ onRunSetupAgain?: () => void;
90
94
  /** Hosted browser terminal: nothing is reachable until a session exists. */
91
95
  signInGateActive?: boolean;
92
96
  /** Fires once the startup state is in place and the first real layout can paint. */
@@ -127,6 +131,7 @@ function AppInner({
127
131
  updatesEnabled = true,
128
132
  onboardingActive = false,
129
133
  onOnboardingComplete,
134
+ onRunSetupAgain,
130
135
  signInGateActive = false,
131
136
  onInitialized,
132
137
  pluginsReady,
@@ -186,6 +191,8 @@ function AppInner({
186
191
  const dialog = useDialog();
187
192
  const toast = useToastHost();
188
193
  const isDetachedWindow = desktopWindowBridge?.kind === "detached";
194
+ // Not while setup is already showing.
195
+ const runSetupAgain = useRunSetupAgain(onboardingActive ? undefined : onRunSetupAgain);
189
196
  const detachedPaneId = isDetachedWindow ? desktopWindowBridge.paneId ?? null : null;
190
197
  const focusDetachedPane = useMemo(() => {
191
198
  const focus = desktopWindowBridge?.kind === "main" ? desktopWindowBridge.focusDetachedPane : undefined;
@@ -222,6 +229,7 @@ function AppInner({
222
229
  onClick: dismissAfter(() => notification.secondaryAction?.onClick()),
223
230
  }
224
231
  : undefined,
232
+ onShown: notification.onShown,
225
233
  };
226
234
  if (type === "success") toastId = toast.success(notification.body, options);
227
235
  else if (type === "error") toastId = toast.error(notification.body, options);
@@ -232,6 +240,9 @@ function AppInner({
232
240
  const notify = useCallback((body: string, options?: { type?: "info" | "success" | "error" }) => {
233
241
  pluginRegistry.notify({ body, ...options });
234
242
  }, [pluginRegistry]);
243
+ const notifyRequest = useCallback((request: AppNotificationRequest) => {
244
+ pluginRegistry.notify(request);
245
+ }, [pluginRegistry]);
235
246
 
236
247
  useEffect(() => {
237
248
  if (desktopWindowBridge?.kind !== "main" || !desktopWindowBridge.subscribeDockPreview) return;
@@ -489,6 +500,7 @@ function AppInner({
489
500
  />
490
501
  </TransientLayoutProvider>
491
502
  {!onboardingActive ? <CompanyPickerHost pluginRegistry={pluginRegistry} /> : null}
503
+ {initialized && !onboardingActive && !signInGateActive ? <AttentionCountsNotice notify={notifyRequest} /> : null}
492
504
  <TerminalRelayHost device={remoteControlAdapter?.terminalDevice} />
493
505
  {onboardingActive && onOnboardingComplete ? (
494
506
  <OnboardingWizard
@@ -505,6 +517,7 @@ function AppInner({
505
517
  pluginRegistry={pluginRegistry}
506
518
  quitApp={() => rendererHost.requestExit()}
507
519
  onCheckForUpdates={updatesEnabled ? runUpdateCommand : undefined}
520
+ onRunSetupAgain={runSetupAgain}
508
521
  onNativeOccluderChange={setCommandBarNativeOccluder}
509
522
  />
510
523
  )}
@@ -534,6 +547,11 @@ interface AppProps {
534
547
  * terminal sets this; desktop and the TUI keep sign-in optional.
535
548
  */
536
549
  requireSignIn?: boolean;
550
+ /**
551
+ * Settings can open setup again (Run Setup Again). The browser keeps no
552
+ * setup progress, so it turns this off.
553
+ */
554
+ setupEnabled?: boolean;
537
555
  /** Fires once the startup state is in place and the first real layout can paint. */
538
556
  onInitialized?: () => void;
539
557
  }
@@ -552,6 +570,7 @@ export function App({
552
570
  remoteControlAdapter,
553
571
  updatesEnabled = true,
554
572
  requireSignIn = false,
573
+ setupEnabled = true,
555
574
  onInitialized,
556
575
  }: AppProps) {
557
576
  useAppLanguage();
@@ -594,6 +613,8 @@ export function App({
594
613
  && (!effectiveInitialConfig.onboardingComplete || !!effectiveInitialConfig.onboardingProgress)
595
614
  ));
596
615
 
616
+ const showSetup = useCallback(() => setShowOnboarding(true), []);
617
+
597
618
  useEffect(() => bindAppActivity(renderer), [renderer]);
598
619
 
599
620
  const services = useMemo(() => {
@@ -656,6 +677,7 @@ export function App({
656
677
  setConfig(updatedConfig);
657
678
  setShowOnboarding(false);
658
679
  }}
680
+ onRunSetupAgain={setupEnabled && !shareHandoff ? showSetup : undefined}
659
681
  />
660
682
  </AppProvider>
661
683
  </RemoteUiRegistryProvider>
@@ -9,7 +9,7 @@
9
9
  "src/cli/commands/options-chain.ts": ["options","options-calculator"],
10
10
  "src/cli/commands/options-leaps.ts": ["iv-history","options","vol-surface"],
11
11
  "src/cli/commands/overview.ts": ["correlation","econ","market-movers","sectors","world-indices"],
12
- "src/cli/commands/ticker.ts": ["ipo-calendar","notes"],
12
+ "src/cli/commands/ticker.ts": ["ipo-calendar","notes","sec"],
13
13
  "src/cli/desktop-pane-shot.ts": ["market-valuation","time-sales"],
14
14
  "src/cli/pane-functions/data.ts": ["chart-composer","correlation","seasonality","ticker-detail"],
15
15
  "src/cli/pane-functions/financial-ratio-shot.ts": ["ticker-detail"],
@@ -28,6 +28,7 @@
28
28
  "src/components/onboarding/use-onboarding-upgrade.ts": ["chat"],
29
29
  "src/layout/desks.ts": ["chart-composer"],
30
30
  "src/plugins/catalog-browser.ts": ["alerts","analytics","attention","awards","backtest","bond-calculator","catalysts","cds","central-bank-rates","changelog","chart-composer","clinical-trials","cloud","comment-letters","commodities-energy","commodity-balances","company-attention","company-kpis","connections","correlation","cot","cpi","credit-boards","credit-conditions","credit-documents","crypto-board","crypto-etf-flows","debt-maturities","dividend-yield","docs","doe","earnings","earnings-calls","earnings-ripple","econ","econ-statistics","equity-screener","estimate-revisions","executives","exposure","fear-greed","filing-events","fixed-income","futures","futures-curve","fx-matrix","gpu","help","holders","insider","ipo-calendar","iv-history","jobs","jodi","kelly-sizer","layout-manager","macro-day","market-halts","market-heatmap","market-valuation","members","mna","money-markets","news","openfda","options","options-calculator","options-positioning","options-scenario","pe-band","perps","portfolio-list","power","primary-dealers","rate-path","realized-vol","relative-rotation","research","research-search","revenue-breakdown","reverse-dcf","risk-factors","roadmap","scanner","seasonality","sec","sectors","short-interest","short-volume","social-mentions","supply-chain","thirteenf","ticker-detail","time-sales","trace-bonds","treasury-auctions","treasury-daily","vol-surface","volatility","world-indices","world-venue-map","yield-curve"],
31
+ "src/plugins/catalog-cli.ts": ["alerts","fear-greed","news","notes","portfolio-list"],
31
32
  "src/plugins/catalog-ui.ts": ["alerts","clinical-trials","cloud","comment-letters","custom-view","fear-greed","ipo-calendar","market-halts","market-heatmap","members","news","notes","openfda","research-search"],
32
33
  "src/plugins/catalog.ts": ["debug"],
33
34
  "src/remote/controller.ts": ["custom-view"],
@@ -203,7 +203,7 @@ function resolvedOutput(value: unknown): ResolvedSeries {
203
203
  const input = object(value, "resolve output");
204
204
  onlyKeys(input, "resolve output", [
205
205
  "id", "label", "color", "unit", "unitGroup", "nativeFrequency", "timestampMode", "dataShape", "style", "transform",
206
- "axis", "panelId", "interpolation", "timeBasis", "latestChangePercent", "points", "warning", "hidden", "attribution",
206
+ "axis", "panelId", "interpolation", "timeBasis", "latestChangePercent", "points", "warning", "savedAt", "hidden", "attribution",
207
207
  "priceOf",
208
208
  ]);
209
209
  if (!Array.isArray(input.points)) fail("resolve output points", "expected an array.");
@@ -247,6 +247,7 @@ function resolvedOutput(value: unknown): ResolvedSeries {
247
247
  : {}),
248
248
  points: input.points.map(point),
249
249
  ...(warning !== undefined ? { warning } : {}),
250
+ ...(input.savedAt !== undefined ? { savedAt: finiteNumber(input.savedAt, "resolve output saved copy time") as number } : {}),
250
251
  ...(attribution ? { attribution: {
251
252
  source: boundedString(attribution.source, "resolve output source", 160),
252
253
  ...(publisher !== undefined ? { publisher } : {}),
@@ -36,6 +36,7 @@ export function assetDataProvider(provider: AssetDataProvider): AssetDataCapabil
36
36
  operations: {
37
37
  canProvide: op((input: any) => provider.canProvide?.(input.ticker, input.exchange, input.context) ?? true, "query"),
38
38
  primaryMarketSourceName: op(() => provider.primaryMarketSourceName?.() ?? provider.name, "query"),
39
+ batchesReads: op((input: any) => provider.batchesReads?.(input.method) ?? false, "query"),
39
40
  getCachedFinancialsForTargets: op((input: any) => provider.getCachedFinancialsForTargets?.(input.targets ?? [], input.options) ?? new Map()),
40
41
  getQuotesBatch: op((input: any) => provider.getQuotesBatch?.(input.targets ?? [], input.options) ?? Promise.resolve([])),
41
42
  getTickerFinancialsBatch: op((input: any) => provider.getTickerFinancialsBatch?.(input.targets ?? [], input.options) ?? Promise.resolve([])),
@@ -0,0 +1,42 @@
1
+ import { format } from "util";
2
+ import { asciiText } from "../utils/ascii-text";
3
+
4
+ const NON_ASCII = /[^\x00-\x7F]/;
5
+
6
+ type ConsoleMethod = "log" | "info" | "warn" | "error";
7
+ const CONSOLE_STREAMS: ReadonlyArray<readonly [ConsoleMethod, "stdout" | "stderr"]> = [
8
+ ["log", "stdout"], ["info", "stdout"], ["warn", "stderr"], ["error", "stderr"],
9
+ ];
10
+
11
+ /**
12
+ * Writes the command's text in ASCII while `enabled` says so (`cliAsciiEnabled`:
13
+ * plain output to a terminal that cannot show UTF-8), whichever way it is
14
+ * written: `process.stdout.write`, `process.stderr.write` or the console, which
15
+ * Bun writes without going through either stream. Tables are already ASCII
16
+ * when they are drawn, so their columns line up (`renderTable`); this catches
17
+ * the lines around them, such as a source line's `·`. A chunk that is not a
18
+ * string (a PNG on stdout) passes as it is, and so does all output while
19
+ * `enabled` is false.
20
+ */
21
+ export function writeAsciiWhile(enabled: () => boolean): void {
22
+ const needsAscii = (text: string) => NON_ASCII.test(text) && enabled();
23
+ for (const name of ["stdout", "stderr"] as const) {
24
+ const stream = process[name];
25
+ const write = stream.write.bind(stream) as (chunk: unknown, ...rest: unknown[]) => boolean;
26
+ stream.write = ((chunk: unknown, ...rest: unknown[]) => write(
27
+ typeof chunk === "string" && needsAscii(chunk) ? asciiText(chunk) : chunk,
28
+ ...rest,
29
+ )) as typeof stream.write;
30
+ }
31
+ for (const [method, name] of CONSOLE_STREAMS) {
32
+ const original = console[method].bind(console);
33
+ console[method] = (...args: unknown[]) => {
34
+ const text = format(...args);
35
+ if (!needsAscii(text)) {
36
+ original(...args);
37
+ return;
38
+ }
39
+ process[name].write(`${asciiText(text)}\n`);
40
+ };
41
+ }
42
+ }
@@ -3,12 +3,14 @@ import { fixedUsdRate, heldCurrencyUnit } from "../utils/currency-units";
3
3
  import { logFailure } from "../utils/log-failure";
4
4
 
5
5
  /** One rate a converter used: units of `baseCurrency` per unit of `currency`, and when it was observed. */
6
- interface BaseConversion {
6
+ export interface BaseConversion {
7
7
  currency: string;
8
8
  baseCurrency: string;
9
9
  rate: number;
10
10
  /** Epoch ms of the older leg's observation; null when the source did not date it. */
11
11
  asOf: number | null;
12
+ /** A leg is past its fresh window, or its refresh failed and the last copy stands. */
13
+ stale: boolean;
12
14
  }
13
15
 
14
16
  /** Converts an amount into the base currency, and lists the rates it used so a report can state them. */
@@ -21,6 +23,8 @@ export type BaseConverter = ((value: number, fromCurrency: string) => Promise<nu
21
23
  interface UsdRate {
22
24
  rate: number;
23
25
  asOf: number | null;
26
+ /** Past its fresh window, or kept after a failed refresh. */
27
+ stale?: boolean;
24
28
  }
25
29
 
26
30
  export function createBaseConverter(
@@ -38,7 +42,10 @@ export function createBaseConverter(
38
42
  if (dataProvider.getCachedQuery) {
39
43
  const entry = await dataProvider.getCachedQuery("getExchangeRate", [currency])
40
44
  .load({ background: dataProvider.revalidatesInBackground });
41
- return { rate: Number.isFinite(entry.value) && entry.value > 0 ? entry.value : Number.NaN, asOf: entry.asOf ?? null };
45
+ return {
46
+ rate: Number.isFinite(entry.value) && entry.value > 0 ? entry.value : Number.NaN, asOf: entry.asOf ?? null,
47
+ stale: entry.refreshError != null || entry.staleAt <= Date.now(),
48
+ };
42
49
  }
43
50
  const rate = await dataProvider.getExchangeRate(currency);
44
51
  return { rate: Number.isFinite(rate) && rate > 0 ? rate : Number.NaN, asOf: null };
@@ -73,6 +80,7 @@ export function createBaseConverter(
73
80
  baseCurrency: base.currency,
74
81
  rate: fromRate.rate / baseRate.rate,
75
82
  asOf: dates.length > 0 ? Math.min(...dates) : null,
83
+ stale: fromRate.stale === true || baseRate.stale === true,
76
84
  });
77
85
  return (value / from.divisor * fromRate.rate) / baseRate.rate * base.divisor;
78
86
  };
@@ -55,6 +55,21 @@ function declaredOptions(command: CliCommandDef): Map<string, DeclaredOption> |
55
55
  const EXPLAIN_HINT = "--explain follows the reports of fn <function> and portfolio show. "
56
56
  + "gloom catalog explain <term> prints what one term means; gloom catalog glossary lists every term.";
57
57
 
58
+ /** Options people reach for to see a price in another currency, which no command takes: `fx` converts. */
59
+ const CURRENCY_OPTIONS = new Set(["--currency", "--ccy", "--cur", "--convert", "--fx", "--to-currency", "--in-currency"]);
60
+
61
+ /**
62
+ * `quote SBLK --currency EUR`: prices are in each listing's currency, and
63
+ * `fx` converts an amount, so the error names it, with the code given.
64
+ */
65
+ function currencyOptionHint(flag: string, args: readonly string[]): string | null {
66
+ if (!CURRENCY_OPTIONS.has(flag)) return null;
67
+ const at = args.findIndex((arg) => arg === flag || arg.startsWith(`${flag}=`));
68
+ const typed = (args[at]?.includes("=") ? args[at]!.slice(flag.length + 1) : args[at + 1] ?? "").trim().toUpperCase();
69
+ const code = /^[A-Z]{3}$/.test(typed) ? typed : "EUR";
70
+ return `Prices are in each listing's own currency. To convert an amount, use fx: gloom fx 100 USD/${code}.`;
71
+ }
72
+
58
73
  function failUnknownOption(
59
74
  command: BuiltinCliCommandDef,
60
75
  flag: string,
@@ -65,7 +80,7 @@ function failUnknownOption(
65
80
  const suggestion = suggestCliOption(flag, flags);
66
81
  const help = `See gloom help ${command.name}.`;
67
82
  fail(`Unknown option ${flag} for ${command.name}.`, [
68
- command.unknownOptionHint?.(flag, args) ?? (flag === "--explain" ? EXPLAIN_HINT : ""),
83
+ command.unknownOptionHint?.(flag, args) ?? currencyOptionHint(flag, args) ?? (flag === "--explain" ? EXPLAIN_HINT : ""),
69
84
  suggestion ? `Did you mean ${suggestion}?` : "",
70
85
  flags.length > 0 ? `Options: ${flags.join(", ")}. ${help}` : `${command.name} takes no options. ${help}`,
71
86
  ].filter(Boolean).join("\n"));
@@ -73,21 +73,32 @@ export function coinElsewhereNote(symbol: string, listings: ReadonlyArray<{ key:
73
73
  return `${symbol} is ${named}, not ${coin}. For ${coin} use ${symbol}-USD.`;
74
74
  }
75
75
 
76
+ /** A top coin quoted in dollars (BTC-USD, or on the crypto venue BTC-USD:CCC), which the CRYP board lists. */
77
+ function isBoardCoinPair(symbol: string): boolean {
78
+ const [pair = "", venue] = symbol.trim().toUpperCase().split(":");
79
+ const match = venue === undefined || venue === "CCC" ? /^([A-Z0-9]+)-USD$/.exec(pair) : null;
80
+ return !!match && MAJOR_COINS.has(match[1]!);
81
+ }
82
+
76
83
  interface QuoteNoteResult {
77
84
  target: { symbol: string };
78
- quote: Pick<Quote, "name" | "instrumentType"> | null;
85
+ quote: Pick<Quote, "name" | "instrumentType"> & Partial<Pick<Quote, "dataSource">> | null;
79
86
  error: string | null;
80
87
  }
81
88
 
82
89
  /**
83
- * The router words a failure as "<reason> for <symbol>"; drop the symbol so equal reasons group.
84
- * Any other line, such as a sentence the data service wrote, is kept as it reads.
90
+ * The router words a failure as "<reason> for <symbol>", alone or closing its
91
+ * first sentence ("Gloom's data service did not answer for X. Try again in a
92
+ * moment."); drop the symbol so equal reasons group. Any other line, such as a
93
+ * sentence the data service wrote, is kept as it reads.
85
94
  */
86
95
  function failureReason(message: string, symbol: string): string {
87
96
  const line = (message.split("\n")[0] ?? "").trim();
88
97
  const bare = line.replace(/\.+$/, "");
89
98
  const suffix = ` for ${symbol}`;
90
- return bare.toLowerCase().endsWith(suffix.toLowerCase()) ? bare.slice(0, -suffix.length) : line;
99
+ if (bare.toLowerCase().endsWith(suffix.toLowerCase())) return bare.slice(0, -suffix.length);
100
+ const at = line.toLowerCase().indexOf(`${suffix.toLowerCase()}. `);
101
+ return at > 0 ? `${line.slice(0, at)}${line.slice(at + suffix.length)}` : line;
91
102
  }
92
103
 
93
104
  /**
@@ -112,6 +123,14 @@ export function quoteNotes(results: QuoteNoteResult[]): string[] {
112
123
  const perpetuals = results
113
124
  .filter((result) => result.quote && isCryptoVenuePerpetual(result.quote.instrumentType, result.quote.name))
114
125
  .map((result) => result.target.symbol);
126
+ // A top coin's delayed quote is live on the crypto board, which needs no plan to stream it.
127
+ const boardCoins = results
128
+ .filter((result) => result.quote?.dataSource === "delayed" && isCryptoInstrumentType(result.quote.instrumentType ?? "")
129
+ && isBoardCoinPair(result.target.symbol))
130
+ .map((result) => result.target.symbol);
131
+ if (boardCoins.length > 0) {
132
+ notes.push(`${boardCoins.join(", ")} ${boardCoins.length === 1 ? "streams" : "stream"} live on the CRYP board (gloom fn CRYP).`);
133
+ }
115
134
  if (perpetuals.length > 0) {
116
135
  notes.push(`${perpetuals.join(", ")}: perpetual futures ${perpetuals.length === 1 ? "price" : "prices"} on crypto venues, 24/7; not the listed future, not spot.`);
117
136
  }