gloomberb 0.17.6 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (768) hide show
  1. package/README.md +2 -0
  2. package/README.zh-CN.md +2 -0
  3. package/package.json +6 -1
  4. package/patches/electrobun@1.18.1.patch +74 -0
  5. package/src/account/auth-model.ts +3 -2
  6. package/src/account/device-signin-dialog.tsx +38 -13
  7. package/src/account/device-signin.ts +2 -1
  8. package/src/account/upgrade-dialog.tsx +6 -2
  9. package/src/api-client/askg.ts +5 -3
  10. package/src/api-client/bank-figures.ts +73 -0
  11. package/src/api-client/credit-boards.ts +21 -1
  12. package/src/api-client/crypto-markets.ts +88 -1
  13. package/src/api-client/data.ts +104 -4
  14. package/src/api-client/debt-maturities.ts +18 -0
  15. package/src/api-client/equity-screener.ts +3 -0
  16. package/src/api-client/errors.ts +13 -0
  17. package/src/api-client/fund-facts.ts +72 -0
  18. package/src/api-client/futures-curve.ts +26 -3
  19. package/src/api-client/geo.ts +11 -1
  20. package/src/api-client/index.ts +25 -2
  21. package/src/api-client/insider-signals.ts +95 -11
  22. package/src/api-client/normalizers.ts +1 -0
  23. package/src/api-client/paths.ts +20 -1
  24. package/src/api-client/request.ts +11 -3
  25. package/src/api-client/research-activity.ts +15 -8
  26. package/src/api-client/socket.ts +6 -3
  27. package/src/api-client/supply-chain-graph.ts +2 -2
  28. package/src/api-client/supply-chain.ts +8 -0
  29. package/src/api-client/tape.ts +12 -0
  30. package/src/api-client/types.ts +66 -2
  31. package/src/api-client/upgrade-experiment.ts +4 -3
  32. package/src/api-client/wall-experiments.ts +5 -3
  33. package/src/api-client/wall-summary.ts +3 -1
  34. package/src/api-client/web-experiments.ts +5 -2
  35. package/src/api-client/yield-curves.ts +17 -0
  36. package/src/app/command-bar-intro.ts +38 -0
  37. package/src/app/keybindings/actions.ts +1 -1
  38. package/src/app/pane-runtime/pane-template-runtime.ts +35 -7
  39. package/src/app/pane-runtime/plugin-bindings.ts +4 -0
  40. package/src/app/pane-runtime/ticker-open-runtime.ts +4 -14
  41. package/src/app/pane-runtime/ticker-open-target.ts +31 -0
  42. package/src/app/runtime/desktop-deeplink.ts +3 -4
  43. package/src/app/runtime/plugin-bindings.ts +3 -2
  44. package/src/app/runtime/startup.ts +3 -4
  45. package/src/app/runtime/ticker-refresh.ts +13 -12
  46. package/src/app/runtime/update.ts +3 -2
  47. package/src/architecture/core-builtin-allowlist.json +0 -3
  48. package/src/architecture/silent-catch-allowlist.json +3 -0
  49. package/src/architecture/ui-literals-allowlist.json +186 -0
  50. package/src/architecture/ui-tokens-allowlist.json +40 -0
  51. package/src/ask-gloom/pane-context.ts +3 -1
  52. package/src/brokers/signed-in/catalog.ts +2 -1
  53. package/src/brokers/signed-in/client.ts +7 -2
  54. package/src/brokers/signed-in/sign-in-dialog.tsx +120 -26
  55. package/src/brokers/signed-in/sign-in.ts +22 -20
  56. package/src/brokers/sync-broker-instance.ts +2 -1
  57. package/src/capabilities/chart-series.ts +2 -0
  58. package/src/capabilities/registry.ts +1 -3
  59. package/src/cli/bank-section.ts +147 -0
  60. package/src/cli/base-converter.ts +5 -2
  61. package/src/cli/board-coins.ts +70 -0
  62. package/src/cli/commands/fred-series.ts +90 -0
  63. package/src/cli/commands/market.ts +340 -69
  64. package/src/cli/commands/news-search.ts +35 -2
  65. package/src/cli/commands/options-chain.ts +7 -5
  66. package/src/cli/commands/options-leaps.ts +3 -3
  67. package/src/cli/commands/overview.ts +78 -29
  68. package/src/cli/commands/plugins.ts +1 -0
  69. package/src/cli/commands/search.ts +87 -24
  70. package/src/cli/commands/system.ts +5 -2
  71. package/src/cli/commands/ticker.ts +337 -60
  72. package/src/cli/context.ts +2 -1
  73. package/src/cli/desktop-pane-shot.ts +11 -3
  74. package/src/cli/earnings-calendar.ts +2 -1
  75. package/src/cli/errors.ts +10 -0
  76. package/src/cli/export-source.ts +18 -3
  77. package/src/cli/glossary.ts +196 -14
  78. package/src/cli/history-rows.ts +60 -9
  79. package/src/cli/index-roots.ts +26 -0
  80. package/src/cli/index.ts +34 -9
  81. package/src/cli/known-gaps.ts +156 -22
  82. package/src/cli/listing-arg.ts +156 -12
  83. package/src/cli/listing-suggestion.ts +4 -2
  84. package/src/cli/name-entries.ts +76 -0
  85. package/src/cli/not-a-ticker.ts +15 -6
  86. package/src/cli/pane-functions/access-gate.ts +22 -0
  87. package/src/cli/pane-functions/capabilities.ts +62 -4
  88. package/src/cli/pane-functions/catalog.ts +94 -39
  89. package/src/cli/pane-functions/data.ts +6 -5
  90. package/src/cli/pane-functions/discovery.ts +1 -1
  91. package/src/cli/pane-functions/dom.ts +3 -3
  92. package/src/cli/pane-functions/freshness.ts +49 -8
  93. package/src/cli/pane-functions/function-help.ts +13 -10
  94. package/src/cli/pane-functions/headless.ts +177 -42
  95. package/src/cli/pane-functions/index.ts +64 -8
  96. package/src/cli/pane-functions/options.ts +17 -3
  97. package/src/cli/pane-functions/report-notices.ts +17 -3
  98. package/src/cli/pane-functions/resolver.ts +48 -13
  99. package/src/cli/pane-functions/screenshot.ts +124 -23
  100. package/src/cli/pane-functions/shot-options.ts +68 -0
  101. package/src/cli/perpetual-contract.ts +3 -1
  102. package/src/cli/report-tables.ts +10 -2
  103. package/src/cli/staged-tickers.ts +5 -0
  104. package/src/cli/statement-filings.ts +261 -0
  105. package/src/cli/symbol-args.ts +47 -8
  106. package/src/cli/symbol-list.ts +9 -2
  107. package/src/cli/symbol-rows.ts +269 -29
  108. package/src/cli/ticker-resolution.ts +148 -34
  109. package/src/cli/treasury-yields.ts +86 -0
  110. package/src/cli/types.ts +3 -0
  111. package/src/cli/uncovered-instrument.ts +20 -0
  112. package/src/components/chart/composite/axis-overlays.tsx +16 -9
  113. package/src/components/chart/composite/composite-chart.tsx +85 -6
  114. package/src/components/chart/composite/downsample.ts +19 -3
  115. package/src/components/chart/composite/format.ts +3 -0
  116. package/src/components/chart/composite/legend.tsx +155 -76
  117. package/src/components/chart/composite/panel-bitmap.ts +8 -2
  118. package/src/components/chart/composite/panel-surface.tsx +3 -3
  119. package/src/components/chart/composite/toolbar.tsx +12 -7
  120. package/src/components/chart/composite/types.ts +6 -0
  121. package/src/components/chart/composite/use-composite-chart-keyboard.ts +28 -1
  122. package/src/components/chart/curve/curve-surface.tsx +1 -1
  123. package/src/components/chart/static/series.ts +39 -0
  124. package/src/components/chart/static/trail-chart-surface.tsx +2 -1
  125. package/src/components/command-bar/commands/collection-list.ts +45 -15
  126. package/src/components/command-bar/commands/collection.ts +10 -3
  127. package/src/components/command-bar/commands/registry.ts +2 -2
  128. package/src/components/command-bar/list/badge.ts +4 -3
  129. package/src/components/command-bar/list/model.ts +5 -0
  130. package/src/components/command-bar/list/view.tsx +1 -1
  131. package/src/components/command-bar/panel/index.tsx +19 -8
  132. package/src/components/command-bar/panel/native-surface.ts +6 -4
  133. package/src/components/command-bar/panel/prompt-example.ts +22 -0
  134. package/src/components/command-bar/routes/root/provider-search.ts +3 -9
  135. package/src/components/command-bar/routes/root/results.ts +13 -0
  136. package/src/components/command-bar/routes/root/start-here.ts +90 -0
  137. package/src/components/command-bar/routes/ticker-search/results.ts +42 -3
  138. package/src/components/command-bar/routes/ticker-search/route.ts +3 -10
  139. package/src/components/command-bar/theme-picker.tsx +3 -1
  140. package/src/components/command-bar/workflow/builtin.ts +5 -1
  141. package/src/components/command-bar/workflow/collection-actions.ts +21 -12
  142. package/src/components/command-bar/workflow/ops.ts +21 -1
  143. package/src/{plugins/builtin/portfolio-list/command-bar.ts → components/command-bar/workflow/portfolio-position.ts} +42 -9
  144. package/src/components/command-bar/workflow/tickers.ts +6 -4
  145. package/src/components/feedback-dialog.tsx +1 -1
  146. package/src/components/form-modal/broker-step.tsx +7 -63
  147. package/src/components/form-modal/content.tsx +7 -2
  148. package/src/components/form-modal/field-row.tsx +6 -8
  149. package/src/components/form-modal/host.tsx +3 -3
  150. package/src/components/form-modal/model.ts +3 -0
  151. package/src/components/form-modal/routes.ts +17 -2
  152. package/src/components/index.ts +6 -6
  153. package/src/components/input-search-bar.tsx +43 -6
  154. package/src/components/layout/detached-pane-shell.tsx +0 -1
  155. package/src/components/layout/floating-pane.tsx +0 -1
  156. package/src/components/layout/header.tsx +8 -7
  157. package/src/components/layout/pane/footer/index.tsx +7 -4
  158. package/src/components/layout/pane/footer/model.ts +28 -2
  159. package/src/components/layout/pane/header.tsx +9 -19
  160. package/src/components/layout/pane/index.tsx +0 -1
  161. package/src/components/layout/pane/instrument-coverage-gate.tsx +57 -0
  162. package/src/components/layout/pane/pane-tabs.tsx +4 -3
  163. package/src/components/layout/pane/sizing.ts +9 -0
  164. package/src/components/layout/pane/ticker-fate-gate.tsx +8 -2
  165. package/src/components/layout/shell/pane/capture.ts +44 -20
  166. package/src/components/layout/status-bar.tsx +3 -6
  167. package/src/components/markdown-text.tsx +17 -2
  168. package/src/components/market-board/index.tsx +19 -8
  169. package/src/components/metric-treemap/heat-surface.tsx +2 -7
  170. package/src/components/onboarding/account-step/qr-panel.tsx +5 -2
  171. package/src/components/onboarding/onboarding-frame.tsx +24 -21
  172. package/src/components/onboarding/portfolio-step/positions-panel.tsx +20 -10
  173. package/src/components/onboarding/wizard-positions.ts +40 -11
  174. package/src/components/pane-settings-dialog/desktop.tsx +12 -50
  175. package/src/components/pane-settings-dialog/field-dialogs.tsx +1 -1
  176. package/src/components/price-performance.tsx +18 -2
  177. package/src/components/reader/article-reader.tsx +11 -10
  178. package/src/components/reader/detail-reader.tsx +9 -5
  179. package/src/components/reader/reader-text.tsx +51 -24
  180. package/src/components/sign-in-code-panel.tsx +129 -75
  181. package/src/components/ticker/badge/index.tsx +2 -1
  182. package/src/components/ui/action-row.tsx +5 -2
  183. package/src/components/ui/audio-player.tsx +70 -0
  184. package/src/components/ui/card.tsx +75 -0
  185. package/src/components/ui/data-table/index.tsx +4 -2
  186. package/src/components/ui/data-table/types.ts +11 -0
  187. package/src/components/ui/detail-scroll-body.tsx +1 -1
  188. package/src/components/ui/dialog-actions.tsx +1 -21
  189. package/src/components/ui/display.tsx +13 -5
  190. package/src/components/ui/external-link.tsx +4 -2
  191. package/src/components/ui/fields.tsx +12 -0
  192. package/src/components/ui/figure.tsx +5 -3
  193. package/src/components/ui/frame.tsx +40 -6
  194. package/src/components/ui/icon.tsx +4 -0
  195. package/src/components/ui/index.ts +4 -1
  196. package/src/components/ui/list-view.tsx +8 -0
  197. package/src/components/ui/prose.tsx +97 -25
  198. package/src/components/ui/query-bar-keys.tsx +3 -1
  199. package/src/components/ui/query-bar.tsx +6 -0
  200. package/src/components/ui/quote.ts +42 -0
  201. package/src/components/ui/range-track.tsx +15 -2
  202. package/src/components/ui/reveal-in-scroll-box.ts +21 -3
  203. package/src/components/ui/select-button.tsx +38 -3
  204. package/src/components/ui/status.tsx +73 -4
  205. package/src/components/ui/table-layout.ts +20 -0
  206. package/src/components/use-pinned-moment.ts +19 -0
  207. package/src/core/app-runtime.ts +2 -2
  208. package/src/core/state/app/instrument.ts +18 -1
  209. package/src/core/state/app/layout.ts +6 -0
  210. package/src/core/state/app/state.ts +14 -2
  211. package/src/data/cached-query.ts +1 -1
  212. package/src/data/config/chart-settings.ts +3 -1
  213. package/src/data/config/home.ts +4 -1
  214. package/src/data/config/store/node.ts +9 -4
  215. package/src/data/config/store/normalize.ts +9 -0
  216. package/src/data/json-storage.ts +6 -3
  217. package/src/data/json-ticker-repository.ts +3 -1
  218. package/src/data/plugin-cache.ts +5 -1
  219. package/src/data/sqlite/json.ts +3 -1
  220. package/src/data/ticker-repository.ts +5 -2
  221. package/src/feedback/diagnostics.ts +2 -6
  222. package/src/i18n/es.ts +86 -6
  223. package/src/i18n/index.ts +3 -9
  224. package/src/i18n/ja.ts +86 -6
  225. package/src/i18n/ko.ts +86 -6
  226. package/src/i18n/zh-cn.ts +86 -6
  227. package/src/i18n/zh-tw.ts +86 -6
  228. package/src/layout-marketplace/gallery-desktop.tsx +8 -4
  229. package/src/market-data/bars-per-year.ts +43 -0
  230. package/src/market-data/bond-funds.ts +85 -0
  231. package/src/market-data/coordinator/auxiliary.ts +5 -2
  232. package/src/market-data/coordinator/index.ts +6 -5
  233. package/src/market-data/futures-contract.ts +102 -5
  234. package/src/market-data/hooks.tsx +20 -11
  235. package/src/market-data/market/bar-period.ts +36 -0
  236. package/src/market-data/market/format.ts +5 -13
  237. package/src/market-data/market/freshness.ts +1 -3
  238. package/src/market-data/market/index-level.ts +51 -0
  239. package/src/market-data/model-dividend-yield.ts +57 -16
  240. package/src/market-data/quotes/live-valuation.ts +48 -2
  241. package/src/market-data/realized-volatility.ts +16 -7
  242. package/src/market-data/tax-equivalent.ts +344 -0
  243. package/src/news/aggregator.ts +4 -2
  244. package/src/notifications/notification-log.ts +5 -3
  245. package/src/plugins/auto-update-node.ts +1 -0
  246. package/src/plugins/builtin/account-management/footer.ts +1 -1
  247. package/src/plugins/builtin/account-management/keyboard.ts +3 -0
  248. package/src/plugins/builtin/account-management/model.ts +1 -0
  249. package/src/plugins/builtin/account-management/pane.tsx +71 -19
  250. package/src/plugins/builtin/account-management/trial-cancel.ts +40 -0
  251. package/src/plugins/builtin/alerts/cli.ts +7 -18
  252. package/src/plugins/builtin/alerts/constants.ts +8 -0
  253. package/src/plugins/builtin/alerts/event-rows.ts +16 -0
  254. package/src/plugins/builtin/alerts/events-pane.tsx +2 -14
  255. package/src/plugins/builtin/alerts/headless.ts +182 -0
  256. package/src/plugins/builtin/alerts/index.tsx +3 -0
  257. package/src/plugins/builtin/alerts/pane.tsx +1 -7
  258. package/src/plugins/builtin/alerts/storage.ts +17 -1
  259. package/src/plugins/builtin/analytics/index.tsx +6 -1
  260. package/src/plugins/builtin/analytics/metrics.ts +47 -9
  261. package/src/plugins/builtin/analytics/risk-headless.ts +14 -2
  262. package/src/plugins/builtin/analytics/risk-math.ts +83 -0
  263. package/src/plugins/builtin/analytics/risk-model.ts +97 -4
  264. package/src/plugins/builtin/analytics/risk-pane.tsx +11 -6
  265. package/src/plugins/builtin/analytics/sector-model.ts +14 -3
  266. package/src/plugins/builtin/awards/headless.ts +6 -5
  267. package/src/plugins/builtin/awards/index.tsx +1 -1
  268. package/src/plugins/builtin/backtest/client.ts +38 -8
  269. package/src/plugins/builtin/backtest/engine.ts +25 -13
  270. package/src/plugins/builtin/backtest/export.ts +27 -0
  271. package/src/plugins/builtin/backtest/format.ts +19 -3
  272. package/src/plugins/builtin/backtest/headless.ts +42 -28
  273. package/src/plugins/builtin/backtest/index.tsx +3 -0
  274. package/src/plugins/builtin/backtest/pane.tsx +39 -10
  275. package/src/plugins/builtin/backtest/report.ts +160 -0
  276. package/src/plugins/builtin/backtest/rules.ts +2 -0
  277. package/src/plugins/builtin/backtest/window.ts +112 -0
  278. package/src/plugins/builtin/bond-calculator/headless.ts +3 -2
  279. package/src/plugins/builtin/broker-manager/add-flow.tsx +4 -4
  280. package/src/plugins/builtin/catalysts/headless.ts +24 -13
  281. package/src/plugins/builtin/catalysts/index.tsx +4 -2
  282. package/src/plugins/builtin/catalysts/model.ts +18 -1
  283. package/src/plugins/builtin/catalysts/pane.tsx +2 -2
  284. package/src/plugins/builtin/cds/client.ts +28 -5
  285. package/src/plugins/builtin/cds/headless.ts +183 -31
  286. package/src/plugins/builtin/cds/index.tsx +1 -1
  287. package/src/plugins/builtin/cds/model.ts +229 -53
  288. package/src/plugins/builtin/cds/pane.tsx +82 -26
  289. package/src/plugins/builtin/central-bank-rates/headless.ts +1 -1
  290. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +39 -1
  291. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +77 -0
  292. package/src/plugins/builtin/chart-composer/chart-spec.ts +15 -0
  293. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +22 -2
  294. package/src/plugins/builtin/chart-composer/editor/desktop-view.tsx +2 -2
  295. package/src/plugins/builtin/chart-composer/headless-schema.ts +10 -2
  296. package/src/plugins/builtin/chart-composer/headless.ts +99 -21
  297. package/src/plugins/builtin/chart-composer/index.tsx +70 -13
  298. package/src/plugins/builtin/chart-composer/pane.tsx +65 -15
  299. package/src/plugins/builtin/chart-composer/presets.ts +79 -11
  300. package/src/plugins/builtin/chart-composer/series-catalog.ts +50 -14
  301. package/src/plugins/builtin/chart-composer/series-expression.ts +9 -7
  302. package/src/plugins/builtin/chart-composer/series-listings.ts +178 -0
  303. package/src/plugins/builtin/chart-composer/session-range.ts +87 -0
  304. package/src/plugins/builtin/chat/attachments/desktop.tsx +4 -1
  305. package/src/plugins/builtin/chat/content/composer-runtime.ts +49 -14
  306. package/src/plugins/builtin/chat/content/composer.tsx +22 -1
  307. package/src/plugins/builtin/chat/content/index.tsx +35 -5
  308. package/src/plugins/builtin/chat/content/layout-metrics.ts +3 -0
  309. package/src/plugins/builtin/chat/content/shortcuts.ts +32 -13
  310. package/src/plugins/builtin/chat/content/snapshot.ts +29 -6
  311. package/src/plugins/builtin/chat/ghost-user.ts +11 -3
  312. package/src/plugins/builtin/chat/layout.ts +2 -0
  313. package/src/plugins/builtin/chat/message/desktop.tsx +13 -5
  314. package/src/plugins/builtin/chat/message/header.tsx +26 -4
  315. package/src/plugins/builtin/chat/message/pane-chip.tsx +131 -35
  316. package/src/plugins/builtin/chat/message/render-state.ts +28 -1
  317. package/src/plugins/builtin/chat/message/terminal.tsx +9 -3
  318. package/src/plugins/builtin/chat/pane-links/composer.ts +87 -0
  319. package/src/plugins/builtin/chat/pane-links/model.ts +1 -1
  320. package/src/plugins/builtin/chat/share/flow.tsx +9 -73
  321. package/src/plugins/builtin/cloud/askg/controller.ts +5 -3
  322. package/src/plugins/builtin/cloud/askg/executor.ts +3 -1
  323. package/src/plugins/builtin/cloud/askg/lock-note.ts +16 -0
  324. package/src/plugins/builtin/cloud/askg/pane.tsx +6 -2
  325. package/src/plugins/builtin/cloud/auth-actions.tsx +4 -2
  326. package/src/plugins/builtin/cloud/company-picker.tsx +21 -26
  327. package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +5 -3
  328. package/src/plugins/builtin/cloud/plugin.tsx +2 -0
  329. package/src/plugins/builtin/cloud/team/module.tsx +5 -1
  330. package/src/plugins/builtin/cloud/team/pane.tsx +11 -4
  331. package/src/plugins/builtin/cloud/team/views.ts +11 -4
  332. package/src/plugins/builtin/cloud/terminal-relay/engine.ts +9 -4
  333. package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +3 -2
  334. package/src/plugins/builtin/cloud/thesis/detail.tsx +2 -1
  335. package/src/plugins/builtin/cloud/thesis/exposure.ts +3 -0
  336. package/src/plugins/builtin/cloud/thesis/prompts.tsx +3 -2
  337. package/src/plugins/builtin/cloud/thesis/ticker-tab.tsx +2 -1
  338. package/src/plugins/builtin/cloud/trial-offer-status-widget.tsx +2 -1
  339. package/src/plugins/builtin/cloud/verification-status-widget.tsx +2 -1
  340. package/src/plugins/builtin/commodities-energy/index.tsx +8 -5
  341. package/src/plugins/builtin/commodities-energy/view-state.ts +11 -0
  342. package/src/plugins/builtin/company-attention/headless.ts +15 -7
  343. package/src/plugins/builtin/company-attention/index.tsx +1 -1
  344. package/src/plugins/builtin/company-attention/model.ts +49 -4
  345. package/src/plugins/builtin/company-attention/pane.tsx +11 -9
  346. package/src/plugins/builtin/company-kpis/headless.ts +4 -3
  347. package/src/plugins/builtin/company-kpis/index.tsx +2 -2
  348. package/src/plugins/builtin/company-kpis/pane.tsx +9 -3
  349. package/src/plugins/builtin/congress-trades/headless.ts +23 -2
  350. package/src/plugins/builtin/correlation/relationship/pane.tsx +18 -46
  351. package/src/plugins/builtin/cot/headless.ts +5 -2
  352. package/src/plugins/builtin/credit-boards/cdx-pane.tsx +41 -13
  353. package/src/plugins/builtin/credit-boards/client.ts +9 -2
  354. package/src/plugins/builtin/credit-boards/headless.ts +93 -27
  355. package/src/plugins/builtin/credit-boards/index.tsx +15 -4
  356. package/src/plugins/builtin/credit-boards/model.ts +105 -6
  357. package/src/plugins/builtin/credit-boards/sovr-pane.tsx +14 -3
  358. package/src/plugins/builtin/credit-documents/detail.tsx +2 -1
  359. package/src/plugins/builtin/credit-documents/index.tsx +3 -0
  360. package/src/plugins/builtin/credit-documents/model.ts +3 -10
  361. package/src/plugins/builtin/crypto-board/client.ts +152 -2
  362. package/src/plugins/builtin/crypto-board/headless.ts +138 -19
  363. package/src/plugins/builtin/crypto-board/index.tsx +5 -3
  364. package/src/plugins/builtin/crypto-board/model.ts +210 -12
  365. package/src/plugins/builtin/crypto-board/pane.tsx +148 -9
  366. package/src/plugins/builtin/crypto-board/series.ts +52 -1
  367. package/src/plugins/builtin/crypto-board/supply.ts +123 -0
  368. package/src/plugins/builtin/debt-maturities/client.ts +54 -1
  369. package/src/plugins/builtin/debt-maturities/headless.ts +27 -3
  370. package/src/plugins/builtin/debt-maturities/index.tsx +2 -0
  371. package/src/plugins/builtin/debt-maturities/model.ts +58 -13
  372. package/src/plugins/builtin/debt-maturities/pane.tsx +47 -7
  373. package/src/plugins/builtin/dividend-yield/client.ts +42 -36
  374. package/src/plugins/builtin/dividend-yield/headless.ts +113 -18
  375. package/src/plugins/builtin/dividend-yield/index.tsx +5 -2
  376. package/src/plugins/builtin/dividend-yield/pane.tsx +37 -13
  377. package/src/plugins/builtin/dividend-yield/provider-client.ts +7 -3
  378. package/src/plugins/builtin/dividend-yield/ranking.ts +187 -0
  379. package/src/plugins/builtin/dividend-yield/reference-price.ts +28 -5
  380. package/src/plugins/builtin/dividend-yield/types.ts +6 -1
  381. package/src/plugins/builtin/dividend-yield/view.ts +1 -1
  382. package/src/plugins/builtin/docs/blocks.tsx +54 -8
  383. package/src/plugins/builtin/docs/pane.tsx +8 -13
  384. package/src/plugins/builtin/earnings/headless.ts +3 -2
  385. package/src/plugins/builtin/earnings-calls/data.ts +51 -0
  386. package/src/plugins/builtin/earnings-calls/headless.ts +7 -0
  387. package/src/plugins/builtin/earnings-calls/index.tsx +1 -0
  388. package/src/plugins/builtin/earnings-calls/model.ts +97 -0
  389. package/src/plugins/builtin/earnings-calls/pane.tsx +107 -7
  390. package/src/plugins/builtin/earnings-calls/transcript-view.tsx +140 -22
  391. package/src/plugins/builtin/earnings-calls/use-call-playback.ts +194 -0
  392. package/src/plugins/builtin/econ/calendar-model.ts +22 -0
  393. package/src/plugins/builtin/econ/calendar-source.ts +35 -0
  394. package/src/plugins/builtin/econ/index.tsx +40 -8
  395. package/src/plugins/builtin/econ-statistics/defs.ts +7 -0
  396. package/src/plugins/builtin/econ-statistics/detail.tsx +8 -1
  397. package/src/plugins/builtin/econ-statistics/headless.ts +26 -5
  398. package/src/plugins/builtin/econ-statistics/pane.tsx +4 -2
  399. package/src/plugins/builtin/econ-statistics/stats.ts +10 -0
  400. package/src/plugins/builtin/econ-statistics/view.ts +19 -0
  401. package/src/plugins/builtin/equity-screener/client.ts +1 -1
  402. package/src/plugins/builtin/equity-screener/model.ts +46 -4
  403. package/src/plugins/builtin/equity-screener/pane.tsx +3 -0
  404. package/src/plugins/builtin/estimate-revisions/client.ts +32 -22
  405. package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
  406. package/src/plugins/builtin/estimate-revisions/index.tsx +1 -0
  407. package/src/plugins/builtin/estimate-revisions/pane.tsx +5 -3
  408. package/src/plugins/builtin/executives/index.tsx +1 -0
  409. package/src/plugins/builtin/exposure/editor.tsx +3 -3
  410. package/src/plugins/builtin/fear-greed/index.tsx +9 -0
  411. package/src/plugins/builtin/filing-events/index.tsx +1 -0
  412. package/src/plugins/builtin/futures/index.tsx +2 -2
  413. package/src/plugins/builtin/futures/model.ts +34 -21
  414. package/src/plugins/builtin/futures/table.tsx +1 -1
  415. package/src/plugins/builtin/futures/use-board-terms.ts +2 -2
  416. package/src/plugins/builtin/futures-curve/headless.ts +4 -2
  417. package/src/plugins/builtin/futures-curve/model.ts +5 -7
  418. package/src/plugins/builtin/help/index.tsx +55 -8
  419. package/src/plugins/builtin/help/shortcut-table.tsx +15 -2
  420. package/src/plugins/builtin/holders/headless.ts +12 -0
  421. package/src/plugins/builtin/insider/headless.ts +311 -41
  422. package/src/plugins/builtin/insider/index.tsx +280 -106
  423. package/src/plugins/builtin/insider/insiders.tsx +224 -0
  424. package/src/plugins/builtin/insider/signals-cells.tsx +52 -0
  425. package/src/plugins/builtin/insider/signals-client.ts +135 -11
  426. package/src/plugins/builtin/insider/signals-model.ts +628 -56
  427. package/src/plugins/builtin/insider/signals.tsx +283 -83
  428. package/src/plugins/builtin/ipo-calendar/headless.ts +17 -7
  429. package/src/plugins/builtin/ipo-calendar/index.tsx +23 -3
  430. package/src/plugins/builtin/ipo-calendar/model.ts +84 -36
  431. package/src/plugins/builtin/ipo-calendar/pane.tsx +20 -8
  432. package/src/plugins/builtin/iv-history/headless.ts +2 -0
  433. package/src/plugins/builtin/jobs/headless.ts +1 -0
  434. package/src/plugins/builtin/jobs/index.tsx +1 -0
  435. package/src/plugins/builtin/jodi/headless.ts +2 -0
  436. package/src/plugins/builtin/kelly-sizer/pane.tsx +1 -1
  437. package/src/plugins/builtin/kelly-sizer/portfolio.ts +1 -1
  438. package/src/plugins/builtin/market-heatmap/headless.ts +1 -0
  439. package/src/plugins/builtin/market-heatmap/portfolio.ts +3 -1
  440. package/src/plugins/builtin/market-valuation/pane.tsx +1 -1
  441. package/src/plugins/builtin/market-valuation/zone-scale/desktop.tsx +31 -57
  442. package/src/plugins/builtin/mna/distress/headless.ts +2 -1
  443. package/src/plugins/builtin/mna/headless.ts +14 -2
  444. package/src/plugins/builtin/mna/index.tsx +1 -0
  445. package/src/plugins/builtin/news/headless.ts +4 -0
  446. package/src/plugins/builtin/news/wire/news/footer.ts +5 -3
  447. package/src/plugins/builtin/news/wire/news/table.tsx +57 -11
  448. package/src/plugins/builtin/notes/cli.ts +8 -4
  449. package/src/plugins/builtin/notes/files.ts +66 -20
  450. package/src/plugins/builtin/notes/migration.ts +18 -6
  451. package/src/plugins/builtin/notes/owner.tsx +3 -2
  452. package/src/plugins/builtin/notes/quick-notes-pane.tsx +3 -2
  453. package/src/plugins/builtin/options-scenario/client.ts +7 -4
  454. package/src/plugins/builtin/options-scenario/headless.ts +5 -3
  455. package/src/plugins/builtin/pe-band/index.tsx +1 -1
  456. package/src/plugins/builtin/pe-band/model.ts +1 -15
  457. package/src/plugins/builtin/perps/headless.ts +30 -13
  458. package/src/plugins/builtin/perps/model.ts +45 -3
  459. package/src/plugins/builtin/perps/pane.tsx +7 -7
  460. package/src/plugins/builtin/portfolio-list/cell-version.ts +10 -4
  461. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +128 -14
  462. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +108 -46
  463. package/src/plugins/builtin/portfolio-list/cli/render.ts +368 -45
  464. package/src/plugins/builtin/portfolio-list/cli/shared.ts +8 -2
  465. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +24 -34
  466. package/src/plugins/builtin/portfolio-list/grid.tsx +3 -1
  467. package/src/plugins/builtin/portfolio-list/headless.ts +151 -29
  468. package/src/plugins/builtin/portfolio-list/income.ts +296 -0
  469. package/src/plugins/builtin/portfolio-list/metrics.ts +2 -2
  470. package/src/plugins/builtin/portfolio-list/pane/futures-terms.ts +58 -0
  471. package/src/plugins/builtin/portfolio-list/pane/index.tsx +27 -10
  472. package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +47 -28
  473. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +3 -2
  474. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +10 -3
  475. package/src/plugins/builtin/portfolio-list/summary/index.tsx +26 -4
  476. package/src/plugins/builtin/portfolio-list/summary/totals.ts +31 -3
  477. package/src/plugins/builtin/portfolio-list/table.tsx +25 -5
  478. package/src/plugins/builtin/power/prices-headless.ts +2 -1
  479. package/src/plugins/builtin/realized-vol/chart-model.ts +29 -5
  480. package/src/plugins/builtin/realized-vol/charts.tsx +14 -8
  481. package/src/plugins/builtin/realized-vol/evidence.ts +2 -0
  482. package/src/plugins/builtin/realized-vol/headless.ts +6 -4
  483. package/src/plugins/builtin/realized-vol/model.ts +5 -1
  484. package/src/plugins/builtin/realized-vol/pane.tsx +31 -11
  485. package/src/plugins/builtin/realized-vol/settings.ts +1 -1
  486. package/src/plugins/builtin/research/analyst-headless.ts +4 -0
  487. package/src/plugins/builtin/research/corporate-actions-pane.tsx +2 -0
  488. package/src/plugins/builtin/research/event-model.ts +22 -2
  489. package/src/plugins/builtin/research/headless-schema.ts +1 -0
  490. package/src/plugins/builtin/research/headless.ts +3 -0
  491. package/src/plugins/builtin/research/index.tsx +3 -0
  492. package/src/plugins/builtin/research/relative-valuation-columns.ts +27 -5
  493. package/src/plugins/builtin/research/relative-valuation-headless.ts +2 -0
  494. package/src/plugins/builtin/revenue-breakdown/index.tsx +1 -0
  495. package/src/plugins/builtin/reverse-dcf/headless.ts +9 -6
  496. package/src/plugins/builtin/reverse-dcf/index.tsx +2 -2
  497. package/src/plugins/builtin/reverse-dcf/model.ts +51 -4
  498. package/src/plugins/builtin/reverse-dcf/pane.tsx +23 -10
  499. package/src/plugins/builtin/risk-factors/headless.ts +7 -0
  500. package/src/plugins/builtin/risk-factors/index.tsx +1 -0
  501. package/src/plugins/builtin/scanner/feed.ts +5 -3
  502. package/src/plugins/builtin/scanner/headless.ts +9 -57
  503. package/src/plugins/builtin/scanner/index.ts +1 -2
  504. package/src/plugins/builtin/sec/forms.ts +2 -6
  505. package/src/plugins/builtin/sec/fund-facts-view.tsx +53 -0
  506. package/src/plugins/builtin/sec/fund-facts.ts +328 -0
  507. package/src/plugins/builtin/sec/headless.ts +140 -44
  508. package/src/plugins/builtin/sec/index.tsx +95 -30
  509. package/src/plugins/builtin/sec/model.ts +2 -44
  510. package/src/plugins/builtin/shared/headless-options.ts +10 -0
  511. package/src/plugins/builtin/shared/locked-rows.tsx +3 -1
  512. package/src/plugins/builtin/shared/move-rank.ts +108 -0
  513. package/src/plugins/builtin/shared/report-freshness.ts +25 -9
  514. package/src/plugins/builtin/shared/scanner-capture.ts +95 -0
  515. package/src/plugins/builtin/shared/treasury-cutoffs.ts +15 -0
  516. package/src/plugins/builtin/shared/use-quote-board.ts +1 -0
  517. package/src/plugins/builtin/shared/volatility/live-session.ts +34 -0
  518. package/src/plugins/builtin/shared/volatility-indices.ts +32 -0
  519. package/src/plugins/builtin/short-interest/headless.ts +3 -0
  520. package/src/plugins/builtin/short-interest/watch-model.ts +2 -2
  521. package/src/plugins/builtin/social-mentions/client.ts +8 -1
  522. package/src/plugins/builtin/social-mentions/pane.tsx +8 -6
  523. package/src/plugins/builtin/supply-chain/client.ts +12 -3
  524. package/src/plugins/builtin/supply-chain/disclosure-quote.tsx +9 -5
  525. package/src/plugins/builtin/supply-chain/evidence.ts +3 -1
  526. package/src/plugins/builtin/supply-chain/flow-layout.ts +2 -1
  527. package/src/plugins/builtin/supply-chain/flow.tsx +23 -16
  528. package/src/plugins/builtin/supply-chain/graph-client.ts +8 -5
  529. package/src/plugins/builtin/supply-chain/graph-evidence.ts +1 -1
  530. package/src/plugins/builtin/supply-chain/graph-model.ts +10 -2
  531. package/src/plugins/builtin/supply-chain/graph-pane.tsx +9 -7
  532. package/src/plugins/builtin/supply-chain/graph.tsx +8 -6
  533. package/src/plugins/builtin/supply-chain/headless.ts +69 -27
  534. package/src/plugins/builtin/supply-chain/index.tsx +1 -1
  535. package/src/plugins/builtin/supply-chain/model.ts +76 -15
  536. package/src/plugins/builtin/supply-chain/pane.tsx +29 -15
  537. package/src/plugins/builtin/supply-chain/row-evidence.tsx +5 -4
  538. package/src/plugins/builtin/themes/model.ts +2 -5
  539. package/src/plugins/builtin/thirteenf/api.ts +50 -2
  540. package/src/plugins/builtin/thirteenf/data.ts +250 -11
  541. package/src/plugins/builtin/thirteenf/headless.ts +311 -28
  542. package/src/plugins/builtin/thirteenf/index.tsx +4 -1
  543. package/src/plugins/builtin/thirteenf/model.ts +244 -19
  544. package/src/plugins/builtin/thirteenf/overlap-pane.tsx +133 -33
  545. package/src/plugins/builtin/thirteenf/overlap.ts +1 -1
  546. package/src/plugins/builtin/thirteenf/pane.tsx +24 -5
  547. package/src/plugins/builtin/thirteenf/report-notes.ts +78 -0
  548. package/src/plugins/builtin/thirteenf/types.ts +49 -0
  549. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +22 -8
  550. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +17 -1
  551. package/src/plugins/builtin/ticker-detail/financials/model.ts +2 -42
  552. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +1 -1
  553. package/src/plugins/builtin/ticker-detail/headless.ts +23 -10
  554. package/src/plugins/builtin/ticker-detail/overview/components.tsx +27 -3
  555. package/src/plugins/builtin/ticker-detail/overview/dividend.ts +60 -0
  556. package/src/plugins/builtin/ticker-detail/overview/model.ts +46 -9
  557. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +3 -0
  558. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +36 -3
  559. package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +18 -19
  560. package/src/plugins/builtin/time-sales/client.ts +7 -4
  561. package/src/plugins/builtin/time-sales/headless.ts +71 -22
  562. package/src/plugins/builtin/time-sales/model.ts +12 -0
  563. package/src/plugins/builtin/time-sales/pane.tsx +31 -7
  564. package/src/plugins/builtin/time-sales/window.ts +128 -0
  565. package/src/plugins/builtin/trace-bonds/client.ts +351 -33
  566. package/src/plugins/builtin/trace-bonds/headless.ts +60 -22
  567. package/src/plugins/builtin/trace-bonds/index.tsx +4 -2
  568. package/src/plugins/builtin/trace-bonds/model.ts +27 -25
  569. package/src/plugins/builtin/trace-bonds/pane.tsx +63 -45
  570. package/src/plugins/builtin/treasury-auctions/cache.ts +61 -15
  571. package/src/plugins/builtin/treasury-auctions/client.ts +45 -10
  572. package/src/plugins/builtin/treasury-auctions/headless.ts +35 -13
  573. package/src/plugins/builtin/treasury-auctions/index.tsx +5 -2
  574. package/src/plugins/builtin/treasury-auctions/model.ts +20 -16
  575. package/src/plugins/builtin/treasury-auctions/pane.tsx +29 -12
  576. package/src/plugins/builtin/vol-surface/charts.tsx +2 -1
  577. package/src/plugins/builtin/vol-surface/headless.ts +3 -2
  578. package/src/plugins/builtin/vol-surface/pane.tsx +2 -1
  579. package/src/plugins/builtin/vol-surface/stored.ts +4 -7
  580. package/src/plugins/builtin/volatility/chart-model.ts +16 -15
  581. package/src/plugins/builtin/volatility/charts.tsx +5 -5
  582. package/src/plugins/builtin/volatility/client.ts +73 -2
  583. package/src/plugins/builtin/volatility/evidence.ts +13 -14
  584. package/src/plugins/builtin/volatility/headless.ts +13 -7
  585. package/src/plugins/builtin/volatility/index.tsx +1 -1
  586. package/src/plugins/builtin/volatility/model.ts +104 -38
  587. package/src/plugins/builtin/volatility/pane.tsx +42 -24
  588. package/src/plugins/builtin/volatility/series.ts +22 -13
  589. package/src/plugins/builtin/world-venue-map/geo-series.ts +9 -0
  590. package/src/plugins/builtin/world-venue-map/headless.ts +8 -5
  591. package/src/plugins/builtin/world-venue-map/index.ts +16 -2
  592. package/src/plugins/builtin/world-venue-map/map.tsx +13 -17
  593. package/src/plugins/builtin/yield-curve/curves.ts +29 -5
  594. package/src/plugins/builtin/yield-curve/headless.ts +41 -8
  595. package/src/plugins/builtin/yield-curve/history.ts +5 -5
  596. package/src/plugins/builtin/yield-curve/index.tsx +30 -13
  597. package/src/plugins/compat.ts +3 -1
  598. package/src/plugins/dependencies.ts +8 -2
  599. package/src/plugins/host-link.ts +12 -5
  600. package/src/plugins/installer.ts +16 -7
  601. package/src/plugins/loader.ts +9 -2
  602. package/src/plugins/marketplace/activation.ts +10 -4
  603. package/src/plugins/registry/host-actions.ts +3 -0
  604. package/src/plugins/registry/index.ts +3 -1
  605. package/src/{plugins/builtin/portfolio-list → portfolio}/allocation.ts +74 -12
  606. package/src/{plugins/builtin/portfolio-list → portfolio}/column-values.ts +140 -53
  607. package/src/portfolio/futures-positions.ts +213 -0
  608. package/src/portfolio/futures-terms.ts +75 -0
  609. package/src/portfolio/manual-lots.ts +78 -0
  610. package/src/portfolio/mutations.ts +54 -10
  611. package/src/portfolio/position-metrics.ts +44 -10
  612. package/src/portfolio/valuation-basis.ts +31 -4
  613. package/src/public/__snapshots__/public-api.test.ts.snap +4 -0
  614. package/src/public/time-series.ts +2 -1
  615. package/src/remote/confirm-change.tsx +2 -1
  616. package/src/remote/server.ts +1 -1
  617. package/src/remote/watchlist.ts +9 -1
  618. package/src/renderers/dom/data-table/row.tsx +1 -1
  619. package/src/renderers/dom/desktop/audio-player.tsx +312 -0
  620. package/src/renderers/dom/desktop/control-styles.ts +17 -82
  621. package/src/renderers/dom/desktop/controls.tsx +39 -63
  622. package/src/renderers/dom/desktop/dialog-actions.tsx +13 -53
  623. package/src/renderers/dom/desktop/icons.tsx +8 -0
  624. package/src/renderers/dom/desktop/list-view.tsx +6 -6
  625. package/src/renderers/dom/desktop/popover.tsx +0 -3
  626. package/src/renderers/dom/desktop/query-bar.tsx +6 -4
  627. package/src/renderers/dom/desktop/select-field.tsx +9 -8
  628. package/src/renderers/dom/desktop/stack-header.ts +3 -0
  629. package/src/renderers/dom/dom-ui-host.tsx +3 -2
  630. package/src/renderers/dom/host/chart-surface.tsx +3 -3
  631. package/src/renderers/dom/host/size-observer.ts +33 -4
  632. package/src/renderers/dom/host/surface-3d.tsx +3 -2
  633. package/src/renderers/dom/host/surface-fit.ts +4 -1
  634. package/src/renderers/dom/host/tabs.tsx +22 -132
  635. package/src/renderers/dom/styles.css +358 -160
  636. package/src/renderers/electrobun/bun/core-capabilities.ts +1 -1
  637. package/src/renderers/electrobun/bun/desktop/backend.ts +1 -1
  638. package/src/renderers/electrobun/bun/desktop/initialization.ts +1 -0
  639. package/src/renderers/electrobun/bun/desktop/state-broadcaster.ts +43 -1
  640. package/src/renderers/electrobun/bun/desktop/workspace/requests.ts +5 -1
  641. package/src/renderers/electrobun/shared/rpc-codec.ts +7 -0
  642. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +21 -17
  643. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +3 -3
  644. package/src/renderers/electrobun/view/desktop/window/bridge.ts +6 -8
  645. package/src/renderers/electrobun/view/desktop/window/snapshot.ts +18 -0
  646. package/src/series/capability.ts +1 -0
  647. package/src/series/files.ts +9 -3
  648. package/src/series/registry.ts +40 -14
  649. package/src/series/resolve.ts +121 -18
  650. package/src/series/standalone.ts +3 -2
  651. package/src/series/types.ts +55 -1
  652. package/src/series/validate.ts +39 -0
  653. package/src/shares/api.ts +26 -7
  654. package/src/shares/bug-report-dialog.tsx +2 -2
  655. package/src/shares/bug-report-flow.tsx +4 -7
  656. package/src/shares/capture-flow.ts +5 -4
  657. package/src/shares/capture-preview.tsx +2 -2
  658. package/src/shares/chat.ts +7 -27
  659. package/src/shares/flow.tsx +86 -40
  660. package/src/shares/location.ts +1 -3
  661. package/src/shares/pane-image.ts +11 -9
  662. package/src/shares/pane.ts +5 -2
  663. package/src/shares/payload.ts +1 -1
  664. package/src/shares/personal-pane.ts +3 -3
  665. package/src/shares/portable-layout.ts +9 -2
  666. package/src/shares/ready.ts +42 -0
  667. package/src/shares/test-harness.ts +62 -0
  668. package/src/sources/gloomberb-cloud/batched-lookups.ts +73 -0
  669. package/src/sources/gloomberb-cloud/index.ts +64 -12
  670. package/src/sources/gloomberb-cloud/normalizers.ts +31 -2
  671. package/src/sources/gloomberb-cloud/perpetuals.ts +20 -1
  672. package/src/sources/history-omitted.ts +34 -0
  673. package/src/sources/history-result.ts +3 -0
  674. package/src/sources/history-retention.ts +1 -1
  675. package/src/sources/provider-errors.ts +43 -1
  676. package/src/sources/provider-router/batches.ts +3 -2
  677. package/src/sources/provider-router/cache.ts +2 -1
  678. package/src/sources/provider-router/cached-routes.ts +9 -3
  679. package/src/sources/provider-router/history.ts +9 -8
  680. package/src/sources/provider-router/index.ts +18 -3
  681. package/src/sources/provider-router/primary.ts +5 -4
  682. package/src/sources/provider-router/quote-route.ts +3 -1
  683. package/src/sources/provider-router/routing.ts +2 -1
  684. package/src/sources/provider-router/search.ts +47 -13
  685. package/src/sources/provider-router/streaming.ts +7 -4
  686. package/src/sources/sec-edgar.ts +1 -3
  687. package/src/state/app/context/index.tsx +9 -13
  688. package/src/state/app/tab-cursor.ts +149 -12
  689. package/src/state/hooks/quote-streaming.ts +3 -2
  690. package/src/state/hooks/session-snapshot.ts +3 -2
  691. package/src/state/persist-scheduler.ts +12 -4
  692. package/src/sync/controller.ts +22 -1
  693. package/src/sync/core-contributors.ts +58 -15
  694. package/src/team/collections-sync.ts +14 -4
  695. package/src/team/collections.ts +40 -11
  696. package/src/team/store.ts +5 -4
  697. package/src/telemetry/attention-counts.ts +8 -2
  698. package/src/telemetry/crash-reports-dom.ts +3 -0
  699. package/src/telemetry/crash-reports-node.ts +7 -4
  700. package/src/telemetry/crash-reports.ts +11 -11
  701. package/src/telemetry/usage-counts.ts +16 -12
  702. package/src/theme/colors.ts +2 -0
  703. package/src/theme/font-scale.ts +2 -0
  704. package/src/theme/ui-tokens.ts +71 -0
  705. package/src/tickers/batched-lookups.ts +186 -0
  706. package/src/tickers/company-name-listing.ts +97 -0
  707. package/src/tickers/company-name.ts +13 -0
  708. package/src/tickers/instrument-coverage.ts +112 -0
  709. package/src/tickers/listing-fate.ts +49 -9
  710. package/src/tickers/listing-venues.ts +24 -5
  711. package/src/tickers/open-target.ts +13 -5
  712. package/src/tickers/search/index.ts +112 -35
  713. package/src/tickers/search/ranking.ts +49 -1
  714. package/src/tickers/terminal-codes.ts +79 -0
  715. package/src/tickers/ticker-changes.ts +74 -3
  716. package/src/tickers/us-listing.ts +2 -1
  717. package/src/time-series/chart-data.ts +79 -8
  718. package/src/time-series/fundamentals.ts +55 -7
  719. package/src/time-series/ice-credit.ts +17 -2
  720. package/src/time-series/live-bars.ts +21 -8
  721. package/src/time-series/live-quotes.ts +2 -3
  722. package/src/time-series/price-comparison.ts +6 -1
  723. package/src/time-series/resolve.ts +65 -10
  724. package/src/time-series/spec.ts +2 -1
  725. package/src/time-series/studies.ts +3 -3
  726. package/src/time-series/types.ts +22 -0
  727. package/src/time-series/use-chart-resolution.ts +2 -1
  728. package/src/types/config.ts +7 -0
  729. package/src/types/data-provider.ts +20 -0
  730. package/src/types/headless.ts +142 -1
  731. package/src/types/instrument.ts +6 -0
  732. package/src/types/plugin.ts +32 -9
  733. package/src/types/price-history.ts +5 -0
  734. package/src/types/ticker-changes.ts +19 -0
  735. package/src/types/ticker.ts +10 -2
  736. package/src/ui/context-menu.tsx +2 -0
  737. package/src/ui/host.tsx +40 -4
  738. package/src/ui/measured-cells.ts +13 -7
  739. package/src/ui/qr.ts +7 -5
  740. package/src/updater/index.ts +5 -5
  741. package/src/utils/calendar-date.ts +86 -27
  742. package/src/utils/currency-units.ts +17 -0
  743. package/src/utils/debug-log.ts +1 -1
  744. package/src/utils/dividend-cash.ts +48 -0
  745. package/src/utils/dom-screenshot-rasters.ts +3 -1
  746. package/src/utils/dom-screenshot.ts +14 -10
  747. package/src/utils/exchange-rate-snapshot.ts +9 -4
  748. package/src/utils/external-url.ts +1 -0
  749. package/src/utils/fiscal-period.ts +47 -0
  750. package/src/utils/format.ts +5 -2
  751. package/src/utils/forward-dividend.ts +160 -11
  752. package/src/utils/futures-generic.ts +34 -8
  753. package/src/utils/http-proxy-response.ts +2 -1
  754. package/src/utils/local-utc-offset.ts +2 -0
  755. package/src/utils/log-failure.ts +31 -0
  756. package/src/utils/option-expiry.ts +12 -12
  757. package/src/utils/price-history-integrity.ts +56 -0
  758. package/src/utils/price-history.ts +13 -1
  759. package/src/utils/sec-filings.ts +245 -0
  760. package/src/utils/selection-clipboard.ts +5 -2
  761. package/src/utils/throttled-fetch.ts +1 -0
  762. package/src/{plugins/builtin/dividend-yield/trailing-cash.ts → utils/trailing-dividend.ts} +55 -8
  763. package/src/utils/url.ts +1 -0
  764. package/src/utils/utc-time.ts +11 -0
  765. package/src/plugins/builtin/chat/share/targets.ts +0 -27
  766. package/src/renderers/dom/host/top-surface.ts +0 -119
  767. package/src/shares/dialog.tsx +0 -221
  768. package/src/shares/live.ts +0 -19
@@ -49,6 +49,7 @@ export function resolveChatContentHeightMetrics({
49
49
  replyTo,
50
50
  stackHeader = false,
51
51
  draftAttachmentCount = 0,
52
+ draftLinkCount = 0,
52
53
  promptRows = 0,
53
54
  }: {
54
55
  canSend: boolean;
@@ -61,6 +62,7 @@ export function resolveChatContentHeightMetrics({
61
62
  /** The narrow stack's Back row is drawn above the transcript. */
62
63
  stackHeader?: boolean;
63
64
  draftAttachmentCount?: number;
65
+ draftLinkCount?: number;
64
66
  /** Terminal rows the handle prompt above the composer takes. */
65
67
  promptRows?: number;
66
68
  }) {
@@ -77,6 +79,7 @@ export function resolveChatContentHeightMetrics({
77
79
  nativePaneChrome,
78
80
  replyTo,
79
81
  draftAttachmentCount,
82
+ draftLinkCount,
80
83
  promptRows,
81
84
  });
82
85
  // In the terminal the Back row replaces the top rule.
@@ -1,11 +1,13 @@
1
- import type { MutableRefObject } from "react";
1
+ import { useState, type MutableRefObject } from "react";
2
2
  import { useShortcut } from "../../../../react/input";
3
3
  import type { ScrollBoxRenderable } from "../../../../ui";
4
4
  import type { ChatMessage } from "../../../../api-client";
5
5
  import { countEscapeTowardClose } from "../../../../utils/double-escape-close";
6
6
  import { isPlainKey } from "../../../../utils/keyboard";
7
+ import { createOneShot } from "../../../../utils/one-shot";
7
8
  import { scrollToBottom } from "../layout";
8
9
  import type { ChatSidebarRow } from "../sidebar-rows";
10
+ import type { ComposerShareLink } from "../pane-links/composer";
9
11
 
10
12
  export function useChatContentShortcuts({
11
13
  beginEditLatestMessage,
@@ -42,6 +44,8 @@ export function useChatContentShortcuts({
42
44
  returnToComposer,
43
45
  retryMessage,
44
46
  removeLastDraftAttachment,
47
+ draftLinksRef,
48
+ removeLastDraftLink,
45
49
  scrollRef,
46
50
  selectedIdx,
47
51
  setFollowMessages,
@@ -88,6 +92,10 @@ export function useChatContentShortcuts({
88
92
  retryMessage: (index: number) => void;
89
93
  /** Drops the last image waiting in the composer; false when there is none. */
90
94
  removeLastDraftAttachment: () => boolean;
95
+ /** The share links waiting as chips above the field: with any, the composer is not empty. */
96
+ draftLinksRef: MutableRefObject<ComposerShareLink[]>;
97
+ /** Drops the last of them; false when there is none. */
98
+ removeLastDraftLink: () => boolean;
91
99
  scrollRef: MutableRefObject<ScrollBoxRenderable | null>;
92
100
  selectedIdx: number;
93
101
  setFollowMessages: (followMessages: boolean) => void;
@@ -99,6 +107,10 @@ export function useChatContentShortcuts({
99
107
  sidebarCursorRow: ChatSidebarRow | null;
100
108
  sidebarFocusedRef: MutableRefObject<boolean>;
101
109
  }) {
110
+ // A terminal says a key is held only where its keyboard protocol can;
111
+ // elsewhere a held Backspace is a stream of presses, told apart by the gaps.
112
+ const [backspaceShot] = useState(createOneShot);
113
+
102
114
  useShortcut((event) => {
103
115
  if (!focused || commandBarOpen || !inputFocused || !mentionMenuOpen) return;
104
116
  if (
@@ -200,23 +212,29 @@ export function useChatContentShortcuts({
200
212
  } else {
201
213
  // Leaving an empty composer is the first half of a double-Esc close;
202
214
  // leaving a draft is not, so a quick Esc Esc never closes over it.
203
- if (inputValueRef.current.trim().length === 0) countEscapeTowardClose(event);
215
+ if (inputValueRef.current.trim().length === 0 && draftLinksRef.current.length === 0) countEscapeTowardClose(event);
204
216
  blurInput();
205
217
  }
206
218
  return;
207
219
  }
208
220
 
209
- // The terminal's image rows have no focus of their own: Backspace in an
210
- // empty composer takes the last one back out.
211
- if (
212
- !nativePaneChrome
213
- && isPlainKey(event, "backspace")
214
- && inputValueRef.current.length === 0
215
- && removeLastDraftAttachment()
216
- ) {
217
- event.preventDefault?.();
218
- event.stopPropagation?.();
219
- return;
221
+ // A pasted link is one chip, and the terminal's image rows have no
222
+ // focus of their own: Backspace in an empty composer takes the nearest
223
+ // one back out, the links right above the field first. One for each
224
+ // new press: a Backspace held to clear the text, or held on after one
225
+ // went, takes out nothing more. Every press counts toward the gap.
226
+ if (isPlainKey(event, "backspace")) {
227
+ const freshPress = nativePaneChrome ? event.repeat !== true : !backspaceShot.refuses({ repeat: event.repeat });
228
+ if (freshPress && !nativePaneChrome) backspaceShot.end();
229
+ if (
230
+ freshPress
231
+ && inputValueRef.current.length === 0
232
+ && (removeLastDraftLink() || (!nativePaneChrome && removeLastDraftAttachment()))
233
+ ) {
234
+ event.preventDefault?.();
235
+ event.stopPropagation?.();
236
+ return;
237
+ }
220
238
  }
221
239
 
222
240
  const verticalDirection = event.name === "up" || event.name === "down" ? event.name : null;
@@ -225,6 +243,7 @@ export function useChatContentShortcuts({
225
243
  && canSend
226
244
  && isPlainKey(event, "up")
227
245
  && inputValueRef.current.trim().length === 0
246
+ && draftLinksRef.current.length === 0
228
247
  && beginEditLatestMessage({ deferFocus: true })
229
248
  ) {
230
249
  event.preventDefault?.();
@@ -3,6 +3,7 @@ import type { TextareaRenderable } from "../../../../ui";
3
3
  import type { ChatMessage } from "../../../../api-client";
4
4
  import type { ChatContentController } from "./types";
5
5
  import type { ChatPrependAnchor } from "./scroll";
6
+ import { composerViewOfDraft, type ComposerShareLink } from "../pane-links/composer";
6
7
 
7
8
  type ChatSnapshot = ReturnType<ChatContentController["getSnapshot"]>;
8
9
 
@@ -19,6 +20,10 @@ interface ChatSnapshotStateArgs {
19
20
  inputRef: MutableRef<TextareaRenderable | null>;
20
21
  inputValueRef: MutableRef<string>;
21
22
  onComposerStateChange?: (draft: string, cursorOffset: number) => void;
23
+ /** The share links at the end of the saved draft, drawn as chips above the field. */
24
+ draftLinksRef: MutableRef<ComposerShareLink[]>;
25
+ /** Sets the chips; also updates `draftLinksRef`. */
26
+ onDraftLinksChange: (links: ComposerShareLink[]) => void;
22
27
  prependAnchorRef: MutableRef<ChatPrependAnchor | null>;
23
28
  setFollowMessages: Dispatch<SetStateAction<boolean>>;
24
29
  setSelectedIdx: Dispatch<SetStateAction<number>>;
@@ -26,30 +31,42 @@ interface ChatSnapshotStateArgs {
26
31
  useDefaultControllerChannel: boolean;
27
32
  }
28
33
 
34
+ function sameLinks(a: readonly ComposerShareLink[], b: readonly ComposerShareLink[]): boolean {
35
+ return a.length === b.length && a.every((link, index) => link.url === b[index]!.url);
36
+ }
37
+
29
38
  function syncDraftFromSnapshot({
30
39
  applyingExternalDraftRef,
40
+ draftLinksRef,
31
41
  inputRef,
32
42
  inputValueRef,
33
43
  onComposerStateChange,
44
+ onDraftLinksChange,
34
45
  snapshot,
35
46
  updateComposerRows,
36
47
  }: {
37
48
  applyingExternalDraftRef: MutableRef<boolean>;
49
+ draftLinksRef: MutableRef<ComposerShareLink[]>;
38
50
  inputRef: MutableRef<TextareaRenderable | null>;
39
51
  inputValueRef: MutableRef<string>;
40
52
  onComposerStateChange?: (draft: string, cursorOffset: number) => void;
53
+ onDraftLinksChange: (links: ComposerShareLink[]) => void;
41
54
  snapshot: ChatSnapshot;
42
55
  updateComposerRows: (draft: string) => void;
43
56
  }) {
44
- if (inputValueRef.current !== snapshot.draft) {
45
- inputValueRef.current = snapshot.draft;
46
- updateComposerRows(snapshot.draft);
47
- onComposerStateChange?.(snapshot.draft, snapshot.draft.length);
57
+ // Every snapshot carries the draft, this composer's own included: only one
58
+ // that changed elsewhere is read afresh, never what is being typed.
59
+ const { text, links } = composerViewOfDraft(snapshot.draft, { text: inputValueRef.current, links: draftLinksRef.current });
60
+ if (!sameLinks(draftLinksRef.current, links)) onDraftLinksChange(links);
61
+ if (inputValueRef.current !== text) {
62
+ inputValueRef.current = text;
63
+ updateComposerRows(text);
64
+ onComposerStateChange?.(text, text.length);
48
65
  }
49
66
  const textarea = inputRef.current;
50
- if (textarea && textarea.editBuffer.getText() !== snapshot.draft) {
67
+ if (textarea && textarea.editBuffer.getText() !== text) {
51
68
  applyingExternalDraftRef.current = true;
52
- textarea.setText(snapshot.draft);
69
+ textarea.setText(text);
53
70
  applyingExternalDraftRef.current = false;
54
71
  }
55
72
  }
@@ -69,6 +86,8 @@ export function useChatSnapshotState({
69
86
  inputRef,
70
87
  inputValueRef,
71
88
  onComposerStateChange,
89
+ draftLinksRef,
90
+ onDraftLinksChange,
72
91
  prependAnchorRef,
73
92
  setFollowMessages,
74
93
  setSelectedIdx,
@@ -128,9 +147,11 @@ export function useChatSnapshotState({
128
147
  setDraftAttachments(snapshot.draftAttachments);
129
148
  syncDraftFromSnapshot({
130
149
  applyingExternalDraftRef,
150
+ draftLinksRef,
131
151
  inputRef,
132
152
  inputValueRef,
133
153
  onComposerStateChange,
154
+ onDraftLinksChange,
134
155
  snapshot,
135
156
  updateComposerRows,
136
157
  });
@@ -149,9 +170,11 @@ export function useChatSnapshotState({
149
170
  applyingExternalDraftRef,
150
171
  channelId,
151
172
  controller,
173
+ draftLinksRef,
152
174
  inputRef,
153
175
  inputValueRef,
154
176
  onComposerStateChange,
177
+ onDraftLinksChange,
155
178
  prependAnchorRef,
156
179
  setFollowMessages,
157
180
  setSelectedIdx,
@@ -1,4 +1,4 @@
1
- import type { ChatUserSummary } from "../../../api-client";
1
+ import type { ChatMessage, ChatUserSummary } from "../../../api-client";
2
2
 
3
3
  /**
4
4
  * A person on the Gloom Discord with no linked Gloom account. Their messages
@@ -18,14 +18,22 @@ export function isManagedBot(user: Pick<ChatUserSummary, "accountType"> | null |
18
18
 
19
19
  /**
20
20
  * A reply quotes its author by name only, so whether that author is a managed
21
- * assistant comes from the users the pane has seen.
21
+ * assistant comes from the users the pane has seen. A quoted announcement is
22
+ * Gloom speaking, not a bot, when the pane has it to tell.
22
23
  */
23
24
  export function isQuotedAuthorManagedBot(
24
25
  quoted: { user: { username?: string | null } },
25
26
  userByUsername: ReadonlyMap<string, ChatUserSummary>,
27
+ /** The quoted message, when the pane holds it. */
28
+ findQuoted?: () => Pick<ChatMessage, "announcement"> | null | undefined,
26
29
  ): boolean {
27
30
  const username = quoted.user.username?.toLowerCase();
28
- return !!username && isManagedBot(userByUsername.get(username));
31
+ return !!username && isManagedBot(userByUsername.get(username)) && !findQuoted?.()?.announcement;
32
+ }
33
+
34
+ /** A message among those the pane holds, by id. */
35
+ export function heldMessage(messages: readonly ChatMessage[], id: string | null | undefined): ChatMessage | null {
36
+ return id ? messages.find((message) => message.id === id) ?? null : null;
29
37
  }
30
38
 
31
39
  /** The name a message is signed with: the username, or for a ghost that has none the Discord name it carries. */
@@ -27,6 +27,8 @@ export function isGroupedWithPrevious(messages: ChatMessage[], index: number) {
27
27
  const prev = messages[index - 1]!;
28
28
  const curr = messages[index]!;
29
29
  if (prev.user.id !== curr.user.id) return false;
30
+ // An announcement is a card of its own, with its own header.
31
+ if (prev.announcement || curr.announcement) return false;
30
32
  // The Discord tag sits on a header, so a linked person's Discord and app messages do not share one.
31
33
  if ((prev.origin === "discord") !== (curr.origin === "discord")) return false;
32
34
  return new Date(curr.createdAt).getTime() - new Date(prev.createdAt).getTime() < MESSAGE_GROUP_THRESHOLD_MS;
@@ -1,12 +1,13 @@
1
1
  import { memo } from "react";
2
2
  import { Box, Text } from "../../../../ui";
3
+ import { accentRuleOverlayStyle } from "../../../../components/ui/quote";
3
4
  import { useThemeColors } from "../../../../theme/theme-context";
4
5
  import { t } from "../../../../i18n";
5
6
  import { useAppLanguage } from "../../../../i18n/react";
6
7
  import { normalizeInlinePreview } from "../layout";
7
8
  import { DesktopChatMessageImages } from "../attachments/desktop";
8
9
  import { chatReplyQuoteText } from "../attachments/model";
9
- import { chatAuthorName, isQuotedAuthorManagedBot } from "../ghost-user";
10
+ import { chatAuthorName, heldMessage, isQuotedAuthorManagedBot } from "../ghost-user";
10
11
  import { ChatBotIcon } from "./person-icons";
11
12
  import { ChatMessageActions, ChatMessageHeader, chatHeaderFitsEveryIcon } from "./header";
12
13
  import { MESSAGE_ACTION_WIDTH } from "../layout";
@@ -16,7 +17,7 @@ import { DesktopChatMessageText } from "./inline-tokens";
16
17
  import { DesktopChatPaneChip } from "./pane-chip";
17
18
  import { chatMessagePaneLinks } from "../pane-links/model";
18
19
  import { useSlowPendingSend } from "./pending-send";
19
- import { chatHighlightBg, getChatMessageRenderState } from "./render-state";
20
+ import { chatAnnouncementBg, chatHighlightBg, getChatMessageRenderState } from "./render-state";
20
21
  import type { ChatMessageBaseProps } from "./types";
21
22
 
22
23
  const DESKTOP_MESSAGE_RIGHT_PADDING = 2;
@@ -99,7 +100,7 @@ export const DesktopChatMessage = memo(function DesktopChatMessage({
99
100
  ) : null;
100
101
  const actionProps = { state, index, beginReplyTo, beginEditMessage, retryMessage, reactAction, reactionPickerOpen };
101
102
  const { links: paneLinks, content } = chatMessagePaneLinks(msg);
102
- // A share posted with its picture (what Share > Post to chat sends): the
103
+ // A share link sent with one picture, such as a pasted screenshot: the
103
104
  // picture is the chip's thumbnail rather than a second copy below it.
104
105
  const chipPreview = paneLinks.length === 1 && paneLinks[0]!.kind === "share"
105
106
  && msg.attachments?.length === 1 && !msg.attachmentReview
@@ -131,7 +132,12 @@ export const DesktopChatMessage = memo(function DesktopChatMessage({
131
132
  data-selected={state.isSelected ? "true" : "false"}
132
133
  data-hovered={state.isHovered ? "true" : "false"}
133
134
  data-highlighted={state.isHighlighted ? "true" : "false"}
134
- style={{ "--chat-highlight-bg": chatHighlightBg(themeColors), minWidth: 0 }}
135
+ data-announcement={state.isAnnouncement ? "true" : undefined}
136
+ style={{
137
+ "--chat-highlight-bg": chatHighlightBg(themeColors),
138
+ minWidth: 0,
139
+ ...(state.isAnnouncement ? { position: "relative", "--chat-highlight-rest": chatAnnouncementBg("desktop") } : {}),
140
+ }}
135
141
  >
136
142
  {msg.replyTo && (
137
143
  <Box
@@ -148,7 +154,7 @@ export const DesktopChatMessage = memo(function DesktopChatMessage({
148
154
  >
149
155
  {/* One line: the quoted text ends in an ellipsis, the whole message is a click away. */}
150
156
  <Text fg={state.replyMetaColor} style={{ flexShrink: 0, whiteSpace: "pre" }}>{`${t("reply")} `}</Text>
151
- {isQuotedAuthorManagedBot(msg.replyTo, userByUsername) ? (
157
+ {isQuotedAuthorManagedBot(msg.replyTo, userByUsername, () => heldMessage(messages, msg.replyToId)) ? (
152
158
  // The bot's icon stands where the colon would.
153
159
  <>
154
160
  <Text fg={state.replyAuthorColor} style={{ flexShrink: 0, whiteSpace: "pre" }}>{msg.replyTo.user.username}</Text>
@@ -262,6 +268,8 @@ export const DesktopChatMessage = memo(function DesktopChatMessage({
262
268
  />
263
269
  </Box>
264
270
  )}
271
+ {/* Last, so it draws over the rows' backgrounds. */}
272
+ {state.isAnnouncement && <Box data-gloom-role="chat-announcement-rule" style={accentRuleOverlayStyle()} />}
265
273
  </Box>
266
274
  );
267
275
  });
@@ -3,7 +3,7 @@ import { Box, Text, useUiCapabilities, type BoxRenderable } from "../../../../ui
3
3
  import { t } from "../../../../i18n";
4
4
  import { displayWidth } from "../../../../utils/format";
5
5
  import { chatAuthorName, isDiscordGhost } from "../ghost-user";
6
- import { Button } from "../../../../components/ui";
6
+ import { Badge, Button } from "../../../../components/ui";
7
7
  import { MESSAGE_ACTION_WIDTH } from "../layout";
8
8
  import { CHAT_PERSON_ICON_WIDTH, chatPersonIcons, fitChatPersonIcons } from "../people";
9
9
  import { ChatPersonIcons } from "./person-icons";
@@ -90,7 +90,7 @@ const WIDEST_HEADER_ACTIONS = 1 + MESSAGE_ACTION_WIDTH * 3;
90
90
  * no longer depend on the width, so a row need not draw again as it changes.
91
91
  */
92
92
  export function chatHeaderFitsEveryIcon(msg: ChatMessageBaseProps["msg"], rowWidth: number): boolean {
93
- const icons = chatPersonIcons(msg.user).length;
93
+ const icons = chatHeaderIcons(msg).length;
94
94
  if (icons === 0) return true;
95
95
  const spare = rowWidth - 1 - displayWidth(chatAuthorName(msg.user))
96
96
  - (msg.origin === "discord" ? 8 : 0)
@@ -99,6 +99,19 @@ export function chatHeaderFitsEveryIcon(msg: ChatMessageBaseProps["msg"], rowWid
99
99
  return spare >= icons * CHAT_PERSON_ICON_WIDTH;
100
100
  }
101
101
 
102
+ /** The mark an announcement carries beside its author, in place of the author's icons. */
103
+ const ANNOUNCEMENT_LABEL = "Announcement";
104
+
105
+ /** Cells the mark takes in the terminal: a cell of space, then the chip with a cell inside each edge. */
106
+ function announcementMarkWidth(): number {
107
+ return 1 + displayWidth(t(ANNOUNCEMENT_LABEL)) + 2;
108
+ }
109
+
110
+ /** An announcement is signed by its mark alone: Gloom's account is not a bot speaking. */
111
+ function chatHeaderIcons(msg: ChatMessageBaseProps["msg"]) {
112
+ return msg.announcement ? [] : chatPersonIcons(msg.user);
113
+ }
114
+
102
115
  /**
103
116
  * Author, send status and inline actions for the first message of a group.
104
117
  *
@@ -106,7 +119,9 @@ export function chatHeaderFitsEveryIcon(msg: ChatMessageBaseProps["msg"], rowWid
106
119
  * the row is pointed at or selected, after the status, in the space the row
107
120
  * already has: nothing before them moves, and a row that is not pointed at
108
121
  * keeps no room for them. A row too narrow for its icons, its status and its
109
- * actions drops Pro first, then the role, and never cuts the name.
122
+ * actions drops Pro first, then the role, and never cuts the name. An
123
+ * announcement carries its mark beside the name instead, dropped only by a
124
+ * terminal row too narrow for it (the band and its rule still say what it is).
110
125
  */
111
126
  export function ChatMessageHeader({
112
127
  msg,
@@ -141,7 +156,8 @@ export function ChatMessageHeader({
141
156
  - (msg.origin === "discord" ? 8 : 0)
142
157
  - 1 - displayWidth(state.headerStatus)
143
158
  - state.actionsWidth;
144
- const icons = chatPersonIcons(msg.user);
159
+ const icons = chatHeaderIcons(msg);
160
+ const showAnnouncementMark = msg.announcement === true && spare >= announcementMarkWidth();
145
161
  const besideName = fitChatPersonIcons(icons.filter((icon) => icon.id === "bot"), spare);
146
162
  const onPoint = fitChatPersonIcons(icons.filter((icon) => icon.id !== "bot"), spare - besideName.length * CHAT_PERSON_ICON_WIDTH);
147
163
  // An open reaction picker keeps the row's actions, so it keeps what stands before them too.
@@ -177,6 +193,12 @@ export function ChatMessageHeader({
177
193
  </Text>
178
194
  </Box>
179
195
  <ChatPersonIcons icons={besideName} selectedColor={iconColor} terminalTarget={profileTarget} />
196
+ {showAnnouncementMark && (
197
+ <>
198
+ <Text fg={state.headerStatusColor}> </Text>
199
+ <Badge label={ANNOUNCEMENT_LABEL} tone="accent" />
200
+ </>
201
+ )}
180
202
  {msg.origin === "discord" && <Text fg={state.originTagColor}> Discord</Text>}
181
203
  <Text fg={state.headerStatusColor}> {state.headerStatus}</Text>
182
204
  {showOnPoint && <ChatPersonIcons icons={onPoint} selectedColor={iconColor} terminalTarget={profileTarget} />}
@@ -1,11 +1,15 @@
1
1
  import { createElement, useState } from "react";
2
2
  import type { ChatAttachment } from "../../../../api-client";
3
+ import { IconButton } from "../../../../components/ui";
4
+ import { tf } from "../../../../i18n";
3
5
  import { Box, Text, TextAttributes } from "../../../../ui";
4
6
  import { blendHex, colors } from "../../../../theme/colors";
5
7
  import { useThemeColors } from "../../../../theme/theme-context";
6
8
  import { formatInlinePreview } from "../layout";
7
9
  import { wirePaneTarget, type ChatMessagePaneLink } from "../pane-links/model";
8
10
  import { chatPaneLinkPane, useSharePreview } from "../pane-links/previews";
11
+ import type { ComposerShareLink } from "../pane-links/composer";
12
+ import { DESKTOP_DRAFT_STRIP_STYLE } from "../attachments/desktop";
9
13
 
10
14
  /**
11
15
  * A chip for something a message opens in the terminal: a shared pane (its
@@ -62,6 +66,7 @@ export function DesktopChatPaneChip({
62
66
  dimmed,
63
67
  onOpen,
64
68
  onPreviewError,
69
+ onRemove,
65
70
  }: {
66
71
  link: ChatMessagePaneLink;
67
72
  /** The picture the sender posted with the link: the chip's thumbnail. */
@@ -70,6 +75,8 @@ export function DesktopChatPaneChip({
70
75
  onOpen: (link: ChatMessagePaneLink) => void;
71
76
  /** The picture did not load, perhaps because its signed link expired. */
72
77
  onPreviewError?: (attachment: ChatAttachment) => void;
78
+ /** In the composer: the x at the chip's end that takes the link back out. */
79
+ onRemove?: () => void;
73
80
  }) {
74
81
  const themeColors = useThemeColors();
75
82
  const content = useChatPaneChipContent(link);
@@ -138,34 +145,36 @@ export function DesktopChatPaneChip({
138
145
  },
139
146
  }, text);
140
147
  const label = [content.title, content.detail].filter(Boolean).join(", ");
141
- return createElement("button", {
142
- type: "button",
143
- "data-gloom-role": "chat-pane-chip",
144
- "data-gloom-pane-link": link.kind === "share" ? `share:${link.id}` : link.link.kind,
148
+ const text = compact
149
+ ? createElement("span", {
150
+ key: "text",
151
+ style: { display: "flex", flexDirection: "row", gap: 6, minWidth: 0, alignItems: "baseline" },
152
+ }, line(content.title, "title"), content.detail ? line(content.detail, "detail") : null)
153
+ : createElement("span", {
154
+ key: "text",
155
+ style: { display: "flex", flexDirection: "column", justifyContent: "center", minWidth: 0, flex: "1 1 auto", gap: 1 },
156
+ }, line(content.title, "title"), line(content.detail, "detail"));
157
+ const frame = {
158
+ boxSizing: "border-box",
159
+ display: "flex",
160
+ flexDirection: "row",
161
+ alignItems: "center",
162
+ gap: compact ? 6 : 8,
163
+ height,
164
+ width: compact ? "auto" : `min(100%, ${CHIP_MAX_WIDTH}px)`,
165
+ maxWidth: "100%",
166
+ flex: "none",
167
+ margin: "2px 0",
168
+ padding: compact ? "0 10px 0 5px" : "4px 10px 4px 4px",
169
+ border: `1px solid ${border}`,
170
+ borderRadius: 6,
171
+ background: surface,
172
+ opacity: dimmed ? 0.6 : 1,
173
+ overflow: "hidden",
174
+ };
175
+ const pressable = {
145
176
  "aria-label": label || undefined,
146
177
  title: link.kind === "share" ? link.url : undefined,
147
- style: {
148
- boxSizing: "border-box",
149
- display: "flex",
150
- flexDirection: "row",
151
- alignItems: "center",
152
- gap: compact ? 6 : 8,
153
- height,
154
- width: compact ? "auto" : `min(100%, ${CHIP_MAX_WIDTH}px)`,
155
- maxWidth: "100%",
156
- flex: "none",
157
- margin: "2px 0",
158
- padding: compact ? "0 10px 0 5px" : "4px 10px 4px 4px",
159
- border: `1px solid ${border}`,
160
- borderRadius: 6,
161
- background: surface,
162
- opacity: dimmed ? 0.6 : 1,
163
- cursor: "pointer",
164
- font: "inherit",
165
- color: "inherit",
166
- textAlign: "left",
167
- overflow: "hidden",
168
- },
169
178
  onMouseEnter: () => setHovered(true),
170
179
  onMouseLeave: () => setHovered(false),
171
180
  // A press on the chip is not a press on the row behind it.
@@ -174,15 +183,102 @@ export function DesktopChatPaneChip({
174
183
  event.stopPropagation();
175
184
  onOpen(link);
176
185
  },
177
- }, lead, compact
178
- ? createElement("span", {
179
- key: "text",
180
- style: { display: "flex", flexDirection: "row", gap: 6, minWidth: 0, alignItems: "baseline" },
181
- }, line(content.title, "title"), content.detail ? line(content.detail, "detail") : null)
182
- : createElement("span", {
183
- key: "text",
184
- style: { display: "flex", flexDirection: "column", justifyContent: "center", minWidth: 0, flex: "1 1 auto", gap: 1 },
185
- }, line(content.title, "title"), line(content.detail, "detail")));
186
+ };
187
+ const buttonReset = { cursor: "pointer", font: "inherit", color: "inherit", textAlign: "left" };
188
+ const dataAttributes = {
189
+ "data-gloom-role": "chat-pane-chip",
190
+ "data-gloom-pane-link": link.kind === "share" ? `share:${link.id}` : link.link.kind,
191
+ };
192
+ if (!onRemove) {
193
+ return createElement("button", { type: "button", ...dataAttributes, ...pressable, style: { ...frame, ...buttonReset } }, lead, text);
194
+ }
195
+ // The same chip with its x inside the frame, where a waiting image keeps its own.
196
+ return createElement("div", { ...dataAttributes, style: { ...frame, paddingRight: 4 } },
197
+ createElement("button", {
198
+ key: "open",
199
+ type: "button",
200
+ ...pressable,
201
+ style: {
202
+ ...buttonReset,
203
+ display: "flex",
204
+ flexDirection: "row",
205
+ alignItems: "center",
206
+ gap: frame.gap,
207
+ flex: "1 1 auto",
208
+ minWidth: 0,
209
+ height: "100%",
210
+ padding: 0,
211
+ border: "none",
212
+ background: "transparent",
213
+ },
214
+ }, lead, text),
215
+ <IconButton key="remove" icon="close" label={tf("Remove {name}", { name: content.title })} onPress={onRemove} />);
216
+ }
217
+
218
+ /**
219
+ * The share links waiting in the composer, above the field: the chips the
220
+ * message will show, each with its x. A draft from an older app can hold the
221
+ * same link twice, so a chip is known by its place: its x takes out that one.
222
+ */
223
+ export function DesktopComposerPaneChips({
224
+ links,
225
+ onOpen,
226
+ onRemove,
227
+ }: {
228
+ links: readonly ComposerShareLink[];
229
+ onOpen: (link: ChatMessagePaneLink) => void;
230
+ /** Takes out the chip at this place in `links`. */
231
+ onRemove: (index: number) => void;
232
+ }) {
233
+ if (links.length === 0) return null;
234
+ return (
235
+ <Box flexDirection="column" data-gloom-role="chat-draft-links" style={DESKTOP_DRAFT_STRIP_STYLE}>
236
+ {links.map((link, index) => (
237
+ <DesktopChatPaneChip key={`${index}:${link.id}`} link={link} dimmed={false} onOpen={onOpen} onRemove={() => onRemove(index)} />
238
+ ))}
239
+ </Box>
240
+ );
241
+ }
242
+
243
+ /** The terminal's composer rows for waiting share links: the chip a message draws, then its x at the row's end. */
244
+ export function TerminalComposerPaneChips({
245
+ links,
246
+ width,
247
+ onOpen,
248
+ onRemove,
249
+ }: {
250
+ links: readonly ComposerShareLink[];
251
+ width: number;
252
+ onOpen: (link: ChatMessagePaneLink) => void;
253
+ /** Takes out the chip at this place in `links`, as on the desktop. */
254
+ onRemove: (index: number) => void;
255
+ }) {
256
+ // Lined up with the field's text after its prompt, as a message's chips line up with its text.
257
+ const inset = 3;
258
+ const removeWidth = 3;
259
+ return (
260
+ <>
261
+ {links.map((link, index) => (
262
+ <Box key={`${index}:${link.id}`} width={width} height={1} flexDirection="row">
263
+ <Box width={inset} />
264
+ <TerminalChatPaneChip
265
+ link={link}
266
+ width={Math.max(1, width - inset - removeWidth - 1)}
267
+ selected={false}
268
+ selectedTextColor={colors.textBright}
269
+ onOpen={onOpen}
270
+ />
271
+ <Box flexGrow={1} />
272
+ <TerminalComposerChipRemove link={link} onRemove={() => onRemove(index)} />
273
+ </Box>
274
+ ))}
275
+ </>
276
+ );
277
+ }
278
+
279
+ function TerminalComposerChipRemove({ link, onRemove }: { link: ComposerShareLink; onRemove: () => void }) {
280
+ const content = useChatPaneChipContent(link);
281
+ return <IconButton icon="close" label={tf("Remove {name}", { name: content.title })} onPress={onRemove} />;
186
282
  }
187
283
 
188
284
  /** One row in the terminal: the pane's letter, the title and the pane, cut to the line. */