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
@@ -1,10 +1,13 @@
1
1
  import { logFailure } from "../../utils/log-failure";
2
2
  import type { CliCommandDef } from "../../types/plugin";
3
3
  import { TIME_RANGES, type TimeRange } from "../../time-series/range";
4
+ import { CHART_RESOLUTION_STEP_MS } from "../../time-series/resolution";
4
5
  import { yearToDateStartIndex } from "../../market-data/market/year-to-date";
5
6
  import type { EarningsEvent, QuoteBatchResult, QuoteSubscriptionTarget, SecFilingItem } from "../../types/data-provider";
6
7
  import { companyDataNotes, type CompanyFrom } from "../../types/company-from";
7
8
  import type { NewsArticle, NewsFeed, NewsQuery } from "../../news/types";
9
+ import { newsSummaryLine } from "../../news/news-model";
10
+ import { shortStoryId } from "../../news/story-id";
8
11
  import type {
9
12
  AnalystResearchData,
10
13
  CorporateActionsData,
@@ -40,7 +43,7 @@ import {
40
43
  quoteChangeText,
41
44
  } from "../helpers";
42
45
  import { cliArrow, cliStyles, colorBySign, renderSection, renderStats } from "../../utils/cli-output";
43
- import { filledPeriodsNote, stalePeriodNote, statementHistoryNotes } from "../../utils/financial-statements";
46
+ import { filledPeriodsNote, hasOlderStatements, stalePeriodNote, statementHistoryNotes } from "../../utils/financial-statements";
44
47
  import { formatPerShareNumber } from "../../utils/reported-money";
45
48
  import { isCurrencyPairListing } from "../../utils/fx-market-hours";
46
49
  import {
@@ -52,6 +55,7 @@ import {
52
55
  analystReferenceMetadata,
53
56
  analystUpside,
54
57
  formatAnalystReference,
58
+ ratingReason,
55
59
  } from "../../plugins/builtin/research/analyst-model";
56
60
  import { getPublishedUsEquityCalendarYears, getPublishedUsEquitySession } from "../../market-data/published-us-sessions";
57
61
  import { isQuoteStaleForCurrentSession, noPrintsTodayText } from "../../market-data/quotes/freshness";
@@ -103,6 +107,7 @@ import {
103
107
  } from "../../utils/option-expiry";
104
108
  import { DATE_OPTION_EXAMPLES, isoDateOption, isoDateToday } from "../../utils/calendar-date";
105
109
  import { apiClient } from "../../api-client";
110
+ import { CLOUD_QUOTE_DELAY_MINUTES } from "../../api-client/plan-rules";
106
111
  import type { ExchangeAnnouncementsPayload } from "../../api-client/exchange-announcements";
107
112
  import { exchangeAnnouncementsPage, listsExchangeAnnouncements, type ExchangeAnnouncementsPage } from "../../utils/exchange-announcements";
108
113
  import { dailyFxLeg, fxCloseOnDate, type FxCloseReading } from "../../market-data/fx-closes";
@@ -120,7 +125,7 @@ import {
120
125
  type CliReportTables,
121
126
  } from "../report-tables";
122
127
  import { historyCoverageNotice } from "../../sources/history-coverage";
123
- import { maxDrawdown, maxDrawdownText } from "../../utils/max-drawdown";
128
+ import { maxDrawdownText } from "../../utils/max-drawdown";
124
129
  import { isPastPriceWindow, loadPriceWindowHistory, PRICE_WINDOW_FROM_HELP, PRICE_WINDOW_TO_HELP, priceWindowText, readPriceWindow, type PriceWindow } from "../../utils/price-window";
125
130
  import {
126
131
  BAR_INTERVAL_LABELS,
@@ -131,6 +136,10 @@ import {
131
136
  historyCoverageWarning,
132
137
  historyFacts,
133
138
  historyFlagNote,
139
+ historyWickNote,
140
+ historyContractDrawdown,
141
+ historyRollNote,
142
+ historyThinNote,
134
143
  historyGapNote,
135
144
  historyJumpNote,
136
145
  historyUnbrokenFrom,
@@ -145,13 +154,14 @@ import {
145
154
  historyUnit,
146
155
  quotedPriceDivisor,
147
156
  historyVolume,
157
+ historyVolumeBasis,
148
158
  historyVolumeText,
149
159
  type HistoryRow,
150
160
  type HistoryUnit,
151
161
  type HistoryVolume,
152
162
  } from "../history-rows";
153
163
  import {
154
- HISTORY_EXPORT_COLUMNS,
164
+ historyExportColumns,
155
165
  historyExportStatus,
156
166
  historyFailureRow,
157
167
  oneLineFailure,
@@ -190,7 +200,7 @@ import { DAY_SO_FAR_TEXT, withSessionBar } from "../../time-series/session-bar";
190
200
  import { isFiniteNumber } from "../../utils/guards";
191
201
  import { exportedFundamentals } from "../../utils/price-earnings";
192
202
  import { fundamentalsFreshness, fxPairFreshness, quotesFreshness, rowsFreshness, valuationFreshness } from "../freshness";
193
- import { fxRateNotes } from "../../plugins/builtin/shared/fx-rate-freshness";
203
+ import { fxRateNotes, refreshedFxRateNotes } from "../../plugins/builtin/shared/fx-rate-freshness";
194
204
  import { quoteBarNotes } from "../../market-data/quotes/intraday-bar";
195
205
  import { cedearRatioText, depositaryPairText, isReceiptSide, listingCedearRatio, listingDepositaryPair } from "../../market-data/depositary-pair";
196
206
  import { isPesoDollarPair, loadPesoDollarRates, pesoDollarRateLines, pesoDollarRatesJson } from "../peso-dollar-rates";
@@ -245,13 +255,13 @@ import {
245
255
  type CliListing,
246
256
  type ListingIdentity,
247
257
  } from "../listing-arg";
248
- import { bareListingNote, listingFateNotes, noLongerTradingNote, tradingListing } from "../../tickers/listing-fate";
258
+ import { bareListingNote, listingFateNotes, noLongerTradingNote, SUCCESSOR_CHANGE_WAIT_MS, tradingListing } from "../../tickers/listing-fate";
249
259
  import { isYieldIndexSymbol } from "../../tickers/index-roots";
250
260
  import {
251
261
  analyzeTaxEquivalent, distributionBasis, loadTreasuryTenors, parseTaxRates, TAX_RATE_HELP_OPTIONS, taxEquivalentJson, type TaxRates,
252
262
  } from "../../market-data/tax-equivalent";
253
263
  import { CBOE_YIELD_INDEX_CLOSE } from "../../plugins/builtin/shared/treasury-cutoffs";
254
- import { earningsCalendarFailure, earningsChoiceNote, earningsDateLabel, isListingAbroad, noListingCalendarNote } from "../earnings-calendar";
264
+ import { earningsCalendarFailure, earningsChoiceNote, earningsDateLabel, isListingAbroad, noListingCalendarNote, undatedListingsNote } from "../earnings-calendar";
255
265
  import { formatBasisPoints, toBasisPoints } from "../../utils/basis-points";
256
266
  import { providerMissReason } from "../../sources/provider-errors";
257
267
  import { isNetworkFailure } from "../../utils/network-failure";
@@ -804,7 +814,10 @@ function financialStatementRows(financials: FinancialsCliData) {
804
814
 
805
815
  function newsRows(articles: NewsArticle[]) {
806
816
  return articles.map((article) => ({
817
+ id: article.id,
807
818
  title: article.title,
819
+ // Whole, as exports write it; the text table's line under the row (newsRowNote) runs it together.
820
+ summary: article.summary ?? null,
808
821
  source: article.source,
809
822
  publishedAt: isoDate(article.publishedAt),
810
823
  topic: article.topic,
@@ -822,6 +835,8 @@ function filingRows(filings: SecFilingItem[]) {
822
835
  companyName: filing.companyName ?? "",
823
836
  accessionNumber: filing.accessionNumber,
824
837
  url: filing.primaryDocumentUrl ?? filing.filingUrl,
838
+ // A current report's press release exhibit, where its index names one: the figures, not the cover page.
839
+ pressReleaseUrl: filing.pressReleaseUrl ?? "",
825
840
  items: secFilingItemCodes(filing.items) ?? "",
826
841
  // A current report's items by number and name: the results 8-K reads apart from another filed that day.
827
842
  itemsLabel: currentReportItemsLabel(filing.items) ?? "",
@@ -866,9 +881,16 @@ function analystRows(data: AnalystResearchData) {
866
881
  current: rating.current ?? "",
867
882
  prior: rating.prior ?? "",
868
883
  target: rating.currentPriceTarget ?? null,
884
+ ...(ratingReason(rating) ? { reason: rating.reason } : {}),
869
885
  }));
870
886
  }
871
887
 
888
+ /** The reason coverage of an action gave, under its row with the article. */
889
+ function analystRowNote(row: { reason?: AnalystResearchData["ratings"][number]["reason"] }): string | null {
890
+ const reason = row.reason;
891
+ return reason ? `${reason.text} · ${reason.url}` : null;
892
+ }
893
+
872
894
  /** Provider values carry binary floating-point noise such as 0.26940000000000003. */
873
895
  function cleanDecimal(value: number | undefined): string {
874
896
  return value == null || !Number.isFinite(value) ? "" : String(Number(value.toFixed(6)));
@@ -1043,7 +1065,7 @@ async function runQuote(rawArgs: string[], ctx: Parameters<CliCommandDef["execut
1043
1065
  const listing = asked[index]!;
1044
1066
  // A bare symbol read on a listing abroad (SXR8 -> XETRA) is not the US symbol the changes are of.
1045
1067
  if (result.quote && bareListingNote(listing, result.quote)) return { change: null, formerIssuer: null };
1046
- const payload = await changes.get(listing)?.settle() ?? null;
1068
+ const payload = await changes.get(listing)?.settle(SUCCESSOR_CHANGE_WAIT_MS) ?? null;
1047
1069
  const current = tradingListing(result.quote, now);
1048
1070
  return { change: describeTickerChange(listing.symbol, payload, current), formerIssuer: describeFormerIssuer(listing.symbol, payload, current) };
1049
1071
  }));
@@ -1390,7 +1412,7 @@ async function loadListingHistory(
1390
1412
  : market.dataProvider.getPriceHistory(symbol, exchange, loadRange, context).then((points): PriceHistoryResult => ({ points, resolution: null }));
1391
1413
  const quoteAnswer = loadListingQuoteAnswer(market.dataProvider, listing);
1392
1414
  const quoted = quoteAnswer.then((answer) => answer.quote);
1393
- const fate = lookups ? listingFateLoader(listing, market, quoted) : null;
1415
+ const fate = lookups ? listingFateLoader(listing, market, quoted, { successor: true }) : null;
1394
1416
  const request = { command: historyCommand(ask), noun: "history", ...(fate ? { fate } : {}) };
1395
1417
  const [loaded, quote] = await Promise.all([
1396
1418
  loadForListing(listing, market, ctx, load, (loaded) => loaded.points.length === 0, request)
@@ -1434,21 +1456,28 @@ async function loadListingHistory(
1434
1456
  // A bar history: dated by its last bar, stale once bars of its size stop arriving.
1435
1457
  // The day's own bar, while its session trades, is not a close: dated by the quote it was read from.
1436
1458
  const dayToDate = fromQuote && interval === "1d" && data.at(-1)?.partial === true;
1459
+ // Signed out or free, the bars of a session in progress run as late as the delayed quote they end on, and say how late.
1460
+ const sessionTrading = quote?.marketState === "REGULAR" || quote?.marketState === "PRE" || quote?.marketState === "POST";
1461
+ const delayedTail = quote?.dataSource === "delayed" && !quote.delisting && (dayToDate || (intraday && sessionTrading));
1437
1462
  // The source that served the bars, a broker or another source when Gloom Cloud could not.
1438
1463
  const source = loaded.sourceName ? { source: loaded.sourceName } : {};
1439
1464
  // A window that closed before today is the history asked for: no later bar makes it stale.
1440
1465
  const freshness = withSavedCopy(window && isPastPriceWindow(window) ? rowsFreshness(data, {
1441
1466
  ...source,
1442
1467
  status: "not-a-feed", basis: `${interval ? BAR_INTERVAL_LABELS[interval] : "price"} bars, ${priceWindowText(window)}`, observedKey: "date", oldest: null,
1468
+ ...(volume ? { note: historyVolumeText(volume, interval, historyVolumeBasis(data)) } : {}),
1443
1469
  }) : rowsFreshness(data, {
1444
1470
  ...source,
1445
1471
  ...barHistoryFreshness(intraday ? null : barResolutionFromDates(data.map((row) => row.date))),
1446
1472
  observedKey: "date",
1447
1473
  oldest: null,
1448
1474
  cadenceExchange: venue,
1475
+ // An intraday bar is dated by its open, so the line names its span: `last bar 15:00–16:00 UTC`.
1476
+ ...(intraday && interval && interval in CHART_RESOLUTION_STEP_MS ? { barMinutes: CHART_RESOLUTION_STEP_MS[interval] / 60_000 } : {}),
1449
1477
  ...(forming ? { periodToDate: forming.periodToDate } : closedDay ? { asOf: closedDay } : {}),
1450
1478
  ...(dayToDate ? { basis: "daily bars", ...(quote && Number.isFinite(quote.lastUpdated) ? { asOf: new Date(quote.lastUpdated).toISOString() } : {}) } : {}),
1451
- ...(volume || dayToDate ? { note: [volume ? historyVolumeText(volume, interval) : null, dayToDate ? `the newest bar is ${DAY_SO_FAR_TEXT}` : null].filter(Boolean).join("; ") } : {}),
1479
+ ...(delayedTail ? { status: "delayed" as const, delayMinutes: CLOUD_QUOTE_DELAY_MINUTES } : {}),
1480
+ ...(volume || dayToDate ? { note: [volume ? historyVolumeText(volume, interval, historyVolumeBasis(data)) : null, dayToDate ? `the newest bar is ${DAY_SO_FAR_TEXT}` : null].filter(Boolean).join("; ") } : {}),
1452
1481
  // The rows are drawn from the bars served, which say whether they are the saved copy.
1453
1482
  }), loaded);
1454
1483
  const gaps = historyGapNote(data, traded);
@@ -1464,8 +1493,10 @@ async function loadListingHistory(
1464
1493
  ...window ? [...windowHistoryNotes(window, data), coverage ?? []]
1465
1494
  : range === "YTD" ? ytdHistoryNotes(data) : [...historyNotes(range, interval, data[0]?.date, Date.now(), coverage != null), coverage ?? []],
1466
1495
  // The status line says how far a bar still forming runs; the note is for the bars it does not name.
1467
- gaps ?? [], historyJumpNote(data) ?? [], historyFlagNote(data) ?? [], historyMissingVolumeNote(data) ?? [],
1496
+ gaps ?? [], historyJumpNote(data) ?? [], historyFlagNote(data) ?? [], historyWickNote(data) ?? [], historyMissingVolumeNote(data) ?? [],
1468
1497
  historyVenueVolumeNote(data) ?? [],
1498
+ // NG=F's rows are November's to the 23rd and December's from the 26th: each roll named, and thin bars said.
1499
+ historyRollNote(listing.symbol, data) ?? [], historyThinNote(data) ?? [],
1469
1500
  historyBarStatusNote(forming ? served : data, { tradingDay: venueTradingDay(venue, Date.now()) }) ?? [],
1470
1501
  ].flat();
1471
1502
  return {
@@ -1474,6 +1505,19 @@ async function loadListingHistory(
1474
1505
  };
1475
1506
  }
1476
1507
 
1508
+ /**
1509
+ * A continuous future's history is the front month's, not the contract its
1510
+ * quote names now: NG=F's rows from before the roll are November's under a
1511
+ * quote of "Natural Gas Dec 2026". The heading says "Natural Gas front month"
1512
+ * once the bars name their contracts.
1513
+ */
1514
+ function frontMonthIdentity(identity: ListingIdentity, symbol: string, rows: readonly HistoryRow[]): ListingIdentity {
1515
+ if (!/=F$/i.test(symbol) || !rows.some((row) => row.contract)) return identity;
1516
+ const board = futuresBoardContract(symbol);
1517
+ const name = board?.name ?? identity.name?.replace(/\s+[A-Z][a-z]{2}\s+\d{4}$/, "");
1518
+ return name ? { ...identity, name: `${name} front month` } : identity;
1519
+ }
1520
+
1477
1521
  /** What a listing with no bar for what was asked says, in a warning and in a list's status column. */
1478
1522
  function emptyHistoryNote(symbol: string, { range, window }: HistoryAsk): string {
1479
1523
  return window ? `No bars for ${symbol} from ${priceWindowText(window)}.` : `No bars for ${symbol} in ${range}.`;
@@ -1519,6 +1563,8 @@ const HISTORY_FLAG_TEXT_COLUMN: CliResultColumn = {
1519
1563
  row.partial ? cliStyles.muted("partial") : "",
1520
1564
  row.filled ? cliStyles.muted("filled") : "",
1521
1565
  row.unsettled ? cliStyles.muted("unsettled") : "",
1566
+ row.roll && typeof row.contract === "string" ? cliStyles.muted(`roll to ${row.contract}`) : "",
1567
+ row.thin ? cliStyles.muted("thin") : "",
1522
1568
  typeof row.status === "string" ? cliStyles.warning(row.status) : "",
1523
1569
  ].filter(Boolean).join(" "),
1524
1570
  };
@@ -1572,8 +1618,10 @@ async function runHistory(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
1572
1618
  const missingVolume = historyReportsVolume(data) ? MISSING_VOLUME_TEXT : "";
1573
1619
  const textColumns = historyTextColumns(intraday, price).map((column) => column.key !== "volume" ? column
1574
1620
  : { ...column, format: historyVolumeCell(() => missingVolume) });
1575
- // The largest fall from a close to a later one in the bars shown, said under the heading.
1576
- const drawdown = maxDrawdown(data);
1621
+ // The largest fall from a close to a later one in the bars shown, said under the heading: within one contract
1622
+ // of a continuous future, never from one month's close to another's across a roll.
1623
+ const contractDrawdown = historyContractDrawdown(data);
1624
+ const drawdown = contractDrawdown?.drawdown ?? null;
1577
1625
  ctx.printResult({
1578
1626
  data,
1579
1627
  metadata: {
@@ -1590,20 +1638,21 @@ async function runHistory(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
1590
1638
  // The first bar after the last gap or jump; the first bar when there is none.
1591
1639
  unbrokenFrom: historyUnbrokenFrom(data) ?? data[0]?.date ?? null,
1592
1640
  bars: data.length,
1593
- maxDrawdown: drawdown,
1641
+ maxDrawdown: drawdown && contractDrawdown?.contract ? { ...drawdown, contract: contractDrawdown.contract } : drawdown,
1594
1642
  asOf: freshness?.asOf ?? null,
1595
1643
  ...(volume ? { volumeUnit: volume.unit, volumePeriod: interval === "1d" ? "UTC day" : interval } : {}),
1596
1644
  },
1597
1645
  ...(notes.length > 0 ? { warnings: notes } : {}),
1598
1646
  freshness,
1599
1647
  }, {
1600
- heading: [listingHeading(identity), cliStyles.muted(historyFacts(unit, data).join(" · ")),
1601
- ...drawdown && interval ? [cliStyles.muted(maxDrawdownText(drawdown, { basis: `${BAR_INTERVAL_LABELS[interval]} closes`, price,
1648
+ heading: [listingHeading(frontMonthIdentity(identity, history.listing.symbol, data)), cliStyles.muted(historyFacts(unit, data).join(" · ")),
1649
+ ...drawdown && interval ? [cliStyles.muted(maxDrawdownText(drawdown, {
1650
+ basis: `${BAR_INTERVAL_LABELS[interval]} closes${contractDrawdown?.contract ? `, ${contractDrawdown.contract}` : ""}`, price,
1602
1651
  date: (text) => intraday ? formatUtcTime(text) : text.slice(0, 10) }))] : []].join("\n"),
1603
1652
  dateKey: "date",
1604
1653
  textColumns: [...textColumns, HISTORY_FLAG_TEXT_COLUMN],
1605
- // One header whatever the market is doing, for one symbol as for a list (HISTORY_EXPORT_COLUMNS).
1606
- columns: HISTORY_EXPORT_COLUMNS,
1654
+ // One header whatever the market is doing, for one symbol as for a list (historyExportColumns).
1655
+ columns: historyExportColumns(data),
1607
1656
  exportStatus: historyExportStatus,
1608
1657
  // Every exported row says what it is a bar of, the currency a price is in and its bar size, so it survives head and concatenation.
1609
1658
  exportIdentity: { symbolOrSeries: history.listing.key, currencyOrUnit: unit.currency ?? unit.unit, interval },
@@ -1709,7 +1758,7 @@ async function runHistoryList(
1709
1758
  dateKey: "date",
1710
1759
  textColumns: [{ key: "symbol", header: "Symbol", shrink: false }, ...textColumns,
1711
1760
  { key: "currency", header: "Cur", shrink: false, format: currencyCell }, HISTORY_FLAG_TEXT_COLUMN],
1712
- columns: HISTORY_EXPORT_COLUMNS,
1761
+ columns: historyExportColumns(rows),
1713
1762
  exportStatus: historyExportStatus,
1714
1763
  // Every row names its symbol, the currency its prices are in, its bar size and the as-of of its own symbol's bars.
1715
1764
  exportIdentity: (row) => {
@@ -1881,7 +1930,11 @@ async function runFinancials(rawArgs: string[], ctx: Parameters<CliCommandDef["e
1881
1930
  // Years filled from the listing's exchange, for the revenue and net income columns.
1882
1931
  const filled = filledPeriodsNote(financials.annualStatements.filter((statement) => rows.some((row) => row.date === statement.date)),
1883
1932
  new Set(["totalRevenue", "netIncome"]));
1884
- const historyNotes = [...stale ? [stale] : [], ...filled ? [filled] : [], ...statementHistoryNotes("annual", rows.map((row) => row.date), listing.key)];
1933
+ // GF is pointed to only when the listing's extended history goes further back than these years.
1934
+ const dates = rows.map((row) => row.date);
1935
+ const older = await hasOlderStatements(() => market.dataProvider.getTickerFinancials(listing.request.symbol, listing.request.exchange,
1936
+ { statementHistory: "extended" }), "annual", dates);
1937
+ const historyNotes = [...stale ? [stale] : [], ...filled ? [filled] : [], ...statementHistoryNotes("annual", dates, listing.key, older)];
1885
1938
  // NDJSON keeps the raw statement rows it always wrote; CSV gets the table and its closing lines.
1886
1939
  const tables = tabular
1887
1940
  ? selectTables({
@@ -1924,9 +1977,18 @@ const NEWS_COLUMNS = [
1924
1977
  { key: "source", header: "Source" },
1925
1978
  { key: "title", header: "Title" },
1926
1979
  { key: "tickers", header: "Tickers" },
1980
+ // The short id `fn news-story-pane` opens the story by; exports keep the whole id.
1981
+ { key: "id", header: "ID", format: (value: unknown) => typeof value === "string" ? shortStoryId(value) : "" },
1927
1982
  { key: "url", header: "URL", optional: true },
1928
1983
  ];
1929
1984
 
1985
+ /**
1986
+ * A story's summary under its row, on one line, cut to the width (`rowNote`): the figure a headline leaves out.
1987
+ * None for a summary that only repeats the headline; exports keep the summary whole.
1988
+ */
1989
+ const newsRowNote = (row: Record<string, unknown>) => typeof row.summary === "string"
1990
+ ? newsSummaryLine({ title: String(row.title ?? ""), summary: row.summary }) : null;
1991
+
1930
1992
  /**
1931
1993
  * Stories matching text, printed as a symbol's news is, under a line saying
1932
1994
  * what they match. A text naming a commodity that matched nothing says so and
@@ -1963,6 +2025,7 @@ async function printNewsSearch(
1963
2025
  heading: newsSearchHeading(text, [reason, closestReason].filter(Boolean).join(" · ") || undefined),
1964
2026
  rows: newsRows,
1965
2027
  columns: NEWS_COLUMNS,
2028
+ rowNote: newsRowNote,
1966
2029
  empty: named ? noStoriesMessage(text, route) : empty ?? (searched ? noStoriesMessage(text, null) : "No stories to show."),
1967
2030
  });
1968
2031
  }
@@ -2006,6 +2069,7 @@ async function printMetalNews(route: MetalNewsRoute, limit: number, ctx: Paramet
2006
2069
  heading: metalNewsHeading(route),
2007
2070
  rows: newsRows,
2008
2071
  columns: NEWS_COLUMNS,
2072
+ rowNote: newsRowNote,
2009
2073
  empty: failure === undefined ? noMetalStoriesMessage(route) : "No stories to show.",
2010
2074
  ...(ticker ? { footnote: `${word} ${cliArrow("→")} ${route.metal}'s market news. For ${ticker.name ?? ticker.symbol} (ticker ${ticker.symbol}), try: ${companyNews}` } : {}),
2011
2075
  });
@@ -2108,6 +2172,7 @@ async function runNews(rawArgs: string[], ctx: Parameters<CliCommandDef["execute
2108
2172
  ...(identity ? { heading: listingHeading(identity) } : {}),
2109
2173
  rows: newsRows,
2110
2174
  columns: NEWS_COLUMNS,
2175
+ rowNote: newsRowNote,
2111
2176
  ...(empty ? { empty } : {}),
2112
2177
  ...(wordHint ? { footnote: wordHint } : {}),
2113
2178
  });
@@ -2122,15 +2187,18 @@ const FILING_COLUMNS = [
2122
2187
  { key: "url", header: "URL", optional: true },
2123
2188
  { key: "items", header: "Items" },
2124
2189
  { key: "itemsLabel", header: "Item names" },
2190
+ { key: "pressReleaseUrl", header: "Press release URL" },
2125
2191
  ];
2126
2192
 
2127
- // The text table names the items before the URL, which a narrow terminal drops first.
2193
+ // The text table names the items before the URL, which a narrow terminal drops first. A current report's
2194
+ // URL is its press release where it has one, the page its figures are on; exports keep both links.
2128
2195
  const FILING_TEXT_COLUMNS = [
2129
2196
  { key: "filingDate", header: "Date" },
2130
2197
  { key: "form", header: "Form" },
2131
2198
  { key: "companyName", header: "Company", maxWidth: 24 },
2132
2199
  { key: "itemsLabel", header: "Items" },
2133
- { key: "url", header: "URL", optional: true },
2200
+ { key: "url", header: "URL", optional: true,
2201
+ format: (value: unknown, row: Record<string, unknown>) => String(row.pressReleaseUrl || (value ?? "")) },
2134
2202
  ];
2135
2203
 
2136
2204
  /** The US listing the SEC files a symbol under, from the symbol's venues: NYSE for SAN's Banco Santander. */
@@ -2626,6 +2694,7 @@ async function runAnalyst(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2626
2694
  heading: listingHeading(identity),
2627
2695
  rows: analystRows,
2628
2696
  summary: (research) => analystSummary(research, quote),
2697
+ rowNote: analystRowNote,
2629
2698
  columns: [
2630
2699
  { key: "date", header: "Date" },
2631
2700
  { key: "firm", header: "Firm" },
@@ -2717,7 +2786,7 @@ async function runOptions(rawArgs: string[], ctx: Parameters<CliCommandDef["exec
2717
2786
  const refresh = ctx.cliOptions.refresh;
2718
2787
  const venues = loadBareVenues(listing, market);
2719
2788
  const quotePromise = loadListingQuote(market.dataProvider, listing);
2720
- const fate = listingFateLoader(listing, market, quotePromise);
2789
+ const fate = listingFateLoader(listing, market, quotePromise, { successor: true });
2721
2790
  const inputsPromise = loadOptionModelInputs(market.dataProvider, listing, quotePromise, refresh);
2722
2791
  const now = Date.now();
2723
2792
  // Expiries close on the listing's clock: a coin's options (Deribit) settle at 08:00 UTC on any day.
@@ -3073,7 +3142,9 @@ async function runFx(rawArgs: string[], ctx: Parameters<CliCommandDef["execute"]
3073
3142
  }));
3074
3143
  const freshness = fxPairFreshness(loaded);
3075
3144
  // A rate that is its pair's bar says which bar, and a stale one why it stands.
3076
- const rateNotes = fxRateNotes(new Map([...loaded].map(([code, leg]) => [code, leg.timing])));
3145
+ const timings = new Map([...loaded].map(([code, leg]) => [code, leg.timing]));
3146
+ // --refresh read every leg again: one that is still stale says the data service has no newer rate.
3147
+ const rateNotes = [...fxRateNotes(timings), ...ctx.cliOptions.refresh ? refreshedFxRateNotes(timings) : []];
3077
3148
  if (tenor && shortRates && !("error" in tenor)) {
3078
3149
  const read = await shortRates;
3079
3150
  if ("error" in read) throw read.error;
@@ -3209,12 +3280,14 @@ async function runEarnings(rawArgs: string[], ctx: Parameters<CliCommandDef["exe
3209
3280
  return listed ? earningsChoiceNote(listing, eventOf(listing), await listed) : null;
3210
3281
  })),
3211
3282
  ]);
3212
- const noCalendar = abroadNotes.join("\n");
3283
+ // A listing at home the calendar has no date for is named as well: a list never drops a symbol unsaid.
3284
+ const undated = undatedListingsNote(listings.filter((listing) => !isListingAbroad(listing) && !eventOf(listing)));
3285
+ const noCalendar = [...abroadNotes, ...undated ? [undated] : []].join("\n");
3213
3286
  // Text prints the listings without a calendar under the table; other formats carry them as warnings.
3214
3287
  const warnings = [
3215
3288
  ...listings.flatMap(listingReadNotes),
3216
3289
  ...choiceNotes.filter((note): note is string => !!note),
3217
- ...ctx.cliOptions.format === "text" ? [] : abroadNotes,
3290
+ ...ctx.cliOptions.format === "text" ? [] : [...abroadNotes, ...undated ? [undated] : []],
3218
3291
  ];
3219
3292
  ctx.printResult({
3220
3293
  data: events,
@@ -3280,14 +3353,15 @@ export const marketDataCliCommands: BuiltinCliCommandDef[] = [
3280
3353
  title: "Bars",
3281
3354
  lines: [
3282
3355
  `Each range comes in one bar size: ${historyIntervalsByRange()}. The line under the heading, and the --json metadata, give the currency, the bar size actually served, the first and last bar and the bar count. A warning says when the bars are coarser, or start later, than the range asked for, and for a coin, which trades every day, names each day it has no bar for.`,
3283
- "A bar whose prices contradict each other (high below the open or close, or low above them) is left blank and flagged, such as high<open, with the count in a warning. --json rows carry currency, unit, interval and flag.",
3356
+ "A bar whose prices contradict each other (high below the open or close, or low above them) is left blank and flagged, such as high<open, with the count in a warning. A low under half the open and close, or a high over twice them, is left blank alone and flagged low<close/2 or high>2*open. --json rows carry currency, unit, interval and flag.",
3284
3357
  "A break in the series flags the bar after it, which keeps its prices: gap after more than three months with no bar (weeks for weekly, daily and intraday bars), jump when the close is over 100 times the one before or under a hundredth of it. A warning names each break, and the heading says the date the series runs unbroken from.",
3285
3358
  "The heading's last line is the max drawdown of the bars shown: the largest fall from a close to a later close, with the peak and the trough, their dates, and the date a close got back to the peak, if one did (maxDrawdown in --json).",
3286
3359
  ],
3287
3360
  }, {
3288
3361
  title: "CSV",
3289
3362
  lines: [
3290
- "Every --csv has one header, whatever the symbol, range or market state: Date, Open, High, Low, Close, Volume, Flag, Partial, Filled, Unsettled, Volume unit, Volume note, Venue volume, Volume venue, status, then symbol_or_series, currency_or_unit, interval, source and as_of. Prices are plain numbers in the currency currency_or_unit names. Partial, Filled and Unsettled are true or false, and status says why a row has no prices.",
3363
+ "Every --csv has one header, whatever the symbol, range or market state: Date, Open, High, Low, Close, Volume, Flag, Partial, Filled, Unsettled, Volume unit, Volume note, Venue volume, Volume venue, Volume basis, status, then symbol_or_series, currency_or_unit, interval, source and as_of. Prices are plain numbers in the currency currency_or_unit names. Partial, Filled and Unsettled are true or false, and status says why a row has no prices.",
3364
+ "A continuous future whose bars name their contracts (NG=F) adds Contract, Roll and Thin before status: the contract per bar, and true or false for the bar it rolled at and a bar that traded far below those around it.",
3291
3365
  ],
3292
3366
  }, {
3293
3367
  title: "Several symbols",
@@ -72,14 +72,30 @@ export function newsFallbackText(symbol: string): string | null {
72
72
  }
73
73
 
74
74
  /**
75
- * The stories matching the text, in the service's order: stories with every
76
- * word in the headline first, then the ones with some only in the summary,
77
- * newest first within each. The service holds stories back from an account
75
+ * Stories newest first, as `news <words>` lists them. The service picks the
76
+ * best matches (every word in the headline before words only in the summary);
77
+ * the list is then read by date, which its help promises. A story with no
78
+ * date goes last; equal dates keep the service's order.
79
+ */
80
+ function newestFirst(articles: readonly NewsArticle[]): NewsArticle[] {
81
+ const time = (article: NewsArticle) => {
82
+ const at = new Date(article.publishedAt as Date | string | number).getTime();
83
+ return Number.isFinite(at) ? at : -Infinity;
84
+ };
85
+ return articles.map((article, index) => ({ article, index, at: time(article) }))
86
+ .sort((left, right) => right.at - left.at || left.index - right.index)
87
+ .map(({ article }) => article);
88
+ }
89
+
90
+ /**
91
+ * The stories matching the text, newest first (`newestFirst`): the service
92
+ * chooses them, stories with every word in the headline ahead of the ones with
93
+ * some only in the summary. The service holds stories back from an account
78
94
  * without real-time access, as every other news request.
79
95
  */
80
96
  export async function searchNewsStories(text: string, limit: number, topics?: readonly string[]): Promise<NewsArticle[]> {
81
97
  const response = await apiClient.searchCloudNews(text, limit, topics);
82
- return response.items.map((item) => mapCloudNewsArticle(item));
98
+ return newestFirst(response.items.map((item) => mapCloudNewsArticle(item)));
83
99
  }
84
100
 
85
101
  /** A search's stories, and whether they are its closest ones because no story has every word. */
@@ -96,7 +112,10 @@ export interface NewsSearchAnswer {
96
112
  */
97
113
  export async function searchClosestNewsStories(text: string, limit: number): Promise<NewsSearchAnswer> {
98
114
  const response = await apiClient.searchCloudNews(text, limit, undefined, { closest: true });
99
- return { found: response.items.map((item) => mapCloudNewsArticle(item)), closest: response.match === "closest" };
115
+ const found = response.items.map((item) => mapCloudNewsArticle(item));
116
+ // The closest stories stay most words first, as their heading says; a match of every word is read by date.
117
+ const closest = response.match === "closest";
118
+ return { found: closest ? found : newestFirst(found), closest };
100
119
  }
101
120
 
102
121
  /** What the heading says of a search no story has every word of. */
@@ -1,6 +1,6 @@
1
1
  import { logFailure } from "../../utils/log-failure";
2
2
  import { apiClient } from "../../api-client";
3
- import { ApiRequestError, isPermanentClientError } from "../../api-client/errors";
3
+ import { ApiRequestError } from "../../api-client/errors";
4
4
  import type { CliCommandDef } from "../../types/plugin";
5
5
  import { withCliServices, withConfigData, withMarketData } from "../context";
6
6
  import { CLI_ERROR_CODE, failWithFields } from "../errors";
@@ -59,7 +59,7 @@ import { buildCorrelationSeries } from "../../plugins/builtin/correlation/matrix
59
59
  import { alignDailyCloses, correlateDailyCloses } from "../../plugins/builtin/correlation/compute";
60
60
  import { mixedSessionCloseNote } from "../../market-data/market/session-close-note";
61
61
  import { CORRELATION_RETURN_BASIS, loadCorrelationHistory } from "../../plugins/builtin/correlation/history";
62
- import { EXCHANGE_OPTION, listingIdentity, listingReadNotes, loadForListing, loadListingQuote, requireCliListing, type CliListing } from "../listing-arg";
62
+ import { coinListingNotes, EXCHANGE_OPTION, listingIdentity, listingReadNotes, loadForListing, loadListingQuote, requireCliListing, type CliListing } from "../listing-arg";
63
63
  import { CLI_COMMAND_GROUPS } from "../help";
64
64
  import { formatChangePercentCell, formatCompactCell } from "../helpers";
65
65
  import { WORLD_INDICES } from "../../plugins/builtin/world-indices/indices";
@@ -481,7 +481,7 @@ async function runEcon(args: string[], ctx: Parameters<CliCommandDef["execute"]>
481
481
  const country = parseCountry(takeOption(rawArgs, "--country"), ctx);
482
482
  const impact: ImpactFilter = parseFilter(takeOption(rawArgs, "--impact"), FILTER_CYCLE, "impact", ctx);
483
483
  const search = takeOption(rawArgs, "--search")?.trim() ?? null;
484
- if (search === "") ctx.fail("--search needs the words of an event's name.", "Such as econ --search nonfarm.");
484
+ if (search === "") ctx.fail("--search needs the words of an event's name or its publisher.", "Such as econ --search nonfarm.");
485
485
  const fromOption = parseDateOption(takeOption(rawArgs, "--from"), "--from", ctx);
486
486
  const tzOption = takeOption(rawArgs, "--tz");
487
487
  const viewerZone = tzOption == null ? null : canonicalTimeZone(tzOption);
@@ -646,16 +646,15 @@ function withSavedFredSeries<T>(ctx: Parameters<CliCommandDef["execute"]>[1], ru
646
646
 
647
647
  /**
648
648
  * A FRED series from Gloom Cloud, or the copy an earlier read saved when it
649
- * cannot be refreshed (marked as such). A refusal asking again will not change
650
- * (a series Gloom Cloud no longer serves, access denied) is said, not covered.
649
+ * cannot be refreshed (marked as such). A refusal (a series Gloom Cloud no
650
+ * longer serves, access denied) is said, not covered: `loadCachedFredSeries`
651
+ * throws it.
651
652
  */
652
653
  async function loadFredSeries(
653
654
  seriesId: string,
654
655
  params: { startDate?: string; limit?: number; sortOrder: "asc" | "desc" },
655
656
  ): Promise<CloudFredSeriesPayload> {
656
- const result = await loadCachedFredSeries({ seriesId, ...params }, () => apiClient.getCloudFredSeries(seriesId, params));
657
- if (result.source === "stale-fallback" && isPermanentClientError(result.error)) throw result.error;
658
- return result.data;
657
+ return (await loadCachedFredSeries({ seriesId, ...params }, () => apiClient.getCloudFredSeries(seriesId, params))).data;
659
658
  }
660
659
 
661
660
  async function runFredList(filter: string, ctx: Parameters<CliCommandDef["execute"]>[1]) {
@@ -910,7 +909,12 @@ async function runCorrelation(rawArgs: string[], ctx: Parameters<CliCommandDef["
910
909
  asOf: newestReportTime(lastBars),
911
910
  oldest: oldestReportTime(lastBars),
912
911
  });
913
- const warnings = [...listingReadNotes(leftListing!), ...listingReadNotes(rightListing!), ...sessionNote ? [sessionNote] : []];
912
+ // A coin's code read as a listing (BTC, the Grayscale fund) says so, as `quote BTC` does.
913
+ const warnings = [
914
+ ...listingReadNotes(leftListing!), ...listingReadNotes(rightListing!),
915
+ ...coinListingNotes(leftListing!, leftQuote), ...coinListingNotes(rightListing!, rightQuote),
916
+ ...sessionNote ? [sessionNote] : [],
917
+ ];
914
918
  ctx.printResult({
915
919
  data: [{ left, right, samples: sampleSize, correlation }],
916
920
  ...(warnings.length > 0 ? { warnings } : {}),
@@ -972,7 +976,7 @@ export const overviewCliCommands: CliCommandDef[] = [
972
976
  options: [
973
977
  { flags: "--country <regions or countries>", description: "US, G7, EU, all (default), or countries by their two-letter codes, comma separated, such as MX or MX,BR,ZA" },
974
978
  { flags: "--impact <level>", description: "high, medium, low, or all (default all)" },
975
- { flags: "--search <words>", description: "Events whose name has these words, case, spaces and hyphens aside, such as nonfarm or fed funds" },
979
+ { flags: "--search <words>", description: "Events whose name or publisher has these words, case, spaces and hyphens aside, such as nonfarm, fed funds or USDA" },
976
980
  { flags: "--from <date>", description: `First day listed, as ${DATE_OPTION_EXAMPLES} (default today, UTC); an earlier day lists past events from the stored calendar and says where it starts` },
977
981
  { flags: "--tz <zone>", description: "Add a column with each release's time on that clock, an IANA zone such as America/New_York; with the weekday when it falls on another day than the UTC date" },
978
982
  ],