@gloom-sh/terminal 0.18.5 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (436) hide show
  1. package/package.json +1 -1
  2. package/patches/electrobun@1.18.1.patch +140 -7
  3. package/src/api-client/cot.ts +6 -2
  4. package/src/api-client/credit-documents.ts +6 -0
  5. package/src/api-client/data.ts +17 -6
  6. package/src/api-client/equity-screener.ts +24 -0
  7. package/src/api-client/fund-facts.ts +45 -4
  8. package/src/api-client/index.ts +11 -0
  9. package/src/api-client/market-discovery.ts +10 -0
  10. package/src/api-client/market-movers.ts +7 -0
  11. package/src/api-client/members.ts +1 -1
  12. package/src/api-client/perps.ts +43 -0
  13. package/src/api-client/research-activity.ts +3 -2
  14. package/src/api-client/types.ts +70 -2
  15. package/src/app/pane-runtime/plugin-bindings.ts +9 -5
  16. package/src/app/runtime/broker-import.ts +0 -2
  17. package/src/app/runtime/plugin-bindings.ts +73 -56
  18. package/src/architecture/pane-tabs-allowlist.json +3 -0
  19. package/src/architecture/ttl-caches-allowlist.json +19 -0
  20. package/src/brokers/sync-broker-instance.ts +2 -8
  21. package/src/capabilities/chart-series.ts +1 -1
  22. package/src/cli/commands/crypto-hints.ts +40 -24
  23. package/src/cli/commands/market.ts +72 -26
  24. package/src/cli/commands/options-chain.ts +48 -7
  25. package/src/cli/commands/options-leaps.ts +9 -3
  26. package/src/cli/commands/overview.ts +61 -12
  27. package/src/cli/commands/search.ts +21 -1
  28. package/src/cli/commands/themes.ts +11 -2
  29. package/src/cli/commands/ticker.ts +55 -34
  30. package/src/cli/company-name-hint.ts +41 -0
  31. package/src/cli/earnings-calendar.ts +1 -1
  32. package/src/cli/errors.ts +8 -0
  33. package/src/cli/glossary.ts +25 -2
  34. package/src/cli/history-rows.ts +57 -9
  35. package/src/cli/index.ts +2 -0
  36. package/src/cli/listing-arg.ts +180 -52
  37. package/src/cli/output-file.ts +68 -0
  38. package/src/cli/pane-functions/capabilities.ts +3 -0
  39. package/src/cli/pane-functions/catalog.ts +80 -7
  40. package/src/cli/pane-functions/dom.ts +13 -3
  41. package/src/cli/pane-functions/freshness.ts +86 -3
  42. package/src/cli/pane-functions/function-help.ts +13 -10
  43. package/src/cli/pane-functions/headless.ts +17 -7
  44. package/src/cli/pane-functions/index.ts +49 -14
  45. package/src/cli/pane-functions/market-session.ts +66 -4
  46. package/src/cli/pane-functions/options.ts +19 -1
  47. package/src/cli/pane-functions/resolver.ts +19 -8
  48. package/src/cli/pane-functions/screenshot-assessment.ts +6 -4
  49. package/src/cli/pane-functions/screenshot-types.ts +5 -0
  50. package/src/cli/quote-answer.ts +22 -11
  51. package/src/cli/ticker-resolution.ts +3 -2
  52. package/src/components/chart/composite/composite-chart.tsx +4 -0
  53. package/src/components/chart/composite/interactions.ts +6 -0
  54. package/src/components/chart/composite/legend.tsx +45 -7
  55. package/src/components/chart/composite/panel-gestures.ts +33 -0
  56. package/src/components/chart/composite/panel-surface.tsx +52 -3
  57. package/src/components/chart/composite/rasterizer.ts +24 -13
  58. package/src/components/chart/composite/scene.ts +39 -4
  59. package/src/components/chart/composite/series-cues.ts +14 -0
  60. package/src/components/chart/composite/text-renderer.ts +9 -2
  61. package/src/components/chart/composite/tool-catalog.ts +36 -0
  62. package/src/components/chart/composite/tools.ts +203 -44
  63. package/src/components/chart/composite/use-composite-chart-keyboard.ts +11 -4
  64. package/src/components/command-bar/assist/inventory.ts +2 -1
  65. package/src/components/command-bar/commands/direct/index.ts +28 -13
  66. package/src/components/command-bar/pane-templates/items.ts +3 -2
  67. package/src/components/command-bar/workflow/collection-actions.ts +3 -3
  68. package/src/components/onboarding/onboarding-wizard.tsx +4 -1
  69. package/src/components/onboarding/portfolio-step/positions-panel.tsx +12 -7
  70. package/src/components/onboarding/wizard-broker-sync.ts +0 -1
  71. package/src/components/onboarding/wizard-positions.ts +3 -3
  72. package/src/components/ticker/list-table-view.tsx +4 -1
  73. package/src/components/ui/choice-dialog.tsx +23 -18
  74. package/src/components/ui/choice-groups.ts +18 -0
  75. package/src/components/ui/data-table/opentui/index.tsx +9 -7
  76. package/src/components/ui/data-table/opentui/model.ts +26 -1
  77. package/src/components/ui/data-table/types.ts +2 -0
  78. package/src/components/ui/list-view.tsx +8 -4
  79. package/src/components/ui/query-bar-keys.tsx +2 -0
  80. package/src/components/ui/query-bar.tsx +1 -0
  81. package/src/components/ui/select-button.tsx +5 -1
  82. package/src/components/ui/select-field.tsx +1 -0
  83. package/src/components/ui/table-layout.ts +8 -5
  84. package/src/core/app-runtime.ts +2 -0
  85. package/src/core/app-services.ts +2 -2
  86. package/src/data/config/chart-settings.ts +1 -1
  87. package/src/data/json-ticker-repository.ts +17 -8
  88. package/src/data/ticker-repository.ts +16 -9
  89. package/src/data/ticker-writes.ts +81 -0
  90. package/src/data/ttl-cache.ts +165 -0
  91. package/src/docs/snapshot.json +71 -137
  92. package/src/i18n/es.ts +18 -2
  93. package/src/i18n/ja.ts +18 -2
  94. package/src/i18n/ko.ts +18 -2
  95. package/src/i18n/zh-cn.ts +18 -2
  96. package/src/i18n/zh-tw.ts +18 -2
  97. package/src/market-data/depositary-pair.ts +2 -2
  98. package/src/market-data/fund-facts.ts +50 -0
  99. package/src/market-data/market/change-basis.ts +16 -3
  100. package/src/market-data/market/format.ts +25 -0
  101. package/src/market-data/market/freshness.ts +2 -1
  102. package/src/market-data/options-alternatives.ts +81 -4
  103. package/src/news/aggregator.ts +113 -9
  104. package/src/news/cloud-session.ts +21 -0
  105. package/src/news/hooks.ts +1 -0
  106. package/src/news/news-model.ts +1 -0
  107. package/src/news/types.ts +11 -0
  108. package/src/plugins/builtin/alerts/alert-engine.ts +20 -1
  109. package/src/plugins/builtin/alerts/alert-log.ts +33 -0
  110. package/src/plugins/builtin/alerts/cli-forms.ts +216 -0
  111. package/src/plugins/builtin/alerts/cli.ts +336 -77
  112. package/src/plugins/builtin/alerts/command.ts +25 -1
  113. package/src/plugins/builtin/alerts/events-pane.tsx +19 -4
  114. package/src/plugins/builtin/alerts/fired-log.ts +73 -9
  115. package/src/plugins/builtin/alerts/format.ts +75 -5
  116. package/src/plugins/builtin/alerts/headless.ts +24 -6
  117. package/src/plugins/builtin/alerts/history-rows.ts +3 -2
  118. package/src/plugins/builtin/alerts/history.ts +1 -1
  119. package/src/plugins/builtin/alerts/index.tsx +79 -16
  120. package/src/plugins/builtin/alerts/metric-command.ts +77 -4
  121. package/src/plugins/builtin/alerts/metric-data.ts +54 -13
  122. package/src/plugins/builtin/alerts/metric-model.ts +163 -14
  123. package/src/plugins/builtin/alerts/metric-parity-fixture.json +1 -1
  124. package/src/plugins/builtin/alerts/pane.tsx +61 -23
  125. package/src/plugins/builtin/alerts/quotes.ts +6 -0
  126. package/src/plugins/builtin/alerts/storage.ts +12 -8
  127. package/src/plugins/builtin/alerts/types.ts +4 -0
  128. package/src/plugins/builtin/analytics/index.tsx +2 -1
  129. package/src/plugins/builtin/analytics/risk-client.ts +16 -5
  130. package/src/plugins/builtin/analytics/risk-fx.ts +70 -15
  131. package/src/plugins/builtin/analytics/risk-headless.ts +27 -0
  132. package/src/plugins/builtin/analytics/risk-model.ts +55 -9
  133. package/src/plugins/builtin/analytics/risk-pane.tsx +8 -2
  134. package/src/plugins/builtin/attention/index.tsx +2 -1
  135. package/src/plugins/builtin/attention/listing.ts +14 -0
  136. package/src/plugins/builtin/broker-manager/index.tsx +7 -3
  137. package/src/plugins/builtin/buildout/cells.tsx +12 -4
  138. package/src/plugins/builtin/buildout/format.ts +38 -0
  139. package/src/plugins/builtin/buildout/model/normalizers.ts +36 -1
  140. package/src/plugins/builtin/buildout/pane/index.tsx +4 -1
  141. package/src/plugins/builtin/buildout/table-model.ts +23 -2
  142. package/src/plugins/builtin/builtin-plugin-meta.ts +6 -2
  143. package/src/plugins/builtin/changelog/index.tsx +9 -6
  144. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +3 -0
  145. package/src/plugins/builtin/chart-composer/cli-options.ts +4 -0
  146. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +7 -0
  147. package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -2
  148. package/src/plugins/builtin/chart-composer/headless-schema.ts +7 -1
  149. package/src/plugins/builtin/chart-composer/headless.ts +6 -1
  150. package/src/plugins/builtin/chart-composer/index.tsx +1 -1
  151. package/src/plugins/builtin/chart-composer/pane.tsx +37 -8
  152. package/src/plugins/builtin/chart-composer/settings.ts +27 -0
  153. package/src/plugins/builtin/chat/content/command-suggestions.ts +1 -0
  154. package/src/plugins/builtin/chat/pane-links/commands.ts +7 -1
  155. package/src/plugins/builtin/clinical-trials/model.ts +0 -9
  156. package/src/plugins/builtin/clinical-trials/pane.tsx +15 -22
  157. package/src/plugins/builtin/clinical-trials/sponsor-tickers.ts +8 -6
  158. package/src/plugins/builtin/cloud/askg/manifest.ts +2 -0
  159. package/src/plugins/builtin/company-attention/building.tsx +5 -1
  160. package/src/plugins/builtin/company-attention/client.ts +8 -9
  161. package/src/plugins/builtin/company-attention/evidence.ts +4 -1
  162. package/src/plugins/builtin/company-attention/moves.tsx +5 -1
  163. package/src/plugins/builtin/company-attention/pane.tsx +9 -2
  164. package/src/plugins/builtin/company-attention/signals.tsx +5 -1
  165. package/src/plugins/builtin/correlation/headless.ts +13 -5
  166. package/src/plugins/builtin/correlation/history.ts +22 -0
  167. package/src/plugins/builtin/cot/client.ts +22 -18
  168. package/src/plugins/builtin/cot/headless.ts +15 -10
  169. package/src/plugins/builtin/cot/model.ts +14 -1
  170. package/src/plugins/builtin/cot/pane.tsx +22 -14
  171. package/src/plugins/builtin/credit-boards/client.ts +6 -10
  172. package/src/plugins/builtin/credit-conditions/headless.ts +8 -2
  173. package/src/plugins/builtin/credit-conditions/index.tsx +5 -1
  174. package/src/plugins/builtin/credit-conditions/model.ts +4 -0
  175. package/src/plugins/builtin/credit-conditions/series.ts +3 -1
  176. package/src/plugins/builtin/credit-documents/detail.tsx +2 -2
  177. package/src/plugins/builtin/credit-documents/export.ts +173 -0
  178. package/src/plugins/builtin/credit-documents/headless.ts +7 -7
  179. package/src/plugins/builtin/credit-documents/model.ts +104 -14
  180. package/src/plugins/builtin/credit-documents/pane.tsx +12 -5
  181. package/src/plugins/builtin/custom-view/sources.ts +2 -0
  182. package/src/plugins/builtin/dividend-yield/client.ts +131 -23
  183. package/src/plugins/builtin/dividend-yield/headless.ts +44 -16
  184. package/src/plugins/builtin/dividend-yield/model.ts +8 -5
  185. package/src/plugins/builtin/dividend-yield/pane.tsx +38 -13
  186. package/src/plugins/builtin/dividend-yield/ranking.ts +37 -14
  187. package/src/plugins/builtin/dividend-yield/types.ts +20 -2
  188. package/src/plugins/builtin/dividend-yield/view.ts +30 -2
  189. package/src/plugins/builtin/docs/targets.ts +5 -1
  190. package/src/plugins/builtin/earnings/board-model.ts +16 -15
  191. package/src/plugins/builtin/earnings/board.tsx +62 -71
  192. package/src/plugins/builtin/earnings/headless.ts +40 -4
  193. package/src/plugins/builtin/earnings/scope.ts +31 -43
  194. package/src/plugins/builtin/earnings-calls/calendar.tsx +2 -2
  195. package/src/plugins/builtin/earnings-calls/format.ts +31 -2
  196. package/src/plugins/builtin/earnings-calls/headless.ts +7 -2
  197. package/src/plugins/builtin/earnings-calls/model.ts +6 -1
  198. package/src/plugins/builtin/earnings-calls/pane.tsx +5 -4
  199. package/src/plugins/builtin/econ/types.ts +2 -0
  200. package/src/plugins/builtin/econ-statistics/defs.ts +6 -0
  201. package/src/plugins/builtin/econ-statistics/headless.ts +6 -4
  202. package/src/plugins/builtin/econ-statistics/stats.ts +36 -9
  203. package/src/plugins/builtin/equity-screener/categories.ts +179 -0
  204. package/src/plugins/builtin/equity-screener/client.ts +4 -2
  205. package/src/plugins/builtin/equity-screener/headless.ts +144 -13
  206. package/src/plugins/builtin/equity-screener/ideas.ts +49 -0
  207. package/src/plugins/builtin/equity-screener/model.ts +99 -10
  208. package/src/plugins/builtin/equity-screener/pane.tsx +68 -13
  209. package/src/plugins/builtin/fixed-income/pane.tsx +2 -1
  210. package/src/plugins/builtin/futures/use-board-terms.ts +42 -28
  211. package/src/plugins/builtin/futures/use-front-returns.ts +45 -28
  212. package/src/plugins/builtin/fx-matrix/client.ts +6 -3
  213. package/src/plugins/builtin/fx-matrix/headless.ts +1 -1
  214. package/src/plugins/builtin/fx-matrix/index.tsx +4 -2
  215. package/src/plugins/builtin/fx-matrix/live-legs.ts +42 -3
  216. package/src/plugins/builtin/gpu/headless.ts +8 -2
  217. package/src/plugins/builtin/help/function-index.ts +4 -1
  218. package/src/plugins/builtin/help/index.tsx +1 -0
  219. package/src/plugins/builtin/help/shortcut-model.ts +1 -1
  220. package/src/plugins/builtin/holders/fund-holders.ts +51 -0
  221. package/src/plugins/builtin/holders/headless.ts +18 -1
  222. package/src/plugins/builtin/iv-history/client.ts +52 -11
  223. package/src/plugins/builtin/iv-history/format.ts +36 -23
  224. package/src/plugins/builtin/iv-history/headless.ts +33 -18
  225. package/src/plugins/builtin/iv-history/index.tsx +2 -2
  226. package/src/plugins/builtin/iv-history/model.ts +163 -27
  227. package/src/plugins/builtin/iv-history/pane.tsx +10 -6
  228. package/src/plugins/builtin/iv-history/screen-pane.tsx +22 -15
  229. package/src/plugins/builtin/iv-history/universe.ts +5 -1
  230. package/src/plugins/builtin/jobs/client.ts +25 -29
  231. package/src/plugins/builtin/kelly-sizer/model.ts +12 -8
  232. package/src/plugins/builtin/kelly-sizer/pane.tsx +9 -9
  233. package/src/plugins/builtin/kelly-sizer/sections.tsx +19 -10
  234. package/src/plugins/builtin/kelly-sizer/types.ts +10 -4
  235. package/src/plugins/builtin/macro-day/release-table.ts +2 -2
  236. package/src/plugins/builtin/market-heatmap/data.ts +8 -33
  237. package/src/plugins/builtin/market-movers/client.ts +25 -7
  238. package/src/plugins/builtin/market-movers/headless.ts +32 -12
  239. package/src/plugins/builtin/market-movers/index.tsx +26 -14
  240. package/src/plugins/builtin/market-movers/min-float.ts +74 -0
  241. package/src/plugins/builtin/market-movers/model.ts +4 -1
  242. package/src/plugins/builtin/market-movers/screener.ts +14 -0
  243. package/src/plugins/builtin/market-movers/session-body.tsx +13 -8
  244. package/src/plugins/builtin/market-movers/session-table.ts +4 -3
  245. package/src/plugins/builtin/market-movers/table.ts +17 -5
  246. package/src/plugins/builtin/members/breadth-pane.tsx +2 -1
  247. package/src/plugins/builtin/news/index.tsx +1 -0
  248. package/src/plugins/builtin/news/wire/categories.ts +19 -3
  249. package/src/plugins/builtin/news/wire/industry-pane.tsx +1 -0
  250. package/src/plugins/builtin/news/wire/news/footer.ts +31 -5
  251. package/src/plugins/builtin/news/wire/news/preset-pane.tsx +6 -1
  252. package/src/plugins/builtin/news/wire/news/table.tsx +2 -2
  253. package/src/plugins/builtin/openfda/client.ts +14 -2
  254. package/src/plugins/builtin/openfda/index.tsx +3 -2
  255. package/src/plugins/builtin/openfda/model.ts +9 -0
  256. package/src/plugins/builtin/openfda/pane.tsx +42 -6
  257. package/src/plugins/builtin/options/analytics.ts +29 -5
  258. package/src/plugins/builtin/options/enrichment.ts +17 -5
  259. package/src/plugins/builtin/options/table.ts +5 -2
  260. package/src/plugins/builtin/options/types.ts +2 -0
  261. package/src/plugins/builtin/options/view.tsx +17 -4
  262. package/src/plugins/builtin/options-positioning/client.ts +11 -0
  263. package/src/plugins/builtin/options-positioning/headless.ts +21 -8
  264. package/src/plugins/builtin/options-positioning/index.tsx +1 -1
  265. package/src/plugins/builtin/options-positioning/model.ts +78 -9
  266. package/src/plugins/builtin/options-positioning/pane.tsx +21 -6
  267. package/src/plugins/builtin/options-scenario/client.ts +116 -47
  268. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +142 -10
  269. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +206 -55
  270. package/src/plugins/builtin/options-scenario/csp-screen.ts +63 -23
  271. package/src/plugins/builtin/options-scenario/csp.ts +8 -2
  272. package/src/plugins/builtin/options-scenario/index.tsx +9 -7
  273. package/src/plugins/builtin/options-scenario/strategy-screen.ts +532 -0
  274. package/src/plugins/builtin/pe-band/model.ts +12 -49
  275. package/src/plugins/builtin/perps/cascade-tabs.tsx +161 -0
  276. package/src/plugins/builtin/perps/cascade.ts +236 -0
  277. package/src/plugins/builtin/perps/client.ts +56 -2
  278. package/src/plugins/builtin/perps/headless.ts +65 -9
  279. package/src/plugins/builtin/perps/index.tsx +7 -5
  280. package/src/plugins/builtin/perps/model.ts +18 -4
  281. package/src/plugins/builtin/perps/pane.tsx +19 -22
  282. package/src/plugins/builtin/perps/status-line.ts +25 -0
  283. package/src/plugins/builtin/plugin-module.ts +5 -1
  284. package/src/plugins/builtin/portfolio-list/cached-account.ts +3 -1
  285. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +2 -8
  286. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +4 -4
  287. package/src/plugins/builtin/portfolio-list/cli/render.ts +7 -5
  288. package/src/plugins/builtin/portfolio-list/pane/futures-front.ts +40 -0
  289. package/src/plugins/builtin/portfolio-list/pane/index.tsx +4 -1
  290. package/src/plugins/builtin/portfolio-list/pane/streaming.ts +5 -2
  291. package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +3 -2
  292. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +3 -1
  293. package/src/plugins/builtin/portfolio-list/table.tsx +11 -3
  294. package/src/plugins/builtin/primary-dealers/client.ts +13 -38
  295. package/src/plugins/builtin/realized-vol/index.tsx +2 -2
  296. package/src/plugins/builtin/realized-vol/pane.tsx +3 -3
  297. package/src/plugins/builtin/relative-rotation/client.ts +18 -4
  298. package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
  299. package/src/plugins/builtin/relative-rotation/index.tsx +2 -1
  300. package/src/plugins/builtin/relative-rotation/model.ts +16 -40
  301. package/src/plugins/builtin/relative-rotation/pane.tsx +3 -2
  302. package/src/plugins/builtin/research/corporate-actions-pane.tsx +3 -2
  303. package/src/plugins/builtin/research/event-model.ts +10 -8
  304. package/src/plugins/builtin/research/headless.ts +1 -1
  305. package/src/plugins/builtin/research/relative-valuation-headless.ts +5 -1
  306. package/src/plugins/builtin/research/relative-valuation-model.ts +31 -3
  307. package/src/plugins/builtin/research/relative-valuation-pane.tsx +7 -5
  308. package/src/plugins/builtin/reverse-dcf/headless.ts +5 -3
  309. package/src/plugins/builtin/reverse-dcf/model.ts +61 -6
  310. package/src/plugins/builtin/reverse-dcf/pane.tsx +7 -4
  311. package/src/plugins/builtin/scanner/flow-model.ts +50 -4
  312. package/src/plugins/builtin/scanner/flow-pane.tsx +367 -65
  313. package/src/plugins/builtin/scanner/flow-session.ts +146 -0
  314. package/src/plugins/builtin/scanner/headless.ts +204 -35
  315. package/src/plugins/builtin/scanner/index.ts +16 -5
  316. package/src/plugins/builtin/scanner/live-headless.ts +27 -3
  317. package/src/plugins/builtin/scanner/live-model.ts +11 -0
  318. package/src/plugins/builtin/scanner/live-pane.tsx +3 -3
  319. package/src/plugins/builtin/scanner/lock-note.ts +3 -2
  320. package/src/plugins/builtin/seasonality/headless.ts +10 -1
  321. package/src/plugins/builtin/sec/fund-facts-view.tsx +5 -2
  322. package/src/plugins/builtin/sec/fund-facts.ts +116 -34
  323. package/src/plugins/builtin/sec/headless.ts +2 -1
  324. package/src/plugins/builtin/series-inventory.ts +2 -0
  325. package/src/plugins/builtin/shared/cloud-resource.ts +3 -2
  326. package/src/plugins/builtin/shared/cloud-upgrade.ts +4 -3
  327. package/src/plugins/builtin/shared/earnings-calendar.ts +6 -2
  328. package/src/plugins/builtin/shared/earnings-report.ts +2 -2
  329. package/src/plugins/builtin/shared/job-posting.ts +1 -0
  330. package/src/plugins/builtin/shared/members-menu.tsx +3 -2
  331. package/src/plugins/builtin/shared/pro-lock-note.ts +12 -12
  332. package/src/plugins/builtin/shared/report-freshness.ts +3 -2
  333. package/src/plugins/builtin/shared/ticker-choice.tsx +2 -1
  334. package/src/plugins/builtin/shared/ticker-company.ts +77 -0
  335. package/src/plugins/builtin/shared/use-quote-board.ts +2 -1
  336. package/src/plugins/builtin/shared/volatility/live-session.ts +34 -8
  337. package/src/plugins/builtin/shared/volatility/pricing.ts +19 -0
  338. package/src/plugins/builtin/shared/wall-view-lifecycle.ts +3 -1
  339. package/src/plugins/builtin/themes/model.ts +16 -7
  340. package/src/plugins/builtin/themes/pane.tsx +5 -5
  341. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +43 -18
  342. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +3 -2
  343. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +62 -0
  344. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +83 -46
  345. package/src/plugins/builtin/ticker-detail/headless.ts +31 -16
  346. package/src/plugins/builtin/ticker-detail/overview/model.ts +1 -1
  347. package/src/plugins/builtin/ticker-detail/pane.tsx +3 -2
  348. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +2 -1
  349. package/src/plugins/builtin/ticker-detail/settings.ts +1 -0
  350. package/src/plugins/builtin/time-sales/pane.tsx +31 -19
  351. package/src/plugins/builtin/treasury-daily/client.ts +41 -5
  352. package/src/plugins/builtin/treasury-daily/headless.ts +2 -2
  353. package/src/plugins/builtin/treasury-daily/index.tsx +1 -1
  354. package/src/plugins/builtin/treasury-daily/model.ts +50 -3
  355. package/src/plugins/builtin/treasury-daily/pane.tsx +81 -2
  356. package/src/plugins/builtin/vol-surface/client.ts +3 -13
  357. package/src/plugins/builtin/vol-surface/headless.ts +3 -3
  358. package/src/plugins/builtin/vol-surface/index.tsx +1 -1
  359. package/src/plugins/builtin/vol-surface/pane.tsx +7 -5
  360. package/src/plugins/builtin/volatility/index.tsx +2 -2
  361. package/src/plugins/builtin/volatility/pane.tsx +2 -2
  362. package/src/plugins/builtin/world-venue-map/headless.ts +3 -3
  363. package/src/plugins/catalog-manifest.ts +2 -1
  364. package/src/plugins/marketplace/model.ts +18 -5
  365. package/src/portfolio/futures-positions.ts +6 -3
  366. package/src/portfolio/position-quantity.ts +15 -9
  367. package/src/remote/resources.ts +2 -1
  368. package/src/renderers/dom/data-table/row.tsx +26 -0
  369. package/src/renderers/dom/desktop/list-view.tsx +13 -10
  370. package/src/renderers/dom/desktop/query-bar.tsx +4 -2
  371. package/src/renderers/dom/desktop/select-field.tsx +4 -2
  372. package/src/renderers/dom/host/chart-surface.tsx +21 -0
  373. package/src/renderers/electrobun/bun/desktop/app-name.ts +3 -3
  374. package/src/renderers/electrobun/bun/desktop/backend.ts +12 -0
  375. package/src/renderers/electrobun/bun/desktop/host-requests.ts +7 -0
  376. package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -0
  377. package/src/renderers/electrobun/bun/desktop/update.ts +115 -14
  378. package/src/renderers/electrobun/bun/desktop/view-ids.ts +52 -0
  379. package/src/renderers/electrobun/shared/app-name.ts +13 -0
  380. package/src/renderers/electrobun/shared/protocol.ts +10 -0
  381. package/src/renderers/electrobun/view/backend-rpc.ts +6 -0
  382. package/src/renderers/electrobun/view/main.tsx +24 -1
  383. package/src/renderers/electrobun/view/news-source.ts +3 -1
  384. package/src/renderers/electrobun/view/remote/ticker-repository.ts +14 -7
  385. package/src/renderers/electrobun/view/view-ids.ts +85 -0
  386. package/src/renderers/opentui/start.tsx +5 -0
  387. package/src/series/registry.ts +1 -0
  388. package/src/series/types.ts +6 -0
  389. package/src/series/validate.ts +1 -0
  390. package/src/sources/gloomberb-cloud/index.ts +1 -0
  391. package/src/sources/gloomberb-cloud/news.ts +47 -7
  392. package/src/sources/provider-router/financials.ts +15 -3
  393. package/src/sources/provider-router/index.ts +8 -5
  394. package/src/state/ticker-cleanup.ts +50 -0
  395. package/src/sync/controller.ts +4 -3
  396. package/src/sync/core-contributors.ts +90 -31
  397. package/src/telemetry/stall-reports-dom.ts +38 -0
  398. package/src/telemetry/stall-reports-node.ts +75 -0
  399. package/src/telemetry/stall-reports.ts +214 -0
  400. package/src/test-support/preload.ts +14 -0
  401. package/src/theme/themes.ts +10 -0
  402. package/src/tickers/company-name.ts +44 -3
  403. package/src/tickers/listing-venues.ts +15 -3
  404. package/src/tickers/terminal-codes.ts +19 -0
  405. package/src/time-series/alignment.ts +1 -1
  406. package/src/time-series/economic.ts +18 -4
  407. package/src/time-series/field-catalog.ts +1 -1
  408. package/src/time-series/filed-trailing-eps.ts +197 -0
  409. package/src/time-series/fundamentals.ts +44 -1
  410. package/src/time-series/ice-credit.ts +3 -0
  411. package/src/time-series/price-comparison.ts +30 -2
  412. package/src/time-series/resolve-context.ts +3 -1
  413. package/src/time-series/resolve.ts +56 -4
  414. package/src/time-series/session-bar.ts +11 -0
  415. package/src/time-series/spec.ts +3 -2
  416. package/src/time-series/studies.ts +8 -2
  417. package/src/time-series/total-return.ts +160 -0
  418. package/src/time-series/transforms.ts +2 -3
  419. package/src/time-series/types.ts +22 -1
  420. package/src/types/financials.ts +32 -1
  421. package/src/types/headless.ts +21 -3
  422. package/src/types/news-source.ts +1 -0
  423. package/src/types/plugin.ts +9 -0
  424. package/src/ui/host.tsx +3 -0
  425. package/src/updater/failure.ts +4 -1
  426. package/src/utils/cli-output.ts +42 -1
  427. package/src/utils/crypto-pair.ts +44 -0
  428. package/src/utils/forward-dividend.ts +2 -0
  429. package/src/utils/fundamentals.ts +24 -3
  430. package/src/utils/fx-market-hours.ts +26 -3
  431. package/src/utils/main-thread-stall.ts +35 -2
  432. package/src/utils/market-capitalization.ts +24 -1
  433. package/src/utils/price-history.ts +7 -1
  434. package/src/utils/shell-word.ts +8 -0
  435. package/src/utils/trailing-dividend.ts +53 -4
  436. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +0 -17
@@ -0,0 +1,160 @@
1
+ import type { CorporateActionsData } from "../types/financials";
2
+ import { cashInMajorUnits } from "../utils/dividend-cash";
3
+ import { resolveCurrencyUnit } from "../utils/currency-units";
4
+ import { logFailure } from "../utils/log-failure";
5
+ import { dividendReferencePrice } from "../utils/trailing-dividend";
6
+ import { observationDate } from "./price-comparison";
7
+ import { CHART_RESOLUTION_STEP_MS, chartBarSizeStepMs } from "./resolution";
8
+ import type { ResolvedSeries, TimeSeriesPoint } from "./types";
9
+
10
+ /** One cash distribution per share: its ex-date (`YYYY-MM-DD`) and its amount in the listing's major currency unit. */
11
+ export interface CashDistribution {
12
+ exDate: string;
13
+ amount: number;
14
+ }
15
+
16
+ export interface TotalReturnOptions {
17
+ /** The session day a bar belongs to, `YYYY-MM-DD`. */
18
+ dayOf: (point: TimeSeriesPoint) => string;
19
+ /**
20
+ * A bar's price in the distributions' currency unit, or null when the two
21
+ * currencies differ (nothing is converted).
22
+ */
23
+ cashPrice: (price: number) => number | null;
24
+ /**
25
+ * Bars longer than a session (weekly, monthly) are dated at their start, so a
26
+ * distribution belongs to the bar that holds its ex-date, not the first one
27
+ * dated on or after it. This is how many days a bar holds; the last bar holds
28
+ * that many from its own date, and a distribution after that precedes no bar.
29
+ */
30
+ barDays?: number;
31
+ /** Today, `YYYY-MM-DD`: a distribution dated after it has not gone ex. */
32
+ asOf?: string;
33
+ }
34
+
35
+ export interface TotalReturnResult {
36
+ points: TimeSeriesPoint[];
37
+ /** Distributions reinvested inside the series; one before its first bar or after its last is not. */
38
+ applied: number;
39
+ }
40
+
41
+ /** The day a bar of `barDays` days dated `day` ends on; 30-day multiples are calendar months. */
42
+ function barEnd(day: string, barDays: number): string {
43
+ const end = new Date(`${day}T00:00:00Z`);
44
+ if (barDays >= 28 && barDays % 30 === 0) end.setUTCMonth(end.getUTCMonth() + barDays / 30);
45
+ else end.setUTCDate(end.getUTCDate() + barDays);
46
+ return end.toISOString().slice(0, 10);
47
+ }
48
+
49
+ function scaled(value: number | null | undefined, factor: number): number | null | undefined {
50
+ return typeof value === "number" && Number.isFinite(value) ? value * factor : value;
51
+ }
52
+
53
+ /**
54
+ * A price series as its total return: every cash distribution is reinvested at
55
+ * the close of its ex-date bar, so the series moves by (close + cash) over the
56
+ * bar before. Each price is multiplied by the shares the cash has bought
57
+ * since the series began, which leaves its first bar as it was; volume is
58
+ * left alone. A distribution dated at or before the first bar precedes the
59
+ * series, so nothing is reinvested for it.
60
+ */
61
+ export function reinvestDistributions(
62
+ points: readonly TimeSeriesPoint[],
63
+ distributions: readonly CashDistribution[],
64
+ { dayOf, cashPrice, barDays, asOf }: TotalReturnOptions,
65
+ ): TotalReturnResult {
66
+ const ordered = [...points].sort((left, right) => left.date.getTime() - right.date.getTime());
67
+ const holdingBar = barDays !== undefined && barDays > 1;
68
+ const cash = distributions
69
+ .filter((entry) => /^\d{4}-\d{2}-\d{2}$/.test(entry.exDate) && Number.isFinite(entry.amount) && entry.amount > 0
70
+ && (asOf === undefined || entry.exDate <= asOf))
71
+ .sort((left, right) => left.exDate.localeCompare(right.exDate));
72
+ const days = ordered.map(dayOf);
73
+ let factor = 1;
74
+ let applied = 0;
75
+ let next = 0;
76
+ const adjusted = ordered.map((point, index) => {
77
+ const barDay = days[index]!;
78
+ const before = holdingBar ? days[index + 1] ?? barEnd(barDay, barDays!) : null;
79
+ while (next < cash.length) {
80
+ const entry = cash[next]!;
81
+ if (before !== null ? entry.exDate >= before : entry.exDate > barDay) break;
82
+ if (index === 0) { next += 1; continue; }
83
+ const close = point.close ?? point.value;
84
+ // A bar with no price leaves the cash for the next bar that has one.
85
+ if (typeof close !== "number" || !Number.isFinite(close) || close <= 0) break;
86
+ // Cash in another currency than the price buys nothing: the series stays a price series.
87
+ const price = cashPrice(close);
88
+ if (price !== null && price > 0) {
89
+ factor *= 1 + entry.amount / price;
90
+ applied += 1;
91
+ }
92
+ next += 1;
93
+ }
94
+ if (factor === 1) return point;
95
+ return {
96
+ ...point,
97
+ value: scaled(point.value, factor) ?? null,
98
+ ...point.rawValue !== undefined ? { rawValue: scaled(point.rawValue, factor) ?? null } : {},
99
+ ...point.open !== undefined ? { open: scaled(point.open, factor) } : {},
100
+ ...point.high !== undefined ? { high: scaled(point.high, factor) } : {},
101
+ ...point.low !== undefined ? { low: scaled(point.low, factor) } : {},
102
+ ...point.close !== undefined ? { close: scaled(point.close, factor) } : {},
103
+ };
104
+ });
105
+ return { points: adjusted, applied };
106
+ }
107
+
108
+ export interface TotalReturnOutcome {
109
+ series: ResolvedSeries;
110
+ /** Why the series stays a price series, when it does. */
111
+ notice?: string;
112
+ }
113
+
114
+ const DAY_MS = 86_400_000;
115
+
116
+ /** How many days a bar holds when it is longer than a session (a month counts as 30), so a distribution belongs to the bar holding its ex-date. */
117
+ function barDaysLongerThanSession(series: Pick<ResolvedSeries, "barSize" | "historyResolution">): number | undefined {
118
+ const step = series.barSize ? chartBarSizeStepMs(series.barSize)
119
+ : series.historyResolution ? CHART_RESOLUTION_STEP_MS[series.historyResolution] : null;
120
+ return step !== null && step > DAY_MS ? Math.round(step / DAY_MS) : undefined;
121
+ }
122
+
123
+ /**
124
+ * A price series as its total return, from the cash history its listing pays.
125
+ * The series says which basis it ended up on: `total` once its distributions
126
+ * are reinvested (a listing that pays none is its price), `price` with the
127
+ * reason when the history cannot be read, covers no distributions, or is in
128
+ * another currency than the prices. Nothing is converted.
129
+ */
130
+ export async function totalReturnSeries(
131
+ series: ResolvedSeries,
132
+ loadActions: () => Promise<CorporateActionsData | null>,
133
+ priceCurrency: string | undefined,
134
+ asOf: Date,
135
+ ): Promise<TotalReturnOutcome> {
136
+ const priceOnly = (notice: string): TotalReturnOutcome => ({ series: { ...series, returnBasis: "price" }, notice });
137
+ const actions = await loadActions().catch(logFailure("total-return", "Loading distribution history failed", null));
138
+ if (!actions) return priceOnly("distribution history unavailable; showing the price return.");
139
+ const cash = cashInMajorUnits(actions);
140
+ const dividends = Array.isArray(cash.dividends) ? cash.dividends : [];
141
+ if (cash.coverage?.dividends === "unavailable" || (cash.coverage?.dividends !== "available" && dividends.length === 0)) {
142
+ return priceOnly("distribution history unavailable; showing the price return.");
143
+ }
144
+ const currency = resolveCurrencyUnit(cash.currency).currency;
145
+ if (dividends.length > 0 && !currency) return priceOnly("distribution currency unknown; showing the price return.");
146
+ if (dividends.length > 0 && !resolveCurrencyUnit(priceCurrency).currency) {
147
+ return priceOnly("price currency unknown; showing the price return.");
148
+ }
149
+ if (dividends.length > 0 && dividendReferencePrice(1, priceCurrency, currency) === null) {
150
+ return priceOnly(`distributions are in ${currency}, not the price currency; showing the price return.`);
151
+ }
152
+ const { points } = reinvestDistributions(series.points, dividends, {
153
+ dayOf: (point) => observationDate(point.date.getTime(), series),
154
+ cashPrice: (price) => dividendReferencePrice(price, priceCurrency, currency),
155
+ barDays: barDaysLongerThanSession(series),
156
+ asOf: asOf.toISOString().slice(0, 10),
157
+ });
158
+ // "ECC Close" is its price: a label the chart wrote from the field says what the series is now.
159
+ return { series: { ...series, points, returnBasis: "total", label: series.label.replace(/ (?:Close|Price|Open|High|Low)$/, " Total return") } };
160
+ }
@@ -1,6 +1,7 @@
1
1
  import type { ResolvedSeries, SeriesTransform, TimeSeriesPoint } from "./types";
2
2
  import { calendarMonthsBefore } from "../utils/calendar-date";
3
3
  import { isFiniteNumber } from "../utils/guards";
4
+ import { isOhlcSeriesStyle } from "./spec";
4
5
 
5
6
  const DAY_MS = 24 * 60 * 60 * 1_000;
6
7
  // Volume is separate supporting data, not another price. A volume series has
@@ -166,9 +167,7 @@ export function applyResolvedSeriesTransform(
166
167
  unit: percent ? "%" : transform === "index100" ? "index" : "log",
167
168
  unitGroup: percent ? "percent" : transform === "index100" ? "index" : "log",
168
169
  dataShape: "scalar",
169
- style: series.style === "candles" || series.style === "ohlc" || series.style === "hlc"
170
- ? "line"
171
- : series.style,
170
+ style: isOhlcSeriesStyle(series.style) ? "line" : series.style,
172
171
  points: applySeriesTransform(series.points, transform, options),
173
172
  };
174
173
  }
@@ -10,7 +10,7 @@ export type SeriesPeriod = "auto" | "daily" | "weekly" | "monthly" | "quarterly"
10
10
  * "band" draws a line through each point's value inside a shaded range from
11
11
  * its `low` to its `high`: an average within its historical range.
12
12
  */
13
- export type SeriesStyle = "line" | "area" | "step" | "columns" | "points" | "candles" | "ohlc" | "hlc" | "band";
13
+ export type SeriesStyle = "line" | "area" | "step" | "columns" | "points" | "candles" | "hollow" | "heikin-ashi" | "ohlc" | "hlc" | "band";
14
14
  export type SeriesTransform = "raw" | "percent" | "index100" | "yoy" | "qoq" | "log";
15
15
  export type SeriesAxis = "auto" | "left" | "right";
16
16
  export type SeriesInterpolation = "none" | "step-after";
@@ -110,6 +110,11 @@ export interface ChartViewportSpec {
110
110
  maxPoints?: number;
111
111
  /** Intraday market history includes pre-market and after-hours bars where the venue has them. */
112
112
  extendedHours?: boolean;
113
+ /**
114
+ * Security price series are drawn as total returns: each cash distribution
115
+ * is reinvested at the close of its ex-date bar. Price returns otherwise.
116
+ */
117
+ totalReturn?: boolean;
113
118
  }
114
119
 
115
120
  export interface ChartSpec {
@@ -141,6 +146,8 @@ export interface TimeSeriesPoint {
141
146
  low?: number | null;
142
147
  close?: number | null;
143
148
  volume?: number | null;
149
+ /** The bar this figure traded in closed below its open: volume draws it in the falling colour. */
150
+ fell?: boolean;
144
151
  periodLabel?: string;
145
152
  /**
146
153
  * A financial statement period as the FA columns name it: `FY2025`, `Q3 FY26`,
@@ -183,6 +190,12 @@ export interface ResolvedSeries {
183
190
  unit: string;
184
191
  /** Unit of rawValue, retained when presentation transforms change unit. */
185
192
  rawUnit?: string;
193
+ /**
194
+ * What a price series' returns are, set when the chart asked for total
195
+ * returns: `total` once its distributions are reinvested, `price` when the
196
+ * source gave none to reinvest (`warning` says why).
197
+ */
198
+ returnBasis?: "total" | "price";
186
199
  unitGroup: string;
187
200
  /**
188
201
  * The unit the legend states beside each value, read bare as FUT prints its
@@ -311,6 +324,14 @@ export interface ChartResolutionResult {
311
324
  loading: boolean;
312
325
  errors: string[];
313
326
  warnings: string[];
327
+ /**
328
+ * Where a series' source starts after the range asked for, and why (a
329
+ * publisher's cap on history), as `warnings` also carries it, so a report
330
+ * says it where it would otherwise print a range that quietly starts later.
331
+ */
332
+ coverageNotices?: string[];
333
+ /** What the price levels of a total-return chart without a comparison are (`warnings` also carries it). */
334
+ returnBasisNotice?: string;
314
335
  /**
315
336
  * Each charted listing that no longer trades: its symbol and label
316
337
  * ("Delisted Oct 27, 2022"), which `warnings` carries as "TWTR: Delisted Oct 27, 2022".
@@ -330,7 +330,12 @@ export interface Fundamentals extends DepositaryReceiptFacts {
330
330
  /** Set where Gloom Cloud checked `enterpriseValue` against market cap + total debt - cash; pairs with that value only. */
331
331
  enterpriseValueCheck?: EnterpriseValueCheck;
332
332
  /** Explicit provider retractions; omitted fields alone remain eligible for fallback. */
333
- unavailableFields?: Array<"enterpriseValue" | "enterpriseToRevenue">;
333
+ unavailableFields?: Array<"enterpriseValue" | "enterpriseToRevenue" | "marketCap">;
334
+ /**
335
+ * Why `marketCap` is retracted, with "marketCap" in `unavailableFields`: a depositary receipt its source priced as
336
+ * an ordinary share (the receipt's price times the company's ordinary shares), with no ratio to convert them.
337
+ */
338
+ marketCapUnavailable?: "receipt-priced-as-ordinary";
334
339
  operatingCashFlow?: number;
335
340
  freeCashFlow?: number;
336
341
  dividendYield?: number;
@@ -345,6 +350,18 @@ export interface Fundamentals extends DepositaryReceiptFacts {
345
350
  revenue?: number;
346
351
  netIncome?: number;
347
352
  eps?: number;
353
+ /**
354
+ * Where `eps` and `trailingPE` come from: `filed-quarters` when `eps` is the
355
+ * diluted EPS of the last four filed quarters (or the fiscal year they end
356
+ * with), as PEB and GE read the statements, its last period ending
357
+ * `trailingEpsPeriodEnd`, and `trailingPE` the price over it; `served` when
358
+ * those quarters give none (or one that cannot be priced: see
359
+ * time-series/filed-trailing-eps) and both are Gloom Cloud's trailing
360
+ * figures, including a P/E it serves with no EPS (a fund's). Absent when
361
+ * there is neither an EPS nor a P/E.
362
+ */
363
+ trailingEpsSource?: "filed-quarters" | "served";
364
+ trailingEpsPeriodEnd?: string;
348
365
  operatingMargin?: number;
349
366
  profitMargin?: number;
350
367
  revenueGrowth?: number;
@@ -556,10 +573,24 @@ export interface CorporateActionsData {
556
573
  dividends: DividendAction[];
557
574
  /** Declared and unpaid, for the listings Gloom Cloud has them for; absent elsewhere and from older servers. */
558
575
  declaredDividends?: DeclaredDividendAction[];
576
+ /**
577
+ * What each paid row was declared as when the company declares in another
578
+ * currency than the listing pays (BP's dollars beside its London pence), per
579
+ * ordinary share, keyed by the paid row's ex-date. Absent elsewhere and from older servers.
580
+ */
581
+ declaredCash?: DeclaredCash;
582
+ /** Set when `dividends` is the last good history standing in for a refresh that could not read it: when that history was read. */
583
+ dividendsAsOf?: string;
559
584
  splits: SplitAction[];
560
585
  earnings: EarningsAction[];
561
586
  }
562
587
 
588
+ /** Paid rows as their company declared them, in `currency` (its major unit). */
589
+ export interface DeclaredCash {
590
+ currency: string;
591
+ rows: DividendAction[];
592
+ }
593
+
563
594
  export interface CompanyProfile {
564
595
  description?: string;
565
596
  /**
@@ -34,6 +34,12 @@ export interface HeadlessPaneArgumentDef {
34
34
  examples?: readonly string[];
35
35
  }
36
36
 
37
+ /** A list the catalog prints under a function's options, such as the sector names a screen's criteria match. */
38
+ export interface HeadlessPaneReference {
39
+ title: string;
40
+ items: readonly string[];
41
+ }
42
+
37
43
  export interface HeadlessPaneOptionValue {
38
44
  value: string;
39
45
  aliases?: string[];
@@ -83,6 +89,8 @@ export interface HeadlessPaneOptionDef {
83
89
  * absent.
84
90
  */
85
91
  valueWords?: number;
92
+ /** The value is a comma list (`--metric trailingPE,dividendYieldPercent`), and the flag typed again adds to it. */
93
+ list?: boolean;
86
94
  /** The option in use as typed after the function, such as `--expiration 2028-01-21`; the catalog shows it as an example. */
87
95
  example?: string;
88
96
  /** The example runs without the function's optional argument, as an option that works only then does (`fn INS --side sell`). */
@@ -138,8 +146,10 @@ export interface HeadlessPaneContext {
138
146
  * known. A code several companies list (BDI) throws asking which, with
139
147
  * `quote`'s message; `argumentWith(key)` is the function's argument naming
140
148
  * that listing instead (`BDI:TSX`), for the retry each listing offers.
149
+ * `coinNote` is what `quote` says of a bare coin ticker read as a listing
150
+ * that is not the coin (ETH, the Grayscale fund), for the report's warnings.
141
151
  */
142
- resolveListing?: (symbol: string, argumentWith: (key: string) => string) => Promise<{ symbol: string; exchange?: string; name?: string } | null>;
152
+ resolveListing?: (symbol: string, argumentWith: (key: string) => string) => Promise<{ symbol: string; exchange?: string; name?: string; coinNote?: string } | null>;
143
153
  /**
144
154
  * What a plugin keeps on this device only (its `ctx.resume` state, never
145
155
  * synced), such as ALRT's log of the alerts the app fired; null when none.
@@ -602,6 +612,8 @@ export interface HeadlessSeries {
602
612
  interval?: string;
603
613
  /** Decimal places the text report prints the latest value to (a correlation to 3); JSON and CSV keep every digit. */
604
614
  textDecimals?: number;
615
+ /** The text report prints the latest value as the tables print an amount (63.33B), for a company's reported total; JSON and CSV keep every digit. */
616
+ textCompact?: boolean;
605
617
  /** Each point's `value` is its bar's close: `--csv` and `--ndjson` write Close alone, JSON keeps both. */
606
618
  valueIsClose?: boolean;
607
619
  points: HeadlessSeriesPoint[];
@@ -615,6 +627,8 @@ export interface HeadlessSeriesResult extends HeadlessPaneResultBase {
615
627
  export interface HeadlessSnapshotResult extends HeadlessPaneResultBase {
616
628
  asOf: string | number | Date;
617
629
  items: HeadlessPaneRow[];
630
+ /** What the report says when `items` is empty, in place of "No data.": why there are none. */
631
+ empty?: string;
618
632
  }
619
633
 
620
634
  export interface HeadlessPaneResultByShape {
@@ -640,6 +654,8 @@ export interface HeadlessPaneDefinition<Shape extends HeadlessPaneShape = Headle
640
654
  intents?: string[];
641
655
  dataRequirements?: string[];
642
656
  limitations?: string[];
657
+ /** Names an option's values match, listed by the catalog under each title: EQS's sectors and industries. */
658
+ reference?: HeadlessPaneReference[];
643
659
  screenshotReadiness?: "ready" | "partial" | "live-dom" | "unsupported";
644
660
  };
645
661
  /**
@@ -672,9 +688,11 @@ export interface HeadlessPaneDefinition<Shape extends HeadlessPaneShape = Headle
672
688
  /**
673
689
  * A listing the function has no data for, answered before any request with
674
690
  * what exists instead: OPX and OVDV answer a coin nothing lists options on
675
- * (SOL-USD) with BTC and ETH options. `key` is the listing as read.
691
+ * (SOL-USD) with BTC and ETH options, and OVDV, VCA and HIVG an FX pair with
692
+ * the currency funds' options. `key` is the listing as read; `details` is
693
+ * the line after `message`, left out when the message says it all.
676
694
  */
677
- refuseSymbol?(key: string): { message: string; details: string } | null;
695
+ refuseSymbol?(key: string): { message: string; details?: string } | null;
678
696
  /**
679
697
  * `fn` exits 1 when the report has no name with data: no rows, or every row
680
698
  * is one of `unavailableSymbols`. A list that gives data for some names
@@ -1,4 +1,5 @@
1
1
  export type {
2
+ NewsAccess,
2
3
  NewsArticle,
3
4
  NewsQuery,
4
5
  NewsQueryState,
@@ -20,6 +20,7 @@ export type {
20
20
  HeadlessPaneOptionType,
21
21
  HeadlessPaneOptionValue,
22
22
  HeadlessPaneOptionValues,
23
+ HeadlessPaneReference,
23
24
  HeadlessPaneResult,
24
25
  HeadlessPaneResultByShape,
25
26
  HeadlessPaneRow,
@@ -529,6 +530,14 @@ export interface PaneTemplateDef {
529
530
  description: string;
530
531
  keywords?: string[];
531
532
  shortcut?: PaneTemplateShortcut;
533
+ /**
534
+ * False leaves the function out of every list and search of functions
535
+ * (command-bar browse, search and assistant, Help, `gloom catalog` and
536
+ * search, the plugin directory, chat suggestions) while typing its code
537
+ * still opens it, `fn` and `shot` still run it and its help still answers.
538
+ * ATTN until it publishes (attention/listing.ts).
539
+ */
540
+ listed?: boolean;
532
541
  /** Template-specific headless model. Takes precedence over the pane-level model. */
533
542
  headless?: HeadlessPaneDefinition;
534
543
  /**
package/src/ui/host.tsx CHANGED
@@ -82,6 +82,8 @@ export interface ChartVectorShape {
82
82
  gradient?: readonly string[];
83
83
  /** Opacity of the whole shape, so others can recede behind a highlighted one. */
84
84
  opacity?: number;
85
+ /** Text set just above the shape's first point, such as a retracement level's ratio and price. */
86
+ label?: string;
85
87
  }
86
88
 
87
89
  interface TextEditBuffer {
@@ -508,6 +510,7 @@ export interface HostCheckboxProps {
508
510
  interface HostQueryBarOption {
509
511
  value: string;
510
512
  label: string;
513
+ group?: string;
511
514
  description?: string;
512
515
  disabled?: boolean;
513
516
  selected: boolean;
@@ -24,7 +24,7 @@ const UPDATE_FAILURE_CODES = [
24
24
  "no_build",
25
25
  /** The download stopped before the whole file arrived. */
26
26
  "interrupted",
27
- /** The file arrived whole but does not match its checksum, or does not unpack. */
27
+ /** The download does not match its checksum, or does not unpack (part of it is missing or damaged). */
28
28
  "corrupt",
29
29
  "permission_denied",
30
30
  /** The macOS app runs from where it cannot be replaced: a disk image, App Translocation, another volume. */
@@ -112,6 +112,9 @@ export function classifyUpdateError(error: unknown): UpdateFailureCode {
112
112
  if (status) return httpStatusFailureCode(Number(status));
113
113
  if (/checksum mismatch|hash mismatch/i.test(message)) return "corrupt";
114
114
  if (/zstd|decompress|gunzip|incorrect header|unexpected end of (?:file|data)/i.test(message)) return "corrupt";
115
+ // Bun.Archive on a tar that does not read: cut off, damaged, or none at all.
116
+ // Unpacking says only "ReadError", whatever stopped it.
117
+ if (/\bReadError\b|truncated tar|damaged tar|unrecognized archive format/i.test(message)) return "corrupt";
115
118
  if (/timed? ?out/i.test(message)) return "timeout";
116
119
  if (/rate limit/i.test(message)) return "rate_limited";
117
120
  if (/read-only file system/i.test(message)) return "read_only";
@@ -74,6 +74,47 @@ const PLAIN_EMPTY_CELL = "—";
74
74
  let colorEnabledOverride: boolean | null = null;
75
75
  let widthOverride: number | null = null;
76
76
  let plainOverride: boolean | null = null;
77
+ /** Output is being rendered for a file (`renderForFile`), which has no terminal width. */
78
+ let renderingForFile = false;
79
+
80
+ /** Renders for a file from here on; the function returned puts the terminal's rendering back. */
81
+ function enterFileRendering(): () => void {
82
+ const saved = { color: colorEnabledOverride, plain: plainOverride, file: renderingForFile };
83
+ colorEnabledOverride = false;
84
+ plainOverride = true;
85
+ renderingForFile = true;
86
+ return () => {
87
+ colorEnabledOverride = saved.color;
88
+ plainOverride = saved.plain;
89
+ renderingForFile = saved.file;
90
+ };
91
+ }
92
+
93
+ /**
94
+ * Output rendered for a file (`fn --output`) as a redirect gets it: plain,
95
+ * without colour, and fitted to no width but `--width`'s.
96
+ */
97
+ export function renderForFile<T>(render: () => T): T {
98
+ const restore = enterFileRendering();
99
+ try {
100
+ return render();
101
+ } finally {
102
+ restore();
103
+ }
104
+ }
105
+
106
+ /**
107
+ * `renderForFile` around work that renders as it loads: a report whose text is
108
+ * drawn while it is built is drawn for the file, though stdout is a terminal.
109
+ */
110
+ export async function buildForFile<T>(build: () => Promise<T>): Promise<T> {
111
+ const restore = enterFileRendering();
112
+ try {
113
+ return await build();
114
+ } finally {
115
+ restore();
116
+ }
117
+ }
77
118
 
78
119
  function colorEnabled(): boolean {
79
120
  if (colorEnabledOverride != null) return colorEnabledOverride;
@@ -176,7 +217,7 @@ export function setCliWidthOverride(value: number | null): void {
176
217
  /** Columns the output is fitted to: `--width`, else the terminal's, or null when output is piped or redirected. */
177
218
  export function cliTerminalWidth(): number | null {
178
219
  if (widthOverride != null) return widthOverride;
179
- if (!process.stdout.isTTY) return null;
220
+ if (renderingForFile || !process.stdout.isTTY) return null;
180
221
  const columns = process.stdout.columns;
181
222
  return typeof columns === "number" && columns > 0 ? columns : null;
182
223
  }
@@ -91,6 +91,50 @@ export const MAJOR_COIN_NAMES: ReadonlyMap<string, string> = new Map([
91
91
  ["BNB", "BNB"],
92
92
  ]);
93
93
 
94
+ /**
95
+ * The largest coins by market value, stablecoins and gold tokens left out, with
96
+ * how a note names each: the coins whose bare ticker a listed company or fund
97
+ * may hold instead (SOL is a stale Emeren Group, LINK is Interlink Electronics).
98
+ * A hint reads this list; `MAJOR_COIN_NAMES` stays the shorter one stories and
99
+ * company-name lookups use, so a word such as "stellar" is still a company's.
100
+ */
101
+ export const TOP_COIN_NAMES: ReadonlyMap<string, string> = new Map([
102
+ ...MAJOR_COIN_NAMES,
103
+ ["TRX", "tron"],
104
+ ["ZEC", "zcash"],
105
+ ["HYPE", "hyperliquid"],
106
+ ["XMR", "monero"],
107
+ ["XLM", "stellar"],
108
+ ["NEAR", "near protocol"],
109
+ ["TON", "toncoin"],
110
+ ["UNI", "uniswap"],
111
+ ["SUI", "sui"],
112
+ ["HBAR", "hedera"],
113
+ ["TAO", "bittensor"],
114
+ ["SHIB", "shiba inu"],
115
+ ["ENA", "ethena"],
116
+ ["CRO", "cronos"],
117
+ ["AAVE", "aave"],
118
+ ["ONDO", "ondo"],
119
+ ["PEPE", "pepe"],
120
+ ["ICP", "internet computer"],
121
+ ["ETC", "ethereum classic"],
122
+ ["ARB", "arbitrum"],
123
+ ["ALGO", "algorand"],
124
+ ["ATOM", "cosmos"],
125
+ ["APT", "aptos"],
126
+ ["FIL", "filecoin"],
127
+ ["POL", "polygon"],
128
+ ["OP", "optimism"],
129
+ ["WLD", "worldcoin"],
130
+ ["MNT", "mantle"],
131
+ ["KAS", "kaspa"],
132
+ ["QNT", "quant"],
133
+ ["VET", "vechain"],
134
+ ["INJ", "injective"],
135
+ ["RENDER", "render"],
136
+ ]);
137
+
94
138
  const COIN_PAIR = /^([A-Z0-9]{1,15})[-/](?:USD|EUR|GBP|USDT|USDC|BTC)$/;
95
139
  // What a pair's listing name adds after the coin's: its quote currency, an id in brackets.
96
140
  const PAIR_NAME_SUFFIX = /(?:\s*\([^)]*\))+$|\s+(?:USD|EUR|GBP|USDT|USDC|BTC|US Dollars?)$/i;
@@ -14,6 +14,8 @@ import { formatDistributionAmount } from "./format";
14
14
  * the rate divided back.
15
15
  */
16
16
  export const LATEST_DISTRIBUTION = "latest distribution annualized";
17
+ /** The basis of a forward rate that is the year's regular payments, which differ too widely for one to be annualized (unevenRegularPayments). */
18
+ export const UNEVEN_REGULAR_PAYMENTS = "trailing regular payments: uneven interims";
17
19
 
18
20
  /**
19
21
  * What a trailing dividend yield is everywhere it shows (DVD, a fund's in
@@ -6,16 +6,19 @@ import { formatCompact } from "./format";
6
6
  import { formatUtcTime } from "./utc-time";
7
7
 
8
8
  export const RETRACTABLE_VALUATION_FIELDS = ["enterpriseValue", "enterpriseToRevenue"] as const;
9
+ /** Every field a source can retract: the valuation fields, and a receipt's market cap (`marketCapUnavailable`). */
10
+ export const RETRACTED_FUNDAMENTALS_FIELDS = [...RETRACTABLE_VALUATION_FIELDS, "marketCap"] as const;
9
11
 
10
- /** A retraction survives serialization and overrides a contradictory cached number. */
12
+ /** A retraction survives serialization and overrides a contradictory cached number; its reason goes with it. */
11
13
  export function redactUnavailableFundamentals(value: Fundamentals | undefined): Fundamentals | undefined {
12
- if (!value || value.unavailableFields === undefined) return value;
14
+ if (!value || (value.unavailableFields === undefined && value.marketCapUnavailable === undefined)) return value;
13
15
  const unavailableFields = Array.isArray(value.unavailableFields)
14
- ? RETRACTABLE_VALUATION_FIELDS.filter((field) => value.unavailableFields!.includes(field)) : [];
16
+ ? RETRACTED_FUNDAMENTALS_FIELDS.filter((field) => value.unavailableFields!.includes(field)) : [];
15
17
  const result = { ...value };
16
18
  if (unavailableFields.length) result.unavailableFields = unavailableFields;
17
19
  else delete result.unavailableFields;
18
20
  for (const field of unavailableFields) delete result[field];
21
+ if (!unavailableFields.includes("marketCap")) delete result.marketCapUnavailable;
19
22
  return result;
20
23
  }
21
24
 
@@ -243,6 +246,24 @@ export function epsConversionNote(fundamentals: Pick<Fundamentals, "financialCur
243
246
  return eps && amounts && eps !== amounts ? `EPS (TTM) in ${eps}, converted from ${amounts} at report-date rates.` : undefined;
244
247
  }
245
248
 
249
+ /** What a trailing EPS that is not the filed quarters' is called where it is shown (EE's TTM row). */
250
+ export const SERVED_TRAILING_EPS = "Gloom Cloud's TTM";
251
+
252
+ /**
253
+ * "EPS (TTM) and P/E (TTM) are Gloom Cloud's trailing figures, not the last four filed quarters'.": the headline EPS
254
+ * and P/E are the filed quarters' (time-series/filed-trailing-eps), so served ones say so, naming those `shown`
255
+ * ("P/E (TTM) is Gloom Cloud's trailing figure, ..." for a fund's P/E with no EPS). Undefined otherwise.
256
+ */
257
+ export function trailingEpsSourceNote(
258
+ fundamentals: Pick<Fundamentals, "trailingEpsSource"> | undefined,
259
+ shown: { eps: boolean; pe: boolean },
260
+ ): string | undefined {
261
+ if (fundamentals?.trailingEpsSource !== "served" || (!shown.eps && !shown.pe)) return undefined;
262
+ const figures = shown.eps && shown.pe ? "EPS (TTM) and P/E (TTM) are Gloom Cloud's trailing figures"
263
+ : `${shown.eps ? "EPS (TTM)" : "P/E (TTM)"} is Gloom Cloud's trailing figure`;
264
+ return `${figures}, not the last four filed quarters'.`;
265
+ }
266
+
246
267
  type PriceEarningsBasis = Pick<Fundamentals, "financialCurrency" | "ttmConversion" | "epsCurrency" | "trailingPEConversion">;
247
268
 
248
269
  /** The trailing EPS in the price's currency: converted at the rate the served P/E used when it says so. */
@@ -30,12 +30,35 @@ export function isFxMarketOpen(time: number): boolean {
30
30
  }
31
31
 
32
32
  /**
33
- * The FX trading day an instant belongs to, as "YYYY-MM-DD": the day rolls
34
- * at 17:00 New York time, so Wednesday 18:00 New York is Thursday's.
33
+ * The FX trading day a print made at `time` belongs to, as "YYYY-MM-DD": the
34
+ * day rolls at 17:00 New York time, so Wednesday 18:00 New York is
35
+ * Thursday's. A print stamped exactly 17:00:00 is that day's close, so it is
36
+ * still that day's.
35
37
  */
36
38
  export function fxTradingDay(time: number): string {
37
39
  // The roll is 17:00, seven hours before New York's midnight, daylight saving or not.
38
- return zonedDateKey(time + 7 * HOUR_MS, NEW_YORK);
40
+ return zonedDateKey(time - 1 + 7 * HOUR_MS, NEW_YORK);
41
+ }
42
+
43
+ /**
44
+ * The FX trading day of a print made at `time` (fxTradingDay), or null for a
45
+ * print made while the market is shut: from just after Friday's 17:00 New
46
+ * York close, whose own print still counts, through Sunday's 17:00 open. A
47
+ * tick over the weekend belongs to no trading day.
48
+ */
49
+ export function fxPrintTradingDay(time: number): string | null {
50
+ return Number.isFinite(time) && isFxMarketOpen(time - 1) ? fxTradingDay(time) : null;
51
+ }
52
+
53
+ /**
54
+ * The FX trading day the market is on at `time`: the day in progress while it
55
+ * trades, or the Friday that closed it while it is shut.
56
+ */
57
+ export function fxTradingDayAt(time: number): string | null {
58
+ const day = fxPrintTradingDay(time);
59
+ if (day != null || !Number.isFinite(time)) return day;
60
+ const shut = currentFxClosureStart(time - 1);
61
+ return shut != null ? fxTradingDay(shut) : null;
39
62
  }
40
63
 
41
64
  /** The latest 17:00 New York on `weekday` (0 is Sunday) at or before `time`. */