gloomberb 0.18.3 → 0.18.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (886) hide show
  1. package/README.md +8 -8
  2. package/README.zh-CN.md +11 -11
  3. package/bin/{gloomberb → gloom} +3 -1
  4. package/package.json +6 -2
  5. package/src/account/checkout-handoff.tsx +225 -0
  6. package/src/account/device-signin-dialog.tsx +2 -2
  7. package/src/account/device-signin.ts +2 -2
  8. package/src/account/upgrade-dialog.tsx +1 -1
  9. package/src/api-client/askg.ts +2 -2
  10. package/src/api-client/auth.ts +2 -2
  11. package/src/api-client/central-bank-rates.ts +6 -0
  12. package/src/api-client/collections.ts +5 -1
  13. package/src/api-client/cot.ts +2 -0
  14. package/src/api-client/crypto-etf-flows.ts +37 -0
  15. package/src/api-client/crypto-markets.ts +60 -0
  16. package/src/api-client/data.ts +84 -5
  17. package/src/api-client/doe.ts +15 -0
  18. package/src/api-client/equity-screener.ts +28 -0
  19. package/src/api-client/exchange-announcements.ts +38 -0
  20. package/src/api-client/fund-facts.ts +39 -0
  21. package/src/api-client/futures-curve.ts +9 -1
  22. package/src/api-client/hiring.ts +301 -0
  23. package/src/api-client/index.ts +22 -5
  24. package/src/api-client/market-discovery.ts +14 -0
  25. package/src/api-client/members.ts +6 -0
  26. package/src/api-client/mna.ts +6 -0
  27. package/src/api-client/paths.ts +18 -1
  28. package/src/api-client/request.ts +21 -4
  29. package/src/api-client/short-side-publications.ts +37 -0
  30. package/src/api-client/socket.ts +64 -4
  31. package/src/api-client/swap-curve.ts +35 -0
  32. package/src/api-client/themes.ts +7 -1
  33. package/src/api-client/types.ts +90 -2
  34. package/src/app/pane-runtime/plugin-bindings.ts +9 -2
  35. package/src/app/runtime/desktop-deeplink.ts +5 -5
  36. package/src/app/runtime/plugin-bindings.ts +2 -2
  37. package/src/app/runtime/startup.ts +13 -0
  38. package/src/app/star-prompt/status-line.tsx +2 -2
  39. package/src/architecture/core-builtin-allowlist.json +5 -2
  40. package/src/architecture/ui-literals-allowlist.json +3 -3
  41. package/src/architecture/ui-tokens-allowlist.json +1 -1
  42. package/src/brokers/broker-portfolio-sync.ts +37 -0
  43. package/src/brokers/directory.ts +11 -0
  44. package/src/brokers/logos.ts +3 -1
  45. package/src/brokers/signed-in/adapter.ts +304 -26
  46. package/src/brokers/signed-in/client.ts +14 -2
  47. package/src/brokers/signed-in/connect.ts +10 -2
  48. package/src/brokers/sync-broker-instance.ts +9 -1
  49. package/src/capabilities/chart-series.ts +22 -6
  50. package/src/cli/bank-section.ts +1 -1
  51. package/src/cli/base-converter.ts +23 -14
  52. package/src/cli/central-bank-events.ts +1 -1
  53. package/src/cli/command-options.ts +59 -4
  54. package/src/cli/commands/api.ts +9 -6
  55. package/src/cli/commands/broker.ts +2 -2
  56. package/src/cli/commands/command-utils.ts +2 -2
  57. package/src/cli/commands/crypto-hints.ts +7 -20
  58. package/src/cli/commands/fred-series.ts +4 -2
  59. package/src/cli/commands/keybindings.ts +2 -2
  60. package/src/cli/commands/market.ts +1117 -264
  61. package/src/cli/commands/news-hints.ts +2 -2
  62. package/src/cli/commands/news-search.ts +59 -6
  63. package/src/cli/commands/options-leaps.ts +41 -26
  64. package/src/cli/commands/overview.ts +121 -48
  65. package/src/cli/commands/plugins.ts +9 -9
  66. package/src/cli/commands/remote.ts +13 -10
  67. package/src/cli/commands/search.ts +64 -44
  68. package/src/cli/commands/system.ts +27 -19
  69. package/src/cli/commands/themes.ts +1 -1
  70. package/src/cli/commands/ticker.ts +192 -47
  71. package/src/cli/context.ts +3 -2
  72. package/src/cli/desktop-pane-shot-view.ts +2 -2
  73. package/src/cli/desktop-pane-shot.ts +1 -1
  74. package/src/cli/earnings-calendar.ts +4 -4
  75. package/src/cli/entry.ts +18 -1
  76. package/src/cli/errors.ts +20 -2
  77. package/src/cli/exit-codes.ts +1 -1
  78. package/src/cli/export-source.ts +10 -4
  79. package/src/cli/freshness.ts +2 -8
  80. package/src/cli/fx-forward.ts +130 -0
  81. package/src/cli/fx-pair.ts +10 -9
  82. package/src/cli/glossary.ts +64 -20
  83. package/src/cli/help.ts +19 -13
  84. package/src/cli/history-export.ts +126 -0
  85. package/src/cli/history-rows.ts +196 -43
  86. package/src/cli/index-roots.ts +5 -45
  87. package/src/cli/index.ts +24 -18
  88. package/src/cli/known-gaps.ts +118 -25
  89. package/src/cli/listing-arg.ts +300 -41
  90. package/src/cli/name-entries.ts +30 -18
  91. package/src/cli/native-smoke.ts +2 -0
  92. package/src/cli/not-a-ticker.ts +19 -9
  93. package/src/cli/opentui-libc.ts +5 -0
  94. package/src/cli/options.ts +12 -0
  95. package/src/cli/pane-functions/capabilities.ts +75 -20
  96. package/src/cli/pane-functions/catalog.ts +24 -23
  97. package/src/cli/pane-functions/discovery.ts +1 -1
  98. package/src/cli/pane-functions/dom.ts +10 -7
  99. package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
  100. package/src/cli/pane-functions/freshness.ts +174 -23
  101. package/src/cli/pane-functions/function-help.ts +66 -27
  102. package/src/cli/pane-functions/headless.ts +24 -11
  103. package/src/cli/pane-functions/index.ts +18 -16
  104. package/src/cli/pane-functions/options.ts +22 -2
  105. package/src/cli/pane-functions/report-notices.ts +12 -4
  106. package/src/cli/pane-functions/report.ts +5 -5
  107. package/src/cli/pane-functions/resolver.ts +47 -10
  108. package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
  109. package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
  110. package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
  111. package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
  112. package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
  113. package/src/cli/pane-functions/screenshot-payload.ts +453 -0
  114. package/src/cli/pane-functions/screenshot-render.ts +316 -0
  115. package/src/cli/pane-functions/screenshot-types.ts +162 -0
  116. package/src/cli/pane-functions/shot-options.ts +8 -3
  117. package/src/cli/peso-dollar-rates.ts +79 -0
  118. package/src/cli/quote-answer.ts +38 -3
  119. package/src/cli/report-tables.ts +61 -16
  120. package/src/cli/restore-plugins.ts +29 -14
  121. package/src/cli/result.ts +111 -22
  122. package/src/cli/series-search.ts +5 -5
  123. package/src/cli/statement-filings.ts +19 -0
  124. package/src/cli/suffixed-listing-rows.ts +49 -0
  125. package/src/cli/symbol-args.ts +50 -15
  126. package/src/cli/symbol-cells.ts +120 -0
  127. package/src/cli/symbol-list.ts +198 -68
  128. package/src/cli/symbol-rows.ts +131 -25
  129. package/src/cli/ticker-resolution.ts +108 -11
  130. package/src/cli/treasury-yields.ts +5 -5
  131. package/src/cli/types.ts +2 -0
  132. package/src/cli/uncovered-instrument.ts +3 -3
  133. package/src/cli/unknown-command.ts +6 -6
  134. package/src/components/chart/composite/chart-layout.ts +131 -0
  135. package/src/components/chart/composite/composite-chart.tsx +373 -16
  136. package/src/components/chart/composite/interactions.ts +7 -2
  137. package/src/components/chart/composite/legend.tsx +75 -3
  138. package/src/components/chart/composite/levels.ts +5 -0
  139. package/src/components/chart/composite/panel-gestures.ts +41 -0
  140. package/src/components/chart/composite/panel-labels.ts +2 -1
  141. package/src/components/chart/composite/panel-surface.tsx +305 -11
  142. package/src/components/chart/composite/price-axis-labels.tsx +27 -3
  143. package/src/components/chart/composite/rasterizer.ts +44 -19
  144. package/src/components/chart/composite/scene.ts +16 -4
  145. package/src/components/chart/composite/text-renderer.ts +48 -21
  146. package/src/components/chart/composite/toolbar.tsx +52 -5
  147. package/src/components/chart/composite/types.ts +13 -0
  148. package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
  149. package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
  150. package/src/components/chart/composite/use-composite-viewport.ts +12 -3
  151. package/src/components/chart/composite/value-scale.ts +149 -0
  152. package/src/components/chart/composite/volume-profile-paint.ts +6 -3
  153. package/src/components/chart/core/pointer.ts +2 -0
  154. package/src/components/chart-table/index.ts +2 -0
  155. package/src/components/chart-table/read.tsx +74 -0
  156. package/src/components/command-bar/commands/collection-list.ts +41 -19
  157. package/src/components/command-bar/commands/collection.ts +9 -3
  158. package/src/components/command-bar/commands/direct/index.ts +1 -1
  159. package/src/components/command-bar/commands/direct/runtime.ts +3 -2
  160. package/src/components/command-bar/pane-templates/items.ts +59 -6
  161. package/src/components/command-bar/pane-templates/workflow.ts +10 -1
  162. package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
  163. package/src/components/command-bar/routes/root/provider-search.ts +42 -11
  164. package/src/components/command-bar/routes/root/results.ts +18 -4
  165. package/src/components/command-bar/routes/root/runtime.ts +15 -3
  166. package/src/components/command-bar/routes/root/search-providers.ts +25 -2
  167. package/src/components/command-bar/routes/root/selection.ts +6 -1
  168. package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
  169. package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
  170. package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
  171. package/src/components/command-bar/selection-runtime.ts +50 -10
  172. package/src/components/command-bar/surface/index.tsx +24 -2
  173. package/src/components/command-bar/view-model.ts +7 -0
  174. package/src/components/command-bar/workflow/broker.ts +2 -2
  175. package/src/components/command-bar/workflow/collection-actions.ts +46 -7
  176. package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
  177. package/src/components/command-bar/workflow/fields.ts +8 -2
  178. package/src/components/command-bar/workflow/ops.ts +18 -4
  179. package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
  180. package/src/components/command-bar/workflow/submit.ts +3 -2
  181. package/src/components/command-bar/workflow/tickers.ts +5 -1
  182. package/src/components/company-logo.tsx +39 -0
  183. package/src/components/data-table/sections.ts +4 -2
  184. package/src/components/form-modal/confirm.tsx +2 -1
  185. package/src/components/form-modal/request.ts +5 -0
  186. package/src/components/form-modal/routes.ts +4 -1
  187. package/src/components/index.ts +12 -6
  188. package/src/components/layout/header.tsx +7 -6
  189. package/src/components/layout/market-summary.ts +9 -6
  190. package/src/components/layout/pane/capture-status.ts +1 -1
  191. package/src/components/layout/pane/footer/model.ts +11 -5
  192. package/src/components/layout/shell/chrome.ts +19 -6
  193. package/src/components/layout/shell/index.tsx +2 -1
  194. package/src/components/layout/shell/pane/layers.tsx +19 -1
  195. package/src/components/layout/status-bar.tsx +2 -2
  196. package/src/components/market-board/index.tsx +11 -3
  197. package/src/components/onboarding/onboarding-wizard.tsx +1 -0
  198. package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
  199. package/src/components/onboarding/wizard-broker-sync.ts +4 -1
  200. package/src/components/pane-settings-dialog/desktop.tsx +20 -7
  201. package/src/components/pane-settings-dialog/tui.tsx +17 -9
  202. package/src/components/pane-settings-dialog/value.ts +8 -1
  203. package/src/components/pane-settings-dialog.tsx +44 -13
  204. package/src/components/sign-in-code-panel.tsx +27 -19
  205. package/src/components/ui/column-grid.tsx +48 -4
  206. package/src/components/ui/country-flag-art.tsx +180 -0
  207. package/src/components/ui/country-flag.tsx +118 -12
  208. package/src/components/ui/data-table/opentui/index.tsx +61 -2
  209. package/src/components/ui/data-table/opentui/model.ts +109 -2
  210. package/src/components/ui/data-table/types.ts +1 -1
  211. package/src/components/ui/display.tsx +5 -1
  212. package/src/components/ui/index.ts +3 -1
  213. package/src/components/ui/logo-mark.tsx +11 -2
  214. package/src/components/ui/query-bar.tsx +1 -1
  215. package/src/components/ui/row-notes.ts +79 -0
  216. package/src/core/state/app/layout.ts +4 -4
  217. package/src/data/cached-query.ts +8 -1
  218. package/src/data/config/chart-settings.ts +3 -3
  219. package/src/data/config/home.ts +10 -2
  220. package/src/data/config/layout.ts +4 -1
  221. package/src/data/config/store/node.ts +4 -0
  222. package/src/data/config/store/normalize.ts +13 -3
  223. package/src/data/config/store/portfolio-as-of-column.ts +2 -2
  224. package/src/data/json-storage.ts +2 -0
  225. package/src/data/saved-copies.ts +84 -0
  226. package/src/docs/snapshot.json +65 -32
  227. package/src/i18n/es.ts +29 -12
  228. package/src/i18n/ja.ts +29 -12
  229. package/src/i18n/ko.ts +29 -12
  230. package/src/i18n/zh-cn.ts +29 -12
  231. package/src/i18n/zh-tw.ts +29 -12
  232. package/src/layout/desks.ts +1 -1
  233. package/src/layout/launch-layout.ts +1 -1
  234. package/src/layout/pane-manager/floating-actions.ts +5 -3
  235. package/src/layout/pane-manager/floating.ts +43 -1
  236. package/src/layout/pane-manager/index.ts +2 -0
  237. package/src/layout/selected-ticker.ts +74 -0
  238. package/src/market-data/depositary-pair.ts +251 -0
  239. package/src/market-data/futures-board.ts +1 -1
  240. package/src/market-data/futures-contract.ts +124 -40
  241. package/src/market-data/fx-closes.ts +17 -2
  242. package/src/market-data/hooks.tsx +19 -11
  243. package/src/market-data/market/change-basis.ts +49 -7
  244. package/src/market-data/market/freshness.ts +34 -5
  245. package/src/market-data/market/period-return.ts +163 -0
  246. package/src/market-data/market/trading-sessions.ts +13 -0
  247. package/src/market-data/market/year-to-date.ts +8 -13
  248. package/src/market-data/performance.ts +20 -14
  249. package/src/market-data/perpetual-premium.ts +32 -0
  250. package/src/market-data/published-apac-sessions.ts +2 -1
  251. package/src/market-data/published-futures-sessions.ts +69 -0
  252. package/src/market-data/quotes/contributions.ts +5 -1
  253. package/src/market-data/quotes/freshness.ts +42 -0
  254. package/src/market-data/quotes/intraday-bar.ts +37 -0
  255. package/src/market-data/quotes/regular-session-valuation.ts +13 -8
  256. package/src/market-data/quotes/resolution.ts +4 -2
  257. package/src/market-data/tax-equivalent.ts +1 -1
  258. package/src/market-data/ticker-price-returns.ts +3 -1
  259. package/src/news/aggregator.ts +5 -1
  260. package/src/news/news-model.ts +4 -0
  261. package/src/news/types.ts +11 -0
  262. package/src/notifications/app-notifier.ts +1 -1
  263. package/src/plugins/auto-update.ts +2 -2
  264. package/src/plugins/builtin/account-management/index.tsx +1 -0
  265. package/src/plugins/builtin/account-management/pane.tsx +9 -8
  266. package/src/plugins/builtin/alerts/alert-engine.ts +29 -19
  267. package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
  268. package/src/plugins/builtin/alerts/cli.ts +485 -76
  269. package/src/plugins/builtin/alerts/command.ts +5 -10
  270. package/src/plugins/builtin/alerts/event-rows.ts +9 -5
  271. package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
  272. package/src/plugins/builtin/alerts/events.ts +107 -5
  273. package/src/plugins/builtin/alerts/fired-log.ts +78 -0
  274. package/src/plugins/builtin/alerts/format.ts +2 -1
  275. package/src/plugins/builtin/alerts/headless.ts +100 -39
  276. package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
  277. package/src/plugins/builtin/alerts/history-rows.ts +89 -0
  278. package/src/plugins/builtin/alerts/index.tsx +45 -18
  279. package/src/plugins/builtin/alerts/iv-level.ts +365 -0
  280. package/src/plugins/builtin/alerts/levels.ts +3 -3
  281. package/src/plugins/builtin/alerts/pane.tsx +97 -29
  282. package/src/plugins/builtin/alerts/price.ts +35 -0
  283. package/src/plugins/builtin/alerts/quotes.ts +24 -0
  284. package/src/plugins/builtin/alerts/research-builder.ts +84 -11
  285. package/src/plugins/builtin/alerts/research-rules.ts +76 -3
  286. package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
  287. package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
  288. package/src/plugins/builtin/alerts/scheduled.ts +188 -29
  289. package/src/plugins/builtin/alerts/storage.ts +13 -10
  290. package/src/plugins/builtin/alerts/targets.ts +12 -3
  291. package/src/plugins/builtin/analytics/index.tsx +8 -2
  292. package/src/plugins/builtin/analytics/metrics.ts +1 -1
  293. package/src/plugins/builtin/analytics/risk-book.ts +215 -0
  294. package/src/plugins/builtin/analytics/risk-client.ts +13 -6
  295. package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
  296. package/src/plugins/builtin/analytics/risk-math.ts +6 -3
  297. package/src/plugins/builtin/analytics/risk-model.ts +297 -104
  298. package/src/plugins/builtin/analytics/risk-options.ts +17 -2
  299. package/src/plugins/builtin/analytics/risk-pane.tsx +97 -36
  300. package/src/plugins/builtin/attention/pane.tsx +6 -2
  301. package/src/plugins/builtin/awards/headless.ts +7 -3
  302. package/src/plugins/builtin/awards/model.ts +18 -0
  303. package/src/plugins/builtin/awards/pane.tsx +6 -3
  304. package/src/plugins/builtin/backtest/headless.ts +3 -3
  305. package/src/plugins/builtin/backtest/rules.ts +41 -5
  306. package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
  307. package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
  308. package/src/plugins/builtin/broker-manager/footer.ts +27 -11
  309. package/src/plugins/builtin/broker-manager/index.tsx +21 -12
  310. package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
  311. package/src/plugins/builtin/broker-manager/model.ts +12 -2
  312. package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
  313. package/src/plugins/builtin/broker-manager/table.ts +28 -12
  314. package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
  315. package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
  316. package/src/plugins/builtin/broker-trading/controller.ts +45 -13
  317. package/src/plugins/builtin/broker-trading/dock.tsx +22 -4
  318. package/src/plugins/builtin/broker-trading/headless.ts +2 -1
  319. package/src/plugins/builtin/broker-trading/index.tsx +7 -1
  320. package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
  321. package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
  322. package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
  323. package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
  324. package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
  325. package/src/plugins/builtin/broker-trading/pane.tsx +110 -23
  326. package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
  327. package/src/plugins/builtin/broker-trading/ticket.tsx +112 -31
  328. package/src/plugins/builtin/buildout/cells.tsx +4 -0
  329. package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
  330. package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
  331. package/src/plugins/builtin/buildout/pane/index.tsx +25 -12
  332. package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
  333. package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
  334. package/src/plugins/builtin/catalysts/detail.tsx +3 -2
  335. package/src/plugins/builtin/catalysts/index.tsx +1 -1
  336. package/src/plugins/builtin/catalysts/model.ts +49 -4
  337. package/src/plugins/builtin/catalysts/pane.tsx +6 -8
  338. package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
  339. package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
  340. package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
  341. package/src/plugins/builtin/changelog/index.tsx +1 -0
  342. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
  343. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
  344. package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
  345. package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
  346. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
  347. package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
  348. package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
  349. package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
  350. package/src/plugins/builtin/chart-composer/headless.ts +253 -35
  351. package/src/plugins/builtin/chart-composer/index.tsx +12 -2
  352. package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
  353. package/src/plugins/builtin/chart-composer/pane.tsx +127 -28
  354. package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
  355. package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
  356. package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
  357. package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
  358. package/src/plugins/builtin/chart-composer/settings.ts +31 -19
  359. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
  360. package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
  361. package/src/plugins/builtin/chat/attachments/model.ts +3 -1
  362. package/src/plugins/builtin/chat/content/index.tsx +1 -1
  363. package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
  364. package/src/plugins/builtin/chat/people.ts +1 -1
  365. package/src/plugins/builtin/clinical-trials/client.ts +5 -2
  366. package/src/plugins/builtin/clinical-trials/model.ts +13 -4
  367. package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
  368. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
  369. package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
  370. package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
  371. package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
  372. package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
  373. package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
  374. package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
  375. package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
  376. package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
  377. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  378. package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
  379. package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
  380. package/src/plugins/builtin/commodity-balances/pane.tsx +11 -4
  381. package/src/plugins/builtin/company-attention/app-rank.tsx +7 -5
  382. package/src/plugins/builtin/company-attention/building-model.ts +222 -0
  383. package/src/plugins/builtin/company-attention/building.tsx +172 -0
  384. package/src/plugins/builtin/company-attention/client.ts +117 -1
  385. package/src/plugins/builtin/company-attention/evidence.ts +16 -3
  386. package/src/plugins/builtin/company-attention/headless.ts +101 -5
  387. package/src/plugins/builtin/company-attention/index.tsx +6 -3
  388. package/src/plugins/builtin/company-attention/model.ts +33 -7
  389. package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
  390. package/src/plugins/builtin/company-attention/moves.tsx +159 -0
  391. package/src/plugins/builtin/company-attention/pane.tsx +79 -23
  392. package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
  393. package/src/plugins/builtin/company-attention/signals.tsx +160 -0
  394. package/src/plugins/builtin/company-kpis/headless.ts +3 -2
  395. package/src/plugins/builtin/company-kpis/model.ts +2 -2
  396. package/src/plugins/builtin/company-kpis/pane.tsx +1 -1
  397. package/src/plugins/builtin/composite-plugins.ts +2 -1
  398. package/src/plugins/builtin/congress-trades/headless.ts +1 -1
  399. package/src/plugins/builtin/connections/index.ts +1 -0
  400. package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
  401. package/src/plugins/builtin/correlation/headless.ts +5 -3
  402. package/src/plugins/builtin/cot/headless.ts +28 -6
  403. package/src/plugins/builtin/cot/model.ts +12 -0
  404. package/src/plugins/builtin/cot/pane.tsx +3 -2
  405. package/src/plugins/builtin/cpi/headless.ts +5 -1
  406. package/src/plugins/builtin/cpi/pane.tsx +11 -9
  407. package/src/plugins/builtin/credit-boards/model.ts +2 -0
  408. package/src/plugins/builtin/credit-documents/headless.ts +1 -1
  409. package/src/plugins/builtin/crypto-board/client.ts +86 -0
  410. package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
  411. package/src/plugins/builtin/crypto-board/defi.ts +239 -0
  412. package/src/plugins/builtin/crypto-board/headless.ts +117 -6
  413. package/src/plugins/builtin/crypto-board/index.tsx +8 -3
  414. package/src/plugins/builtin/crypto-board/model.ts +40 -8
  415. package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
  416. package/src/plugins/builtin/crypto-board/series.ts +19 -1
  417. package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
  418. package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
  419. package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
  420. package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
  421. package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
  422. package/src/plugins/builtin/debug/index.tsx +1 -0
  423. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  424. package/src/plugins/builtin/docs/index.tsx +1 -1
  425. package/src/plugins/builtin/docs/pane.tsx +2 -2
  426. package/src/plugins/builtin/docs/targets.ts +1 -1
  427. package/src/plugins/builtin/doe/client.ts +5 -1
  428. package/src/plugins/builtin/doe/headless.ts +12 -6
  429. package/src/plugins/builtin/doe/model.ts +43 -6
  430. package/src/plugins/builtin/doe/pane.tsx +18 -11
  431. package/src/plugins/builtin/earnings/board-model.ts +13 -6
  432. package/src/plugins/builtin/earnings/board-table.ts +4 -1
  433. package/src/plugins/builtin/earnings/board.tsx +253 -50
  434. package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
  435. package/src/plugins/builtin/earnings/calendar.tsx +338 -0
  436. package/src/plugins/builtin/earnings/client.ts +4 -3
  437. package/src/plugins/builtin/earnings/headless.ts +53 -15
  438. package/src/plugins/builtin/earnings/history-model.ts +53 -36
  439. package/src/plugins/builtin/earnings/index.tsx +15 -22
  440. package/src/plugins/builtin/earnings/model.ts +17 -12
  441. package/src/plugins/builtin/earnings/scope.ts +89 -0
  442. package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
  443. package/src/plugins/builtin/earnings-calls/data.ts +146 -2
  444. package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
  445. package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
  446. package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
  447. package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
  448. package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
  449. package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
  450. package/src/plugins/builtin/econ/calendar-model.ts +132 -20
  451. package/src/plugins/builtin/econ/detail-view.tsx +48 -10
  452. package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
  453. package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
  454. package/src/plugins/builtin/econ/index.tsx +112 -25
  455. package/src/plugins/builtin/econ/print-watch.ts +2 -1
  456. package/src/plugins/builtin/econ/types.ts +32 -1
  457. package/src/plugins/builtin/econ-statistics/client.ts +16 -3
  458. package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
  459. package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
  460. package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
  461. package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
  462. package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
  463. package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
  464. package/src/plugins/builtin/econ-statistics/view.ts +16 -1
  465. package/src/plugins/builtin/equity-screener/client.ts +21 -3
  466. package/src/plugins/builtin/equity-screener/headless.ts +68 -6
  467. package/src/plugins/builtin/equity-screener/live.ts +1 -1
  468. package/src/plugins/builtin/equity-screener/model.ts +6 -0
  469. package/src/plugins/builtin/equity-screener/pane.tsx +45 -10
  470. package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
  471. package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
  472. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
  473. package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
  474. package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
  475. package/src/plugins/builtin/exposure/headless.ts +51 -6
  476. package/src/plugins/builtin/exposure/index.tsx +28 -2
  477. package/src/plugins/builtin/exposure/model.ts +7 -0
  478. package/src/plugins/builtin/exposure/pane.tsx +6 -1
  479. package/src/plugins/builtin/fear-greed/index.tsx +1 -1
  480. package/src/plugins/builtin/filing-events/index.tsx +1 -1
  481. package/src/plugins/builtin/futures/model.ts +10 -9
  482. package/src/plugins/builtin/futures/returns.ts +8 -36
  483. package/src/plugins/builtin/futures/table.tsx +1 -1
  484. package/src/plugins/builtin/futures-curve/client.ts +40 -9
  485. package/src/plugins/builtin/futures-curve/headless.ts +39 -17
  486. package/src/plugins/builtin/futures-curve/model.ts +258 -69
  487. package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
  488. package/src/plugins/builtin/fx-matrix/client.ts +15 -8
  489. package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
  490. package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
  491. package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
  492. package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
  493. package/src/plugins/builtin/gpu/headless.ts +9 -4
  494. package/src/plugins/builtin/help/index.tsx +13 -3
  495. package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
  496. package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
  497. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  498. package/src/plugins/builtin/holders/client.ts +13 -1
  499. package/src/plugins/builtin/holders/format.ts +28 -17
  500. package/src/plugins/builtin/holders/headless.ts +46 -7
  501. package/src/plugins/builtin/holders/index-holders.ts +264 -0
  502. package/src/plugins/builtin/holders/pane.tsx +79 -15
  503. package/src/plugins/builtin/holders/report-rows.ts +35 -7
  504. package/src/plugins/builtin/holders/table-model.ts +2 -1
  505. package/src/plugins/builtin/holders/treemap.tsx +2 -2
  506. package/src/plugins/builtin/insider/headless.ts +1 -1
  507. package/src/plugins/builtin/insider/signals-client.ts +1 -1
  508. package/src/plugins/builtin/insider/signals.tsx +1 -1
  509. package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
  510. package/src/plugins/builtin/iv-history/client.ts +20 -0
  511. package/src/plugins/builtin/iv-history/headless.ts +4 -4
  512. package/src/plugins/builtin/iv-history/index.tsx +1 -1
  513. package/src/plugins/builtin/iv-history/model.ts +13 -4
  514. package/src/plugins/builtin/iv-history/series.ts +3 -1
  515. package/src/plugins/builtin/jobs/lock-note.ts +1 -1
  516. package/src/plugins/builtin/jobs/model.ts +4 -15
  517. package/src/plugins/builtin/jobs/pane.tsx +7 -5
  518. package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
  519. package/src/plugins/builtin/jodi/pane.tsx +10 -4
  520. package/src/plugins/builtin/layout-manager/index.tsx +1 -0
  521. package/src/plugins/builtin/macro-day/headless.ts +20 -7
  522. package/src/plugins/builtin/macro-day/index.tsx +3 -2
  523. package/src/plugins/builtin/macro-day/model.ts +29 -8
  524. package/src/plugins/builtin/macro-day/pane.tsx +46 -10
  525. package/src/plugins/builtin/macro-day/releases.ts +55 -13
  526. package/src/plugins/builtin/market-heatmap/data.ts +9 -2
  527. package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
  528. package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
  529. package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
  530. package/src/plugins/builtin/market-heatmap/model.ts +10 -7
  531. package/src/plugins/builtin/market-movers/client.ts +33 -19
  532. package/src/plugins/builtin/market-movers/headless.ts +8 -2
  533. package/src/plugins/builtin/market-movers/index.tsx +16 -10
  534. package/src/plugins/builtin/market-movers/screener.ts +29 -8
  535. package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
  536. package/src/plugins/builtin/market-movers/session-table.ts +4 -2
  537. package/src/plugins/builtin/market-movers/table.ts +4 -1
  538. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  539. package/src/plugins/builtin/market-valuation/view.ts +5 -0
  540. package/src/plugins/builtin/members/headless.ts +6 -5
  541. package/src/plugins/builtin/members/pane.tsx +11 -4
  542. package/src/plugins/builtin/mna/client.ts +1 -0
  543. package/src/plugins/builtin/mna/detail.tsx +20 -32
  544. package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
  545. package/src/plugins/builtin/mna/distress/model.ts +3 -2
  546. package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
  547. package/src/plugins/builtin/mna/headless.ts +6 -13
  548. package/src/plugins/builtin/mna/model.ts +93 -15
  549. package/src/plugins/builtin/mna/pane.tsx +5 -4
  550. package/src/plugins/builtin/news/headless.ts +12 -6
  551. package/src/plugins/builtin/news/index.tsx +10 -1
  552. package/src/plugins/builtin/news/wire/index.tsx +3 -2
  553. package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
  554. package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
  555. package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
  556. package/src/plugins/builtin/notes/cli.ts +49 -14
  557. package/src/plugins/builtin/openfda/pane.tsx +1 -1
  558. package/src/plugins/builtin/options/carry.ts +2 -2
  559. package/src/plugins/builtin/options/index.tsx +1 -1
  560. package/src/plugins/builtin/options/view.tsx +10 -10
  561. package/src/plugins/builtin/options-calculator/headless.ts +46 -7
  562. package/src/plugins/builtin/options-scenario/client.ts +123 -28
  563. package/src/plugins/builtin/options-scenario/collar.ts +8 -6
  564. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
  565. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
  566. package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
  567. package/src/plugins/builtin/options-scenario/csp.ts +101 -21
  568. package/src/plugins/builtin/options-scenario/headless.ts +36 -15
  569. package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
  570. package/src/plugins/builtin/options-scenario/index.tsx +28 -3
  571. package/src/plugins/builtin/options-scenario/model.ts +13 -0
  572. package/src/plugins/builtin/options-scenario/pane.tsx +9 -5
  573. package/src/plugins/builtin/perps/equity-row.tsx +11 -3
  574. package/src/plugins/builtin/perps/freshness.ts +8 -5
  575. package/src/plugins/builtin/perps/headless.ts +3 -1
  576. package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
  577. package/src/plugins/builtin/perps/live-rows.ts +161 -0
  578. package/src/plugins/builtin/perps/markets-section.tsx +154 -0
  579. package/src/plugins/builtin/perps/pane.tsx +36 -17
  580. package/src/plugins/builtin/perps/venue-markets.ts +96 -0
  581. package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
  582. package/src/plugins/builtin/plugin-marketplace/pane.tsx +143 -59
  583. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +72 -24
  584. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
  585. package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
  586. package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
  587. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
  588. package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
  589. package/src/plugins/builtin/portfolio-list/income.ts +13 -2
  590. package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
  591. package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
  592. package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
  593. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
  594. package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
  595. package/src/plugins/builtin/power/client.ts +4 -1
  596. package/src/plugins/builtin/power/evidence.ts +22 -7
  597. package/src/plugins/builtin/power/gas.tsx +5 -1
  598. package/src/plugins/builtin/power/pane.tsx +8 -1
  599. package/src/plugins/builtin/power/prices.tsx +10 -3
  600. package/src/plugins/builtin/research/analyst-headless.ts +25 -8
  601. package/src/plugins/builtin/research/analyst-model.ts +68 -3
  602. package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
  603. package/src/plugins/builtin/research/event-model.ts +3 -1
  604. package/src/plugins/builtin/research/event-sources.ts +12 -4
  605. package/src/plugins/builtin/research/index.tsx +2 -1
  606. package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
  607. package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
  608. package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
  609. package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
  610. package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
  611. package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
  612. package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
  613. package/src/plugins/builtin/reverse-dcf/model.ts +6 -2
  614. package/src/plugins/builtin/risk-factors/index.tsx +2 -2
  615. package/src/plugins/builtin/scanner/lock-note.ts +1 -1
  616. package/src/plugins/builtin/sec/forms.ts +13 -0
  617. package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
  618. package/src/plugins/builtin/sec/fund-facts.ts +68 -8
  619. package/src/plugins/builtin/sec/headless.ts +85 -8
  620. package/src/plugins/builtin/sec/index.tsx +58 -12
  621. package/src/plugins/builtin/sectors/client.ts +2 -1
  622. package/src/plugins/builtin/sectors/sector-model.ts +11 -15
  623. package/src/plugins/builtin/series-inventory.ts +2 -0
  624. package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
  625. package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
  626. package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
  627. package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
  628. package/src/plugins/builtin/shared/earnings-report.ts +3 -3
  629. package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
  630. package/src/plugins/builtin/shared/job-posting.ts +129 -0
  631. package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
  632. package/src/plugins/builtin/shared/report-freshness.ts +3 -0
  633. package/src/plugins/builtin/shared/research-trading.tsx +21 -0
  634. package/src/plugins/builtin/shared/series-cache.ts +2 -0
  635. package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
  636. package/src/plugins/builtin/short-interest/client.ts +2 -0
  637. package/src/plugins/builtin/short-interest/headless.ts +41 -12
  638. package/src/plugins/builtin/short-interest/index.tsx +23 -1
  639. package/src/plugins/builtin/short-interest/model.ts +70 -19
  640. package/src/plugins/builtin/short-interest/pane.tsx +19 -2
  641. package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
  642. package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
  643. package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
  644. package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
  645. package/src/plugins/builtin/short-interest/schedule.ts +35 -2
  646. package/src/plugins/builtin/short-interest/surface.tsx +11 -4
  647. package/src/plugins/builtin/short-interest/types.ts +9 -0
  648. package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
  649. package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
  650. package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
  651. package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
  652. package/src/plugins/builtin/supply-chain/model.ts +51 -3
  653. package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
  654. package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
  655. package/src/plugins/builtin/themes/headless.ts +8 -5
  656. package/src/plugins/builtin/themes/model.ts +14 -4
  657. package/src/plugins/builtin/themes/pane.tsx +24 -5
  658. package/src/plugins/builtin/thirteenf/headless.ts +5 -5
  659. package/src/plugins/builtin/thirteenf/signals.ts +3 -1
  660. package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
  661. package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
  662. package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
  663. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
  664. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
  665. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
  666. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
  667. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
  668. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
  669. package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
  670. package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
  671. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
  672. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
  673. package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
  674. package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
  675. package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
  676. package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
  677. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
  678. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
  679. package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
  680. package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
  681. package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
  682. package/src/plugins/builtin/vol-surface/client.ts +5 -4
  683. package/src/plugins/builtin/vol-surface/headless.ts +12 -3
  684. package/src/plugins/builtin/vol-surface/model.ts +4 -2
  685. package/src/plugins/builtin/volatility/model.ts +5 -10
  686. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
  687. package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
  688. package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
  689. package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
  690. package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
  691. package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
  692. package/src/plugins/builtin/world-venue-map/index.ts +3 -26
  693. package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
  694. package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
  695. package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
  696. package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
  697. package/src/plugins/builtin/yield-curve/client.ts +25 -0
  698. package/src/plugins/builtin/yield-curve/curves.ts +7 -4
  699. package/src/plugins/builtin/yield-curve/headless.ts +38 -4
  700. package/src/plugins/builtin/yield-curve/history.ts +4 -3
  701. package/src/plugins/builtin/yield-curve/index.tsx +12 -6
  702. package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
  703. package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
  704. package/src/plugins/bundle.ts +1 -1
  705. package/src/plugins/catalog-browser.ts +2 -1
  706. package/src/plugins/compat.ts +3 -3
  707. package/src/plugins/dependencies.ts +75 -14
  708. package/src/plugins/extracted-plugins.ts +132 -34
  709. package/src/plugins/host-link.ts +149 -34
  710. package/src/plugins/installer.ts +35 -10
  711. package/src/plugins/loader.ts +206 -38
  712. package/src/plugins/manager-node.ts +2 -2
  713. package/src/plugins/marketplace/deactivation.ts +22 -0
  714. package/src/plugins/marketplace/model.ts +2 -2
  715. package/src/plugins/marketplace/packs.ts +1 -1
  716. package/src/plugins/ownership.ts +1 -1
  717. package/src/plugins/peer-retry.ts +155 -0
  718. package/src/plugins/registry/contributions.ts +3 -1
  719. package/src/plugins/registry/index.ts +4 -3
  720. package/src/plugins/registry/plugin-state.ts +3 -0
  721. package/src/plugins/seed-notice.ts +20 -0
  722. package/src/plugins/shortcut-argument.ts +39 -0
  723. package/src/portfolio/allocation.ts +1 -1
  724. package/src/portfolio/collection-name.ts +31 -0
  725. package/src/portfolio/column-values.ts +10 -8
  726. package/src/portfolio/cost-fx.ts +296 -19
  727. package/src/portfolio/manual-lots.ts +75 -0
  728. package/src/portfolio/mutations.ts +60 -22
  729. package/src/portfolio/suffixed-listings.ts +209 -0
  730. package/src/portfolio/totals-currency.ts +24 -0
  731. package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
  732. package/src/public/time-series.ts +11 -8
  733. package/src/remote/schema.ts +1 -1
  734. package/src/renderers/browser/config-host.ts +3 -0
  735. package/src/renderers/browser/main.tsx +23 -3
  736. package/src/renderers/dom/boot-frame-page.ts +187 -0
  737. package/src/renderers/dom/boot-frame.ts +237 -0
  738. package/src/renderers/dom/build-assets.ts +46 -8
  739. package/src/renderers/dom/dom-ui-host.tsx +4 -29
  740. package/src/renderers/dom/host/ascii-text.ts +16 -2
  741. package/src/renderers/dom/host/box.tsx +43 -2
  742. package/src/renderers/dom/host/chart-surface.tsx +2 -0
  743. package/src/renderers/dom/host/hls.chunk.ts +3 -0
  744. package/src/renderers/dom/host/image-surface.tsx +49 -0
  745. package/src/renderers/dom/host/media-surface.tsx +24 -18
  746. package/src/renderers/dom/host/mouse.ts +30 -0
  747. package/src/renderers/dom/host/size-observer.ts +1 -1
  748. package/src/renderers/dom/host/style.ts +1 -1
  749. package/src/renderers/dom/styles.css +76 -0
  750. package/src/renderers/dom/test-utils.tsx +2 -1
  751. package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
  752. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
  753. package/src/renderers/electrobun/bun/desktop/backend.ts +46 -3
  754. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
  755. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
  756. package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
  757. package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
  758. package/src/renderers/electrobun/bun/index.ts +11 -1
  759. package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
  760. package/src/renderers/electrobun/bun/window/create.ts +4 -1
  761. package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
  762. package/src/renderers/electrobun/shared/protocol.ts +6 -1
  763. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
  764. package/src/renderers/electrobun/view/config-host.ts +3 -0
  765. package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
  766. package/src/renderers/electrobun/view/main.tsx +30 -4
  767. package/src/renderers/electrobun/view/news-source.ts +5 -5
  768. package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -1
  769. package/src/renderers/electrobun/view/ui-host.tsx +1 -1
  770. package/src/renderers/opentui/browser-open.ts +88 -0
  771. package/src/renderers/opentui/host.tsx +5 -14
  772. package/src/renderers/opentui/image/loader.ts +3 -2
  773. package/src/renderers/opentui/native-smoke.ts +10 -1
  774. package/src/renderers/opentui/pane-image/index.ts +2 -1
  775. package/src/renderers/opentui/render-lib.ts +253 -0
  776. package/src/renderers/opentui/render-timing-smoke.ts +1 -1
  777. package/src/renderers/opentui/start.tsx +1 -1
  778. package/src/renderers/share/layout-view.tsx +2 -2
  779. package/src/renderers/share/main.tsx +4 -4
  780. package/src/renderers/share/view.tsx +1 -1
  781. package/src/series/resolve.ts +22 -6
  782. package/src/series/standalone.ts +30 -2
  783. package/src/series/types.ts +8 -1
  784. package/src/shares/api.ts +4 -1
  785. package/src/shares/pane.ts +1 -1
  786. package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
  787. package/src/sources/gloomberb-cloud/index.ts +32 -16
  788. package/src/sources/gloomberb-cloud/news.ts +39 -0
  789. package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
  790. package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
  791. package/src/sources/listing-symbols.ts +37 -0
  792. package/src/sources/provider-errors.ts +16 -2
  793. package/src/sources/provider-router/financial-routes.ts +21 -3
  794. package/src/sources/provider-router/financials.ts +15 -2
  795. package/src/sources/provider-router/history.ts +30 -8
  796. package/src/sources/provider-router/primary.ts +1 -1
  797. package/src/state/app/bootstrap.ts +23 -0
  798. package/src/state/hooks/inline-tickers.ts +30 -5
  799. package/src/sync/controller.ts +1 -1
  800. package/src/sync/core-contributors.ts +46 -14
  801. package/src/team/collections-sync.ts +2 -1
  802. package/src/team/collections.ts +178 -17
  803. package/src/telemetry/crash-reports.ts +17 -4
  804. package/src/test-support/builtin-panes.ts +1 -1
  805. package/src/theme/colors.ts +3 -30
  806. package/src/theme/ui-tokens.ts +37 -1
  807. package/src/tickers/company-name-listing.ts +210 -33
  808. package/src/tickers/index-roots.ts +47 -0
  809. package/src/tickers/instrument-label.ts +5 -1
  810. package/src/tickers/metadata.ts +10 -0
  811. package/src/tickers/perpetual-listing.ts +5 -2
  812. package/src/tickers/search/home-listing.ts +75 -0
  813. package/src/tickers/search/index.ts +76 -27
  814. package/src/tickers/search/ranking.ts +54 -4
  815. package/src/tickers/search/upsert.ts +29 -0
  816. package/src/tickers/terminal-codes.ts +416 -40
  817. package/src/time-series/bar-aggregation.ts +243 -0
  818. package/src/time-series/base-series.ts +307 -0
  819. package/src/time-series/chart-bounds.ts +349 -0
  820. package/src/time-series/chart-seed.ts +142 -0
  821. package/src/time-series/economic.ts +5 -0
  822. package/src/time-series/fundamentals.ts +18 -3
  823. package/src/time-series/history-acquisition.ts +499 -0
  824. package/src/time-series/leverage.ts +100 -0
  825. package/src/time-series/market-resolution.ts +4 -2
  826. package/src/time-series/market.ts +2 -1
  827. package/src/time-series/price-comparison.ts +175 -30
  828. package/src/time-series/range.ts +9 -1
  829. package/src/time-series/resolution.ts +174 -16
  830. package/src/time-series/resolve-context.ts +157 -0
  831. package/src/time-series/resolve.ts +126 -1577
  832. package/src/time-series/series-name.ts +38 -0
  833. package/src/time-series/series-presentation.ts +208 -0
  834. package/src/time-series/spec.ts +11 -6
  835. package/src/time-series/studies.ts +109 -12
  836. package/src/time-series/tail-reconcile.ts +121 -0
  837. package/src/time-series/types.ts +29 -2
  838. package/src/time-series/use-chart-resolution.ts +4 -5
  839. package/src/types/broker.ts +10 -0
  840. package/src/types/config.ts +14 -0
  841. package/src/types/data-provider.ts +14 -0
  842. package/src/types/exchange-rate.ts +6 -0
  843. package/src/types/financials.ts +104 -7
  844. package/src/types/headless.ts +76 -6
  845. package/src/types/instrument.ts +3 -0
  846. package/src/types/plugin.ts +65 -8
  847. package/src/types/price-history.ts +2 -0
  848. package/src/types/ticker.ts +13 -0
  849. package/src/types/trading.ts +59 -1
  850. package/src/ui/ascii-font.ts +13 -1
  851. package/src/ui/host.tsx +6 -1
  852. package/src/updater/command-names.ts +175 -0
  853. package/src/updater/index.ts +10 -5
  854. package/src/utils/calendar-date.ts +32 -15
  855. package/src/utils/cash-runway.ts +241 -0
  856. package/src/utils/central-banks.ts +42 -0
  857. package/src/utils/cli-output.ts +259 -80
  858. package/src/utils/contract-month.ts +16 -0
  859. package/src/utils/crypto-pair.ts +61 -3
  860. package/src/utils/currency-units.ts +29 -0
  861. package/src/utils/datetime-format.ts +10 -0
  862. package/src/utils/debug-log.ts +1 -1
  863. package/src/utils/decimal-comma.ts +39 -6
  864. package/src/utils/exchange-announcements.ts +71 -0
  865. package/src/utils/exchange-rate-snapshot.ts +10 -0
  866. package/src/utils/financial-statements.ts +83 -4
  867. package/src/utils/format.ts +34 -16
  868. package/src/utils/fundamentals.ts +150 -34
  869. package/src/utils/fx-market-hours.ts +10 -1
  870. package/src/utils/latest-financial-period.ts +8 -0
  871. package/src/utils/linux-libc.ts +54 -0
  872. package/src/utils/market-capitalization.ts +111 -15
  873. package/src/utils/max-drawdown.ts +64 -0
  874. package/src/utils/network-failure.ts +83 -0
  875. package/src/utils/option-expiry.ts +139 -7
  876. package/src/utils/price-earnings.ts +11 -5
  877. package/src/utils/price-history.ts +18 -8
  878. package/src/utils/price-window.ts +131 -0
  879. package/src/utils/release-date.ts +47 -0
  880. package/src/utils/sec.ts +3 -0
  881. package/src/utils/throttled-fetch.ts +11 -4
  882. package/src/utils/trailing-eps.ts +67 -0
  883. package/src/utils/typed-text.ts +21 -0
  884. package/src/utils/utc-time.ts +24 -1
  885. package/src/version.ts +6 -0
  886. package/src/cli/pane-functions/screenshot.ts +0 -2122
@@ -1,3 +1,6 @@
1
+ import { isFigure, isNumberCell, protectFigureCommas, restoreFigureCommas } from "./symbol-cells";
2
+ import { readTerminalListingCode, unknownBloombergMarket } from "../tickers/terminal-codes";
3
+
1
4
  /** The quote marks a pasted list wraps its entries in: "AAPL", 'MSFT', “NVDA”. */
2
5
  const QUOTE_MARKS = "\"'`\u2018\u2019\u201C\u201D";
3
6
  const QUOTE_EDGES = new RegExp(`^[${QUOTE_MARKS}]+|[${QUOTE_MARKS}]+$`, "g");
@@ -12,18 +15,37 @@ const LIST_SEPARATOR = /[,;\t\r\n]/;
12
15
  * in it is split on those, so an entry may be a company's name (`WHR,
13
16
  * Whirlpool Corporation, BRK.B`) or several symbols with spaces between them
14
17
  * (`brk.b bf-b` on a pasted line); one without them is split on spaces (`JNK
15
- * EMB BRK.B`). Which an entry with a space is takes a search: a command that
18
+ * EMB BRK.B`), or with `phrases` kept whole (`splitSymbolArgLines`). Which an
19
+ * entry with a space is takes a search: a command that
16
20
  * resolves its symbols reads them with `readNameEntries`, and a parser that
17
- * looks nothing up takes `splitSymbolWords`.
21
+ * looks nothing up takes `splitSymbolWords`. A comma inside a figure
22
+ * (`2.582,52`, `1,899.21`) is no separator: the figure stays one entry. One
23
+ * between plain digits is a decimal comma only on a line with another
24
+ * separator (`ED 2,5`); alone it splits codes (`9988,5`, `700,388`).
18
25
  */
19
- export function splitSymbolArgs(args: readonly string[]): string[] {
20
- return args
21
- .flatMap((arg) => {
22
- const text = arg.replace(/^\uFEFF/, "");
23
- return LIST_SEPARATOR.test(text) ? text.split(LIST_SEPARATOR) : text.split(/\s+/);
24
- })
25
- .map((entry) => entry.trim().replace(QUOTE_EDGES, "").trim().replace(/\s+/g, " "))
26
- .filter(Boolean);
26
+ export function splitSymbolArgs(args: readonly string[], options: { phrases?: boolean } = {}): string[] {
27
+ return args.flatMap((arg) => splitSymbolArgLines(arg, options).flat());
28
+ }
29
+
30
+ /**
31
+ * `splitSymbolArgs` of one argument, its entries kept by the line they are
32
+ * on, so a figure can be told to sit beside the symbol on its line. With
33
+ * `phrases`, an argument with spaces and no list separator is one entry, as
34
+ * an entry between commas is: a company's name (`"Beyond Meat"`) or symbols
35
+ * typed on one line (`"GME AMC"`), which `readNameEntries` tells apart.
36
+ */
37
+ export function splitSymbolArgLines(arg: string, { phrases = false }: { phrases?: boolean } = {}): string[][] {
38
+ const lines = arg.replace(/^\uFEFF/, "").split(/\r\n?|\n/).map((line) => protectFigureCommas(line));
39
+ const separated = lines.length > 1 || lines.some((line) => LIST_SEPARATOR.test(line));
40
+ // A terminal's code (`VOD LN`, `JPM US Equity`), or words written as one (`AAPL GP`), is one entry.
41
+ return lines.map((line) => (separated ? line.split(/[,;\t]/) : phrases || isTerminalCodeLine(line) ? [line] : line.split(/\s+/))
42
+ .map((entry) => restoreFigureCommas(entry).trim().replace(QUOTE_EDGES, "").trim().replace(/\s+/g, " "))
43
+ .filter(Boolean));
44
+ }
45
+
46
+ function isTerminalCodeLine(line: string): boolean {
47
+ const text = line.trim().replace(QUOTE_EDGES, "").trim();
48
+ return /\s/.test(text) && (readTerminalListingCode(text) != null || unknownBloombergMarket(text) != null);
27
49
  }
28
50
 
29
51
  /**
@@ -31,15 +53,28 @@ export function splitSymbolArgs(args: readonly string[]): string[] {
31
53
  * spaces and no list separator into it: `quote "10 year yield"`, `quote
32
54
  * "Apple Inc"` or a pasted line `quote "AAPL MSFT"`. Which of those it is
33
55
  * takes a lookup (`readPhraseArgument`); `splitSymbolArgs` would split it
34
- * into words, each a symbol (10, YEAR, YIELD). Null for anything else:
35
- * several arguments, one word, or a list with commas.
56
+ * into words, each a symbol (10, YEAR, YIELD). A figure in it is part of
57
+ * the phrase (`"10.5 year yield"`, `"fed funds rate 5.25%"`). Null for
58
+ * anything else: several arguments, one word, a list with commas, or a
59
+ * pasted row of symbols each followed by its prices (`ED 2.582,52`, `AAPL
60
+ * 150.00 MSFT 300.00`), which is read as a list is.
36
61
  */
37
62
  export function quotedPhrase(args: readonly string[]): string | null {
38
63
  if (args.length !== 1) return null;
39
64
  const text = args[0]!.replace(/^\uFEFF/, "");
40
- if (LIST_SEPARATOR.test(text)) return null;
65
+ if (LIST_SEPARATOR.test(protectFigureCommas(text))) return null;
41
66
  const phrase = text.trim().replace(QUOTE_EDGES, "").trim().replace(/\s+/g, " ");
42
- return phrase.includes(" ") ? phrase : null;
67
+ return phrase.includes(" ") && !isPricedRow(phrase.split(" ")) ? phrase : null;
68
+ }
69
+
70
+ /**
71
+ * Words that are a sheet's row rather than a phrase: a number (`2.582,52`)
72
+ * among them, and each word that is no figure followed by one (`ED
73
+ * 2.582,52`), so no two words of a name or a phrase sit side by side.
74
+ */
75
+ function isPricedRow(words: readonly string[]): boolean {
76
+ if (!words.some(isNumberCell) || isFigure(words[0]!)) return false;
77
+ return words.every((word, index) => isFigure(word) || (index + 1 < words.length && isFigure(words[index + 1]!)));
43
78
  }
44
79
 
45
80
  /**
@@ -50,7 +85,7 @@ export function quotedPhrase(args: readonly string[]): string | null {
50
85
  */
51
86
  export function splitSymbolWords(args: readonly string[]): string[] {
52
87
  return splitSymbolArgs(args)
53
- .flatMap((entry) => entry.split(" "))
88
+ .flatMap((entry) => isTerminalCodeLine(entry) ? [entry] : entry.split(" "))
54
89
  .map((word) => word.replace(QUOTE_EDGES, ""))
55
90
  .filter(Boolean);
56
91
  }
@@ -0,0 +1,120 @@
1
+ /**
2
+ * What one cell of a pasted list or a typed argument is before anything is
3
+ * looked up: a symbol, a figure (a price, a weight, a share count) or junk
4
+ * a sheet leaves where a value is missing (`N/A`, `--`, `$$$`). Every list
5
+ * reader and every lookup of a list's symbols decide it here, so a price
6
+ * from a European sheet (`2.582,52`) is never searched for as a ticker.
7
+ */
8
+
9
+ /** A sign before a figure: plus, hyphen-minus or the minus sign. */
10
+ const SIGN = "[+\\-\u2212]";
11
+ /** The currency marks a sheet writes beside an amount. */
12
+ const CURRENCY = "[$\u20ac\u00a3\u00a5\u20b9\u20a9\u20bd\u20ba\u20aa\u0e3f\u20ab\u00a2]";
13
+ /** Thousands written with an apostrophe (1'234.50) or a no-break or thin space (1 234,50). */
14
+ const GROUP_MARK = "['\u2019\u00a0\u202f\u2009]";
15
+ const FIGURE_BODY = [
16
+ // 1,899.21 and 1,899: commas between thousands.
17
+ "\\d{1,3}(?:,\\d{3})+(?:\\.\\d+)?",
18
+ // 2.582,52, 1.899 and 1.234.567: dots between thousands, a decimal comma.
19
+ "\\d{1,3}(?:\\.\\d{3})+(?:,\\d+)?",
20
+ `\\d{1,3}(?:${GROUP_MARK}\\d{3})+(?:[.,]\\d+)?`,
21
+ // 2,5 and 12,345, and 1234,56: a decimal comma.
22
+ "\\d{1,3},\\d+",
23
+ "\\d+,\\d{1,2}",
24
+ "\\d*\\.\\d+",
25
+ "\\d+",
26
+ ].join("|");
27
+ const FIGURE = new RegExp(
28
+ `^(?:${SIGN}?${CURRENCY}?${SIGN}?(?:${FIGURE_BODY})(?:%|\u2030|${CURRENCY})?|\\(${CURRENCY}?(?:${FIGURE_BODY})%?\\))$`,
29
+ "u",
30
+ );
31
+ /** A run of digits and the marks between them, where a comma may be a decimal comma rather than a list's separator. */
32
+ const FIGURE_RUN = new RegExp(`(?<![\\p{L}\\p{N}.])(?:${SIGN}|${CURRENCY})*\\d[\\d.,'\u2019\u00a0\u202f\u2009]*(?:%|\u2030|${CURRENCY})?`, "gu");
33
+ /** Placeholders a sheet writes for a missing value, and its error values: N/A, n.a., #N/A, #VALUE!. */
34
+ const PLACEHOLDER = /^(?:#?n\/a|n\.a\.?|#(?:value!|ref!|div\/0!|name\?|num!|null!|spill!|calc!|getting_data))$/i;
35
+ /** Stands in for a comma inside a figure while a line is split on its separators. */
36
+ const FIGURE_COMMA = "\u0000";
37
+ /** Plain digits split by commas (`7203,10`, `5,700`): a decimal comma, or the line's separator between two codes. */
38
+ const PLAIN_COMMA_RUN = /^\d+(?:,\d+)+$/;
39
+
40
+ /**
41
+ * A figure as a sheet or a keyboard writes it, a bare whole number (7203)
42
+ * included: `2.582,52`, `1,899.21`, `-3.2%`, `€1.234,56`, `(1,234.56)`.
43
+ */
44
+ export function isFigure(cell: string): boolean {
45
+ return FIGURE.test(cell.trim());
46
+ }
47
+
48
+ /**
49
+ * A figure that is never a symbol: one with a decimal or thousands mark, a
50
+ * sign, a percent or a currency mark (`1.899`, `2,5`, `+4`, `12%`, `$12`). A
51
+ * bare whole number is not one, as `7203` and `0700` are tickers on their own.
52
+ */
53
+ export function isNumberCell(cell: string): boolean {
54
+ const text = cell.trim();
55
+ return FIGURE.test(text) && !/^\d+$/.test(text);
56
+ }
57
+
58
+ /** A cell that names nothing: no letter or digit (`$$$`, `--`, `-`, `…`), or a placeholder for a missing value (`N/A`, `#N/A`). */
59
+ export function isJunkCell(cell: string): boolean {
60
+ const text = cell.trim();
61
+ return !/[\p{L}\p{N}]/u.test(text) || PLACEHOLDER.test(text);
62
+ }
63
+
64
+ /** Why a cell is not a symbol, as a lookup refuses it without asking anything; null for one that may be. */
65
+ function notASymbolReason(cell: string): string | null {
66
+ if (isJunkCell(cell)) return "not a symbol";
67
+ if (isNumberCell(cell)) return "a number, not a symbol";
68
+ return null;
69
+ }
70
+
71
+ /** An entry of a list that cannot be a symbol, refused before any lookup and never looked up again. */
72
+ export class NotASymbolError extends Error {
73
+ constructor(readonly input: string, readonly reason: string) {
74
+ super(`${input.trim()} is ${reason}.`);
75
+ this.name = "NotASymbolError";
76
+ }
77
+ }
78
+
79
+ /** `NotASymbolError` for a cell that is not a symbol, else null. */
80
+ export function notASymbolError(cell: string): NotASymbolError | null {
81
+ const reason = notASymbolReason(cell);
82
+ return reason ? new NotASymbolError(cell, reason) : null;
83
+ }
84
+
85
+ /**
86
+ * Whether a comma between plain digits on a line is a decimal comma (`ED
87
+ * 2,5`, `CNX;1899,21`): the line has another separator, a tab, a semicolon or
88
+ * spaces between its cells. Otherwise the comma is the line's only separator
89
+ * and splits the digits into cells, as a sheet of codes exports them
90
+ * (`0700,25`, `7203,10`). Quoted cells and separators at the ends are not
91
+ * counted.
92
+ */
93
+ export function hasDecimalCommas(line: string): boolean {
94
+ const bare = line.replace(/"(?:[^"]|"")*"/g, "\"\"").replace(/^[\s,;]+|[\s,;]+$/g, "");
95
+ return /[\t;]/.test(bare) || /[^\s,;]\s+[^\s,;]/.test(bare);
96
+ }
97
+
98
+ /**
99
+ * The text with each comma inside a figure swapped for a stand-in, so
100
+ * splitting on commas leaves the figure whole; `restoreFigureCommas` puts
101
+ * them back. A figure only a number can be (`2.582,52`, `1,899.21`, `2,5%`)
102
+ * keeps its comma. One of plain digits (`7203,10`) keeps it only where its
103
+ * comma is a decimal comma: `decimalCommas`, else `hasDecimalCommas` of each
104
+ * line. A run that is no figure keeps its commas as separators.
105
+ */
106
+ export function protectFigureCommas(text: string, decimalCommas?: boolean): string {
107
+ if (decimalCommas == null) {
108
+ return text.split(/(\r\n?|\n)/).map((part, index) => index % 2 === 1 ? part : protectFigureCommas(part, hasDecimalCommas(part))).join("");
109
+ }
110
+ return text.replace(FIGURE_RUN, (run) => {
111
+ const body = run.replace(/[.,'\u2019]+$/, "");
112
+ const tail = run.slice(body.length);
113
+ const figure = body.includes(",") && isFigure(body) && (decimalCommas || !PLAIN_COMMA_RUN.test(body));
114
+ return figure ? `${body.replaceAll(",", FIGURE_COMMA)}${tail}` : run;
115
+ });
116
+ }
117
+
118
+ export function restoreFigureCommas(text: string): string {
119
+ return text.replaceAll(FIGURE_COMMA, ",");
120
+ }
@@ -1,6 +1,8 @@
1
1
  import { readFile } from "fs/promises";
2
2
  import { fstatSync } from "fs";
3
- import { splitSymbolArgs, splitSymbolWords, stripStrayEdges, uniqueSymbols } from "./symbol-args";
3
+ import { splitSymbolArgLines, splitSymbolWords, stripStrayEdges, uniqueSymbols } from "./symbol-args";
4
+ import { foldTypedText } from "../utils/typed-text";
5
+ import { hasDecimalCommas, isFigure, isJunkCell, isNumberCell, protectFigureCommas, restoreFigureCommas } from "./symbol-cells";
4
6
 
5
7
  /** Header cells that name a spreadsheet's symbol column, compared without case, spaces or punctuation. */
6
8
  const SYMBOL_HEADERS = new Set(["symbol", "symbols", "ticker", "tickers", "code", "stockcode", "securitycode", "instrument"]);
@@ -9,8 +11,6 @@ const NAME_HEADERS = new Set(["name", "names", "company", "companies", "companyn
9
11
 
10
12
  /** One symbol as it can be typed: AAPL, $nvda, TTF.AS, SAN:EPA, BRK-B, 7203.T, ^GSPC, ES=F. */
11
13
  const SYMBOL_TOKEN = /^\$?[\p{L}\p{N}^][\p{L}\p{N}.:\-^=/&]{0,23}$/u;
12
- /** A plain number: a price, a weight or a share count in a spreadsheet's other columns. */
13
- const NUMBER_CELL = /^[+-]?(?:\d{1,3}(?:,\d{3})+|\d*)(?:\.\d+)?%?$/;
14
14
 
15
15
  function headerKey(cell: string): string {
16
16
  return cell.toLowerCase().replace(/[^\p{L}\p{N}]/gu, "");
@@ -20,21 +20,61 @@ function isComment(cell: string): boolean {
20
20
  return cell.startsWith("#") || cell.startsWith("//");
21
21
  }
22
22
 
23
- /** The delimiter of the first data line: tab, comma or semicolon, or null for a list split by spaces. */
24
- function detectDelimiter(lines: readonly string[]): string | null {
25
- const first = lines.find((line) => line.trim() && !isComment(line.trim()));
26
- if (!first) return null;
27
- const unquoted = first.replace(/"[^"]*"/g, "");
28
- for (const delimiter of ["\t", ",", ";"]) {
29
- if (unquoted.includes(delimiter)) return delimiter;
23
+ /** Whether a quote mark at `index` closes a quoted cell: it is followed by a separator, a line end or the end. */
24
+ function closesCell(text: string, index: number): boolean {
25
+ return /^[^\S\n]*(?:[\t,;\n]|$)/.test(text.slice(index + 1, index + 40));
26
+ }
27
+
28
+ /** Where the quoted cell opened at `index` ends, or -1 when no quote mark closes it, so the mark is only a stray. */
29
+ function closingQuote(text: string, index: number): number {
30
+ for (let at = text.indexOf("\"", index + 1); at >= 0; at = text.indexOf("\"", at + 1)) {
31
+ if (text[at + 1] === "\"") {
32
+ at += 1;
33
+ continue;
34
+ }
35
+ if (closesCell(text, at)) return at;
30
36
  }
31
- return null;
37
+ return -1;
32
38
  }
33
39
 
34
- /** RFC 4180 records: a quoted cell may hold the delimiter, a newline and doubled quotes. */
35
- function parseDelimited(text: string, delimiter: string): string[][] {
36
- const records: string[][] = [];
37
- let record: string[] = [];
40
+ /**
41
+ * The records of a text: its lines, except that a quoted cell (RFC 4180)
42
+ * may hold a line break. A quote mark opens a cell only at the start of
43
+ * one and when a mark closes it, so a stray one never swallows the lines after it.
44
+ */
45
+ function splitRecords(text: string): string[] {
46
+ const records: string[] = [];
47
+ let start = 0;
48
+ for (let index = 0; index < text.length; index += 1) {
49
+ const char = text[index]!;
50
+ if (char === "\"" && /(?:^|[\t,;])[^\S\n]*$/.test(text.slice(start, index))) {
51
+ const end = closingQuote(text, index);
52
+ if (end >= 0) index = end;
53
+ } else if (char === "\n") {
54
+ records.push(text.slice(start, index));
55
+ start = index + 1;
56
+ }
57
+ }
58
+ records.push(text.slice(start));
59
+ return records;
60
+ }
61
+
62
+ /**
63
+ * The separator of one line: a tab, else a semicolon, else a comma that
64
+ * splits cells, not one inside a figure (`ED 2.582,52` is split by its space,
65
+ * `CNX;1.899,21` by its semicolon). Null for a line split by spaces. A
66
+ * separator at either end is a stray (`UPST;`), named when the cell is read.
67
+ * `decimalCommas` says whether a comma between plain digits is a decimal one.
68
+ */
69
+ function lineDelimiter(record: string, decimalCommas: boolean): string | null {
70
+ const bare = protectFigureCommas(record, decimalCommas).replace(/^[\s,;]+|[\s,;]+$/g, "").replace(/"(?:[^"]|"")*"/g, "");
71
+ return ["\t", ";", ","].find((delimiter) => bare.includes(delimiter)) ?? null;
72
+ }
73
+
74
+ /** The cells of a line split by `delimiter`; a quoted cell may hold the delimiter and doubled quotes. */
75
+ function splitCells(record: string, delimiter: string, decimalCommas: boolean): string[] {
76
+ const text = protectFigureCommas(record, decimalCommas);
77
+ const cells: string[] = [];
38
78
  let cell = "";
39
79
  let quoted = false;
40
80
  for (let index = 0; index < text.length; index += 1) {
@@ -50,30 +90,58 @@ function parseDelimited(text: string, delimiter: string): string[][] {
50
90
  }
51
91
  continue;
52
92
  }
53
- if (char === "\"" && !cell.trim()) {
93
+ if (char === "\"" && !cell.trim() && closingQuote(text, index) >= 0) {
54
94
  quoted = true;
55
95
  cell = "";
56
96
  } else if (char === delimiter) {
57
- record.push(cell);
58
- cell = "";
59
- } else if (char === "\n") {
60
- record.push(cell);
61
- records.push(record);
62
- record = [];
97
+ cells.push(cell);
63
98
  cell = "";
64
99
  } else {
65
100
  cell += char;
66
101
  }
67
102
  }
68
- if (cell || record.length > 0) {
69
- record.push(cell);
70
- records.push(record);
71
- }
72
- return records.map((cells) => cells.map((value) => value.trim()));
103
+ cells.push(cell);
104
+ return cells.map((value) => restoreFigureCommas(value).trim());
105
+ }
106
+
107
+ /**
108
+ * The cells of each line, each line split by its own separator
109
+ * (`lineDelimiter`), as a list pasted from several sheets mixes them. A line
110
+ * with no separator in a list whose other lines have one is one cell (a
111
+ * company's name), unless a figure follows its first word (`ED 2.582,52`).
112
+ * A comma between plain digits is a decimal comma on a line with another
113
+ * separator, or under a header split by tabs or semicolons; otherwise it
114
+ * splits the line (`0700,25` is a code and a weight). `delimited` says
115
+ * whether any line had a separator.
116
+ */
117
+ function readRecords(text: string): { records: string[][]; delimited: boolean } {
118
+ const kept = splitRecords(text).filter((record) => record.replace(/[\s,;"']/g, ""));
119
+ const sheetDecimals = headerSplitsOnTabsOrSemicolons(kept[0]);
120
+ const lines = kept.map((record) => {
121
+ const decimalCommas = sheetDecimals || hasDecimalCommas(record);
122
+ const delimiter = lineDelimiter(record, decimalCommas);
123
+ return delimiter
124
+ ? { cells: splitCells(record, delimiter, decimalCommas), delimited: true }
125
+ : { cells: record.trim().split(/\s+/), delimited: false };
126
+ });
127
+ const delimited = lines.some((line) => line.delimited);
128
+ const records = lines.map(({ cells, delimited: own }) => (
129
+ own || !delimited || cells.slice(1).some(isFigure) ? cells : [cells.join(" ")]
130
+ ));
131
+ return { records: records.filter((cells) => cells.some(Boolean) && !isComment(cells[0] ?? "")), delimited };
132
+ }
133
+
134
+ /** Whether a header line (one with a Symbol, Ticker, Code or Name cell) splits its cells on tabs or semicolons. */
135
+ function headerSplitsOnTabsOrSemicolons(record: string | undefined): boolean {
136
+ if (!record) return false;
137
+ const delimiter = lineDelimiter(record, false);
138
+ if (delimiter !== "\t" && delimiter !== ";") return false;
139
+ return splitCells(record, delimiter, false).map(headerKey)
140
+ .some((key) => SYMBOL_HEADERS.has(key) || NAME_HEADERS.has(key) || key.includes("symbol") || key.includes("ticker"));
73
141
  }
74
142
 
75
143
  function looksLikeSymbol(cell: string): boolean {
76
- return SYMBOL_TOKEN.test(cell) && !(NUMBER_CELL.test(cell) && /[.,%]/.test(cell));
144
+ return SYMBOL_TOKEN.test(cell) && !isNumberCell(cell);
77
145
  }
78
146
 
79
147
  /** How many cells a table's ignored-cells note names before it counts the rest. */
@@ -94,43 +162,45 @@ interface SymbolText {
94
162
  }
95
163
 
96
164
  /**
97
- * The symbols in a file or piped text, in order. A spreadsheet export reads
98
- * from the column its header names (Symbol, Ticker, Code), else from its
99
- * Name or Company column, as `entries`. Without a header,
100
- * every cell is a symbol unless some column after the first holds a name, a
101
- * price or a weight: that table is read by its first column, and the cells
102
- * beside it are returned as `ignored` so the command can name them. A list
103
- * split by commas, spaces or newlines gives every entry, even when a line of
104
- * it is ragged or carries a stray separator (`"BIMAS ,"`). A list of lines
105
- * gives each line whole, and a list of names split by semicolons or commas
106
- * (one line, or one name a line) each cell, as `entries`: a line with spaces
107
- * is a company's name (`Altria Group`) or symbols on one line, which reading
108
- * the entries tells apart. Names beside other text (`Apple Inc,Technology`)
109
- * are a table read by its first column, its names as `entries`. A list split
110
- * by spaces with figures beside the symbols (`AAPL 150.00`) is a table. A
111
- * byte order mark, Windows line ends, blank lines and lines starting with #
112
- * or // are ignored.
165
+ * The symbols in a file or piped text, in order. Each line is split by its
166
+ * own separator (`readRecords`): a tab, a semicolon, a comma that is not a
167
+ * decimal comma, or spaces. A figure (`2.582,52`, `1,899.21`, `12%`) is never
168
+ * a symbol, and a bare whole number beside a symbol is a value: such a cell
169
+ * makes the list a table. A spreadsheet export reads from the column its
170
+ * header names (Symbol, Ticker, Code), else from its Name or Company column,
171
+ * as `entries`. Without a header, every cell is a symbol unless some column
172
+ * after the first holds a name, a price or a weight: that table is read by
173
+ * its first column, and the cells beside it are returned as `ignored` so the
174
+ * command can name them. A list split by commas, spaces or newlines gives
175
+ * every entry, even when a line of it is ragged or carries a stray separator
176
+ * (`"BIMAS ,"`); a cell that names nothing (`N/A`, `$$$`) does not make it a
177
+ * table, and is refused by the lookup. A list of lines gives each line whole,
178
+ * and a list of names split by semicolons or commas (one line, or one name a
179
+ * line) each cell, as `entries`: a line with spaces is a company's name
180
+ * (`Altria Group`) or symbols on one line, which reading the entries tells
181
+ * apart. Names beside other text (`Apple Inc,Technology`) are a table read by
182
+ * its first column, its names as `entries`. A byte order mark, Windows line
183
+ * ends, blank lines and lines starting with # or // are ignored.
113
184
  */
114
185
  export function parseSymbolText(text: string): SymbolText {
115
186
  const normalized = text.replace(/^\uFEFF/, "").replace(/\r\n?/g, "\n");
116
- const lines = normalized.split("\n");
117
- const delimiter = detectDelimiter(lines);
118
- const records = (delimiter ? parseDelimited(normalized, delimiter) : lines.map((line) => line.trim().split(/\s+/)))
119
- .filter((cells) => cells.some(Boolean) && !isComment(cells[0] ?? ""));
187
+ const { records, delimited } = readRecords(normalized);
120
188
  if (records.length === 0) return { symbols: [], ignored: [] };
121
189
  const header = records[0]!.map(headerKey);
122
190
  const exact = header.findIndex((cell) => SYMBOL_HEADERS.has(cell));
123
191
  const column = exact >= 0 ? exact : header.findIndex((cell) => cell.includes("symbol") || cell.includes("ticker"));
124
192
  if (column >= 0) return { symbols: records.slice(1).map((cells) => cells[column] ?? "").filter(Boolean), ignored: [] };
125
193
  // Without one, a delimited export's Name or Company column holds the companies, read as typed names are.
126
- const nameColumn = delimiter ? header.findIndex((cell) => NAME_HEADERS.has(cell)) : -1;
194
+ const nameColumn = delimited ? header.findIndex((cell) => NAME_HEADERS.has(cell)) : -1;
127
195
  if (nameColumn >= 0) return { symbols: records.slice(1).map((cells) => cells[nameColumn] ?? "").filter(Boolean), ignored: [], entries: true };
128
196
  // A separator or quote mark stuck to a cell is dropped (and named) when it is read, so it does not make the list a table.
129
197
  const cleaned = records.map((cells) => cells.map((cell) => stripStrayEdges(cell).text));
130
- const figures = cleaned.some((cells) => cells.some((cell, index) => index > 0 && NUMBER_CELL.test(cell) && /\d/.test(cell)));
198
+ const figures = cleaned.some((cells) => cells.some((cell, index) => index > 0 && isFigure(cell)));
131
199
  // Lines split by spaces alone are entries, unless figures sit beside the symbols.
132
- if (!delimiter && !figures) return { symbols: records.map((cells) => cells.join(" ")), ignored: [], entries: true };
133
- const grid = cleaned.every((cells) => cells.every((cell, index) => !cell || (looksLikeSymbol(cell) && (index === 0 || !NUMBER_CELL.test(cell)))));
200
+ if (!delimited && !figures) return { symbols: records.map((cells) => cells.join(" ")), ignored: [], entries: true };
201
+ const grid = cleaned.every((cells) => cells.every((cell, index) => (
202
+ !cell || isJunkCell(cell) || (looksLikeSymbol(cell) && (index === 0 || !isFigure(cell)))
203
+ )));
134
204
  if (grid) return { symbols: records.flat().filter(Boolean), ignored: [] };
135
205
  // Names split by semicolons or commas, with no figures: one pasted line, or one name a line with a separator left
136
206
  // on it, is a list. A name beside a sector or any other text is a table, read by its first column below.
@@ -146,6 +216,19 @@ export function parseSymbolText(text: string): SymbolText {
146
216
  };
147
217
  }
148
218
 
219
+ /** Cells named in a note, split by semicolons when one of them has a comma of its own (`2.582,52; 1.899,21`). */
220
+ function listCells(cells: readonly string[]): string {
221
+ const named = cells.slice(0, IGNORED_PREVIEW);
222
+ const more = cells.length - IGNORED_PREVIEW;
223
+ return `${named.join(named.some((cell) => cell.includes(",")) ? "; " : ", ")}${more > 0 ? ` and ${more} more` : ""}`;
224
+ }
225
+
226
+ /** "the cell", "the 3 number cells": number when every one is a figure. */
227
+ function cellsNoun(cells: readonly string[]): string {
228
+ const kind = cells.every(isFigure) ? "number cell" : "cell";
229
+ return cells.length === 1 ? `the ${kind}` : `the ${cells.length} ${kind}s`;
230
+ }
231
+
149
232
  /**
150
233
  * The note a table read by its first column gets, naming what was left out:
151
234
  * `Read the first column as symbols; ignored the 4 cells beside it: Apple
@@ -154,10 +237,47 @@ export function parseSymbolText(text: string): SymbolText {
154
237
  */
155
238
  function ignoredCellsNote(ignored: readonly string[]): string | null {
156
239
  if (ignored.length === 0) return null;
157
- const named = ignored.slice(0, IGNORED_PREVIEW).join(", ");
158
- const more = ignored.length - IGNORED_PREVIEW;
159
- const cells = ignored.length === 1 ? "the cell" : `the ${ignored.length} cells`;
160
- return `Read the first column as symbols; ignored ${cells} beside it: ${named}${more > 0 ? ` and ${more} more` : ""}.`;
240
+ return `Read the first column as symbols; ignored ${cellsNoun(ignored)} beside it: ${listCells(ignored)}.`;
241
+ }
242
+
243
+ /**
244
+ * The one note for the numbers read where a symbol goes, typed beside a
245
+ * symbol (`ED 2.582,52`) or on a line of their own: `Ignored 3 numbers, not
246
+ * symbols: 2.582,52; 1.899,21; 3.594,10.`
247
+ */
248
+ function ignoredNumbersNote(numbers: readonly string[]): string | null {
249
+ if (numbers.length === 0) return null;
250
+ return numbers.length === 1
251
+ ? `Ignored ${numbers[0]}, a number, not a symbol.`
252
+ : `Ignored ${numbers.length} numbers, not symbols: ${listCells(numbers)}.`;
253
+ }
254
+
255
+ /**
256
+ * The entries of one line of what was typed, with the figures beside its
257
+ * symbols moved to `beside`: a number (`2.582,52`) on a line that has a
258
+ * symbol, and a bare whole number after a symbol when only figures follow it
259
+ * (`ED 2582`, `AAPL 150`). A bare whole number among symbols, or alone, is a
260
+ * code (`amd 2222 pltr`, `7203`).
261
+ */
262
+ function withoutFigures(words: readonly string[], beside: string[]): string[] {
263
+ const symbolAt = words.findIndex((word) => !isFigure(word) && !isJunkCell(word));
264
+ if (symbolAt < 0) return [...words];
265
+ const row = symbolAt === 0 && words.length > 1 && words.slice(1).every(isFigure);
266
+ const value = (word: string, index: number) => index !== symbolAt && (isNumberCell(word) || (row && isFigure(word)));
267
+ beside.push(...words.filter(value));
268
+ return words.filter((word, index) => !value(word, index));
269
+ }
270
+
271
+ /**
272
+ * The entries of typed arguments (`splitSymbolArgs`), without the figures
273
+ * beside their symbols (`withoutFigures`), which go to `beside`. An entry with
274
+ * spaces (`ED 2.582,52` between semicolons) loses its figures the same way.
275
+ */
276
+ function typedEntries(args: readonly string[], beside: string[]): string[] {
277
+ // An argument of words is one entry, read as a list's line is: `"Beyond Meat"` is a company, `"GME AMC"` two symbols.
278
+ return args.flatMap((arg) => splitSymbolArgLines(arg, { phrases: true }).flatMap((line) => withoutFigures(line, beside)
279
+ .map((entry) => withoutFigures(entry.split(" "), beside).join(" "))
280
+ .filter(Boolean)));
161
281
  }
162
282
 
163
283
  /** Whether standard input is a pipe or a file rather than a terminal, so a command may read its list from it. */
@@ -200,29 +320,37 @@ export class SymbolListError extends Error {
200
320
  /**
201
321
  * The symbols a command was given: as arguments, from `--file`, and from
202
322
  * standard input when an argument is `-` or nothing else was given and input
203
- * is piped in. Repeats are dropped. A separator stuck to a symbol in a file, or
204
- * left on the end of what was typed (`UPST;`), is dropped with the quote marks
205
- * around it, and the cells beside the symbols of a table read by its first
206
- * column are left out; `notes` names each so the command can say so.
323
+ * is piped in. This is the one reader of `watchlist add`, `portfolio add`,
324
+ * `quote`, `compare` and the command bar's pasted list. Repeats are dropped. A
325
+ * separator stuck to a symbol in a file, or left on the end of what was typed
326
+ * (`UPST;`), is dropped with the quote marks around it, and the cells beside
327
+ * the symbols of a table read by its first column, or the figures typed beside
328
+ * a symbol, are left out; `notes` names each so the command can say so, the
329
+ * numbers in one line: a number (`2.582,52`, `1,899.21`, `12%`) is never a
330
+ * symbol, beside one or on its own. An entry that names nothing (`N/A`, `$$$`,
331
+ * `--`) stays in `symbols`, for the lookup to refuse without asking anything
332
+ * (`notASymbolError`) and the command to name.
207
333
  */
208
334
  export async function readSymbolList(source: SymbolListSource): Promise<{ symbols: string[]; repeated: number; notes: string[] }> {
209
335
  const readStdin = source.readStdin ?? (() => Bun.stdin.text());
210
336
  const wantsStdin = source.args.includes("-") || source.file === "-";
211
337
  const typedArgs = source.args.filter((arg) => arg !== "-");
212
- const readEntries = (entries: string[]) => source.readEntries ? source.readEntries(entries) : Promise.resolve(splitSymbolWords(entries));
213
- const typed = source.readEntries ? await source.readEntries(splitSymbolArgs(typedArgs)) : splitSymbolWords(typedArgs);
338
+ const figures: string[] = [];
339
+ const entries = typedEntries(typedArgs, figures);
340
+ const readEntries = (read: string[]) => source.readEntries ? source.readEntries(read) : Promise.resolve(splitSymbolWords(read));
341
+ const typed = source.readEntries ? await source.readEntries(entries) : splitSymbolWords(entries);
214
342
  const collected = [...typed];
215
343
  // A separator left on the end of what was typed: `UPST;`, or a list that ends in a comma.
216
344
  const strays = new Set<string>(stripStrayEdges(typedArgs.join(" ")).notes);
217
345
  const ignored: string[] = [];
218
- const addCells = async ({ symbols, ignored: beside, entries }: SymbolText) => {
346
+ const addCells = async ({ symbols, ignored: beside, entries: whole }: SymbolText) => {
219
347
  const cells = symbols.map((cell) => {
220
348
  const cleaned = stripStrayEdges(cell);
221
349
  cleaned.notes.forEach((note) => strays.add(note));
222
350
  return cleaned.text;
223
351
  }).filter(Boolean);
224
352
  // A list's lines and names are read as typed entries are: `Altria Group` stays one company.
225
- collected.push(...entries ? await readEntries(cells) : cells);
353
+ collected.push(...whole ? await readEntries(cells) : cells);
226
354
  ignored.push(...beside);
227
355
  };
228
356
  if (source.file != null && source.file !== "-") {
@@ -234,11 +362,13 @@ export async function readSymbolList(source: SymbolListSource): Promise<{ symbol
234
362
  const code = (error as NodeJS.ErrnoException).code;
235
363
  throw new SymbolListError(code === "ENOENT" ? `No file at ${source.file}.` : `Could not read ${source.file}: ${error instanceof Error ? error.message : String(error)}`);
236
364
  }
237
- await addCells(parseSymbolText(text));
365
+ await addCells(parseSymbolText(foldTypedText(text)));
238
366
  }
239
367
  if (wantsStdin || (typed.length === 0 && source.file == null && (source.stdinPiped ?? stdinIsPiped()))) {
240
- await addCells(parseSymbolText(await readStdin()));
368
+ await addCells(parseSymbolText(foldTypedText(await readStdin())));
241
369
  }
242
- const ignoredNote = ignoredCellsNote(ignored);
243
- return { ...uniqueSymbols(collected), notes: [...strays, ...ignoredNote ? [ignoredNote] : []] };
370
+ // A number where a symbol goes (a line of prices, a typed 1.899) is left out with those typed beside a symbol.
371
+ const numbers = [...figures, ...collected.filter(isNumberCell)];
372
+ const notes = [ignoredCellsNote(ignored), ignoredNumbersNote(numbers)].filter((note): note is string => !!note);
373
+ return { ...uniqueSymbols(collected.filter((symbol) => !isNumberCell(symbol))), notes: [...strays, ...notes] };
244
374
  }