gloomberb 0.16.4 → 0.16.6

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 (852) hide show
  1. package/README.md +14 -91
  2. package/package.json +5 -1
  3. package/src/{plugins/builtin/cloud → account}/auth-form.tsx +9 -9
  4. package/src/{plugins/builtin/cloud → account}/auth-model.ts +4 -4
  5. package/src/account/billing.ts +57 -0
  6. package/src/{plugins/builtin/cloud → account}/device-signin-dialog.tsx +18 -12
  7. package/src/{plugins/builtin/cloud → account}/device-signin.ts +2 -2
  8. package/src/{plugins/builtin/cloud → account}/email-auth-attempt.ts +2 -2
  9. package/src/account/session.ts +16 -0
  10. package/src/{plugins/builtin/cloud → account}/upgrade-dialog.tsx +16 -15
  11. package/src/{plugins/builtin/cloud → account}/upgrade-personalization.ts +7 -7
  12. package/src/{plugins/builtin/cloud → account}/upgrade-tickers.ts +6 -6
  13. package/src/{plugins/builtin/cloud → account}/verification-panel.tsx +6 -6
  14. package/src/api-client/central-bank-rates.ts +6 -1
  15. package/src/api-client/chat.ts +26 -0
  16. package/src/api-client/credit-boards.ts +2 -0
  17. package/src/api-client/data.ts +73 -3
  18. package/src/api-client/earnings.ts +6 -0
  19. package/src/api-client/europe-energy.ts +106 -0
  20. package/src/api-client/futures-curve.ts +56 -0
  21. package/src/api-client/index.ts +13 -1
  22. package/src/api-client/market-discovery.ts +13 -1
  23. package/src/api-client/normalizers.ts +32 -0
  24. package/src/api-client/paths.ts +7 -0
  25. package/src/api-client/perps.ts +8 -0
  26. package/src/api-client/request.ts +9 -2
  27. package/src/api-client/research-activity.ts +15 -10
  28. package/src/api-client/socket.ts +29 -0
  29. package/src/api-client/themes.ts +22 -1
  30. package/src/api-client/types.ts +78 -2
  31. package/src/api-client/yield-curves.ts +8 -0
  32. package/src/app/global-shortcuts.ts +50 -2
  33. package/src/app/keybindings/actions.ts +12 -1
  34. package/src/app/pane-runtime/plugin-bindings.ts +2 -2
  35. package/src/app/pane-runtime/ticker-open-runtime.ts +16 -6
  36. package/src/app/runtime/desktop-deeplink.ts +10 -5
  37. package/src/app/runtime/startup.ts +1 -1
  38. package/src/app.tsx +6 -0
  39. package/src/architecture/core-builtin-allowlist.json +8 -26
  40. package/src/ask-gloom/pane-context.ts +114 -0
  41. package/src/ask-gloom/pane-request.ts +70 -0
  42. package/src/ask-gloom/pane-text.ts +201 -0
  43. package/src/brokers/signed-in/sign-in-dialog.tsx +11 -5
  44. package/src/capabilities/chart-series.ts +19 -2
  45. package/src/capabilities/factories.ts +1 -0
  46. package/src/cli/central-bank-events.ts +23 -0
  47. package/src/cli/command-options.ts +17 -5
  48. package/src/cli/commands/crypto-hints.ts +35 -2
  49. package/src/cli/commands/fred-series.ts +146 -0
  50. package/src/cli/commands/market.ts +501 -115
  51. package/src/cli/commands/news-hints.ts +62 -0
  52. package/src/cli/commands/news-search.ts +53 -0
  53. package/src/cli/commands/options-leaps.ts +5 -2
  54. package/src/cli/commands/overview.ts +132 -26
  55. package/src/cli/commands/remote.ts +2 -1
  56. package/src/cli/commands/search.ts +317 -13
  57. package/src/cli/commands/system.ts +55 -8
  58. package/src/cli/commands/ticker.ts +155 -18
  59. package/src/cli/context.ts +45 -14
  60. package/src/cli/desktop-pane-shot.ts +76 -7
  61. package/src/cli/earnings-calendar.ts +71 -0
  62. package/src/cli/errors.ts +7 -5
  63. package/src/cli/exit-codes.ts +8 -0
  64. package/src/cli/export-source.ts +58 -0
  65. package/src/cli/freshness.ts +18 -7
  66. package/src/cli/glossary.ts +483 -0
  67. package/src/cli/help.ts +10 -0
  68. package/src/cli/helpers.ts +2 -5
  69. package/src/cli/history-rows.ts +118 -7
  70. package/src/cli/index-roots.ts +7 -0
  71. package/src/cli/index.ts +29 -9
  72. package/src/cli/known-gaps.ts +84 -0
  73. package/src/cli/listing-arg.ts +551 -97
  74. package/src/cli/not-a-ticker.ts +24 -9
  75. package/src/cli/pane-functions/access-gate.ts +13 -2
  76. package/src/cli/pane-functions/capabilities.ts +4 -3
  77. package/src/cli/pane-functions/catalog.ts +214 -40
  78. package/src/cli/pane-functions/data.ts +42 -8
  79. package/src/cli/pane-functions/discovery.ts +1 -0
  80. package/src/cli/pane-functions/dom.ts +37 -8
  81. package/src/cli/pane-functions/freshness.ts +393 -49
  82. package/src/cli/pane-functions/function-help.ts +31 -15
  83. package/src/cli/pane-functions/headless.ts +98 -30
  84. package/src/cli/pane-functions/index.ts +101 -19
  85. package/src/cli/pane-functions/market-session.ts +22 -8
  86. package/src/cli/pane-functions/options.ts +71 -22
  87. package/src/cli/pane-functions/report-notices.ts +25 -7
  88. package/src/cli/pane-functions/report.ts +15 -8
  89. package/src/cli/pane-functions/resolver.ts +74 -19
  90. package/src/cli/pane-functions/screenshot.ts +250 -27
  91. package/src/cli/perpetual-contract.ts +60 -0
  92. package/src/cli/registry.ts +3 -1
  93. package/src/cli/report-tables.ts +26 -7
  94. package/src/cli/result.ts +45 -11
  95. package/src/cli/series-search.ts +111 -0
  96. package/src/cli/staged-tickers.ts +52 -0
  97. package/src/cli/symbol-args.ts +27 -0
  98. package/src/cli/symbol-list.ts +154 -0
  99. package/src/cli/symbol-rows.ts +154 -0
  100. package/src/cli/ticker-resolution.ts +311 -27
  101. package/src/cli/types.ts +5 -0
  102. package/src/components/chart/composite/axis-overlays.tsx +14 -3
  103. package/src/components/chart/composite/composite-chart.tsx +71 -11
  104. package/src/components/chart/composite/crosshair-readout.tsx +150 -0
  105. package/src/components/chart/composite/downsample.ts +1 -1
  106. package/src/components/chart/composite/format.ts +29 -0
  107. package/src/components/chart/composite/interactions.ts +9 -2
  108. package/src/components/chart/composite/legend.tsx +100 -33
  109. package/src/components/chart/composite/panel-bitmap.ts +70 -35
  110. package/src/components/chart/composite/panel-labels.ts +18 -17
  111. package/src/components/chart/composite/panel-series.ts +1 -0
  112. package/src/components/chart/composite/panel-surface.tsx +46 -21
  113. package/src/components/chart/composite/price-axis-labels.tsx +3 -1
  114. package/src/components/chart/composite/rasterizer.ts +50 -8
  115. package/src/components/chart/composite/scene.ts +2 -1
  116. package/src/components/chart/composite/time-scale.ts +26 -9
  117. package/src/components/chart/composite/types.ts +18 -0
  118. package/src/components/chart/composite/use-composite-viewport.ts +30 -2
  119. package/src/components/chart/native/raster/crosshair.ts +8 -3
  120. package/src/components/chart/native/raster/primitives.ts +85 -21
  121. package/src/components/chart/native/surface/manager.ts +33 -8
  122. package/src/components/chart/surface3d/chart.tsx +1 -1
  123. package/src/components/command-bar/action-runtime.ts +1 -1
  124. package/src/components/command-bar/commands/collection-list.ts +210 -0
  125. package/src/components/command-bar/commands/collection.ts +40 -1
  126. package/src/components/command-bar/commands/direct/index.ts +4 -0
  127. package/src/components/command-bar/commands/registry.ts +8 -0
  128. package/src/components/command-bar/panel/index.tsx +11 -3
  129. package/src/components/command-bar/panel/runtime.ts +3 -0
  130. package/src/components/command-bar/panel/types.ts +2 -0
  131. package/src/components/command-bar/routes/root/plugin-install.ts +4 -4
  132. package/src/components/command-bar/routes/root/provider-search.ts +4 -3
  133. package/src/components/command-bar/routes/ticker-search/results.ts +12 -11
  134. package/src/components/command-bar/routes/ticker-search/route.ts +4 -3
  135. package/src/components/command-bar/routing/actions.ts +1 -1
  136. package/src/components/command-bar/workflow/tickers.ts +42 -17
  137. package/src/components/layout/detached-pane-shell.tsx +68 -39
  138. package/src/components/layout/floating-pane.tsx +10 -1
  139. package/src/components/layout/header.tsx +25 -5
  140. package/src/components/layout/missing-pane.tsx +3 -3
  141. package/src/components/layout/pane/capture-stamp.ts +41 -0
  142. package/src/components/layout/pane/capture-status.ts +12 -0
  143. package/src/components/layout/pane/content.tsx +7 -13
  144. package/src/components/layout/pane/footer/index.tsx +6 -2
  145. package/src/components/layout/pane/footer/keyboard.ts +3 -0
  146. package/src/components/layout/pane/footer/model.ts +41 -1
  147. package/src/components/layout/pane/header.tsx +50 -1
  148. package/src/components/layout/pane/index.tsx +21 -3
  149. package/src/components/layout/pane/sidebar.tsx +88 -21
  150. package/src/components/layout/shell/active-drag.ts +21 -5
  151. package/src/components/layout/shell/cursor-occlusion.ts +2 -1
  152. package/src/components/layout/shell/drag/index.ts +39 -9
  153. package/src/components/layout/shell/drag/live.ts +61 -51
  154. package/src/components/layout/shell/drag/runtime.ts +54 -12
  155. package/src/components/layout/shell/index.tsx +84 -65
  156. package/src/components/layout/shell/menu.ts +14 -1
  157. package/src/components/layout/shell/native/pointer-runtime.ts +3 -1
  158. package/src/components/layout/shell/pane/actions.ts +32 -10
  159. package/src/components/layout/shell/pane/ask.ts +131 -0
  160. package/src/components/layout/shell/pane/capture.ts +162 -0
  161. package/src/components/layout/shell/pane/layers.tsx +218 -50
  162. package/src/components/layout/shell/pane/management-shortcuts.ts +46 -1
  163. package/src/components/layout/shell/shortcuts.ts +21 -4
  164. package/src/components/layout/shell/terminal-pointer-runtime.ts +24 -0
  165. package/src/components/markdown-text.tsx +62 -20
  166. package/src/components/metric-treemap/heat-surface.tsx +8 -1
  167. package/src/components/onboarding/account-step/form-panel.tsx +1 -1
  168. package/src/components/onboarding/account-step/index.tsx +1 -1
  169. package/src/components/onboarding/account-step/qr-panel.tsx +1 -1
  170. package/src/components/onboarding/account-step/signed-in-panel.tsx +1 -1
  171. package/src/components/onboarding/onboarding-keyboard.ts +1 -1
  172. package/src/components/onboarding/onboarding-wizard.tsx +2 -2
  173. package/src/components/onboarding/use-onboarding-upgrade.ts +3 -3
  174. package/src/components/onboarding/wizard-account.ts +2 -2
  175. package/src/components/pane-template-wizard.tsx +9 -1
  176. package/src/components/price-selector-dialog.tsx +11 -2
  177. package/src/components/reader/article-reader.tsx +642 -0
  178. package/src/components/reader/article-text.ts +527 -0
  179. package/src/components/sign-in-gate.tsx +3 -3
  180. package/src/components/ticker/list-table-view.tsx +43 -2
  181. package/src/components/ui/action-row.tsx +2 -1
  182. package/src/components/ui/button.tsx +7 -1
  183. package/src/components/ui/choice-dialog.tsx +6 -4
  184. package/src/components/ui/confirm-dialog.tsx +28 -18
  185. package/src/components/ui/data-table/index.tsx +18 -6
  186. package/src/components/ui/data-table/opentui/index.tsx +37 -6
  187. package/src/components/ui/data-table/types.ts +12 -0
  188. package/src/components/ui/dialog-actions.tsx +64 -0
  189. package/src/components/ui/display.tsx +17 -3
  190. package/src/components/ui/frame.tsx +35 -2
  191. package/src/components/ui/icon.tsx +6 -1
  192. package/src/components/ui/query-bar.tsx +10 -1
  193. package/src/components/ui/text-prompt-dialog.tsx +11 -9
  194. package/src/data/cached-query.ts +2 -0
  195. package/src/data/config/store/migrations.ts +7 -0
  196. package/src/data/config/store/normalize.ts +7 -2
  197. package/src/data/config/store/portfolio-as-of-column.ts +57 -0
  198. package/src/data/ticker-repository.ts +5 -0
  199. package/src/data/ticker-store.ts +15 -0
  200. package/src/docs/content.ts +215 -0
  201. package/src/docs/load.ts +139 -0
  202. package/src/docs/requests.ts +39 -0
  203. package/src/docs/snapshot.chunk.ts +8 -0
  204. package/src/docs/snapshot.json +7555 -0
  205. package/src/docs/topics.ts +216 -0
  206. package/src/i18n/es.ts +65 -5
  207. package/src/i18n/ja.ts +65 -5
  208. package/src/i18n/ko.ts +65 -5
  209. package/src/i18n/zh-cn.ts +65 -5
  210. package/src/i18n/zh-tw.ts +65 -5
  211. package/src/layout/desks.ts +1 -1
  212. package/src/layout/pane-manager/dock-tree.ts +18 -0
  213. package/src/layout/pane-manager/index.ts +1 -0
  214. package/src/layout-marketplace/gallery.tsx +1 -1
  215. package/src/market-data/coordinator/chart.ts +10 -4
  216. package/src/market-data/coordinator/index.ts +6 -3
  217. package/src/{plugins/builtin/futures/contracts.ts → market-data/futures-board.ts} +81 -28
  218. package/src/market-data/futures-contract.ts +151 -0
  219. package/src/market-data/hooks.tsx +10 -2
  220. package/src/market-data/market/format.ts +39 -21
  221. package/src/market-data/market/freshness.ts +84 -20
  222. package/src/market-data/market/session-close-note.ts +3 -2
  223. package/src/market-data/market/status.ts +19 -23
  224. package/src/market-data/published-apac-sessions.ts +23 -1
  225. package/src/market-data/quotes/contributions.ts +5 -0
  226. package/src/market-data/quotes/metadata.ts +19 -24
  227. package/src/market-data/quotes/resolution.ts +5 -0
  228. package/src/market-data/quotes/screener-live-quotes.ts +5 -4
  229. package/src/market-data/result-types.ts +2 -0
  230. package/src/notifications/app-notifier.ts +17 -1
  231. package/src/notifications/notification-log.ts +180 -0
  232. package/src/plugins/auto-update-node.ts +2 -2
  233. package/src/plugins/auto-update.ts +2 -2
  234. package/src/plugins/builtin/account-management/index.tsx +1 -0
  235. package/src/plugins/builtin/account-management/model.ts +1 -56
  236. package/src/plugins/builtin/account-management/pane.tsx +6 -4
  237. package/src/plugins/builtin/account-management/password-dialog.tsx +1 -1
  238. package/src/plugins/builtin/alerts/catalysts.ts +1 -1
  239. package/src/plugins/builtin/alerts/cli.ts +313 -47
  240. package/src/plugins/builtin/alerts/events-pane.tsx +45 -7
  241. package/src/plugins/builtin/alerts/events.ts +23 -2
  242. package/src/plugins/builtin/alerts/focus.ts +27 -0
  243. package/src/plugins/builtin/alerts/history-pane.tsx +7 -2
  244. package/src/plugins/builtin/alerts/history.ts +2 -0
  245. package/src/plugins/builtin/alerts/index.tsx +47 -11
  246. package/src/plugins/builtin/alerts/pane.tsx +27 -1
  247. package/src/plugins/builtin/alerts/research-builder.ts +8 -3
  248. package/src/plugins/builtin/alerts/research-rules.ts +18 -2
  249. package/src/plugins/builtin/alerts/scheduled-check.ts +122 -0
  250. package/src/plugins/builtin/alerts/scheduled-sources.ts +25 -0
  251. package/src/plugins/builtin/alerts/scheduled.ts +254 -0
  252. package/src/plugins/builtin/alerts/targets.ts +92 -0
  253. package/src/plugins/builtin/analytics/index.tsx +8 -3
  254. package/src/plugins/builtin/analytics/risk-headless.ts +60 -27
  255. package/src/plugins/builtin/analytics/risk-math.ts +91 -27
  256. package/src/plugins/builtin/analytics/risk-model.ts +35 -5
  257. package/src/plugins/builtin/analytics/risk-pane.tsx +15 -8
  258. package/src/plugins/builtin/attention/headless.ts +1 -1
  259. package/src/plugins/builtin/attention/index.tsx +2 -0
  260. package/src/plugins/builtin/attention/pane.tsx +3 -1
  261. package/src/plugins/builtin/attention/series.ts +26 -0
  262. package/src/plugins/builtin/awards/headless.ts +88 -18
  263. package/src/plugins/builtin/awards/index.tsx +2 -0
  264. package/src/plugins/builtin/awards/model.ts +41 -1
  265. package/src/plugins/builtin/awards/pane.tsx +22 -13
  266. package/src/plugins/builtin/awards/series.ts +29 -0
  267. package/src/plugins/builtin/backtest/headless.ts +2 -2
  268. package/src/plugins/builtin/bond-calculator/model.ts +2 -1
  269. package/src/plugins/builtin/broker-manager/index.tsx +1 -0
  270. package/src/plugins/builtin/catalysts/headless.ts +1 -1
  271. package/src/plugins/builtin/catalysts/pane.tsx +3 -1
  272. package/src/plugins/builtin/cds/client.ts +49 -12
  273. package/src/plugins/builtin/cds/headless.ts +119 -19
  274. package/src/plugins/builtin/cds/index.tsx +3 -1
  275. package/src/plugins/builtin/cds/model.ts +214 -32
  276. package/src/plugins/builtin/cds/pane.tsx +58 -14
  277. package/src/plugins/builtin/cds/series.ts +19 -0
  278. package/src/plugins/builtin/central-bank-rates/client.ts +4 -0
  279. package/src/plugins/builtin/central-bank-rates/headless.ts +46 -16
  280. package/src/plugins/builtin/central-bank-rates/index.tsx +3 -1
  281. package/src/plugins/builtin/central-bank-rates/model.ts +99 -0
  282. package/src/plugins/builtin/central-bank-rates/pane.tsx +1 -1
  283. package/src/plugins/builtin/central-bank-rates/series.ts +36 -0
  284. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +193 -255
  285. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +84 -46
  286. package/src/plugins/builtin/chart-composer/editor.tsx +5 -4
  287. package/src/plugins/builtin/chart-composer/field-series.ts +40 -0
  288. package/src/plugins/builtin/chart-composer/headless-schema.ts +1 -1
  289. package/src/plugins/builtin/chart-composer/headless.ts +70 -5
  290. package/src/plugins/builtin/chart-composer/index.tsx +15 -3
  291. package/src/plugins/builtin/chart-composer/pane.tsx +81 -38
  292. package/src/plugins/builtin/chart-composer/series-catalog.ts +58 -50
  293. package/src/plugins/builtin/chart-composer/series-expression.ts +18 -10
  294. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +59 -3
  295. package/src/plugins/builtin/chart-composer/user-series.ts +84 -0
  296. package/src/plugins/builtin/chat/content/composer-runtime.ts +6 -1
  297. package/src/plugins/builtin/chat/content/composer.tsx +5 -1
  298. package/src/plugins/builtin/chat/content/footer.tsx +12 -0
  299. package/src/plugins/builtin/chat/content/index.tsx +89 -5
  300. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +10 -2
  301. package/src/plugins/builtin/chat/content/new-messages.tsx +89 -0
  302. package/src/plugins/builtin/chat/content/row-activity.ts +132 -0
  303. package/src/plugins/builtin/chat/content/scroll.ts +127 -27
  304. package/src/plugins/builtin/chat/content/shortcuts.ts +2 -2
  305. package/src/plugins/builtin/chat/content/transcript.tsx +145 -78
  306. package/src/plugins/builtin/chat/content/types.ts +1 -0
  307. package/src/plugins/builtin/chat/controller/fetch.ts +8 -2
  308. package/src/plugins/builtin/chat/controller/index.ts +123 -1
  309. package/src/plugins/builtin/chat/controller/message-loading.ts +3 -0
  310. package/src/plugins/builtin/chat/controller/messages.ts +7 -2
  311. package/src/plugins/builtin/chat/controller/realtime.ts +10 -1
  312. package/src/plugins/builtin/chat/controller/send.ts +61 -1
  313. package/src/plugins/builtin/chat/controller/state.ts +8 -0
  314. package/src/plugins/builtin/chat/ghost-user.ts +20 -0
  315. package/src/plugins/builtin/chat/index.tsx +23 -5
  316. package/src/plugins/builtin/chat/layout.ts +78 -5
  317. package/src/plugins/builtin/chat/message/ai-badge.tsx +18 -0
  318. package/src/plugins/builtin/chat/message/desktop.tsx +55 -6
  319. package/src/plugins/builtin/chat/message/header.tsx +16 -4
  320. package/src/plugins/builtin/chat/message/profile-popover.tsx +5 -1
  321. package/src/plugins/builtin/chat/message/reactions.tsx +210 -0
  322. package/src/plugins/builtin/chat/message/render-state.ts +18 -2
  323. package/src/plugins/builtin/chat/message/terminal.tsx +43 -4
  324. package/src/plugins/builtin/chat/message/types.ts +12 -0
  325. package/src/plugins/builtin/chat/reactions.ts +197 -0
  326. package/src/plugins/builtin/chat/share/flow.tsx +87 -0
  327. package/src/plugins/builtin/chat/share/targets.ts +27 -0
  328. package/src/plugins/builtin/chat/status-widget.tsx +6 -3
  329. package/src/plugins/builtin/chat/unread-inbox-pane.tsx +148 -27
  330. package/src/plugins/builtin/chat/unread-inbox.ts +22 -0
  331. package/src/plugins/builtin/cloud/askg/attached-pane.tsx +69 -0
  332. package/src/plugins/builtin/cloud/askg/controller.ts +111 -19
  333. package/src/plugins/builtin/cloud/askg/executor.ts +57 -3
  334. package/src/plugins/builtin/cloud/askg/manifest.ts +32 -7
  335. package/src/plugins/builtin/cloud/askg/model.ts +27 -8
  336. package/src/plugins/builtin/cloud/askg/pane-attachment.ts +94 -0
  337. package/src/plugins/builtin/cloud/askg/pane.tsx +141 -12
  338. package/src/plugins/builtin/cloud/askg/pending-question.ts +11 -0
  339. package/src/plugins/builtin/cloud/askg/protocol.ts +10 -1
  340. package/src/plugins/builtin/cloud/askg/tool-display.ts +3 -0
  341. package/src/plugins/builtin/cloud/askg/undo.ts +2 -0
  342. package/src/plugins/builtin/cloud/auth-actions.tsx +1 -1
  343. package/src/plugins/builtin/cloud/auth-commands.ts +1 -1
  344. package/src/plugins/builtin/cloud/auth-dialog.tsx +3 -3
  345. package/src/plugins/builtin/cloud/company-picker.tsx +1 -1
  346. package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +3 -0
  347. package/src/plugins/builtin/cloud/plugin.tsx +19 -2
  348. package/src/plugins/builtin/cloud/team/model.ts +5 -0
  349. package/src/plugins/builtin/cloud/team/module.tsx +1 -0
  350. package/src/plugins/builtin/cloud/team/store.ts +8 -3
  351. package/src/plugins/builtin/cloud/terminal-relay/engine.ts +77 -9
  352. package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +6 -1
  353. package/src/plugins/builtin/cloud/terminal-relay/policy.ts +9 -0
  354. package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +35 -11
  355. package/src/plugins/builtin/cloud/thesis/exposure.ts +1 -1
  356. package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
  357. package/src/plugins/builtin/cloud/thesis/prompts.tsx +2 -1
  358. package/src/plugins/builtin/company-attention/app-rank.tsx +1 -1
  359. package/src/plugins/builtin/company-attention/headless.ts +21 -7
  360. package/src/plugins/builtin/company-attention/index.tsx +2 -0
  361. package/src/plugins/builtin/company-attention/model.ts +26 -7
  362. package/src/plugins/builtin/company-attention/pane.tsx +12 -9
  363. package/src/plugins/builtin/company-attention/series.ts +52 -0
  364. package/src/plugins/builtin/company-kpis/headless.ts +97 -10
  365. package/src/plugins/builtin/company-kpis/model.ts +24 -2
  366. package/src/plugins/builtin/company-kpis/pane.tsx +17 -16
  367. package/src/plugins/builtin/composite-plugins.ts +19 -13
  368. package/src/plugins/builtin/connections/index.ts +1 -0
  369. package/src/plugins/builtin/cot/headless.ts +1 -1
  370. package/src/plugins/builtin/cot/index.tsx +3 -1
  371. package/src/plugins/builtin/cot/model.ts +40 -11
  372. package/src/plugins/builtin/cot/series.ts +27 -0
  373. package/src/plugins/builtin/cpi/headless.ts +3 -3
  374. package/src/plugins/builtin/credit-boards/cdx-pane.tsx +10 -1
  375. package/src/plugins/builtin/credit-boards/client.ts +6 -2
  376. package/src/plugins/builtin/credit-boards/headless.ts +108 -31
  377. package/src/plugins/builtin/credit-boards/index.tsx +2 -0
  378. package/src/plugins/builtin/credit-boards/model.ts +11 -1
  379. package/src/plugins/builtin/credit-boards/series.ts +66 -0
  380. package/src/plugins/builtin/credit-conditions/client.ts +12 -9
  381. package/src/plugins/builtin/credit-conditions/headless.ts +13 -2
  382. package/src/plugins/builtin/credit-conditions/index.tsx +18 -9
  383. package/src/plugins/builtin/credit-conditions/model.ts +19 -11
  384. package/src/plugins/builtin/credit-conditions/series.ts +16 -0
  385. package/src/plugins/builtin/credit-documents/headless.ts +33 -3
  386. package/src/plugins/builtin/credit-documents/pane.tsx +3 -1
  387. package/src/plugins/builtin/crypto-board/headless.ts +2 -3
  388. package/src/plugins/builtin/crypto-board/index.tsx +2 -0
  389. package/src/plugins/builtin/crypto-board/model.ts +12 -0
  390. package/src/plugins/builtin/crypto-board/pane.tsx +19 -12
  391. package/src/plugins/builtin/crypto-board/series.ts +48 -0
  392. package/src/plugins/builtin/custom-view/live-quotes.ts +2 -2
  393. package/src/plugins/builtin/debt-maturities/headless.ts +17 -11
  394. package/src/plugins/builtin/debt-maturities/index.tsx +2 -0
  395. package/src/plugins/builtin/debt-maturities/series.ts +45 -0
  396. package/src/plugins/builtin/dividend-yield/client.ts +3 -0
  397. package/src/plugins/builtin/dividend-yield/headless.ts +7 -4
  398. package/src/plugins/builtin/dividend-yield/index.tsx +3 -1
  399. package/src/plugins/builtin/dividend-yield/pane.tsx +3 -1
  400. package/src/plugins/builtin/dividend-yield/series.ts +20 -0
  401. package/src/plugins/builtin/dividend-yield/types.ts +2 -0
  402. package/src/plugins/builtin/docs/blocks.tsx +181 -0
  403. package/src/plugins/builtin/docs/index.tsx +68 -0
  404. package/src/plugins/builtin/docs/pane.tsx +426 -0
  405. package/src/plugins/builtin/docs/targets.ts +72 -0
  406. package/src/plugins/builtin/docs/use-docs.ts +60 -0
  407. package/src/plugins/builtin/doe/headless.ts +12 -8
  408. package/src/plugins/builtin/doe/index.tsx +2 -0
  409. package/src/plugins/builtin/doe/series.ts +62 -0
  410. package/src/plugins/builtin/earnings/client.ts +3 -2
  411. package/src/plugins/builtin/earnings/format.ts +1 -5
  412. package/src/plugins/builtin/earnings/headless.ts +58 -6
  413. package/src/plugins/builtin/earnings/history-model.ts +15 -1
  414. package/src/plugins/builtin/earnings/history-table.ts +13 -2
  415. package/src/plugins/builtin/earnings/history.tsx +7 -3
  416. package/src/plugins/builtin/earnings/index.tsx +9 -0
  417. package/src/plugins/builtin/earnings-calls/headless.ts +28 -2
  418. package/src/plugins/builtin/earnings-calls/index.tsx +1 -1
  419. package/src/plugins/builtin/earnings-ripple/index.tsx +2 -0
  420. package/src/plugins/builtin/econ/fred-catalog.ts +198 -0
  421. package/src/plugins/builtin/econ/fred-series-map.ts +0 -46
  422. package/src/plugins/builtin/econ/index.tsx +2 -0
  423. package/src/plugins/builtin/econ-statistics/defs.ts +5 -0
  424. package/src/plugins/builtin/econ-statistics/headless.ts +19 -4
  425. package/src/plugins/builtin/econ-statistics/stats.ts +1 -0
  426. package/src/plugins/builtin/equity-screener/headless.ts +3 -3
  427. package/src/plugins/builtin/equity-screener/pane.tsx +4 -11
  428. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -3
  429. package/src/plugins/builtin/exposure/drivers.ts +13 -0
  430. package/src/plugins/builtin/exposure/headless.ts +205 -13
  431. package/src/plugins/builtin/exposure/holdings.ts +1 -1
  432. package/src/plugins/builtin/exposure/index.tsx +1 -0
  433. package/src/plugins/builtin/exposure/model.ts +23 -3
  434. package/src/plugins/builtin/exposure/pane.tsx +14 -12
  435. package/src/plugins/builtin/fear-greed/index.tsx +18 -10
  436. package/src/plugins/builtin/fear-greed/series.ts +52 -0
  437. package/src/plugins/builtin/futures/index.tsx +43 -3
  438. package/src/plugins/builtin/futures/model.ts +1 -1
  439. package/src/plugins/builtin/futures/returns.ts +1 -1
  440. package/src/plugins/builtin/futures/series.ts +13 -0
  441. package/src/plugins/builtin/futures/table.tsx +1 -1
  442. package/src/plugins/builtin/futures/use-front-returns.ts +1 -1
  443. package/src/plugins/builtin/futures-curve/client.ts +12 -3
  444. package/src/plugins/builtin/futures-curve/headless.ts +71 -10
  445. package/src/plugins/builtin/futures-curve/index.tsx +1 -1
  446. package/src/plugins/builtin/futures-curve/model.ts +66 -11
  447. package/src/plugins/builtin/futures-curve/pane.tsx +52 -18
  448. package/src/plugins/builtin/fx-matrix/client.ts +63 -0
  449. package/src/plugins/builtin/fx-matrix/export.ts +2 -1
  450. package/src/plugins/builtin/fx-matrix/headless.ts +154 -0
  451. package/src/plugins/builtin/fx-matrix/index.tsx +4 -4
  452. package/src/plugins/builtin/gpu/board.tsx +13 -10
  453. package/src/plugins/builtin/gpu/changes.tsx +4 -4
  454. package/src/plugins/builtin/gpu/client.ts +19 -1
  455. package/src/plugins/builtin/gpu/equities.tsx +14 -10
  456. package/src/plugins/builtin/gpu/headless.ts +58 -27
  457. package/src/plugins/builtin/gpu/history.tsx +3 -3
  458. package/src/plugins/builtin/gpu/index.tsx +2 -0
  459. package/src/plugins/builtin/gpu/model.ts +101 -16
  460. package/src/plugins/builtin/gpu/pane.tsx +28 -12
  461. package/src/plugins/builtin/gpu/series.ts +38 -0
  462. package/src/plugins/builtin/help/function-card.tsx +25 -6
  463. package/src/plugins/builtin/help/function-index.ts +2 -0
  464. package/src/plugins/builtin/help/index.tsx +31 -9
  465. package/src/plugins/builtin/holders/beneficial-model.ts +90 -3
  466. package/src/plugins/builtin/holders/beneficial-report.ts +57 -5
  467. package/src/plugins/builtin/holders/beneficial-view.tsx +55 -11
  468. package/src/plugins/builtin/holders/client.ts +22 -3
  469. package/src/plugins/builtin/holders/format.ts +18 -3
  470. package/src/plugins/builtin/holders/headless.ts +36 -133
  471. package/src/plugins/builtin/holders/pane.tsx +11 -4
  472. package/src/plugins/builtin/holders/report-header.ts +40 -5
  473. package/src/plugins/builtin/holders/report-rows.ts +240 -0
  474. package/src/plugins/builtin/insider/client.ts +35 -20
  475. package/src/plugins/builtin/insider/headless.ts +41 -11
  476. package/src/plugins/builtin/insider/index.tsx +26 -9
  477. package/src/plugins/builtin/insider/insider-data.ts +10 -0
  478. package/src/plugins/builtin/insider/issuer.ts +49 -0
  479. package/src/plugins/builtin/insider/model.ts +3 -0
  480. package/src/plugins/builtin/ipo-calendar/headless.ts +1 -1
  481. package/src/plugins/builtin/iv-history/client.ts +20 -6
  482. package/src/plugins/builtin/iv-history/format.ts +9 -0
  483. package/src/plugins/builtin/iv-history/headless.ts +56 -21
  484. package/src/plugins/builtin/iv-history/index.tsx +2 -0
  485. package/src/plugins/builtin/iv-history/model.ts +143 -8
  486. package/src/plugins/builtin/iv-history/screen-pane.tsx +5 -9
  487. package/src/plugins/builtin/iv-history/series.ts +29 -0
  488. package/src/plugins/builtin/jobs/headless.ts +26 -3
  489. package/src/plugins/builtin/jobs/index.tsx +3 -1
  490. package/src/plugins/builtin/jobs/series.ts +19 -0
  491. package/src/plugins/builtin/kelly-sizer/index.tsx +2 -0
  492. package/src/plugins/builtin/kelly-sizer/pane.tsx +2 -1
  493. package/src/plugins/builtin/kelly-sizer/portfolio.ts +0 -39
  494. package/src/plugins/builtin/macro-day/client.ts +44 -3
  495. package/src/plugins/builtin/macro-day/headless.ts +13 -10
  496. package/src/plugins/builtin/macro-day/model.ts +56 -10
  497. package/src/plugins/builtin/macro-day/pane.tsx +30 -20
  498. package/src/plugins/builtin/market-heatmap/headless.ts +20 -5
  499. package/src/plugins/builtin/market-heatmap/index.tsx +6 -0
  500. package/src/plugins/builtin/market-heatmap/model.ts +19 -11
  501. package/src/plugins/builtin/market-heatmap/portfolio.ts +2 -2
  502. package/src/plugins/builtin/market-movers/client.ts +7 -5
  503. package/src/plugins/builtin/market-movers/index.tsx +3 -2
  504. package/src/plugins/builtin/market-movers/model.ts +30 -0
  505. package/src/plugins/builtin/market-movers/screener.ts +31 -0
  506. package/src/plugins/builtin/market-valuation/chart-series.ts +29 -69
  507. package/src/plugins/builtin/market-valuation/index.tsx +3 -3
  508. package/src/plugins/builtin/market-valuation/indicators.ts +0 -5
  509. package/src/plugins/builtin/members/headless.ts +8 -3
  510. package/src/plugins/builtin/members/model.ts +31 -3
  511. package/src/plugins/builtin/members/pane.tsx +6 -8
  512. package/src/plugins/builtin/mna/distress/headless.ts +4 -4
  513. package/src/plugins/builtin/mna/headless.ts +18 -6
  514. package/src/plugins/builtin/money-markets/headless.ts +5 -4
  515. package/src/plugins/builtin/money-markets/index.tsx +2 -0
  516. package/src/plugins/builtin/money-markets/series.ts +41 -0
  517. package/src/plugins/builtin/news/index.tsx +0 -2
  518. package/src/plugins/builtin/news/wire/news/detail-view.tsx +53 -104
  519. package/src/plugins/builtin/news/wire/news/footer.ts +2 -25
  520. package/src/plugins/builtin/news/wire/news/preset-pane.tsx +0 -2
  521. package/src/plugins/builtin/notes/cli.ts +12 -7
  522. package/src/plugins/builtin/notes/index.tsx +1 -0
  523. package/src/plugins/builtin/options/index.tsx +3 -0
  524. package/src/plugins/builtin/options/view.tsx +1 -1
  525. package/src/plugins/builtin/options-calculator/inputs.ts +2 -1
  526. package/src/plugins/builtin/options-positioning/client.ts +7 -3
  527. package/src/plugins/builtin/options-positioning/headless.ts +4 -3
  528. package/src/plugins/builtin/options-positioning/pane.tsx +2 -2
  529. package/src/plugins/builtin/options-scenario/client.ts +2 -1
  530. package/src/plugins/builtin/options-scenario/headless.ts +1 -0
  531. package/src/plugins/builtin/options-scenario/hedge.ts +2 -1
  532. package/src/plugins/builtin/perps/client.ts +90 -16
  533. package/src/plugins/builtin/perps/equity-row.tsx +52 -17
  534. package/src/plugins/builtin/perps/freshness.ts +66 -0
  535. package/src/plugins/builtin/perps/headless.ts +47 -32
  536. package/src/plugins/builtin/perps/index.tsx +23 -4
  537. package/src/plugins/builtin/perps/list-perpetuals.ts +118 -0
  538. package/src/plugins/builtin/perps/model.ts +20 -5
  539. package/src/plugins/builtin/perps/open-market.ts +15 -0
  540. package/src/plugins/builtin/perps/pane.tsx +76 -20
  541. package/src/plugins/builtin/perps/series.ts +76 -0
  542. package/src/plugins/builtin/plugin-marketplace/index.tsx +1 -1
  543. package/src/plugins/builtin/plugin-marketplace/pane.tsx +73 -67
  544. package/src/plugins/builtin/plugin-module.ts +3 -0
  545. package/src/plugins/builtin/portfolio-list/account-metrics.ts +1 -1
  546. package/src/plugins/builtin/portfolio-list/allocation.ts +5 -4
  547. package/src/plugins/builtin/portfolio-list/cell-version.ts +8 -1
  548. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +161 -0
  549. package/src/plugins/builtin/portfolio-list/cli/import-13f.ts +109 -0
  550. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +384 -74
  551. package/src/plugins/builtin/portfolio-list/cli/render.ts +437 -71
  552. package/src/plugins/builtin/portfolio-list/cli/shared.ts +21 -4
  553. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +121 -47
  554. package/src/plugins/builtin/portfolio-list/column-values.ts +104 -26
  555. package/src/plugins/builtin/portfolio-list/grid.tsx +1 -1
  556. package/src/plugins/builtin/portfolio-list/headless.ts +84 -18
  557. package/src/plugins/builtin/portfolio-list/imported-from.ts +8 -0
  558. package/src/plugins/builtin/portfolio-list/index.tsx +5 -1
  559. package/src/plugins/builtin/portfolio-list/live-valuation.ts +6 -2
  560. package/src/plugins/builtin/portfolio-list/mutations.ts +2 -9
  561. package/src/plugins/builtin/portfolio-list/pane/data.ts +5 -1
  562. package/src/plugins/builtin/portfolio-list/pane/index.tsx +52 -9
  563. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +33 -11
  564. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +21 -1
  565. package/src/plugins/builtin/portfolio-list/settings.ts +17 -0
  566. package/src/plugins/builtin/portfolio-list/summary/index.tsx +12 -0
  567. package/src/plugins/builtin/portfolio-list/summary/totals.ts +9 -4
  568. package/src/plugins/builtin/portfolio-list/table.tsx +37 -7
  569. package/src/plugins/builtin/power/client.ts +16 -0
  570. package/src/plugins/builtin/power/evidence.ts +63 -10
  571. package/src/plugins/builtin/power/headless.ts +77 -9
  572. package/src/plugins/builtin/power/index.tsx +28 -3
  573. package/src/plugins/builtin/power/model.ts +73 -2
  574. package/src/plugins/builtin/power/pane.tsx +37 -9
  575. package/src/plugins/builtin/power/prices-client.ts +139 -0
  576. package/src/plugins/builtin/power/prices-headless.ts +137 -0
  577. package/src/plugins/builtin/power/prices-model.ts +103 -0
  578. package/src/plugins/builtin/power/prices.tsx +179 -0
  579. package/src/plugins/builtin/rate-path/headless.ts +46 -18
  580. package/src/plugins/builtin/realized-vol/headless.ts +5 -0
  581. package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
  582. package/src/plugins/builtin/research/corporate-actions-pane.tsx +5 -2
  583. package/src/plugins/builtin/research/event-model.ts +68 -24
  584. package/src/plugins/builtin/research/events-headless.ts +2 -1
  585. package/src/plugins/builtin/research/headless.ts +2 -1
  586. package/src/plugins/builtin/research/index.tsx +2 -0
  587. package/src/plugins/builtin/research-search/article.ts +65 -0
  588. package/src/plugins/builtin/research-search/document-view.tsx +33 -215
  589. package/src/plugins/builtin/research-search/model.ts +0 -9
  590. package/src/plugins/builtin/research-search/pane.tsx +41 -30
  591. package/src/plugins/builtin/research-search/snippet.ts +0 -29
  592. package/src/plugins/builtin/revenue-breakdown/headless.ts +18 -6
  593. package/src/plugins/builtin/seasonality/client.ts +15 -7
  594. package/src/plugins/builtin/seasonality/headless.ts +36 -12
  595. package/src/plugins/builtin/seasonality/index.tsx +2 -2
  596. package/src/plugins/builtin/seasonality/model.ts +119 -0
  597. package/src/plugins/builtin/seasonality/pane.tsx +108 -37
  598. package/src/plugins/builtin/sec/headless.ts +25 -3
  599. package/src/plugins/builtin/sec/index.tsx +2 -1
  600. package/src/plugins/builtin/series-inventory.ts +93 -0
  601. package/src/plugins/builtin/shared/cloud-denied.ts +15 -0
  602. package/src/plugins/builtin/shared/cloud-upgrade.ts +1 -1
  603. package/src/plugins/builtin/shared/command-tab.ts +30 -12
  604. package/src/plugins/builtin/shared/earnings-report.ts +55 -0
  605. package/src/plugins/builtin/shared/fred-points.ts +20 -0
  606. package/src/plugins/builtin/shared/free-preview.ts +47 -0
  607. package/src/plugins/builtin/shared/fx-rate-freshness.ts +101 -0
  608. package/src/plugins/builtin/shared/open-description.ts +29 -0
  609. package/src/plugins/builtin/shared/report-freshness.ts +12 -1
  610. package/src/plugins/builtin/shared/series-warning.ts +5 -0
  611. package/src/plugins/builtin/shared/volatility/options.ts +4 -1
  612. package/src/plugins/builtin/short-interest/headless.ts +1 -0
  613. package/src/plugins/builtin/short-interest/index.tsx +2 -0
  614. package/src/plugins/builtin/short-interest/series.ts +36 -0
  615. package/src/plugins/builtin/short-interest/watch-headless.ts +3 -2
  616. package/src/plugins/builtin/short-interest/watch-model.ts +9 -5
  617. package/src/plugins/builtin/short-volume/headless.ts +2 -1
  618. package/src/plugins/builtin/short-volume/index.tsx +2 -0
  619. package/src/plugins/builtin/short-volume/series.ts +23 -0
  620. package/src/plugins/builtin/social-mentions/headless.ts +1 -1
  621. package/src/plugins/builtin/social-mentions/index.tsx +2 -0
  622. package/src/plugins/builtin/social-mentions/series.ts +23 -0
  623. package/src/plugins/builtin/supply-chain/graph-pane.tsx +3 -2
  624. package/src/plugins/builtin/supply-chain/headless.ts +43 -11
  625. package/src/plugins/builtin/supply-chain/model.ts +13 -0
  626. package/src/plugins/builtin/supply-chain/pane.tsx +8 -6
  627. package/src/plugins/builtin/themes/headless.ts +74 -10
  628. package/src/plugins/builtin/themes/model.ts +71 -4
  629. package/src/plugins/builtin/themes/pane.tsx +22 -5
  630. package/src/plugins/builtin/thirteenf/api.ts +1 -0
  631. package/src/plugins/builtin/thirteenf/data.ts +6 -4
  632. package/src/plugins/builtin/thirteenf/headless.ts +217 -36
  633. package/src/plugins/builtin/thirteenf/model.ts +39 -1
  634. package/src/plugins/builtin/thirteenf/overlap.ts +75 -0
  635. package/src/plugins/builtin/thirteenf/pane.tsx +10 -1
  636. package/src/plugins/builtin/thirteenf/report-notes.ts +103 -1
  637. package/src/plugins/builtin/thirteenf/types.ts +2 -0
  638. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +114 -0
  639. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +57 -2
  640. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +19 -55
  641. package/src/plugins/builtin/ticker-detail/headless-schema.ts +30 -0
  642. package/src/plugins/builtin/ticker-detail/headless.ts +86 -0
  643. package/src/plugins/builtin/ticker-detail/index.tsx +26 -11
  644. package/src/plugins/builtin/ticker-detail/overview/components.tsx +1 -1
  645. package/src/plugins/builtin/ticker-detail/overview/futures-contract.ts +31 -0
  646. package/src/plugins/builtin/ticker-detail/overview/model.ts +3 -3
  647. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +2 -1
  648. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +49 -5
  649. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +13 -3
  650. package/src/plugins/builtin/time-sales/headless.ts +2 -1
  651. package/src/plugins/builtin/time-sales/index.tsx +2 -1
  652. package/src/plugins/builtin/treasury-auctions/headless.ts +16 -2
  653. package/src/plugins/builtin/treasury-auctions/index.tsx +1 -0
  654. package/src/plugins/builtin/treasury-auctions/model.ts +8 -0
  655. package/src/plugins/builtin/vol-surface/evidence.ts +7 -1
  656. package/src/plugins/builtin/vol-surface/headless.ts +51 -17
  657. package/src/plugins/builtin/vol-surface/heat-grid.tsx +113 -0
  658. package/src/plugins/builtin/vol-surface/model.ts +39 -6
  659. package/src/plugins/builtin/vol-surface/pane.tsx +14 -13
  660. package/src/plugins/builtin/vol-surface/stored.ts +63 -3
  661. package/src/plugins/builtin/vol-surface/surface.tsx +30 -2
  662. package/src/plugins/builtin/volatility/index.tsx +2 -0
  663. package/src/plugins/builtin/volatility/series.ts +84 -0
  664. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +6 -5
  665. package/src/plugins/builtin/world-venue-map/basemap.ts +6 -3
  666. package/src/plugins/builtin/world-venue-map/geo-draw.tsx +2 -1
  667. package/src/plugins/builtin/world-venue-map/geo-series.ts +26 -1
  668. package/src/plugins/builtin/world-venue-map/geo-svg.tsx +6 -6
  669. package/src/plugins/builtin/world-venue-map/headless.ts +4 -1
  670. package/src/plugins/builtin/world-venue-map/index.ts +2 -1
  671. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +24 -13
  672. package/src/plugins/builtin/world-venue-map/layers.ts +29 -0
  673. package/src/plugins/builtin/world-venue-map/map.tsx +144 -13
  674. package/src/plugins/builtin/world-venue-map/model.ts +56 -19
  675. package/src/plugins/builtin/world-venue-map/pane.tsx +5 -2
  676. package/src/plugins/builtin/yield-curve/chart.ts +2 -2
  677. package/src/plugins/builtin/yield-curve/curves.ts +21 -8
  678. package/src/plugins/builtin/yield-curve/headless.ts +71 -18
  679. package/src/plugins/builtin/yield-curve/index.tsx +4 -2
  680. package/src/plugins/builtin/yield-curve/series.ts +86 -0
  681. package/src/plugins/catalog-browser.ts +2 -1
  682. package/src/plugins/installer.ts +2 -2
  683. package/src/plugins/loader.ts +15 -0
  684. package/src/plugins/manager-node.ts +1 -1
  685. package/src/plugins/{builtin/plugin-marketplace → marketplace}/feed.ts +2 -2
  686. package/src/plugins/{builtin/plugin-marketplace → marketplace}/model.ts +6 -6
  687. package/src/plugins/{builtin/plugin-marketplace → marketplace}/store.ts +1 -1
  688. package/src/plugins/registry/host-actions.ts +11 -0
  689. package/src/plugins/registry/index.ts +89 -4
  690. package/src/portfolio/collection-name.ts +31 -0
  691. package/src/{plugins/builtin/portfolio-list → portfolio}/position-metrics.ts +6 -6
  692. package/src/portfolio/position-value.ts +40 -0
  693. package/src/portfolio/valuation-basis.ts +79 -0
  694. package/src/public/__snapshots__/public-api.test.ts.snap +7 -0
  695. package/src/public/time-series.ts +17 -0
  696. package/src/react/auto-refresh.ts +13 -3
  697. package/src/react/input.ts +33 -1
  698. package/src/react/key-repeat.ts +86 -0
  699. package/src/remote/app-host.tsx +20 -4
  700. package/src/remote/confirm-change.tsx +85 -0
  701. package/src/remote/controller-utils.ts +8 -1
  702. package/src/remote/controller.ts +144 -7
  703. package/src/remote/pane-screenshot.ts +47 -0
  704. package/src/remote/schema.ts +65 -2
  705. package/src/remote/types.ts +30 -0
  706. package/src/remote/watchlist.ts +306 -0
  707. package/src/renderers/browser/main.tsx +4 -3
  708. package/src/renderers/browser/research-entry.ts +4 -2
  709. package/src/renderers/cloudflare/worker.ts +1 -1
  710. package/src/renderers/dom/data-table/frozen-column.ts +3 -1
  711. package/src/renderers/dom/data-table/index.tsx +33 -6
  712. package/src/renderers/dom/data-table/row.tsx +30 -1
  713. package/src/renderers/dom/desktop/control-styles.ts +63 -1
  714. package/src/renderers/dom/desktop/controls.tsx +30 -23
  715. package/src/renderers/dom/desktop/dialog-actions.tsx +170 -0
  716. package/src/renderers/dom/desktop/icons.tsx +16 -0
  717. package/src/renderers/dom/dom-ui-host.tsx +3 -0
  718. package/src/renderers/dom/host/block-glyph-canvas.tsx +6 -3
  719. package/src/renderers/dom/host/box.tsx +8 -0
  720. package/src/renderers/dom/host/chart-surface.tsx +33 -2
  721. package/src/renderers/dom/host/live-frame.ts +6 -2
  722. package/src/renderers/dom/host/overflow-fade.ts +14 -1
  723. package/src/renderers/dom/host/scroll-box.tsx +32 -0
  724. package/src/renderers/dom/host/size-observer.ts +41 -0
  725. package/src/renderers/dom/host/sticky-scroll.ts +128 -0
  726. package/src/renderers/dom/host/style.ts +1 -1
  727. package/src/renderers/dom/host/surface-3d.tsx +19 -7
  728. package/src/renderers/dom/host/surface-fit.ts +406 -0
  729. package/src/renderers/dom/host/text.tsx +1 -1
  730. package/src/renderers/dom/input-host.tsx +1 -0
  731. package/src/renderers/dom/styles.css +102 -5
  732. package/src/renderers/electrobun/bun/application-menu/click.ts +18 -0
  733. package/src/renderers/electrobun/bun/index.ts +3 -2
  734. package/src/renderers/electrobun/shared/protocol.ts +1 -1
  735. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +29 -2
  736. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +63 -20
  737. package/src/renderers/electrobun/view/cli-pane-shot-health.ts +10 -26
  738. package/src/renderers/electrobun/view/main.tsx +5 -3
  739. package/src/renderers/electrobun/view/remote/asset-data-client.ts +2 -0
  740. package/src/renderers/opentui/chart-surface.tsx +1 -0
  741. package/src/renderers/opentui/frame-capture.ts +33 -0
  742. package/src/renderers/opentui/host.tsx +10 -13
  743. package/src/renderers/opentui/pane-image/glyphs-license.txt +107 -0
  744. package/src/renderers/opentui/pane-image/glyphs.json +1 -0
  745. package/src/renderers/opentui/pane-image/index.ts +107 -0
  746. package/src/renderers/opentui/pane-image/raster.ts +428 -0
  747. package/src/renderers/opentui/start.tsx +3 -3
  748. package/src/renderers/opentui/test-utils.tsx +3 -0
  749. package/src/renderers/opentui/ui-host.tsx +29 -1
  750. package/src/series/capability.ts +75 -0
  751. package/src/series/csv.ts +160 -0
  752. package/src/series/files.ts +107 -0
  753. package/src/series/registry.ts +198 -0
  754. package/src/series/resolve.ts +108 -0
  755. package/src/series/standalone.ts +48 -0
  756. package/src/series/types.ts +153 -0
  757. package/src/series/validate.ts +171 -0
  758. package/src/shares/chat.ts +34 -0
  759. package/src/shares/dialog.tsx +295 -0
  760. package/src/shares/flow.tsx +56 -0
  761. package/src/shares/live.ts +14 -22
  762. package/src/shares/pane-image.ts +152 -0
  763. package/src/shares/personal-pane.ts +64 -0
  764. package/src/shares/portable-layout.ts +4 -2
  765. package/src/shares/prepare.ts +20 -0
  766. package/src/sources/gloomberb-cloud/index.ts +109 -10
  767. package/src/sources/gloomberb-cloud/normalizers.ts +3 -0
  768. package/src/sources/gloomberb-cloud/perpetuals.ts +249 -0
  769. package/src/sources/history-result.ts +1 -0
  770. package/src/sources/history-retention.ts +11 -0
  771. package/src/sources/listing-symbols.ts +4 -1
  772. package/src/sources/listing-target.ts +4 -0
  773. package/src/sources/provider-router/batches.ts +4 -1
  774. package/src/sources/provider-router/cache.ts +4 -2
  775. package/src/sources/provider-router/cached-routes.ts +1 -1
  776. package/src/sources/provider-router/financial-routes.ts +1 -0
  777. package/src/sources/provider-router/financials.ts +13 -0
  778. package/src/sources/provider-router/history.ts +43 -25
  779. package/src/sources/provider-router/index.ts +14 -0
  780. package/src/sources/provider-router/search.ts +1 -0
  781. package/src/state/hooks/inline-tickers.ts +49 -11
  782. package/src/sync/core-contributors.ts +1 -0
  783. package/src/test-support/shell-pane-keys.tsx +1 -0
  784. package/src/theme/theme-context.tsx +15 -1
  785. package/src/tickers/company-name.ts +75 -0
  786. package/src/tickers/instrument-kind.ts +34 -1
  787. package/src/tickers/listing-name.ts +34 -0
  788. package/src/tickers/listing-venues.ts +132 -0
  789. package/src/tickers/open-target.ts +13 -4
  790. package/src/tickers/perpetual-listing.ts +151 -0
  791. package/src/tickers/prediction-listing.ts +26 -0
  792. package/src/tickers/search/index.ts +72 -11
  793. package/src/tickers/search/ranking.ts +98 -20
  794. package/src/tickers/search/types.ts +7 -1
  795. package/src/tickers/ticker-changes.ts +213 -0
  796. package/src/tickers/us-listing.ts +34 -0
  797. package/src/time-series/economic.ts +2 -6
  798. package/src/time-series/hooks.ts +9 -0
  799. package/src/time-series/ice-credit.ts +39 -0
  800. package/src/time-series/resolve.ts +211 -29
  801. package/src/time-series/studies.ts +1 -0
  802. package/src/time-series/types.ts +12 -2
  803. package/src/time-series/use-chart-resolution.ts +32 -0
  804. package/src/types/config.ts +10 -2
  805. package/src/types/data-provider.ts +11 -0
  806. package/src/types/financials.ts +62 -1
  807. package/src/types/headless.ts +113 -0
  808. package/src/types/instrument.ts +4 -0
  809. package/src/types/plugin.ts +52 -2
  810. package/src/types/price-history.ts +7 -0
  811. package/src/types/ticker-changes.ts +26 -0
  812. package/src/types/ticker.ts +14 -0
  813. package/src/ui/context-menu.tsx +13 -1
  814. package/src/ui/host.tsx +57 -3
  815. package/src/ui/live-resize.ts +91 -0
  816. package/src/ui/live-stretch.ts +153 -0
  817. package/src/ui/measured-cells.ts +58 -0
  818. package/src/ui/sticky-scroll.ts +7 -0
  819. package/src/utils/basis-points.ts +17 -0
  820. package/src/utils/central-banks.ts +76 -0
  821. package/src/utils/cli-output.ts +131 -15
  822. package/src/utils/concurrency.ts +25 -0
  823. package/src/utils/crypto-pair.ts +20 -0
  824. package/src/utils/currency-pair.ts +19 -0
  825. package/src/utils/currency-units.ts +11 -0
  826. package/src/utils/datetime-format.ts +27 -6
  827. package/src/utils/decimal-comma.ts +19 -0
  828. package/src/utils/dom-screenshot-css.ts +265 -0
  829. package/src/utils/dom-screenshot-rasters.ts +276 -0
  830. package/src/utils/dom-screenshot.ts +439 -52
  831. package/src/utils/double-escape-close.ts +15 -1
  832. package/src/utils/exchange-rate-snapshot.ts +6 -2
  833. package/src/utils/exchanges.ts +143 -1
  834. package/src/utils/format.ts +35 -5
  835. package/src/utils/forward-dividend.ts +14 -0
  836. package/src/utils/fundamentals.ts +66 -0
  837. package/src/utils/futures-generic.ts +6 -12
  838. package/src/utils/fx-market-hours.ts +15 -5
  839. package/src/utils/fx-status.ts +6 -1
  840. package/src/utils/inline-content-tokenizer.ts +22 -3
  841. package/src/utils/market-capitalization.ts +8 -0
  842. package/src/utils/one-shot.ts +73 -0
  843. package/src/utils/options.ts +37 -8
  844. package/src/utils/price-history.ts +99 -42
  845. package/src/utils/sec-eps-basis.ts +24 -11
  846. package/src/utils/sec.ts +61 -7
  847. package/src/utils/utc-time.ts +63 -4
  848. package/src/plugins/builtin/fx-matrix/freshness.ts +0 -65
  849. /package/src/plugins/{builtin/plugin-marketplace → marketplace}/activation.ts +0 -0
  850. /package/src/plugins/{builtin/plugin-marketplace → marketplace}/ids.ts +0 -0
  851. /package/src/plugins/{builtin/plugin-marketplace → marketplace}/packs.ts +0 -0
  852. /package/src/{plugins/builtin/cloud → tickers}/starter-symbols.ts +0 -0
@@ -0,0 +1,527 @@
1
+ /**
2
+ * Turns the text of an indexed article, call or filing into blocks a reader
3
+ * can lay out: paragraphs of a few sentences, headings, lists and tables, with
4
+ * web page chrome and wire boilerplate left out.
5
+ *
6
+ * Everything here is extractive. Lines are dropped only when they match a
7
+ * known kind of page furniture as a whole ("Share this article", a cookie
8
+ * banner, the headline printed again), sentences are never reworded, and a
9
+ * paragraph is split only between sentences. When a rule is unsure it keeps
10
+ * the text: a stray share link costs a glance, a lost sentence costs the
11
+ * story. The reader keeps the raw text one action away for the same reason.
12
+ */
13
+
14
+ export type ArticleBlock =
15
+ | { kind: "paragraph"; text: string; section: number }
16
+ | { kind: "heading"; text: string; section: number }
17
+ | { kind: "list"; items: string[]; section: number }
18
+ | { kind: "table"; rows: string[][]; section: number };
19
+
20
+ export interface ArticleSection {
21
+ text: string;
22
+ /** Who or what the section is: a speaker, a filing section. Shown as its heading when it changes. */
23
+ heading?: string;
24
+ }
25
+
26
+ export interface ParseArticleOptions {
27
+ /** The headline, dropped where the page prints it again. */
28
+ title?: string;
29
+ /** The publisher or wire, dropped where the page prints it again. */
30
+ source?: string;
31
+ /**
32
+ * Leave out web page chrome and wire boilerplate. For news; a transcript or
33
+ * a filing is kept as written.
34
+ */
35
+ clean?: boolean;
36
+ }
37
+
38
+ /** About three lines at a reading measure: the most a paragraph should hold. */
39
+ const PARAGRAPH_TARGET_WORDS = 45;
40
+ /** How far into an article page furniture (bylines, datelines, share rows) is looked for. */
41
+ const HEADER_LINES = 10;
42
+
43
+ const WORD = /[\p{L}\p{N}][\p{L}\p{N}'’.,$%&/-]*/gu;
44
+
45
+ export function countWords(text: string): number {
46
+ return text.match(WORD)?.length ?? 0;
47
+ }
48
+
49
+ function normalizeKey(text: string): string {
50
+ return text.toLowerCase().replace(/[^\p{L}\p{N}]+/gu, " ").trim();
51
+ }
52
+
53
+ // ---------------------------------------------------------------------------
54
+ // Sentences
55
+
56
+ /**
57
+ * Words that end in a period without ending the sentence. Lowercased, without
58
+ * the period. Initials (J.), dotted acronyms (U.S.) and months are covered by
59
+ * patterns below.
60
+ */
61
+ const ABBREVIATIONS = new Set([
62
+ "mr", "mrs", "ms", "dr", "prof", "sr", "jr", "st", "mt", "ft", "ave", "blvd",
63
+ "inc", "corp", "co", "ltd", "plc", "llc", "lp", "bros", "dept", "no", "nos",
64
+ "vs", "etc", "approx", "est", "fig", "gov", "sen", "rep", "gen", "lt", "col",
65
+ "capt", "sgt", "rev", "hon", "pres", "vol", "op", "cf", "al",
66
+ "jan", "feb", "mar", "apr", "jun", "jul", "aug", "sep", "sept", "oct", "nov", "dec",
67
+ ]);
68
+
69
+ function endsWithAbbreviation(before: string): boolean {
70
+ const token = /(\S+)$/.exec(before)?.[1] ?? "";
71
+ const bare = token.replace(/^[("'“‘[]+/, "");
72
+ // "J." and "U.S." and "e.g.": a dot inside the word, or a single letter.
73
+ if (/^\p{L}$/u.test(bare)) return true;
74
+ if (/^(?:\p{L}\.)+\p{L}?$/u.test(bare)) return true;
75
+ return ABBREVIATIONS.has(bare.toLowerCase());
76
+ }
77
+
78
+ /**
79
+ * Splits text into sentences at a period, question or exclamation mark
80
+ * (with any closing quote or bracket) followed by a space and a capital,
81
+ * an opening quote or a bracket. Never after an abbreviation or an initial,
82
+ * and never before a digit, so "No. 5" and "Oct. 10" hold together. Unsure
83
+ * cases stay one sentence: a missed break costs nothing in a reader.
84
+ */
85
+ export function splitSentences(text: string): string[] {
86
+ const sentences: string[] = [];
87
+ const boundary = /([.!?\u2026]+["'\u201d\u2019)\]]*)\s+(?=["'\u201c\u2018(\[]?\p{Lu})/gu;
88
+ let start = 0;
89
+ for (let match = boundary.exec(text); match; match = boundary.exec(text)) {
90
+ const punctuation = match[1]!;
91
+ // "Inc." or "U.S." before a name is part of the sentence; an ellipsis is not an abbreviation.
92
+ if (punctuation[0] === "." && !punctuation.startsWith("..") && endsWithAbbreviation(text.slice(start, match.index))) continue;
93
+ const sentence = text.slice(start, match.index + punctuation.length).trim();
94
+ if (sentence) sentences.push(sentence);
95
+ start = match.index + match[0].length;
96
+ }
97
+ const rest = text.slice(start).trim();
98
+ if (rest) sentences.push(rest);
99
+ return sentences;
100
+ }
101
+
102
+ /**
103
+ * Where to break `counts` (words per sentence) into `groups` runs so each run
104
+ * is as close to the same size as it can be: a linear partition, small enough
105
+ * to solve exactly for any paragraph a page holds.
106
+ */
107
+ function balancedBreaks(counts: number[], groups: number): number[] {
108
+ const n = counts.length;
109
+ const prefix = [0];
110
+ for (const count of counts) prefix.push(prefix[prefix.length - 1]! + count);
111
+ const budget = prefix[n]! / groups;
112
+ const cost = (from: number, to: number) => (prefix[to]! - prefix[from]! - budget) ** 2;
113
+ // best[g][j]: the least cost of the first j sentences in g runs; from[g][j]: where its last run starts.
114
+ const best = Array.from({ length: groups + 1 }, () => new Array<number>(n + 1).fill(Infinity));
115
+ const from = Array.from({ length: groups + 1 }, () => new Array<number>(n + 1).fill(0));
116
+ best[0]![0] = 0;
117
+ for (let g = 1; g <= groups; g += 1) {
118
+ for (let j = g; j <= n; j += 1) {
119
+ for (let i = g - 1; i < j; i += 1) {
120
+ const value = best[g - 1]![i]! + cost(i, j);
121
+ if (value < best[g]![j]!) {
122
+ best[g]![j] = value;
123
+ from[g]![j] = i;
124
+ }
125
+ }
126
+ }
127
+ }
128
+ const breaks: number[] = [];
129
+ for (let g = groups, j = n; g > 0; g -= 1) {
130
+ j = from[g]![j]!;
131
+ breaks.unshift(j);
132
+ }
133
+ return breaks;
134
+ }
135
+
136
+ /**
137
+ * Splits a long paragraph between sentences into runs of about
138
+ * `targetWords`, as even as the sentences allow. A paragraph within a third
139
+ * of the target, or one long sentence, stays whole.
140
+ */
141
+ export function splitParagraph(text: string, targetWords = PARAGRAPH_TARGET_WORDS): string[] {
142
+ const total = countWords(text);
143
+ if (total <= Math.round(targetWords * 4 / 3)) return [text];
144
+ const sentences = splitSentences(text);
145
+ if (sentences.length < 2) return [text];
146
+ const counts = sentences.map(countWords);
147
+ const groups = Math.min(sentences.length, Math.ceil(total / targetWords));
148
+ const breaks = balancedBreaks(counts, groups);
149
+ return breaks.map((start, index) => sentences.slice(start, breaks[index + 1] ?? sentences.length).join(" "));
150
+ }
151
+
152
+ // ---------------------------------------------------------------------------
153
+ // Page furniture
154
+
155
+ const SHARE_TARGETS = "x|twitter|facebook|linkedin|email|e-mail|whatsapp|reddit|threads|bluesky|telegram|pinterest|mastodon";
156
+
157
+ /** Whole lines that are page chrome wherever they appear. Matched case-insensitively against the trimmed line. */
158
+ const CHROME_LINES: RegExp[] = [
159
+ /^share (?:this|the) (?:article|story|post|page)$/,
160
+ new RegExp(`^share (?:to|on|via|with) (?:${SHARE_TARGETS})$`),
161
+ new RegExp(`^(?:${SHARE_TARGETS})$`),
162
+ /^(?:share|tweet|print|copy link|copy url|save|bookmark|print this (?:page|article)|email this (?:page|article))$/,
163
+ /^(?:advertisement|sponsored(?: content)?|ad|story continues below(?: advertisement)?)$/,
164
+ /^(?:listen to (?:this )?(?:article|story)|\d+\s*min(?:ute)?s?\s+read)$/,
165
+ /^(?:accept|accept all|accept all cookies|accept cookies|reject all|manage (?:cookie )?preferences|cookie settings|cookie policy)$/,
166
+ /^view (?:the )?original content\b.*$/,
167
+ /^(?:skip to (?:main )?content|back to top|return to top)$/,
168
+ /^follow us on\b.{0,60}$/,
169
+ /^(?:related(?: articles| stories| news)?|recommended(?: for you)?|more from [\p{L}\s]{1,30}|trending(?: now)?|see also)\s*:?$/u,
170
+ ];
171
+
172
+ /** Lines that are page chrome only when they are short: a full sentence that mentions cookies is not a banner. */
173
+ function isShortChrome(line: string, words: number): boolean {
174
+ const lower = line.toLowerCase();
175
+ if (words <= 40 && /\b(?:(?:we|this (?:site|website)|our (?:site|website)) uses? cookies|use of cookies|accept (?:all )?cookies|cookie (?:policy|preferences|settings|consent|notice))\b/.test(lower)) return true;
176
+ if (words <= 16 && /^(?:subscribe|sign up|join)\b/.test(lower) && /\b(?:newsletter|updates|alerts|inbox|our|free)\b/.test(lower)) return true;
177
+ if (words <= 12 && /^(?:click here|tap here)\b/.test(lower)) return true;
178
+ return false;
179
+ }
180
+
181
+ const MONTH = "(?:jan(?:uary)?|feb(?:ruary)?|mar(?:ch)?|apr(?:il)?|may|june?|july?|aug(?:ust)?|sep(?:t(?:ember)?)?|oct(?:ober)?|nov(?:ember)?|dec(?:ember)?)";
182
+ const DATE_TEXT = `(?:(?:mon|tue|wed|thu|fri|sat|sun)[a-z]*,?\\s+)?(?:${MONTH}\\.?\\s+\\d{1,2}(?:st|nd|rd|th)?,?\\s+\\d{4}|\\d{1,2}\\s+${MONTH}\\.?,?\\s+\\d{4}|\\d{1,4}[/-]\\d{1,2}[/-]\\d{1,4})`;
183
+ const TIME_TEXT = "(?:,?\\s*(?:at\\s+)?\\d{1,2}(?::\\d{2})?\\s*(?:[ap]\\.?m\\.?)?(?:\\s*[a-z]{2,4})?)?";
184
+ /** A line that is only a date and maybe a time: the reader's header already says when. */
185
+ const DATE_LINE = new RegExp(`^(?:(?:updated|published|posted|last updated)(?: on)?:?\\s*)?${DATE_TEXT}${TIME_TEXT}$`, "i");
186
+
187
+ /**
188
+ * The dateline a wire story opens with: a place in capitals, an optional
189
+ * date, then the wire's name, then a dash. "BOSTON, Oct. 9, 2026 /Wirefeed/ --",
190
+ * "NEW YORK, Oct. 9, 2026 (GLOBE NEWSWIRE) --", "SAN FRANCISCO--(BUSINESS WIRE)--".
191
+ * Only taken with the wire tag present, so an ordinary opening in capitals stays.
192
+ */
193
+ const WIRE_DATELINE = new RegExp(
194
+ "^[A-Z][A-Z .,'’&-]{1,60}(?:,\\s*[A-Z][A-Za-z.]{1,15}\\.?)?\\s*,?\\s*"
195
+ + `(?:${DATE_TEXT}\\s*)?`
196
+ + "(?:/[^/\\n]{2,40}/|\\([A-Z][A-Z .&-]{2,40}\\)|--\\([A-Z][A-Z .&-]{2,40}\\))\\s*(?:--|—|–|-)\\s*",
197
+ "i",
198
+ );
199
+
200
+ function stripWireDateline(line: string): string {
201
+ const match = WIRE_DATELINE.exec(line);
202
+ if (!match) return line;
203
+ // The place has to be in capitals; the "i" flag only loosens the date.
204
+ const place = /^[^,/(-]+/.exec(match[0])?.[0] ?? "";
205
+ if (place !== place.toUpperCase()) return line;
206
+ const rest = line.slice(match[0].length).trim();
207
+ return rest.length > 0 ? rest : line;
208
+ }
209
+
210
+ interface CleanContext {
211
+ title: string;
212
+ source: string;
213
+ }
214
+
215
+ /**
216
+ * Lines of the page with chrome removed. `inHeader` lines (the top of the
217
+ * article) also lose a repeated headline or source, a date standing alone,
218
+ * and the "News provided by" credit with the name under it.
219
+ */
220
+ function cleanLines(lines: string[], context: CleanContext, startIndex: number): string[] {
221
+ const kept: string[] = [];
222
+ let skipNextName = false;
223
+ for (const [offset, raw] of lines.entries()) {
224
+ const line = raw.trim();
225
+ if (!line) {
226
+ kept.push("");
227
+ continue;
228
+ }
229
+ const lower = line.toLowerCase();
230
+ const words = countWords(line);
231
+ const inHeader = startIndex + offset < HEADER_LINES;
232
+ if (skipNextName) {
233
+ skipNextName = false;
234
+ // The credited name: short, and no sentence in it ("Acme Inc." is a name).
235
+ if (words <= 6 && (!/[.!?]$/.test(line) || endsWithAbbreviation(line.slice(0, -1)))) continue;
236
+ }
237
+ if (/^(?:news|content|story) provided by\b:?$/i.test(line)) {
238
+ skipNextName = true;
239
+ continue;
240
+ }
241
+ if (CHROME_LINES.some((pattern) => pattern.test(lower))) continue;
242
+ if (isShortChrome(line, words)) continue;
243
+ if (inHeader) {
244
+ const key = normalizeKey(line);
245
+ if (context.title && key === context.title) continue;
246
+ if (context.source && key === context.source) continue;
247
+ if (words <= 12 && DATE_LINE.test(line)) continue;
248
+ }
249
+ // "SOURCE Acme Inc." closes a wire release: who sent it, said again.
250
+ if (/^SOURCE\s+\S/.test(line) && words <= 8) continue;
251
+ kept.push(inHeader ? stripWireDateline(line) : line);
252
+ }
253
+ return kept;
254
+ }
255
+
256
+ // ---------------------------------------------------------------------------
257
+ // Blocks
258
+
259
+ const LIST_ITEM = /^(?:[•·▪●◦‣∙*]|[-–—](?=\s)|\d{1,2}[.)](?=\s))\s*(.+)$/u;
260
+ const TABLE_SPLIT = /\t+|\s{2,}|\s*\|\s*/;
261
+ const TERMINAL = /[.!?:;,"”’)\]…]$/u;
262
+
263
+ function tableCells(line: string): string[] | null {
264
+ const trimmed = line.trim().replace(/^\||\|$/g, "");
265
+ const cells = trimmed.split(TABLE_SPLIT).map((cell) => cell.trim()).filter((cell) => cell.length > 0);
266
+ return cells.length >= 2 ? cells : null;
267
+ }
268
+
269
+ /** Collapses runs of spaces and tidies the gaps wire text leaves inside brackets. */
270
+ function tidy(text: string): string {
271
+ return text
272
+ .replace(/\s+/g, " ")
273
+ .replace(/([([])\s+/g, "$1")
274
+ .replace(/\s+([)\],;])/g, "$1")
275
+ .trim();
276
+ }
277
+
278
+ type RawBlock =
279
+ | { kind: "text"; text: string }
280
+ | { kind: "list"; items: string[] }
281
+ | { kind: "table"; rows: string[][] };
282
+
283
+ /**
284
+ * Groups cleaned lines into blocks. A blank line always ends a block. Where
285
+ * the source never uses blank lines, every line is its own block, except a
286
+ * line that plainly continues the one before (it starts in lowercase after a
287
+ * line with no closing punctuation). Where it does use them, single line
288
+ * breaks inside a block are soft wraps.
289
+ */
290
+ function groupLines(lines: string[]): RawBlock[] {
291
+ const blankSeparated = lines.some((line, index) => line === "" && index > 0 && index < lines.length - 1);
292
+ const blocks: RawBlock[] = [];
293
+ let index = 0;
294
+ while (index < lines.length) {
295
+ const line = lines[index]!;
296
+ if (!line) {
297
+ index += 1;
298
+ continue;
299
+ }
300
+ // A run of two or more lines that split into the same number of cells.
301
+ const cells = tableCells(line);
302
+ if (cells) {
303
+ const rows = [cells];
304
+ let next = index + 1;
305
+ while (next < lines.length) {
306
+ const nextCells = lines[next] ? tableCells(lines[next]!) : null;
307
+ if (!nextCells || nextCells.length !== cells.length) break;
308
+ rows.push(nextCells);
309
+ next += 1;
310
+ }
311
+ if (rows.length >= 2) {
312
+ blocks.push({ kind: "table", rows });
313
+ index = next;
314
+ continue;
315
+ }
316
+ }
317
+ const item = LIST_ITEM.exec(line);
318
+ if (item) {
319
+ const items = [tidy(item[1]!)];
320
+ let next = index + 1;
321
+ while (next < lines.length) {
322
+ const nextItem = lines[next] ? LIST_ITEM.exec(lines[next]!) : null;
323
+ if (!nextItem) break;
324
+ items.push(tidy(nextItem[1]!));
325
+ next += 1;
326
+ }
327
+ // One dash-led line is a sentence, not a list.
328
+ if (items.length >= 2 || !/^[-–—]/.test(line)) {
329
+ blocks.push({ kind: "list", items });
330
+ index = next;
331
+ continue;
332
+ }
333
+ }
334
+ let text = line;
335
+ let next = index + 1;
336
+ while (next < lines.length && lines[next]) {
337
+ const following = lines[next]!;
338
+ if (LIST_ITEM.test(following) || tableCells(following)) break;
339
+ const continues = blankSeparated || (!TERMINAL.test(text) && /^[\p{Ll}\d($€£¥%&,;]/u.test(following));
340
+ if (!continues) break;
341
+ text = `${text} ${following}`;
342
+ next += 1;
343
+ }
344
+ blocks.push({ kind: "text", text: tidy(text) });
345
+ index = next;
346
+ }
347
+ return blocks;
348
+ }
349
+
350
+ /** Bullets run together on one line: "Highlights: • Revenue up 8% • Margin 46%". */
351
+ function splitInlineBullets(text: string): { lead: string; items: string[] } | null {
352
+ const parts = text.split(/\s+[•▪●]\s+/u);
353
+ if (parts.length < 3) return null;
354
+ const [lead, ...items] = parts;
355
+ return { lead: lead!.replace(/^[•▪●]\s*/u, "").trim(), items: items.map(tidy).filter(Boolean) };
356
+ }
357
+
358
+ /**
359
+ * A short line with no closing punctuation, followed by a paragraph, reads as
360
+ * the heading of what follows: a company name before its news, "Outlook"
361
+ * before the guidance.
362
+ */
363
+ function isHeading(text: string, next: RawBlock | undefined): boolean {
364
+ if (!next || next.kind !== "text") return false;
365
+ if (TERMINAL.test(text) && !/\)$/.test(text)) return false;
366
+ if (text.length > 90 || countWords(text) > 12) return false;
367
+ if (!/^[\p{Lu}\d"“]/u.test(text)) return false;
368
+ return countWords(next.text) > countWords(text) * 2;
369
+ }
370
+
371
+ export function parseArticle(sections: ArticleSection[], options: ParseArticleOptions = {}): ArticleBlock[] {
372
+ const context: CleanContext = {
373
+ title: options.title ? normalizeKey(options.title) : "",
374
+ source: options.source ? normalizeKey(options.source) : "",
375
+ };
376
+ const blocks: ArticleBlock[] = [];
377
+ let lineIndex = 0;
378
+ let previousHeading: string | undefined;
379
+ for (const [section, entry] of sections.entries()) {
380
+ const heading = entry.heading?.trim();
381
+ if (heading && heading !== previousHeading) {
382
+ blocks.push({ kind: "heading", text: heading, section });
383
+ }
384
+ previousHeading = heading || previousHeading;
385
+ const rawLines = (entry.text ?? "").replace(/\r\n?/g, "\n").replace(/\u00a0/g, " ").split("\n");
386
+ const lines = options.clean ? cleanLines(rawLines, context, lineIndex) : rawLines.map((line) => line.trim());
387
+ lineIndex += rawLines.length;
388
+ const grouped = groupLines(lines);
389
+ for (const [index, raw] of grouped.entries()) {
390
+ if (raw.kind === "table") {
391
+ blocks.push({ kind: "table", rows: raw.rows, section });
392
+ continue;
393
+ }
394
+ if (raw.kind === "list") {
395
+ blocks.push({ kind: "list", items: raw.items, section });
396
+ continue;
397
+ }
398
+ const inline = splitInlineBullets(raw.text);
399
+ if (inline) {
400
+ if (inline.lead) blocks.push({ kind: "paragraph", text: inline.lead, section });
401
+ blocks.push({ kind: "list", items: inline.items, section });
402
+ continue;
403
+ }
404
+ if (isHeading(raw.text, grouped[index + 1])) {
405
+ blocks.push({ kind: "heading", text: raw.text, section });
406
+ continue;
407
+ }
408
+ for (const paragraph of splitParagraph(raw.text)) {
409
+ blocks.push({ kind: "paragraph", text: paragraph, section });
410
+ }
411
+ }
412
+ }
413
+ return blocks;
414
+ }
415
+
416
+ // ---------------------------------------------------------------------------
417
+ // Gist
418
+
419
+ export interface ArticleGist {
420
+ /** The opening paragraph, or the article's own summary. */
421
+ lead: string | null;
422
+ /** Up to three sentences of the article that each carry a figure and a move. */
423
+ facts: string[];
424
+ /** What follows the lead. */
425
+ body: ArticleBlock[];
426
+ words: number;
427
+ }
428
+
429
+ /** Articles shorter than this are read whole; a facts list would only repeat them. */
430
+ const FACTS_MIN_WORDS = 250;
431
+ const MAX_FACTS = 3;
432
+ const FACT_FIGURE = /(?:[$€£¥]|\b[A-Z]{2,3}\$)\s?\d|\b\d[\d,]*(?:\.\d+)?\s?(?:%|percent\b|bps\b|basis points\b)/;
433
+ const FACT_MOVE = /\b(?:rose|rise[sn]?|fell|fall(?:s|en)?|gain(?:ed|s)?|lost|los(?:e|es|ing)|declin(?:ed|es|e)|increas(?:ed|es|e)|decreas(?:ed|es|e)|grew|grow(?:s|n)?|jump(?:ed|s)?|sl(?:id|ides?)|climb(?:ed|s)?|drop(?:ped|s)?|surg(?:ed|es)|plung(?:ed|es)|soar(?:ed|s)|tumbl(?:ed|es)|up|down|higher|lower|record|raised|cut|reported|guided)\b/i;
434
+ /** Openings that need the sentence before them to make sense. */
435
+ const DEPENDENT_OPENING = /^(?:it|its|they|their|this|that|these|those|he|she|his|her|we|our|but|and|so|also|however|meanwhile|the (?:company|stock|firm|group|index|shares))\b/i;
436
+
437
+ function isFact(sentence: string): boolean {
438
+ const words = countWords(sentence);
439
+ if (words < 6 || words > 30) return false;
440
+ if (!/[.!]$/.test(sentence)) return false;
441
+ if (DEPENDENT_OPENING.test(sentence)) return false;
442
+ // Someone or something named, past the first word.
443
+ if (!/\s\p{Lu}[\p{Ll}\p{Lu}]/u.test(sentence) && !/^\p{Lu}[\p{Ll}]+\s/u.test(sentence)) return false;
444
+ return FACT_FIGURE.test(sentence) && FACT_MOVE.test(sentence);
445
+ }
446
+
447
+ export function articleGist(blocks: ArticleBlock[], options: { summary?: string | null } = {}): ArticleGist {
448
+ const words = blocks.reduce((sum, block) => sum + blockWords(block), 0);
449
+ const summary = options.summary?.trim() ? tidy(options.summary) : null;
450
+ const firstIndex = blocks.findIndex((block) => block.kind === "paragraph");
451
+ const first = firstIndex >= 0 ? blocks[firstIndex] as Extract<ArticleBlock, { kind: "paragraph" }> : null;
452
+ // Only an opening paragraph leads: one that comes after a heading belongs to that heading.
453
+ const opensWithParagraph = first !== null && blocks.slice(0, firstIndex).every((block) => block.kind !== "heading");
454
+
455
+ let lead: string | null = null;
456
+ let body = blocks;
457
+ if (summary && (!first || normalizeKey(summary) !== normalizeKey(first.text))) {
458
+ lead = summary;
459
+ } else if (first && opensWithParagraph) {
460
+ lead = first.text;
461
+ body = blocks.filter((_, index) => index !== firstIndex);
462
+ }
463
+
464
+ const facts: string[] = [];
465
+ if (words >= FACTS_MIN_WORDS) {
466
+ const leadKey = lead ? normalizeKey(lead) : "";
467
+ for (const block of body) {
468
+ if (block.kind !== "paragraph") continue;
469
+ // One per paragraph, so the list spans the story instead of one passage.
470
+ const fact = splitSentences(block.text).find((sentence) => isFact(sentence) && !leadKey.includes(normalizeKey(sentence)));
471
+ if (fact) facts.push(fact);
472
+ if (facts.length === MAX_FACTS) break;
473
+ }
474
+ }
475
+ return { lead, facts: facts.length >= 2 ? facts : [], body, words };
476
+ }
477
+
478
+ export function blockWords(block: ArticleBlock): number {
479
+ switch (block.kind) {
480
+ case "paragraph":
481
+ case "heading":
482
+ return countWords(block.text);
483
+ case "list":
484
+ return block.items.reduce((sum, item) => sum + countWords(item), 0);
485
+ case "table":
486
+ return block.rows.reduce((sum, row) => sum + row.reduce((cells, cell) => cells + countWords(cell), 0), 0);
487
+ }
488
+ }
489
+
490
+ // ---------------------------------------------------------------------------
491
+ // Tickers
492
+
493
+ /** US venues only: a symbol from another exchange can name a different company here. */
494
+ const US_VENUE = /\b(?:NYSE American|NYSE Arca|NYSE MKT|NYSE|Nasdaq(?:GS|GM|CM)?|NASDAQ(?:GS|GM|CM)?|AMEX|Cboe BZX|OTCQX|OTCQB|OTC Pink|OTC)\s*:\s*([A-Z][A-Z0-9]{0,5}(?:\.[A-Z])?)\b/g;
495
+
496
+ /**
497
+ * Symbols a release names with their listing, "(NASDAQ: ABCD)", in the order
498
+ * they first appear. A bare capitalised word is never taken for a ticker.
499
+ */
500
+ export function listedTickers(text: string): string[] {
501
+ const symbols: string[] = [];
502
+ for (const group of text.matchAll(/\(([^()]{3,80})\)/g)) {
503
+ for (const match of group[1]!.matchAll(US_VENUE)) {
504
+ const symbol = match[1]!;
505
+ if (!symbols.includes(symbol)) symbols.push(symbol);
506
+ }
507
+ }
508
+ return symbols;
509
+ }
510
+
511
+ // ---------------------------------------------------------------------------
512
+ // Search terms
513
+
514
+ /**
515
+ * Splits text on the terms a search matched, case-insensitively, the longest
516
+ * term first so "free cash flow" is one mark rather than "cash" inside it.
517
+ */
518
+ export function markTerms(text: string, terms: readonly string[]): Array<{ text: string; marked: boolean }> {
519
+ const usable = terms.map((term) => term.trim()).filter((term) => term.length > 0);
520
+ if (usable.length === 0) return [{ text, marked: false }];
521
+ const pattern = new RegExp(
522
+ `(${usable.map((term) => term.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).sort((a, b) => b.length - a.length).join("|")})`,
523
+ "gi",
524
+ );
525
+ const keys = new Set(usable.map((term) => term.toLowerCase()));
526
+ return text.split(pattern).filter((part) => part.length > 0).map((part) => ({ text: part, marked: keys.has(part.toLowerCase()) }));
527
+ }
@@ -11,13 +11,13 @@ import { useState } from "react";
11
11
  import { t } from "../i18n";
12
12
  import { useAppLanguage } from "../i18n/react";
13
13
  import { matchesKeyChord, parseKeyChord } from "../app/keybindings";
14
- import { AuthForm, authFormTitle } from "../plugins/builtin/cloud/auth-form";
15
- import type { AccountMode } from "../plugins/builtin/cloud/auth-model";
14
+ import { AuthForm, authFormTitle } from "../account/auth-form";
15
+ import type { AccountMode } from "../account/auth-model";
16
16
  import {
17
17
  DeviceSignInPanel,
18
18
  isDeviceSignInRetryKey,
19
19
  useDeviceSignIn,
20
- } from "../plugins/builtin/cloud/device-signin-dialog";
20
+ } from "../account/device-signin-dialog";
21
21
  import { useShortcut, useViewport } from "../react/input";
22
22
  import { useThemeColors } from "../theme/theme-context";
23
23
  import { Box, Text } from "../ui";
@@ -29,10 +29,19 @@ import type { QuoteFlashDirection } from "../quote-flash";
29
29
  import { objectVersion } from "../../utils/object-version";
30
30
  import { getCompletedRegularSessionDisplay } from "../../market-data/market/status";
31
31
  import { usePaneFooter } from "../layout/pane/footer";
32
+ import { Button } from "../ui/button";
33
+ import { PaneStatusBody } from "../ui/status";
32
34
 
33
35
  export interface TickerTableCell {
34
36
  text: string;
35
37
  color?: string;
38
+ /** The full-precision number behind a rounded `text`, which exports and rendered-view reports keep. */
39
+ value?: number | null;
40
+ /**
41
+ * Makes the cell a link: a click selects the row and calls this instead of
42
+ * the row's own click. The pane gives the same action a key (its menu).
43
+ */
44
+ onPress?: () => void;
36
45
  }
37
46
 
38
47
  type ResolveTickerTableCell = (
@@ -83,6 +92,13 @@ export interface TickerListTableViewProps {
83
92
  rowMenuAccelerators?: Readonly<Record<string, string>>;
84
93
  emptyTitle?: string;
85
94
  emptyHint?: string;
95
+ /**
96
+ * Starts the pane's add-ticker flow. Given, the empty table offers a
97
+ * "+ ticker" button for it and says so before the key.
98
+ */
99
+ onAddTicker?: () => void;
100
+ /** The pane's key for the same flow, named after the click. The command bar's key when absent. */
101
+ addTickerShortcut?: string;
86
102
  virtualize?: boolean;
87
103
  overscan?: number;
88
104
  }
@@ -214,11 +230,24 @@ export function TickerListTableView({
214
230
  rowMenuAccelerators,
215
231
  emptyTitle = t("No tickers."),
216
232
  emptyHint,
233
+ onAddTicker,
234
+ addTickerShortcut,
217
235
  virtualize = true,
218
236
  overscan = 4,
219
237
  }: TickerListTableViewProps) {
220
238
  const commandBarShortcut = useCommandBarShortcut();
221
- const resolvedEmptyHint = emptyHint ?? tf("Press {shortcut} to add one.", { shortcut: commandBarShortcut });
239
+ const addLabel = `+ ${t("ticker")}`;
240
+ const resolvedEmptyHint = emptyHint ?? (onAddTicker
241
+ ? tf("Click {button} to add one, or press {shortcut}.", { button: addLabel, shortcut: addTickerShortcut ?? commandBarShortcut })
242
+ : tf("Press {shortcut} to add one.", { shortcut: commandBarShortcut }));
243
+ const emptyContent = onAddTicker ? (
244
+ <PaneStatusBody
245
+ empty
246
+ emptyTitle={emptyTitle}
247
+ emptyMessage={resolvedEmptyHint}
248
+ actions={<Button label="Add ticker" displayLabel={addLabel} compact onPress={onAddTicker} />}
249
+ />
250
+ ) : undefined;
222
251
  const renderer = useRendererHost();
223
252
  const { showContextMenu } = useContextMenu();
224
253
  const { nativeContextMenu } = useUiCapabilities();
@@ -242,6 +271,8 @@ export function TickerListTableView({
242
271
  resolveCellRef.current = { resolve: resolveCell, epoch: resolveCellRef.current.epoch + 1 };
243
272
  }
244
273
  const resolveEpoch = resolveCellRef.current.epoch;
274
+ const setCursorSymbolRef = useRef(setCursorSymbol);
275
+ setCursorSymbolRef.current = setCursorSymbol;
245
276
 
246
277
  const renderCell = useCallback((
247
278
  ticker: TickerRecord,
@@ -257,13 +288,22 @@ export function TickerListTableView({
257
288
  };
258
289
  }
259
290
 
260
- const { text, color } = resolveCellRef.current.resolve(column, ticker, financials);
291
+ const { text, color, onPress, value } = resolveCellRef.current.resolve(column, ticker, financials);
261
292
  const shouldFlash = flashSymbolsRef.current.has(ticker.metadata.ticker)
262
293
  && flashesOnQuoteTick(column.id, financials?.quote);
263
294
  return {
264
295
  text,
296
+ ...(value !== undefined ? { value } : {}),
265
297
  color: color || (rowState.selected ? colors.selectedText : undefined),
266
298
  attributes: shouldFlash ? TextAttributes.DIM : TextAttributes.NONE,
299
+ // Any other button falls through to the row, so a right click still opens its menu.
300
+ onMouseDown: onPress ? (event: TableMouseEvent) => {
301
+ if ((event.button ?? 0) !== 0) return;
302
+ event.preventDefault?.();
303
+ event.stopPropagation?.();
304
+ setCursorSymbolRef.current(ticker.metadata.ticker);
305
+ onPress();
306
+ } : undefined,
267
307
  };
268
308
  }, []);
269
309
 
@@ -349,6 +389,7 @@ export function TickerListTableView({
349
389
  getRowVersion={getRowVersion}
350
390
  emptyStateTitle={emptyTitle}
351
391
  emptyStateHint={resolvedEmptyHint}
392
+ emptyContent={emptyContent}
352
393
  virtualize={virtualize}
353
394
  overscan={overscan}
354
395
  rootBefore={rootBefore}
@@ -22,7 +22,8 @@ export function ActionRow({ label, children, expanded, active, disabled, fg, ...
22
22
  const foreground = disabled ? colors.textMuted : fg ?? (active ? colors.textBright : colors.text);
23
23
  return (
24
24
  <Button {...props} label={label} active={active} disabled={disabled} expanded={expanded} variant="plain" compact flush stopPropagation>
25
- <Box flexDirection="row" width="100%" alignItems="center" gap={1}>
25
+ {/* A label of two lines reads from the left; a desktop button would centre the shorter one. */}
26
+ <Box flexDirection="row" width="100%" alignItems="center" gap={1} style={{ textAlign: "left" }}>
26
27
  {expanded !== undefined && <DisclosureMarker expanded={expanded} color={foreground} width={2} />}
27
28
  <Text fg={foreground} attributes={active ? TextAttributes.BOLD : 0}>{t(label)}</Text>
28
29
  {children}
@@ -28,6 +28,11 @@ export interface ButtonProps {
28
28
  disabled?: boolean;
29
29
  active?: boolean;
30
30
  shortcut?: string;
31
+ /**
32
+ * The key that presses it, as a keycap on the desktop and the web only: for
33
+ * a dialog button whose key the terminal names in the footer line instead.
34
+ */
35
+ desktopShortcut?: string;
31
36
  /** Tooltip, when it should say more than the label. */
32
37
  title?: string;
33
38
  width?: number;
@@ -86,6 +91,7 @@ export function Button({
86
91
  disabled = false,
87
92
  active = false,
88
93
  shortcut,
94
+ desktopShortcut,
89
95
  width,
90
96
  height,
91
97
  compact = false,
@@ -120,7 +126,7 @@ export function Button({
120
126
  variant={variant}
121
127
  disabled={disabled}
122
128
  active={active}
123
- shortcut={shortcut}
129
+ shortcut={shortcut ?? desktopShortcut}
124
130
  title={title}
125
131
  width={width}
126
132
  height={height}