gloomberb 0.16.5 → 0.17.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 (691) hide show
  1. package/package.json +3 -1
  2. package/src/api-client/central-bank-rates.ts +6 -1
  3. package/src/api-client/chat-pane-link.ts +47 -0
  4. package/src/api-client/chat.ts +35 -1
  5. package/src/api-client/credit-boards.ts +2 -0
  6. package/src/api-client/data.ts +85 -1
  7. package/src/api-client/equity-screener.ts +3 -0
  8. package/src/api-client/europe-energy.ts +197 -0
  9. package/src/api-client/index.ts +15 -0
  10. package/src/api-client/letters.ts +41 -0
  11. package/src/api-client/market-discovery.ts +3 -0
  12. package/src/api-client/normalizers.ts +68 -6
  13. package/src/api-client/organization-tickers.ts +44 -0
  14. package/src/api-client/perps.ts +8 -0
  15. package/src/api-client/request.ts +11 -2
  16. package/src/api-client/socket.ts +29 -0
  17. package/src/api-client/themes.ts +22 -1
  18. package/src/api-client/types.ts +88 -2
  19. package/src/app/global-shortcuts.ts +35 -1
  20. package/src/app/keybindings/actions.ts +12 -1
  21. package/src/app/pane-runtime/plugin-bindings.ts +2 -2
  22. package/src/app/pane-runtime/ticker-open-runtime.ts +9 -3
  23. package/src/app/runtime/desktop-deeplink.ts +58 -20
  24. package/src/app/runtime/startup.ts +1 -1
  25. package/src/app.tsx +6 -0
  26. package/src/architecture/core-builtin-allowlist.json +5 -14
  27. package/src/architecture/dom-cell-metrics-allowlist.json +28 -0
  28. package/src/ask-gloom/pane-context.ts +118 -0
  29. package/src/ask-gloom/pane-request.ts +70 -0
  30. package/src/ask-gloom/pane-text.ts +201 -0
  31. package/src/capabilities/chart-series.ts +8 -1
  32. package/src/capabilities/factories.ts +1 -0
  33. package/src/cli/central-bank-events.ts +23 -0
  34. package/src/cli/command-options.ts +17 -5
  35. package/src/cli/commands/crypto-hints.ts +28 -2
  36. package/src/cli/commands/fred-series.ts +155 -4
  37. package/src/cli/commands/market.ts +175 -35
  38. package/src/cli/commands/overview.ts +62 -20
  39. package/src/cli/commands/search.ts +254 -23
  40. package/src/cli/commands/ticker.ts +137 -24
  41. package/src/cli/desktop-pane-shot-view.ts +114 -0
  42. package/src/cli/desktop-pane-shot.ts +53 -37
  43. package/src/cli/entry.ts +7 -0
  44. package/src/cli/errors.ts +7 -5
  45. package/src/cli/exit-codes.ts +8 -0
  46. package/src/cli/export-source.ts +101 -0
  47. package/src/cli/freshness.ts +18 -3
  48. package/src/cli/glossary.ts +79 -8
  49. package/src/cli/help.ts +10 -0
  50. package/src/cli/helpers.ts +2 -5
  51. package/src/cli/history-rows.ts +244 -13
  52. package/src/cli/index.ts +9 -3
  53. package/src/cli/known-gaps.ts +76 -8
  54. package/src/cli/listing-arg.ts +201 -90
  55. package/src/cli/listing-suggestion.ts +159 -0
  56. package/src/cli/native-smoke.ts +13 -0
  57. package/src/cli/not-a-ticker.ts +24 -4
  58. package/src/cli/pane-functions/access-gate.ts +8 -2
  59. package/src/cli/pane-functions/capabilities.ts +17 -9
  60. package/src/cli/pane-functions/catalog.ts +183 -39
  61. package/src/cli/pane-functions/data.ts +30 -0
  62. package/src/cli/pane-functions/dom.ts +44 -14
  63. package/src/cli/pane-functions/freshness.ts +48 -24
  64. package/src/cli/pane-functions/function-help.ts +66 -12
  65. package/src/cli/pane-functions/headless.ts +81 -22
  66. package/src/cli/pane-functions/index.ts +90 -18
  67. package/src/cli/pane-functions/options.ts +8 -0
  68. package/src/cli/pane-functions/report-notices.ts +6 -3
  69. package/src/cli/pane-functions/report.ts +16 -2
  70. package/src/cli/pane-functions/resolver.ts +32 -11
  71. package/src/cli/pane-functions/screenshot.ts +145 -9
  72. package/src/cli/perpetual-contract.ts +60 -0
  73. package/src/cli/registry.ts +3 -1
  74. package/src/cli/report-tables.ts +53 -13
  75. package/src/cli/result.ts +91 -17
  76. package/src/cli/series-search.ts +111 -0
  77. package/src/cli/staged-tickers.ts +1 -1
  78. package/src/cli/symbol-args.ts +18 -0
  79. package/src/cli/symbol-list.ts +1 -19
  80. package/src/cli/symbol-rows.ts +171 -0
  81. package/src/cli/ticker-resolution.ts +99 -8
  82. package/src/components/chart/composite/axis-overlays.tsx +10 -1
  83. package/src/components/chart/composite/composite-chart.tsx +24 -15
  84. package/src/components/chart/composite/downsample.ts +1 -1
  85. package/src/components/chart/composite/format.ts +29 -0
  86. package/src/components/chart/composite/interactions.ts +9 -2
  87. package/src/components/chart/composite/legend.tsx +57 -33
  88. package/src/components/chart/composite/panel-bitmap.ts +70 -35
  89. package/src/components/chart/composite/panel-labels.ts +18 -17
  90. package/src/components/chart/composite/panel-series.ts +1 -0
  91. package/src/components/chart/composite/panel-surface.tsx +6 -8
  92. package/src/components/chart/composite/price-axis-labels.tsx +1 -0
  93. package/src/components/chart/composite/rasterizer.ts +50 -8
  94. package/src/components/chart/composite/scene.ts +2 -1
  95. package/src/components/chart/composite/time-scale.ts +26 -9
  96. package/src/components/chart/composite/types.ts +18 -0
  97. package/src/components/chart/composite/use-composite-viewport.ts +30 -2
  98. package/src/components/chart/native/raster/crosshair.ts +8 -3
  99. package/src/components/chart/native/raster/primitives.ts +85 -21
  100. package/src/components/chart/native/surface/manager.ts +33 -8
  101. package/src/components/chart/surface3d/chart.tsx +1 -1
  102. package/src/components/command-bar/action-runtime.ts +1 -1
  103. package/src/components/command-bar/commands/collection-list.ts +210 -0
  104. package/src/components/command-bar/commands/collection.ts +40 -1
  105. package/src/components/command-bar/commands/direct/index.ts +4 -0
  106. package/src/components/command-bar/commands/registry.ts +8 -0
  107. package/src/components/command-bar/list/model.ts +2 -0
  108. package/src/components/command-bar/pane-templates/items.ts +1 -1
  109. package/src/components/command-bar/routes/root/plugin-install.ts +4 -4
  110. package/src/components/command-bar/routes/ticker-search/actions.ts +1 -0
  111. package/src/components/command-bar/routes/ticker-search/results.ts +3 -1
  112. package/src/components/command-bar/routing/actions.ts +1 -1
  113. package/src/components/command-bar/workflow/ops.ts +8 -97
  114. package/src/components/command-bar/workflow/pane-reuse.ts +177 -0
  115. package/src/components/command-bar/workflow/tickers.ts +35 -29
  116. package/src/components/data-table/view.tsx +1 -0
  117. package/src/components/feed-data-table/stack-view.tsx +18 -42
  118. package/src/components/layout/detached-pane-shell.tsx +59 -39
  119. package/src/components/layout/floating-pane.tsx +7 -1
  120. package/src/components/layout/header.tsx +5 -0
  121. package/src/components/layout/missing-pane.tsx +5 -3
  122. package/src/components/layout/pane/capture-stamp.ts +41 -0
  123. package/src/components/layout/pane/capture-status.ts +12 -0
  124. package/src/components/layout/pane/footer/keyboard.ts +3 -0
  125. package/src/components/layout/pane/footer/model.ts +7 -1
  126. package/src/components/layout/pane/header.tsx +26 -0
  127. package/src/components/layout/pane/index.tsx +9 -1
  128. package/src/components/layout/pane/sidebar.tsx +10 -11
  129. package/src/components/layout/shell/cursor-occlusion.ts +2 -1
  130. package/src/components/layout/shell/index.tsx +62 -60
  131. package/src/components/layout/shell/menu.ts +9 -1
  132. package/src/components/layout/shell/pane/actions.ts +32 -10
  133. package/src/components/layout/shell/pane/ask.ts +136 -0
  134. package/src/components/layout/shell/pane/capture.ts +136 -0
  135. package/src/components/layout/shell/pane/layers.tsx +26 -5
  136. package/src/components/layout/shell/pane/management-shortcuts.ts +46 -1
  137. package/src/components/layout/shell/shortcuts.ts +21 -4
  138. package/src/components/markdown-text.tsx +37 -6
  139. package/src/components/metric-treemap/heat-surface.tsx +1 -3
  140. package/src/components/reader/article-reader.tsx +467 -0
  141. package/src/components/reader/article-text.ts +527 -0
  142. package/src/components/reader/detail-reader.tsx +210 -0
  143. package/src/components/reader/reader-text.tsx +239 -0
  144. package/src/components/table-view-shared.tsx +8 -4
  145. package/src/components/ticker/badge/list.tsx +15 -4
  146. package/src/components/ticker/list-table-view.tsx +19 -1
  147. package/src/components/ui/choice-dialog.tsx +3 -0
  148. package/src/components/ui/data-table/index.tsx +1 -0
  149. package/src/components/ui/data-table/types.ts +7 -0
  150. package/src/components/ui/detail-scroll-body.tsx +31 -4
  151. package/src/components/ui/display.tsx +46 -1
  152. package/src/components/ui/icon.tsx +14 -1
  153. package/src/components/ui/list-view.tsx +3 -1
  154. package/src/components/ui/query-bar-keys.tsx +2 -0
  155. package/src/components/ui/query-bar.tsx +18 -1
  156. package/src/components/ui/select-button.tsx +3 -0
  157. package/src/data/config/store/fold-panes.ts +202 -11
  158. package/src/data/config/store/migrations.ts +20 -1
  159. package/src/data/config/store/portfolio-as-of-column.ts +57 -0
  160. package/src/docs/snapshot.json +191 -23
  161. package/src/i18n/es.ts +18 -1
  162. package/src/i18n/ja.ts +18 -1
  163. package/src/i18n/ko.ts +18 -1
  164. package/src/i18n/zh-cn.ts +18 -1
  165. package/src/i18n/zh-tw.ts +18 -1
  166. package/src/layout/desk-keys.ts +7 -0
  167. package/src/layout/desks.ts +2 -2
  168. package/src/layout-marketplace/gallery.tsx +1 -1
  169. package/src/market-data/market/freshness.ts +3 -2
  170. package/src/market-data/market/session-close-note.ts +3 -2
  171. package/src/market-data/market/status.ts +67 -6
  172. package/src/market-data/quotes/contributions.ts +17 -0
  173. package/src/market-data/quotes/metadata.ts +12 -0
  174. package/src/market-data/quotes/regular-session-valuation.ts +131 -0
  175. package/src/market-data/quotes/resolution.ts +7 -0
  176. package/src/market-data/snapshot-provider.ts +6 -3
  177. package/src/notifications/app-badge.ts +30 -0
  178. package/src/notifications/app-notifier.ts +17 -1
  179. package/src/notifications/notification-log.ts +180 -0
  180. package/src/plugins/auto-update-node.ts +2 -2
  181. package/src/plugins/auto-update.ts +2 -2
  182. package/src/plugins/builtin/account-management/calendar-tab.tsx +1 -1
  183. package/src/plugins/builtin/account-management/form-components.tsx +53 -1
  184. package/src/plugins/builtin/account-management/index.tsx +1 -0
  185. package/src/plugins/builtin/account-management/keyboard.ts +5 -0
  186. package/src/plugins/builtin/account-management/model.ts +27 -0
  187. package/src/plugins/builtin/account-management/pane.tsx +62 -2
  188. package/src/plugins/builtin/alerts/catalysts.ts +1 -1
  189. package/src/plugins/builtin/alerts/cli.ts +6 -4
  190. package/src/plugins/builtin/alerts/focus.ts +27 -0
  191. package/src/plugins/builtin/alerts/index.tsx +6 -2
  192. package/src/plugins/builtin/alerts/pane.tsx +19 -1
  193. package/src/plugins/builtin/analytics/index.tsx +5 -2
  194. package/src/plugins/builtin/analytics/risk-headless.ts +30 -15
  195. package/src/plugins/builtin/attention/headless.ts +1 -1
  196. package/src/plugins/builtin/awards/headless.ts +88 -18
  197. package/src/plugins/builtin/awards/model.ts +41 -1
  198. package/src/plugins/builtin/awards/pane.tsx +48 -30
  199. package/src/plugins/builtin/backtest/headless.ts +2 -2
  200. package/src/plugins/builtin/backtest/pane.tsx +2 -1
  201. package/src/plugins/builtin/bond-calculator/index.tsx +3 -5
  202. package/src/plugins/builtin/broker-manager/index.tsx +1 -0
  203. package/src/plugins/builtin/buildout/detail/company.tsx +7 -4
  204. package/src/plugins/builtin/builtin-plugin-meta.ts +5 -4
  205. package/src/plugins/builtin/catalysts/headless.ts +1 -1
  206. package/src/plugins/builtin/catalysts/model.ts +92 -10
  207. package/src/plugins/builtin/catalysts/pane.tsx +6 -4
  208. package/src/plugins/builtin/cds/client.ts +11 -31
  209. package/src/plugins/builtin/cds/headless.ts +5 -2
  210. package/src/plugins/builtin/cds/index.tsx +21 -30
  211. package/src/plugins/builtin/cds/model.ts +21 -1
  212. package/src/plugins/builtin/cds/pane.tsx +6 -4
  213. package/src/plugins/builtin/central-bank-rates/client.ts +4 -0
  214. package/src/plugins/builtin/central-bank-rates/headless.ts +46 -16
  215. package/src/plugins/builtin/central-bank-rates/index.tsx +1 -1
  216. package/src/plugins/builtin/central-bank-rates/model.ts +99 -0
  217. package/src/plugins/builtin/central-bank-rates/pane.tsx +1 -1
  218. package/src/plugins/builtin/central-bank-rates/series.ts +19 -25
  219. package/src/plugins/builtin/changelog/index.tsx +11 -12
  220. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
  221. package/src/plugins/builtin/chart-composer/headless-schema.ts +3 -1
  222. package/src/plugins/builtin/chart-composer/headless.ts +151 -9
  223. package/src/plugins/builtin/chart-composer/index.tsx +6 -1
  224. package/src/plugins/builtin/chart-composer/pane.tsx +84 -40
  225. package/src/plugins/builtin/chart-composer/session-history.ts +20 -5
  226. package/src/plugins/builtin/chat/command-bar.ts +6 -8
  227. package/src/plugins/builtin/chat/content/composer-runtime.ts +6 -1
  228. package/src/plugins/builtin/chat/content/composer.tsx +15 -2
  229. package/src/plugins/builtin/chat/content/footer.tsx +27 -5
  230. package/src/plugins/builtin/chat/content/handle-prompt.tsx +326 -0
  231. package/src/plugins/builtin/chat/content/index.tsx +201 -13
  232. package/src/plugins/builtin/chat/content/layout-metrics.ts +4 -0
  233. package/src/plugins/builtin/chat/content/new-messages.tsx +89 -0
  234. package/src/plugins/builtin/chat/content/open-targets.ts +20 -4
  235. package/src/plugins/builtin/chat/content/row-activity.ts +132 -0
  236. package/src/plugins/builtin/chat/content/scroll.ts +133 -28
  237. package/src/plugins/builtin/chat/content/shortcuts.ts +2 -2
  238. package/src/plugins/builtin/chat/content/transcript.tsx +155 -79
  239. package/src/plugins/builtin/chat/content/types.ts +1 -0
  240. package/src/plugins/builtin/chat/controller/fetch.ts +8 -2
  241. package/src/plugins/builtin/chat/controller/index.ts +121 -1
  242. package/src/plugins/builtin/chat/controller/message-loading.ts +3 -0
  243. package/src/plugins/builtin/chat/controller/messages.ts +7 -2
  244. package/src/plugins/builtin/chat/controller/realtime.ts +10 -1
  245. package/src/plugins/builtin/chat/controller/send.ts +61 -1
  246. package/src/plugins/builtin/chat/controller/state.ts +8 -0
  247. package/src/plugins/builtin/chat/ghost-user.ts +20 -0
  248. package/src/plugins/builtin/chat/handle-prompt.ts +128 -0
  249. package/src/plugins/builtin/chat/index.tsx +66 -25
  250. package/src/plugins/builtin/chat/layout.ts +84 -18
  251. package/src/plugins/builtin/chat/message/desktop.tsx +111 -14
  252. package/src/plugins/builtin/chat/message/header.tsx +81 -21
  253. package/src/plugins/builtin/chat/message/pane-chip.tsx +223 -0
  254. package/src/plugins/builtin/chat/message/person-icons.tsx +53 -0
  255. package/src/plugins/builtin/chat/message/profile-popover.tsx +77 -9
  256. package/src/plugins/builtin/chat/message/reactions.tsx +210 -0
  257. package/src/plugins/builtin/chat/message/render-state.ts +33 -4
  258. package/src/plugins/builtin/chat/message/terminal.tsx +72 -8
  259. package/src/plugins/builtin/chat/message/types.ts +15 -0
  260. package/src/plugins/builtin/chat/pane-links/model.ts +149 -0
  261. package/src/plugins/builtin/chat/pane-links/open.ts +29 -0
  262. package/src/plugins/builtin/chat/pane-links/previews.ts +119 -0
  263. package/src/plugins/builtin/chat/pane-state.ts +5 -8
  264. package/src/plugins/builtin/chat/people.ts +202 -0
  265. package/src/plugins/builtin/chat/profile-popover.ts +18 -2
  266. package/src/plugins/builtin/chat/reactions.ts +197 -0
  267. package/src/plugins/builtin/chat/share/flow.tsx +87 -0
  268. package/src/plugins/builtin/chat/share/targets.ts +27 -0
  269. package/src/plugins/builtin/chat/status-widget.tsx +7 -9
  270. package/src/plugins/builtin/chat/unread-badge.ts +65 -0
  271. package/src/plugins/builtin/chat/unread-inbox-pane.tsx +151 -27
  272. package/src/plugins/builtin/chat/unread-inbox.ts +22 -0
  273. package/src/plugins/builtin/clinical-trials/client.ts +26 -1
  274. package/src/plugins/builtin/clinical-trials/index.tsx +10 -2
  275. package/src/plugins/builtin/clinical-trials/model.ts +269 -0
  276. package/src/plugins/builtin/clinical-trials/pane.tsx +247 -62
  277. package/src/plugins/builtin/clinical-trials/sponsor-tickers.ts +156 -0
  278. package/src/plugins/builtin/cloud/askg/attached-pane.tsx +69 -0
  279. package/src/plugins/builtin/cloud/askg/pane-attachment.ts +94 -0
  280. package/src/plugins/builtin/cloud/askg/pane.tsx +141 -12
  281. package/src/plugins/builtin/cloud/askg/pending-question.ts +11 -0
  282. package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +1 -0
  283. package/src/plugins/builtin/cloud/plugin.tsx +19 -2
  284. package/src/plugins/builtin/cloud/team/model.ts +5 -0
  285. package/src/plugins/builtin/cloud/team/module.tsx +1 -0
  286. package/src/plugins/builtin/cloud/team/store.ts +8 -3
  287. package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
  288. package/src/plugins/builtin/comment-letters/pane.tsx +30 -11
  289. package/src/plugins/builtin/commodities-energy/index.tsx +179 -0
  290. package/src/plugins/builtin/commodity-balances/client.ts +208 -0
  291. package/src/plugins/builtin/commodity-balances/headless.ts +66 -0
  292. package/src/plugins/builtin/commodity-balances/index.tsx +32 -0
  293. package/src/plugins/builtin/commodity-balances/model.ts +261 -0
  294. package/src/plugins/builtin/commodity-balances/pane.tsx +227 -0
  295. package/src/plugins/builtin/company-attention/headless.ts +2 -2
  296. package/src/plugins/builtin/company-kpis/headless.ts +97 -10
  297. package/src/plugins/builtin/company-kpis/model.ts +24 -2
  298. package/src/plugins/builtin/company-kpis/pane.tsx +13 -14
  299. package/src/plugins/builtin/composite-plugins.ts +26 -1
  300. package/src/plugins/builtin/connections/index.ts +1 -0
  301. package/src/plugins/builtin/cot/headless.ts +1 -1
  302. package/src/plugins/builtin/cpi/headless.ts +3 -3
  303. package/src/plugins/builtin/credit-boards/cdx-pane.tsx +10 -1
  304. package/src/plugins/builtin/credit-boards/client.ts +6 -2
  305. package/src/plugins/builtin/credit-boards/headless.ts +108 -31
  306. package/src/plugins/builtin/credit-boards/index.tsx +21 -42
  307. package/src/plugins/builtin/credit-boards/model.ts +11 -3
  308. package/src/plugins/builtin/credit-conditions/client.ts +12 -9
  309. package/src/plugins/builtin/credit-conditions/headless.ts +13 -2
  310. package/src/plugins/builtin/credit-conditions/index.tsx +20 -22
  311. package/src/plugins/builtin/credit-conditions/model.ts +19 -11
  312. package/src/plugins/builtin/credit-conditions/series.ts +8 -18
  313. package/src/plugins/builtin/credit-documents/headless.ts +2 -2
  314. package/src/plugins/builtin/credit-documents/index.tsx +27 -10
  315. package/src/plugins/builtin/debt-maturities/headless.ts +17 -11
  316. package/src/plugins/builtin/debt-maturities/index.tsx +3 -17
  317. package/src/plugins/builtin/debug/index.tsx +2 -2
  318. package/src/plugins/builtin/dividend-yield/client.ts +6 -1
  319. package/src/plugins/builtin/dividend-yield/headless.ts +8 -3
  320. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  321. package/src/plugins/builtin/dividend-yield/pane.tsx +6 -2
  322. package/src/plugins/builtin/dividend-yield/provider-client.ts +3 -1
  323. package/src/plugins/builtin/dividend-yield/types.ts +2 -0
  324. package/src/plugins/builtin/docs/blocks.tsx +4 -3
  325. package/src/plugins/builtin/docs/pane.tsx +16 -8
  326. package/src/plugins/builtin/doe/headless.ts +12 -8
  327. package/src/plugins/builtin/earnings/index.tsx +11 -0
  328. package/src/plugins/builtin/earnings-calls/headless.ts +28 -2
  329. package/src/plugins/builtin/earnings-calls/index.tsx +1 -1
  330. package/src/plugins/builtin/earnings-calls/pane.tsx +2 -12
  331. package/src/plugins/builtin/earnings-ripple/index.tsx +2 -0
  332. package/src/plugins/builtin/econ/fred-catalog.ts +9 -0
  333. package/src/plugins/builtin/equity-screener/client.ts +1 -1
  334. package/src/plugins/builtin/equity-screener/headless.ts +39 -5
  335. package/src/plugins/builtin/equity-screener/model.ts +121 -68
  336. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -3
  337. package/src/plugins/builtin/executives/pane.tsx +3 -1
  338. package/src/plugins/builtin/exposure/drivers.ts +13 -0
  339. package/src/plugins/builtin/exposure/headless.ts +205 -13
  340. package/src/plugins/builtin/exposure/index.tsx +1 -0
  341. package/src/plugins/builtin/exposure/model.ts +23 -3
  342. package/src/plugins/builtin/exposure/pane.tsx +11 -11
  343. package/src/plugins/builtin/fear-greed/index.tsx +14 -10
  344. package/src/plugins/builtin/filing-events/index.tsx +20 -0
  345. package/src/plugins/builtin/fixed-income/index.tsx +46 -0
  346. package/src/plugins/builtin/fixed-income/model.ts +27 -0
  347. package/src/plugins/builtin/fixed-income/pane.tsx +162 -0
  348. package/src/plugins/builtin/fixed-income/shortcut.ts +52 -0
  349. package/src/plugins/builtin/futures/index.tsx +24 -7
  350. package/src/plugins/builtin/futures/series.ts +23 -2
  351. package/src/plugins/builtin/futures/use-front-returns.ts +3 -2
  352. package/src/plugins/builtin/futures-curve/headless.ts +1 -1
  353. package/src/plugins/builtin/futures-curve/index.tsx +1 -1
  354. package/src/plugins/builtin/futures-curve/pane.tsx +6 -4
  355. package/src/plugins/builtin/fx-matrix/client.ts +63 -0
  356. package/src/plugins/builtin/fx-matrix/export.ts +2 -1
  357. package/src/plugins/builtin/fx-matrix/headless.ts +154 -0
  358. package/src/plugins/builtin/fx-matrix/index.tsx +3 -3
  359. package/src/plugins/builtin/gpu/headless.ts +4 -4
  360. package/src/plugins/builtin/help/function-index.ts +2 -0
  361. package/src/plugins/builtin/help/index.tsx +14 -1
  362. package/src/plugins/builtin/help/shortcut-table.tsx +4 -2
  363. package/src/plugins/builtin/insider/detail.tsx +20 -12
  364. package/src/plugins/builtin/insider/index.tsx +2 -2
  365. package/src/plugins/builtin/ipo-calendar/headless.ts +1 -1
  366. package/src/plugins/builtin/iv-history/client.ts +6 -2
  367. package/src/plugins/builtin/iv-history/format.ts +9 -0
  368. package/src/plugins/builtin/iv-history/headless.ts +50 -18
  369. package/src/plugins/builtin/iv-history/index.tsx +3 -0
  370. package/src/plugins/builtin/iv-history/model.ts +35 -4
  371. package/src/plugins/builtin/iv-history/screen-pane.tsx +13 -5
  372. package/src/plugins/builtin/jobs/headless.ts +6 -8
  373. package/src/plugins/builtin/jodi/client.ts +220 -0
  374. package/src/plugins/builtin/jodi/headless.ts +63 -0
  375. package/src/plugins/builtin/jodi/index.tsx +32 -0
  376. package/src/plugins/builtin/jodi/model.ts +75 -0
  377. package/src/plugins/builtin/jodi/pane.tsx +141 -0
  378. package/src/plugins/builtin/kelly-sizer/index.tsx +2 -0
  379. package/src/plugins/builtin/market-heatmap/evidence.ts +13 -4
  380. package/src/plugins/builtin/market-heatmap/headless.ts +22 -7
  381. package/src/plugins/builtin/market-heatmap/index.tsx +47 -23
  382. package/src/plugins/builtin/market-heatmap/live.ts +2 -1
  383. package/src/plugins/builtin/market-heatmap/portfolio.ts +67 -21
  384. package/src/plugins/builtin/market-movers/table.ts +2 -2
  385. package/src/plugins/builtin/market-valuation/align.ts +10 -9
  386. package/src/plugins/builtin/members/headless.ts +1 -1
  387. package/src/plugins/builtin/members/pane.tsx +3 -2
  388. package/src/plugins/builtin/mna/distress/headless.ts +4 -4
  389. package/src/plugins/builtin/mna/distress/model.ts +52 -1
  390. package/src/plugins/builtin/mna/distress/pane.tsx +17 -12
  391. package/src/plugins/builtin/mna/headless.ts +3 -3
  392. package/src/plugins/builtin/mna/index.tsx +2 -0
  393. package/src/plugins/builtin/money-markets/headless.ts +5 -4
  394. package/src/plugins/builtin/news/index.tsx +0 -2
  395. package/src/plugins/builtin/news/wire/index.tsx +2 -2
  396. package/src/plugins/builtin/news/wire/industry-pane.tsx +28 -14
  397. package/src/plugins/builtin/news/wire/letters/client.ts +108 -0
  398. package/src/plugins/builtin/news/wire/letters/model.ts +69 -0
  399. package/src/plugins/builtin/news/wire/letters/pane.tsx +155 -0
  400. package/src/plugins/builtin/news/wire/mutes.ts +2 -1
  401. package/src/plugins/builtin/news/wire/news/detail-view.tsx +53 -104
  402. package/src/plugins/builtin/news/wire/news/footer.ts +2 -25
  403. package/src/plugins/builtin/news/wire/news/preset-pane.tsx +0 -2
  404. package/src/plugins/builtin/news/wire/news/query-presets.ts +4 -1
  405. package/src/plugins/builtin/notes/index.tsx +1 -0
  406. package/src/plugins/builtin/openfda/client.ts +123 -15
  407. package/src/plugins/builtin/openfda/model.ts +163 -0
  408. package/src/plugins/builtin/openfda/pane.tsx +109 -65
  409. package/src/plugins/builtin/openfda/types.ts +25 -0
  410. package/src/plugins/builtin/options/index.tsx +3 -0
  411. package/src/plugins/builtin/options/view.tsx +1 -1
  412. package/src/plugins/builtin/options-positioning/headless.ts +3 -3
  413. package/src/plugins/builtin/pe-band/model.ts +3 -2
  414. package/src/plugins/builtin/perps/client.ts +50 -10
  415. package/src/plugins/builtin/perps/equity-row.tsx +29 -16
  416. package/src/plugins/builtin/perps/headless.ts +2 -2
  417. package/src/plugins/builtin/perps/index.tsx +5 -3
  418. package/src/plugins/builtin/perps/list-perpetuals.ts +118 -0
  419. package/src/plugins/builtin/perps/open-market.ts +15 -0
  420. package/src/plugins/builtin/plugin-marketplace/index.tsx +1 -1
  421. package/src/plugins/builtin/plugin-marketplace/pane.tsx +7 -7
  422. package/src/plugins/builtin/plugin-module.ts +3 -1
  423. package/src/plugins/builtin/portfolio-list/allocation.ts +5 -4
  424. package/src/plugins/builtin/portfolio-list/cell-version.ts +8 -1
  425. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +24 -136
  426. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +78 -19
  427. package/src/plugins/builtin/portfolio-list/cli/render.ts +249 -52
  428. package/src/plugins/builtin/portfolio-list/cli/shared.ts +44 -12
  429. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +21 -7
  430. package/src/plugins/builtin/portfolio-list/column-values.ts +103 -25
  431. package/src/plugins/builtin/portfolio-list/headless.ts +51 -15
  432. package/src/plugins/builtin/portfolio-list/index.tsx +5 -1
  433. package/src/plugins/builtin/portfolio-list/live-valuation.ts +25 -13
  434. package/src/plugins/builtin/portfolio-list/mutations.ts +2 -9
  435. package/src/plugins/builtin/portfolio-list/pane/data.ts +5 -1
  436. package/src/plugins/builtin/portfolio-list/pane/index.tsx +46 -8
  437. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +16 -10
  438. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +21 -1
  439. package/src/plugins/builtin/portfolio-list/settings.ts +17 -0
  440. package/src/plugins/builtin/portfolio-list/summary/index.tsx +12 -0
  441. package/src/plugins/builtin/portfolio-list/summary/totals.ts +8 -3
  442. package/src/plugins/builtin/portfolio-list/table.tsx +30 -6
  443. package/src/plugins/builtin/power/evidence.ts +86 -8
  444. package/src/plugins/builtin/power/gas-client.ts +110 -0
  445. package/src/plugins/builtin/power/gas-model.ts +194 -0
  446. package/src/plugins/builtin/power/gas.tsx +145 -0
  447. package/src/plugins/builtin/power/headless.ts +9 -2
  448. package/src/plugins/builtin/power/index.tsx +35 -3
  449. package/src/plugins/builtin/power/model.ts +2 -2
  450. package/src/plugins/builtin/power/pane.tsx +7 -3
  451. package/src/plugins/builtin/power/prices-client.ts +139 -0
  452. package/src/plugins/builtin/power/prices-headless.ts +205 -0
  453. package/src/plugins/builtin/power/prices-model.ts +103 -0
  454. package/src/plugins/builtin/power/prices.tsx +202 -0
  455. package/src/plugins/builtin/primary-dealers/client.ts +108 -0
  456. package/src/plugins/builtin/primary-dealers/headless.ts +53 -0
  457. package/src/plugins/builtin/primary-dealers/index.tsx +17 -0
  458. package/src/plugins/builtin/primary-dealers/model.ts +206 -0
  459. package/src/plugins/builtin/primary-dealers/pane.tsx +149 -0
  460. package/src/plugins/builtin/rate-path/headless.ts +38 -18
  461. package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
  462. package/src/plugins/builtin/relative-rotation/index.tsx +3 -0
  463. package/src/plugins/builtin/research/analyst-model.ts +9 -5
  464. package/src/plugins/builtin/research/headless-schema.ts +2 -1
  465. package/src/plugins/builtin/research/index.tsx +2 -0
  466. package/src/plugins/builtin/research/relative-valuation-headless.ts +68 -32
  467. package/src/plugins/builtin/research/relative-valuation-model.ts +45 -24
  468. package/src/plugins/builtin/research/relative-valuation-pane.tsx +39 -4
  469. package/src/plugins/builtin/research-search/article.ts +65 -0
  470. package/src/plugins/builtin/research-search/document-view.tsx +33 -215
  471. package/src/plugins/builtin/research-search/model.ts +0 -9
  472. package/src/plugins/builtin/research-search/pane.tsx +41 -30
  473. package/src/plugins/builtin/research-search/snippet.ts +0 -29
  474. package/src/plugins/builtin/revenue-breakdown/headless.ts +18 -6
  475. package/src/plugins/builtin/scanner/flow-pane.tsx +8 -1
  476. package/src/plugins/builtin/sec/filing-display.tsx +3 -36
  477. package/src/plugins/builtin/sec/headless.ts +25 -3
  478. package/src/plugins/builtin/sec/index.tsx +133 -44
  479. package/src/plugins/builtin/sec/model.ts +148 -2
  480. package/src/plugins/builtin/sec/row-summaries.ts +105 -0
  481. package/src/plugins/builtin/sectors/index.tsx +2 -0
  482. package/src/plugins/builtin/sectors/sector-model.ts +2 -2
  483. package/src/plugins/builtin/series-inventory.ts +3 -0
  484. package/src/plugins/builtin/shared/cloud-denied.ts +15 -0
  485. package/src/plugins/builtin/shared/free-preview.ts +47 -0
  486. package/src/plugins/builtin/shared/locked-rows.tsx +1 -1
  487. package/src/plugins/builtin/shared/report-freshness.ts +3 -1
  488. package/src/plugins/builtin/shared/use-quote-board.ts +179 -43
  489. package/src/plugins/builtin/shared/volatility/options.ts +4 -1
  490. package/src/plugins/builtin/shared/wall-teaser.tsx +2 -2
  491. package/src/plugins/builtin/shared/zip-text.ts +46 -0
  492. package/src/plugins/builtin/short-interest/watch-headless.ts +2 -2
  493. package/src/plugins/builtin/short-interest/watch-model.ts +11 -2
  494. package/src/plugins/builtin/short-volume/headless.ts +1 -1
  495. package/src/plugins/builtin/social-mentions/headless.ts +1 -1
  496. package/src/plugins/builtin/supply-chain/headless.ts +43 -11
  497. package/src/plugins/builtin/supply-chain/model.ts +13 -0
  498. package/src/plugins/builtin/supply-chain/pane.tsx +5 -5
  499. package/src/plugins/builtin/themes/headless.ts +74 -10
  500. package/src/plugins/builtin/themes/model.ts +71 -4
  501. package/src/plugins/builtin/themes/pane.tsx +22 -5
  502. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +114 -0
  503. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +57 -2
  504. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +19 -55
  505. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +11 -0
  506. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +81 -19
  507. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +1 -1
  508. package/src/plugins/builtin/ticker-detail/headless-schema.ts +30 -0
  509. package/src/plugins/builtin/ticker-detail/headless.ts +88 -2
  510. package/src/plugins/builtin/ticker-detail/index.tsx +23 -11
  511. package/src/plugins/builtin/ticker-detail/overview/model.ts +3 -1
  512. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +8 -6
  513. package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +8 -6
  514. package/src/plugins/builtin/time-sales/headless.ts +23 -1
  515. package/src/plugins/builtin/time-sales/index.tsx +2 -1
  516. package/src/plugins/builtin/trace-bonds/client.ts +196 -0
  517. package/src/plugins/builtin/trace-bonds/headless.ts +69 -0
  518. package/src/plugins/builtin/trace-bonds/index.tsx +33 -0
  519. package/src/plugins/builtin/trace-bonds/model.ts +115 -0
  520. package/src/plugins/builtin/trace-bonds/pane.tsx +191 -0
  521. package/src/plugins/builtin/treasury-auctions/index.tsx +33 -47
  522. package/src/plugins/builtin/treasury-daily/client.ts +96 -0
  523. package/src/plugins/builtin/treasury-daily/headless.ts +69 -0
  524. package/src/plugins/builtin/treasury-daily/index.tsx +17 -0
  525. package/src/plugins/builtin/treasury-daily/model.ts +69 -0
  526. package/src/plugins/builtin/treasury-daily/pane.tsx +140 -0
  527. package/src/plugins/builtin/vol-surface/evidence.ts +7 -1
  528. package/src/plugins/builtin/vol-surface/headless.ts +50 -17
  529. package/src/plugins/builtin/vol-surface/heat-grid.tsx +113 -0
  530. package/src/plugins/builtin/vol-surface/model.ts +39 -6
  531. package/src/plugins/builtin/vol-surface/pane.tsx +14 -13
  532. package/src/plugins/builtin/vol-surface/stored.ts +63 -3
  533. package/src/plugins/builtin/vol-surface/surface.tsx +30 -2
  534. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +6 -5
  535. package/src/plugins/builtin/world-venue-map/basemap.ts +6 -3
  536. package/src/plugins/builtin/world-venue-map/entity-detail.tsx +15 -2
  537. package/src/plugins/builtin/world-venue-map/geo-draw.tsx +2 -1
  538. package/src/plugins/builtin/world-venue-map/geo-svg.tsx +6 -6
  539. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +16 -9
  540. package/src/plugins/builtin/world-venue-map/map.tsx +145 -13
  541. package/src/plugins/builtin/world-venue-map/model.ts +56 -19
  542. package/src/plugins/builtin/world-venue-map/pane.tsx +5 -2
  543. package/src/plugins/builtin/yield-curve/index.tsx +1 -1
  544. package/src/plugins/builtin-editorial.ts +1 -1
  545. package/src/plugins/catalog-browser.ts +25 -2
  546. package/src/plugins/installer.ts +2 -2
  547. package/src/plugins/loader.ts +15 -0
  548. package/src/plugins/manager-node.ts +1 -1
  549. package/src/plugins/{builtin/plugin-marketplace → marketplace}/feed.ts +2 -2
  550. package/src/plugins/{builtin/plugin-marketplace → marketplace}/model.ts +63 -27
  551. package/src/plugins/{builtin/plugin-marketplace → marketplace}/store.ts +1 -1
  552. package/src/plugins/registry/host-actions.ts +11 -0
  553. package/src/portfolio/collection-name.ts +31 -0
  554. package/src/portfolio/valuation-basis.ts +79 -0
  555. package/src/public/time-series.ts +1 -1
  556. package/src/react/input.ts +33 -1
  557. package/src/react/key-repeat.ts +86 -0
  558. package/src/remote/controller.ts +21 -1
  559. package/src/remote/schema.ts +3 -2
  560. package/src/renderers/browser/main.tsx +1 -1
  561. package/src/renderers/browser/research-entry.ts +4 -2
  562. package/src/renderers/dom/build-assets.ts +14 -5
  563. package/src/renderers/dom/data-table/index.tsx +5 -3
  564. package/src/renderers/dom/data-table/row.tsx +3 -0
  565. package/src/renderers/dom/desktop/controls.tsx +2 -1
  566. package/src/renderers/dom/desktop/icons.tsx +34 -0
  567. package/src/renderers/dom/desktop/list-view.tsx +1 -1
  568. package/src/renderers/dom/desktop/menu.tsx +1 -1
  569. package/src/renderers/dom/desktop/query-bar.tsx +3 -1
  570. package/src/renderers/dom/host/block-glyph-canvas.tsx +6 -3
  571. package/src/renderers/dom/host/box.tsx +7 -2
  572. package/src/renderers/dom/host/chart-surface.tsx +34 -2
  573. package/src/renderers/dom/host/resize-rows.ts +111 -0
  574. package/src/renderers/dom/host/scroll-box.tsx +32 -0
  575. package/src/renderers/dom/host/size-observer.ts +24 -9
  576. package/src/renderers/dom/host/sticky-scroll.ts +147 -0
  577. package/src/renderers/dom/host/style.ts +15 -1
  578. package/src/renderers/dom/host/surface-3d.tsx +15 -7
  579. package/src/renderers/dom/host/surface-fit.ts +410 -0
  580. package/src/renderers/dom/host/text.tsx +2 -2
  581. package/src/renderers/dom/input-host.tsx +1 -0
  582. package/src/renderers/dom/styles.css +109 -16
  583. package/src/renderers/electrobun/bun/application-menu/click.ts +18 -0
  584. package/src/renderers/electrobun/bun/desktop/app-badge.ts +37 -0
  585. package/src/renderers/electrobun/bun/desktop/backend.ts +1 -0
  586. package/src/renderers/electrobun/bun/desktop/host-requests.ts +8 -0
  587. package/src/renderers/electrobun/bun/desktop/macos-dock-badge.ts +37 -0
  588. package/src/renderers/electrobun/bun/desktop/macos-dock-icon.ts +2 -40
  589. package/src/renderers/electrobun/bun/desktop/macos-objc.ts +41 -0
  590. package/src/renderers/electrobun/bun/index.ts +3 -2
  591. package/src/renderers/electrobun/bun/tui-entry.ts +18 -1
  592. package/src/renderers/electrobun/shared/protocol.ts +3 -1
  593. package/src/renderers/electrobun/view/app-badge-host.ts +17 -0
  594. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +20 -3
  595. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +59 -24
  596. package/src/renderers/electrobun/view/main.tsx +5 -3
  597. package/src/renderers/electrobun/view/remote/asset-data-client.ts +7 -1
  598. package/src/renderers/opentui/chart-surface.tsx +1 -0
  599. package/src/renderers/opentui/frame-capture.ts +33 -0
  600. package/src/renderers/opentui/host.tsx +10 -13
  601. package/src/renderers/opentui/pane-image/glyphs-license.txt +107 -0
  602. package/src/renderers/opentui/pane-image/glyphs.json +1 -0
  603. package/src/renderers/opentui/pane-image/index.ts +107 -0
  604. package/src/renderers/opentui/pane-image/raster.ts +428 -0
  605. package/src/renderers/opentui/start.tsx +3 -3
  606. package/src/renderers/opentui/test-utils.tsx +3 -0
  607. package/src/renderers/opentui/ui-host.tsx +29 -1
  608. package/src/series/resolve.ts +3 -2
  609. package/src/series/types.ts +8 -0
  610. package/src/series/validate.ts +2 -2
  611. package/src/shares/api.ts +5 -1
  612. package/src/shares/chat.ts +34 -0
  613. package/src/shares/dialog.tsx +295 -0
  614. package/src/shares/flow.tsx +56 -0
  615. package/src/shares/live.ts +14 -22
  616. package/src/shares/location.ts +31 -0
  617. package/src/shares/open.ts +26 -0
  618. package/src/shares/pane-image.ts +164 -0
  619. package/src/shares/personal-pane.ts +52 -0
  620. package/src/shares/portable-layout.ts +4 -2
  621. package/src/shares/prepare.ts +20 -0
  622. package/src/sources/gloomberb-cloud/index.ts +109 -5
  623. package/src/sources/gloomberb-cloud/normalizers.ts +7 -0
  624. package/src/sources/gloomberb-cloud/perpetuals.ts +249 -0
  625. package/src/sources/history-coverage.ts +22 -4
  626. package/src/sources/history-result.ts +3 -1
  627. package/src/sources/history-retention.ts +11 -0
  628. package/src/sources/listing-target.ts +4 -0
  629. package/src/sources/provider-errors.ts +2 -1
  630. package/src/sources/provider-router/batches.ts +18 -2
  631. package/src/sources/provider-router/index.ts +16 -1
  632. package/src/state/app/context/index.tsx +3 -2
  633. package/src/state/hooks/inline-tickers.ts +49 -11
  634. package/src/test-support/builtin-panes.ts +31 -0
  635. package/src/test-support/shell-pane-keys.tsx +1 -0
  636. package/src/theme/theme-context.tsx +15 -1
  637. package/src/tickers/instrument-kind.ts +9 -1
  638. package/src/tickers/listing-name.ts +34 -0
  639. package/src/tickers/listing-venues.ts +154 -0
  640. package/src/tickers/open-target.ts +11 -3
  641. package/src/tickers/perpetual-listing.ts +151 -0
  642. package/src/tickers/prediction-listing.ts +26 -0
  643. package/src/tickers/search/index.ts +34 -6
  644. package/src/tickers/search/ranking.ts +85 -4
  645. package/src/tickers/ticker-changes.ts +213 -0
  646. package/src/time-series/chart-data.ts +2 -0
  647. package/src/time-series/economic.ts +2 -6
  648. package/src/time-series/ice-credit.ts +39 -0
  649. package/src/time-series/parsed-history-cache.ts +41 -11
  650. package/src/time-series/resolve.ts +163 -28
  651. package/src/time-series/studies.ts +1 -0
  652. package/src/time-series/types.ts +8 -0
  653. package/src/types/config.ts +4 -2
  654. package/src/types/data-provider.ts +19 -1
  655. package/src/types/financials.ts +23 -0
  656. package/src/types/headless.ts +74 -0
  657. package/src/types/instrument.ts +4 -0
  658. package/src/types/plugin.ts +60 -2
  659. package/src/types/price-history.ts +2 -0
  660. package/src/types/ticker-changes.ts +26 -0
  661. package/src/ui/context-menu.tsx +13 -1
  662. package/src/ui/host.tsx +49 -7
  663. package/src/ui/live-resize.ts +10 -0
  664. package/src/ui/live-stretch.ts +51 -19
  665. package/src/ui/sticky-scroll.ts +7 -0
  666. package/src/utils/central-banks.ts +76 -0
  667. package/src/utils/cli-output.ts +126 -16
  668. package/src/utils/crypto-pair.ts +1 -1
  669. package/src/utils/currency-pair.ts +66 -0
  670. package/src/utils/currency-units.ts +11 -0
  671. package/src/utils/datetime-format.ts +27 -6
  672. package/src/utils/decimal-comma.ts +57 -0
  673. package/src/utils/dom-screenshot.ts +3 -1
  674. package/src/utils/double-escape-close.ts +15 -1
  675. package/src/utils/exchanges.ts +36 -0
  676. package/src/utils/format.ts +19 -2
  677. package/src/utils/forward-dividend.ts +14 -0
  678. package/src/utils/fx-status.ts +6 -1
  679. package/src/utils/guards.ts +25 -0
  680. package/src/utils/inline-content-tokenizer.ts +22 -3
  681. package/src/utils/local-utc-offset.ts +37 -0
  682. package/src/utils/market-capitalization.ts +8 -0
  683. package/src/utils/one-shot.ts +73 -0
  684. package/src/utils/options.ts +37 -8
  685. package/src/utils/plugin-proxy-hosts.json +8 -1
  686. package/src/utils/utc-time.ts +12 -0
  687. package/src/plugins/builtin/credit-boards/pane.tsx +0 -30
  688. package/src/ui/pane-fill.ts +0 -11
  689. /package/src/plugins/{builtin/plugin-marketplace → marketplace}/activation.ts +0 -0
  690. /package/src/plugins/{builtin/plugin-marketplace → marketplace}/ids.ts +0 -0
  691. /package/src/plugins/{builtin/plugin-marketplace → marketplace}/packs.ts +0 -0
@@ -6,7 +6,11 @@ import type {
6
6
  ChatMessage,
7
7
  ChatMessageOrigin,
8
8
  ChatNotification,
9
+ ChatReaction,
10
+ ChatReactionUser,
9
11
  ChatStateResponse,
12
+ ChatUserBadge,
13
+ ChatUserSummary,
10
14
  CloudSavedSearch,
11
15
  CloudSearchHit,
12
16
  CloudSearchResponse,
@@ -15,6 +19,7 @@ import type {
15
19
  TeamNotification,
16
20
  } from "./types";
17
21
  import { normalizeTimestamp } from "../utils/timestamp";
22
+ import { parseChatPaneLink } from "./chat-pane-link";
18
23
 
19
24
  /**
20
25
  * Saved-search writes answer with either the record itself or `{ search }`.
@@ -80,17 +85,37 @@ export function normalizeChatAttachments(value: unknown): ChatAttachment[] {
80
85
  const CHAT_ACCOUNT_TYPES: readonly string[] = ["human", "managed_llm", "discord"] satisfies ChatAccountType[];
81
86
  const CHAT_MESSAGE_ORIGINS: readonly string[] = ["app", "discord"] satisfies ChatMessageOrigin[];
82
87
 
83
- /** A value a newer server adds that this client does not know reads as absent: a human, a message from the app. */
84
- function chatUserWithKnownAccountType(user: ChatMessage["user"]): ChatMessage["user"] {
85
- if (!user || user.accountType === undefined || CHAT_ACCOUNT_TYPES.includes(user.accountType)) return user;
86
- const { accountType: _unknown, ...known } = user;
87
- return known;
88
+ const CHAT_USER_BADGES: readonly string[] = ["team", "pro"] satisfies ChatUserBadge[];
89
+
90
+ /**
91
+ * A value a newer server adds that this client does not know reads as absent:
92
+ * a human, a message from the app, no badge. A clock or desks that are not
93
+ * what the server promises are dropped rather than shown wrong.
94
+ */
95
+ function normalizeChatUser(user: ChatUserSummary): ChatUserSummary {
96
+ if (!user || typeof user !== "object") return user;
97
+ const { accountType, badges, utcOffsetMinutes, desks, ...rest } = user;
98
+ const knownBadges = Array.isArray(badges)
99
+ ? CHAT_USER_BADGES.filter((badge) => badges.includes(badge as ChatUserBadge)) as ChatUserBadge[]
100
+ : [];
101
+ const knownDesks = Array.isArray(desks) ? desks.filter((desk): desk is string => typeof desk === "string" && !!desk) : [];
102
+ const offset = typeof utcOffsetMinutes === "number" && Number.isInteger(utcOffsetMinutes)
103
+ && utcOffsetMinutes >= -12 * 60 && utcOffsetMinutes <= 14 * 60
104
+ ? utcOffsetMinutes
105
+ : null;
106
+ return {
107
+ ...rest,
108
+ ...(accountType !== undefined && CHAT_ACCOUNT_TYPES.includes(accountType) ? { accountType } : {}),
109
+ ...(knownBadges.length > 0 ? { badges: knownBadges } : {}),
110
+ ...(offset !== null ? { utcOffsetMinutes: offset } : {}),
111
+ ...(knownDesks.length > 0 ? { desks: knownDesks } : {}),
112
+ };
88
113
  }
89
114
 
90
115
  export function normalizeChatMessage(message: ChatMessage): ChatMessage {
91
116
  const normalized: ChatMessage = {
92
117
  ...message,
93
- user: chatUserWithKnownAccountType(message.user),
118
+ user: normalizeChatUser(message.user),
94
119
  content: typeof message.content === "string" ? message.content : "",
95
120
  createdAt: normalizeTimestamp(message.createdAt),
96
121
  ...(message.editedAt
@@ -98,10 +123,16 @@ export function normalizeChatMessage(message: ChatMessage): ChatMessage {
98
123
  : {}),
99
124
  };
100
125
  if ("attachments" in message) normalized.attachments = normalizeChatAttachments(message.attachments);
126
+ if ("reactions" in message) normalized.reactions = normalizeChatReactions(message.reactions);
101
127
  if (message.origin !== undefined && !CHAT_MESSAGE_ORIGINS.includes(message.origin)) delete normalized.origin;
102
128
  if (message.attachmentReview !== "pending" && message.attachmentReview !== "failed") {
103
129
  delete normalized.attachmentReview;
104
130
  }
131
+ if ("paneLink" in message) {
132
+ const paneLink = parseChatPaneLink(message.paneLink);
133
+ if (paneLink) normalized.paneLink = paneLink;
134
+ else delete normalized.paneLink;
135
+ }
105
136
  return normalized;
106
137
  }
107
138
 
@@ -117,6 +148,35 @@ export function normalizeChatDiscordLink(value: unknown): ChatDiscordLink {
117
148
  };
118
149
  }
119
150
 
151
+ /** Reactions as the server sent them, dropping anything malformed. */
152
+ export function normalizeChatReactions(value: unknown): ChatReaction[] {
153
+ if (!Array.isArray(value)) return [];
154
+ const reactions: ChatReaction[] = [];
155
+ for (const entry of value) {
156
+ if (!entry || typeof entry !== "object") continue;
157
+ const raw = entry as Record<string, unknown>;
158
+ if (typeof raw.emoji !== "string" || !raw.emoji) continue;
159
+ const count = typeof raw.count === "number" && Number.isFinite(raw.count) ? Math.max(0, Math.floor(raw.count)) : 0;
160
+ if (count === 0) continue;
161
+ const users = Array.isArray(raw.users)
162
+ ? raw.users.flatMap((user): ChatReactionUser[] => {
163
+ if (!user || typeof user !== "object") return [];
164
+ const candidate = user as Record<string, unknown>;
165
+ if (typeof candidate.id !== "string") return [];
166
+ const accountType = candidate.accountType;
167
+ return [{
168
+ id: candidate.id,
169
+ username: typeof candidate.username === "string" ? candidate.username : null,
170
+ displayName: typeof candidate.displayName === "string" ? candidate.displayName : "User",
171
+ ...(accountType === "human" || accountType === "managed_llm" || accountType === "discord" ? { accountType } : {}),
172
+ }];
173
+ })
174
+ : [];
175
+ reactions.push({ emoji: raw.emoji, count, me: raw.me === true, users });
176
+ }
177
+ return reactions;
178
+ }
179
+
120
180
  export function normalizeChatMessages(messages: ChatMessage[]): ChatMessage[] {
121
181
  return messages.map((message) => normalizeChatMessage(message));
122
182
  }
@@ -139,6 +199,8 @@ export function normalizeChatChannel(
139
199
  ...channel,
140
200
  kind: channel.kind ?? fallbackKind,
141
201
  created_at: normalizeTimestamp(channel.created_at),
202
+ ...(channel.dmUser ? { dmUser: normalizeChatUser(channel.dmUser) } : {}),
203
+ ...(Array.isArray(channel.members) ? { members: channel.members.map(normalizeChatUser) } : {}),
142
204
  };
143
205
  }
144
206
 
@@ -0,0 +1,44 @@
1
+ /** Names per request: one page of a list, such as a clinical trial search page's lead sponsors. */
2
+ export const ORGANIZATION_TICKERS_BATCH_LIMIT = 50;
3
+
4
+ /**
5
+ * What Gloom Cloud resolved an organization name to: the listing of the
6
+ * company the name belongs to, or why there is none. The match is the
7
+ * server's, from reviewed and exact aliases only; the app never matches a
8
+ * name to a ticker itself.
9
+ */
10
+ export interface OrganizationTicker {
11
+ name: string;
12
+ /** Null when the name is unlinked, ambiguous, or resolved to a company without a listing. */
13
+ ticker: string | null;
14
+ exchange: string | null;
15
+ /** The company the name resolved to; null when unlinked. */
16
+ entityName: string | null;
17
+ resolution: "identifier" | "alias" | "unresolved";
18
+ /** Left unlinked because the name fits more than one company. */
19
+ ambiguous: boolean;
20
+ }
21
+
22
+ export interface OrganizationTickersResponse {
23
+ results: OrganizationTicker[];
24
+ }
25
+
26
+ function isResult(value: unknown): value is OrganizationTicker {
27
+ if (!value || typeof value !== "object") return false;
28
+ const row = value as Record<string, unknown>;
29
+ const text = (field: unknown) => field === null || typeof field === "string";
30
+ return typeof row.name === "string"
31
+ && text(row.ticker) && text(row.exchange) && text(row.entityName)
32
+ && (row.resolution === "identifier" || row.resolution === "alias" || row.resolution === "unresolved")
33
+ && typeof row.ambiguous === "boolean";
34
+ }
35
+
36
+ /** The answers in the order asked; throws when the server answered something else. */
37
+ export function validateOrganizationTickers(payload: unknown, names: readonly string[]): OrganizationTicker[] {
38
+ const results = (payload as Partial<OrganizationTickersResponse> | null)?.results;
39
+ if (!Array.isArray(results) || results.length !== names.length || !results.every(isResult)
40
+ || results.some((result, index) => result.name !== names[index])) {
41
+ throw new Error("The server returned invalid organization tickers.");
42
+ }
43
+ return results;
44
+ }
@@ -147,6 +147,14 @@ export interface PerpBoardPayload {
147
147
  access: "pro" | "preview"; sources?: unknown[];
148
148
  }
149
149
  export interface PerpEquityListing { symbol: string; exchange: string }
150
+ /**
151
+ * The batch lookup a watchlist or portfolio makes: one entry per requested listing, in its order, with the contract
152
+ * the single equity lookup would list first, or none. `listing` is null when the server cannot read the listing.
153
+ */
154
+ export interface PerpEquitiesPayload {
155
+ status: string; asOf: string | null; access: "pro" | "preview"; locked: number;
156
+ results: { listing: PerpEquityListing | null; market: PerpBoardRow | null }[];
157
+ }
150
158
  export interface PerpHistoryPayload {
151
159
  status: string; marketId: string; rows: PerpHistoryPoint[]; funding: PerpFunding[]; candles: PerpCandle[];
152
160
  /** Absent from servers older than the long/short series: read as empty. */
@@ -408,8 +408,17 @@ export class CloudApiRequestTransport {
408
408
  // Crash reports, usage counts and command-search reports are background
409
409
  // traffic: a rate-limited, timed-out or missing one must not show up as a
410
410
  // Cloud outage in the connections pane. Nor must the map's probe for geo
411
- // layers, which a server without them answers with 404.
412
- if (path.startsWith("/telemetry/") || path === "/assist/searches" || path === "/cloud/geo/layers") return request();
411
+ // layers, which a server without them answers with 404, or a ticker
412
+ // change lookup: a note beside a quote, never one of the refused market
413
+ // requests a lookup of many symbols waits out and retries. Nor the
414
+ // tickers beside a list of organization names, which say so in place.
415
+ if (
416
+ path.startsWith("/telemetry/")
417
+ || path === "/assist/searches"
418
+ || path === "/cloud/geo/layers"
419
+ || path.startsWith("/market/ticker-changes?")
420
+ || path === "/market/organization-tickers"
421
+ ) return request();
413
422
  return this.connectionHealth.track(
414
423
  GLOOM_CLOUD_HTTP_CONNECTION_ID,
415
424
  operation,
@@ -3,6 +3,7 @@ import type {
3
3
  AuthUser,
4
4
  ChatMessage,
5
5
  ChatNotification,
6
+ ChatReactionsUpdate,
6
7
  CloudQuotePayload,
7
8
  QuoteStreamTarget,
8
9
  ScannerFeedEvent,
@@ -12,6 +13,7 @@ import type {
12
13
  import {
13
14
  normalizeChatMessage,
14
15
  normalizeChatNotification,
16
+ normalizeChatReactions,
15
17
  normalizeTeamNotification,
16
18
  } from "./normalizers";
17
19
  import { debugLog } from "../utils/debug-log";
@@ -41,6 +43,7 @@ const cloudApiLog = debugLog.createLogger("cloud-api");
41
43
  type ChannelListener = (message: ChatMessage) => void;
42
44
  type ChatNotificationListener = (notification: ChatNotification) => void;
43
45
  type ChatPresenceListener = (onlineCount: number) => void;
46
+ type ChatReactionsListener = (update: ChatReactionsUpdate) => void;
44
47
  type TeamNotificationListener = (notification: TeamNotification) => void;
45
48
  type CloudEventListener = (data: unknown) => void;
46
49
  type QuoteListener = (
@@ -106,6 +109,7 @@ export class CloudApiSocket {
106
109
  private readonly chatNotificationListeners =
107
110
  new Set<ChatNotificationListener>();
108
111
  private readonly chatPresenceListeners = new Set<ChatPresenceListener>();
112
+ private readonly chatReactionsListeners = new Set<ChatReactionsListener>();
109
113
  private readonly teamNotificationListeners =
110
114
  new Set<TeamNotificationListener>();
111
115
  private readonly cloudEventListeners = new Map<
@@ -245,6 +249,14 @@ export class CloudApiSocket {
245
249
  };
246
250
  }
247
251
 
252
+ /** A message's reactions changed in a channel this socket reads. */
253
+ subscribeChatReactions(listener: ChatReactionsListener): () => void {
254
+ this.chatReactionsListeners.add(listener);
255
+ return () => {
256
+ this.chatReactionsListeners.delete(listener);
257
+ };
258
+ }
259
+
248
260
  subscribeChatPresence(listener: ChatPresenceListener): () => void {
249
261
  this.chatPresenceListeners.add(listener);
250
262
  return () => {
@@ -500,6 +512,7 @@ export class CloudApiSocket {
500
512
  this.connectionListeners.clear();
501
513
  this.chatNotificationListeners.clear();
502
514
  this.chatPresenceListeners.clear();
515
+ this.chatReactionsListeners.clear();
503
516
  this.teamNotificationListeners.clear();
504
517
  this.cloudEventListeners.clear();
505
518
  this.quoteSubscriptions.clear();
@@ -575,6 +588,22 @@ export class CloudApiSocket {
575
588
  return;
576
589
  }
577
590
 
591
+ if (
592
+ parsed?.type === "chat.reactions" &&
593
+ typeof parsed.channelId === "string" &&
594
+ typeof parsed.data?.messageId === "string"
595
+ ) {
596
+ const update: ChatReactionsUpdate = {
597
+ channelId: parsed.channelId,
598
+ messageId: parsed.data.messageId,
599
+ reactions: normalizeChatReactions(parsed.data.reactions),
600
+ };
601
+ for (const listener of this.chatReactionsListeners) {
602
+ listener(update);
603
+ }
604
+ return;
605
+ }
606
+
578
607
  if (parsed?.type === "chat.notification" && parsed.data) {
579
608
  const notification = normalizeChatNotification(
580
609
  parsed.data as ChatNotification,
@@ -15,6 +15,12 @@ export interface ThemeSummary {
15
15
  worst: { symbol: string; changePercent: number } | null;
16
16
  stale: boolean;
17
17
  }
18
+ /**
19
+ * A member's figures. `price`, `changePercent` and the returns are the regular
20
+ * session's: outside it, its close and that close's move. The extended fields
21
+ * are the pre-market or after-hours print measured from that close; a server
22
+ * sends them only when there is one, and older servers never do.
23
+ */
18
24
  export interface ThemeMember extends Record<ThemePeriod | "price", number | null> {
19
25
  symbol: string;
20
26
  name: string | null;
@@ -22,7 +28,22 @@ export interface ThemeMember extends Record<ThemePeriod | "price", number | null
22
28
  present: boolean;
23
29
  asOf: Record<ThemePeriod | "price", string | null>;
24
30
  stale: boolean;
31
+ extendedSession?: "PRE" | "POST" | null;
32
+ extendedPrice?: number | null;
33
+ extendedChange?: number | null;
34
+ extendedChangePercent?: number | null;
35
+ }
36
+ interface SnapshotMetadata {
37
+ /** When the server put the snapshot together, not a trade time. */
38
+ asOf: string;
39
+ snapshotId: string;
40
+ stale: boolean;
41
+ /** The US market as the server's delayed board reads it. Absent from older servers. */
42
+ session?: "PRE" | "REGULAR" | "POST" | "CLOSED" | null;
43
+ /** Outside the regular session, the completed session every figure describes; null while one trades. */
44
+ regularSessionDate?: string | null;
45
+ /** When that session closed, in epoch milliseconds (13:00 New York on an early close). */
46
+ regularSessionClosedAt?: number | null;
25
47
  }
26
- interface SnapshotMetadata { asOf: string; snapshotId: string; stale: boolean }
27
48
  export interface ThemesPayload extends SnapshotMetadata { themes: ThemeSummary[] }
28
49
  export interface ThemeMembersPayload extends SnapshotMetadata { theme: ThemeSummary; members: ThemeMember[] }
@@ -9,6 +9,7 @@ import type {
9
9
  TickerFinancials,
10
10
  } from "../types/financials";
11
11
  import type { SyncSettings, SyncSnapshot } from "../sync/types";
12
+ import type { ChatPaneLink } from "./chat-pane-link";
12
13
 
13
14
  /**
14
15
  * What stands behind a chat account. `discord` is a person on the Gloom
@@ -20,6 +21,9 @@ export type ChatAccountType = "human" | "managed_llm" | "discord";
20
21
  /** Where a message was written. A message without one came from the app. */
21
22
  export type ChatMessageOrigin = "app" | "discord";
22
23
 
24
+ /** A badge an account earns in chat: `team` for Gloom staff, `pro` with Pro access. */
25
+ export type ChatUserBadge = "team" | "pro";
26
+
23
27
  export interface ChatUserSummary {
24
28
  id: string;
25
29
  /** A person, a managed assistant (Gloombot), or a Discord user bridged into public channels. */
@@ -32,6 +36,15 @@ export interface ChatUserSummary {
32
36
  profilePublic?: boolean;
33
37
  acceptUnknownDms?: boolean;
34
38
  portfolioAnalytics?: PublicPortfolioAnalytics | null;
39
+ /** Badges the account earns. A server that predates them, or a person with none, leaves this out. */
40
+ badges?: ChatUserBadge[];
41
+ /**
42
+ * The person's current offset from UTC in minutes, as their app last
43
+ * reported it: left out while they keep their local time hidden.
44
+ */
45
+ utcOffsetMinutes?: number;
46
+ /** The desks (equities, options, ...) the person chose to show; left out unless they did. */
47
+ desks?: string[];
35
48
  }
36
49
 
37
50
  /**
@@ -49,6 +62,33 @@ export interface ChatAttachment {
49
62
  url: string;
50
63
  }
51
64
 
65
+ /** Someone who reacted, as a reaction lists the first few. */
66
+ export interface ChatReactionUser {
67
+ id: string;
68
+ username: string | null;
69
+ displayName: string;
70
+ accountType?: ChatAccountType | null;
71
+ }
72
+
73
+ /**
74
+ * One emoji on a message: how many reacted, whether you did, and the first
75
+ * few who did, oldest first. `emoji` is the character, or `:name:` for a
76
+ * custom Discord server emoji.
77
+ */
78
+ export interface ChatReaction {
79
+ emoji: string;
80
+ count: number;
81
+ me: boolean;
82
+ users?: ChatReactionUser[];
83
+ }
84
+
85
+ /** A message's reactions as they stand after a change, from the `chat.reactions` frame or a reaction request. */
86
+ export interface ChatReactionsUpdate {
87
+ channelId: string;
88
+ messageId: string;
89
+ reactions: ChatReaction[];
90
+ }
91
+
52
92
  export interface ChatMessage {
53
93
  id: string;
54
94
  channelId: string;
@@ -66,12 +106,20 @@ export interface ChatMessage {
66
106
  } | null;
67
107
  /** Images in display order. A server that predates them leaves this out. */
68
108
  attachments?: ChatAttachment[];
109
+ /**
110
+ * Emoji reactions in the order they first appeared. Message lists from a
111
+ * server that knows reactions always carry it; a live copy of a message
112
+ * (an edit) leaves it out, and the reactions held stay.
113
+ */
114
+ reactions?: ChatReaction[];
69
115
  /**
70
116
  * Only on the author's copy of a public message whose images are still being
71
117
  * checked ("pending") or could not be checked ("failed"). Nobody else has the
72
118
  * message yet.
73
119
  */
74
120
  attachmentReview?: "pending" | "failed";
121
+ /** What the message opens in the terminal (a Gloom Wire story or calendar). Only the server sets it. */
122
+ paneLink?: ChatPaneLink;
75
123
  clientStatus?: "sending" | "failed";
76
124
  clientError?: string | null;
77
125
  /** The idempotency key a local send went out with, so a retry repeats it. */
@@ -175,6 +223,12 @@ export interface AccountProfile {
175
223
  acceptUnknownDms: boolean;
176
224
  chatEmailNotificationsEnabled: boolean;
177
225
  portfolioAnalytics?: PublicPortfolioAnalytics | null;
226
+ /** Chat shows your local time on your card. A server that predates the setting leaves it out. */
227
+ showLocalTime?: boolean;
228
+ /** The desks chat shows beside your name; empty shows none. */
229
+ chatDesks?: string[];
230
+ /** Your answer to "What do you trade?" at the first run: private, it pre-fills `chatDesks`. */
231
+ onboardingDesks?: string[];
178
232
  syncEnabled: boolean;
179
233
  weeklyRoundupEnabled: boolean;
180
234
  positionAlertsEnabled: boolean;
@@ -318,6 +372,9 @@ export type AccountProfileUpdate = Partial<{
318
372
  syncEnabled: boolean;
319
373
  weeklyRoundupEnabled: boolean;
320
374
  positionAlertsEnabled: boolean;
375
+ showLocalTime: boolean;
376
+ /** Null or empty shows no desks. */
377
+ chatDesks: string[] | null;
321
378
  }>;
322
379
 
323
380
  export interface CloudSyncSnapshotResponse {
@@ -402,6 +459,10 @@ export interface CloudPricePointPayload {
402
459
  low?: number;
403
460
  close: number;
404
461
  volume?: number;
462
+ /** A coin's daily bar for the UTC day still forming when served; it has no volume yet. */
463
+ partial?: boolean;
464
+ /** A coin's daily bar whose prices were rebuilt from hourly bars; a day the source left empty has no volume. */
465
+ filled?: boolean;
405
466
  }
406
467
 
407
468
  type CloudEconImpact = "high" | "medium" | "low";
@@ -432,6 +493,13 @@ export interface CloudMacroReleaseDaysPayload {
432
493
  export interface CloudFredObservationPayload {
433
494
  date: string;
434
495
  value: number | null;
496
+ /**
497
+ * Who published a value FRED does not list yet, such as a Treasury yield
498
+ * Gloom Cloud read from the Treasury first. Absent on FRED's own values.
499
+ */
500
+ publisher?: string;
501
+ /** When that publisher's value was first read, ISO in UTC. */
502
+ publishedAt?: string;
435
503
  }
436
504
 
437
505
  export interface CloudFredSeriesInfoPayload {
@@ -538,6 +606,22 @@ export interface CloudCdsHistoryResponse {
538
606
  points: CloudCdsHistoryPointPayload[];
539
607
  }
540
608
 
609
+ /** An issuer's latest 5Y level: the last point of its history over the last month. */
610
+ export interface CloudCdsLevelPayload {
611
+ /** The reference entity as the history response names it. */
612
+ issuer: string;
613
+ spreadBp: number;
614
+ date: string;
615
+ }
616
+
617
+ export interface CloudCdsLevelsResponse {
618
+ source: string;
619
+ tenor: string;
620
+ asOf: string | null;
621
+ /** Every issuer traded in the last month whose 5Y line has a level in it. */
622
+ levels: CloudCdsLevelPayload[];
623
+ }
624
+
541
625
  interface CloudShortInterestPointPayload {
542
626
  settlementDate: string;
543
627
  shortPercentFloat?: number | null;
@@ -1098,7 +1182,7 @@ export interface CloudSearchResponse {
1098
1182
  tookMs: number;
1099
1183
  }
1100
1184
 
1101
- export interface CloudSearchDocumentChunk {
1185
+ interface CloudSearchDocumentChunk {
1102
1186
  id: string;
1103
1187
  chunkIndex: number;
1104
1188
  body: string;
@@ -1361,7 +1445,9 @@ export interface CloudHistoryCoverage {
1361
1445
  /** First bar date (YYYY-MM-DD) the source serves, such as a fund's inception. */
1362
1446
  firstAllowedBarDate?: string;
1363
1447
  inceptionDate?: string;
1364
- sourceUrl: string;
1448
+ /** Why nothing earlier is served, such as "old-shekel quotes before 1992 are not served". */
1449
+ note?: string;
1450
+ sourceUrl?: string;
1365
1451
  firstBarDate: string | null;
1366
1452
  lastBarDate: string | null;
1367
1453
  barCount: number;
@@ -1,4 +1,4 @@
1
- import { useEffect, useRef, type Dispatch } from "react";
1
+ import { useEffect, useRef, useState, type Dispatch } from "react";
2
2
  import { useShortcut } from "../react/input";
3
3
  import { useNativeRenderer, useRendererHost, useUiHost } from "../ui";
4
4
  import { useDialogState } from "../ui/dialog";
@@ -13,6 +13,7 @@ import { getVisiblePaneCycleOrder } from "../components/layout/pane/cycle-order"
13
13
  import { requestFunctionHelp, useFunctionHelpHost } from "../plugins/builtin/help/function-card";
14
14
  import { buildRegistryHelpIndex, helpFunctionForPane } from "../plugins/builtin/help/function-index";
15
15
  import { recordFunctionOpen } from "../telemetry/usage-counts";
16
+ import { createOneShots } from "../utils/one-shot";
16
17
  import { DOCS_PANE_TEMPLATE_ID } from "../docs/content";
17
18
  import { registerPaneDocsHandler } from "../docs/requests";
18
19
  import { isMoveDownShortcut, isMoveUpShortcut } from "../components/command-bar/keyboard-handlers";
@@ -117,6 +118,10 @@ export function useAppGlobalShortcuts({
117
118
  const uiKind = useUiHost().kind;
118
119
  const toastHost = useToastHost();
119
120
  useKeybindingIssueNotice(keybindings, pluginRegistry, state.initialized);
121
+ // Every action here runs once per press: a held key, or a terminal that does
122
+ // not say it is a repeat, must not run it again. Only moving focus between
123
+ // panes (Tab) and switching layouts by number (idempotent) are left to repeat.
124
+ const [shots] = useState(createOneShots);
120
125
  useFunctionHelpHost({
121
126
  closeCommandBar: () => {
122
127
  if (state.commandBarOpen) dispatch({ type: "SET_COMMAND_BAR", open: false });
@@ -149,6 +154,23 @@ export function useAppGlobalShortcuts({
149
154
 
150
155
  const match = matchKeybinding(keybindings, event);
151
156
  const action = match?.kind === "action" ? match.id : null;
157
+ /**
158
+ * Whether the action already ran for this press or hold. An action that
159
+ * takes the key (`claims`) swallows the refused ones as well; one that
160
+ * leaves it to the pane (R) does not, so a pane's own key keeps working.
161
+ */
162
+ const ranAlready = (id: string, claims = true): boolean => {
163
+ const shot = shots.get(id);
164
+ if (shot.refuses(event)) {
165
+ if (claims) {
166
+ event.preventDefault();
167
+ event.stopPropagation();
168
+ }
169
+ return true;
170
+ }
171
+ shot.end();
172
+ return false;
173
+ };
152
174
 
153
175
  // Terminals send Ctrl; the browser and the desktop webview send Cmd on
154
176
  // macOS, which the OpenTUI host also reports as `super` under the kitty
@@ -172,6 +194,7 @@ export function useAppGlobalShortcuts({
172
194
  // The status bar's star line answers the same keys once no toast does,
173
195
  // but only over the workspace itself.
174
196
  if (action === "notification-action" || action === "notification-dismiss") {
197
+ if (ranAlready(action)) return;
175
198
  const toastHandled = action === "notification-action"
176
199
  ? toastHost.activateNewest?.() === true
177
200
  : toastHost.dismissNewest?.() === true;
@@ -195,12 +218,14 @@ export function useAppGlobalShortcuts({
195
218
  // Ctrl+P and Ctrl+N move the open bar's selection, so a bar chord that
196
219
  // is one of them only opens it; Esc and the bar's other chords close it.
197
220
  if (state.commandBarOpen && (isMoveUpShortcut(event) || isMoveDownShortcut(event))) return;
221
+ if (ranAlready(action)) return;
198
222
  event.preventDefault();
199
223
  event.stopPropagation();
200
224
  dispatch({ type: "TOGGLE_COMMAND_BAR" });
201
225
  return;
202
226
  }
203
227
  if (!isDetachedWindow && action === "ticker-search" && !state.commandBarOpen) {
228
+ if (ranAlready(action)) return;
204
229
  event.preventDefault();
205
230
  event.stopPropagation();
206
231
  dispatch({
@@ -233,6 +258,7 @@ export function useAppGlobalShortcuts({
233
258
  // Command and function keys are never text, so they still fire.
234
259
  const editing = state.inputCaptured || event.targetEditable === true;
235
260
  if (editing && event.ctrl && !(event.meta || event.super)) return;
261
+ if (ranAlready(`command:${match.command.query}`)) return;
236
262
  event.preventDefault();
237
263
  event.stopPropagation();
238
264
  dispatch({
@@ -246,6 +272,7 @@ export function useAppGlobalShortcuts({
246
272
 
247
273
  // A function key is never text, so the card opens from a focused field too.
248
274
  if (action === "function-help") {
275
+ if (ranAlready(action)) return;
249
276
  event.preventDefault();
250
277
  event.stopPropagation();
251
278
  recordFunctionOpen({ shortcut: "HELP", externalPluginId: null });
@@ -259,6 +286,7 @@ export function useAppGlobalShortcuts({
259
286
  if (state.inputCaptured) return;
260
287
 
261
288
  if (!isDetachedWindow && action === "help") {
289
+ if (ranAlready(action)) return;
262
290
  event.preventDefault();
263
291
  event.stopPropagation();
264
292
  pluginRegistry.showPane("help");
@@ -266,13 +294,16 @@ export function useAppGlobalShortcuts({
266
294
  }
267
295
 
268
296
  if (!isDetachedWindow && action === "quit") {
297
+ if (ranAlready(action, false)) return;
269
298
  if (uiKind === "opentui") rendererHost.requestExit();
270
299
  } else if (action === "refresh-ticker") {
300
+ if (ranAlready(action, false)) return;
271
301
  if (focusedTickerSymbol) {
272
302
  const ticker = state.tickers.get(focusedTickerSymbol);
273
303
  if (ticker) refreshTicker(ticker.metadata.ticker, ticker.metadata.exchange, ticker, 0);
274
304
  }
275
305
  } else if (action === "refresh-all") {
306
+ if (ranAlready(action, false)) return;
276
307
  for (const ticker of state.tickers.values()) {
277
308
  refreshTicker(ticker.metadata.ticker, ticker.metadata.exchange, ticker, 1);
278
309
  }
@@ -280,10 +311,12 @@ export function useAppGlobalShortcuts({
280
311
  // A release that can install itself downloads on its own, so the key is
281
312
  // for the one that waits for a restart and for the one that failed.
282
313
  if (!isDetachedWindow && canRestartToApply(state.updateProgress)) {
314
+ if (ranAlready(action)) return;
283
315
  event.preventDefault();
284
316
  event.stopPropagation();
285
317
  restartToApplyUpdate();
286
318
  } else if (canRetryUpdate(state)) {
319
+ if (ranAlready(action)) return;
287
320
  event.preventDefault();
288
321
  event.stopPropagation();
289
322
  startUpdate(state.updateAvailable!);
@@ -296,6 +329,7 @@ export function useAppGlobalShortcuts({
296
329
  if (ownerId && disabledPlugins.has(ownerId)) continue;
297
330
  const chords = resolvePluginShortcutChords(keybindingsConfig, shortcut);
298
331
  if (chords.some((chord) => matchesKeyChord(chord, event))) {
332
+ if (ranAlready(`plugin:${shortcut.id}`, false)) return;
299
333
  shortcut.execute();
300
334
  break;
301
335
  }
@@ -28,6 +28,7 @@ export type CoreKeybindingActionId =
28
28
  | "pane-screenshot"
29
29
  | "pane-export-csv"
30
30
  | "pane-share"
31
+ | "pane-ask"
31
32
  | "layout-gallery"
32
33
  | "tidy-windows"
33
34
  | "window-move-mode"
@@ -59,6 +60,7 @@ export const PANE_ACTION_IDS = new Set<CoreKeybindingActionId>([
59
60
  "pane-screenshot",
60
61
  "pane-export-csv",
61
62
  "pane-share",
63
+ "pane-ask",
62
64
  "layout-gallery",
63
65
  "tidy-windows",
64
66
  "window-move-mode",
@@ -225,9 +227,18 @@ export const KEYBINDING_ACTIONS: readonly KeybindingActionDef[] = [
225
227
  {
226
228
  id: "pane-share",
227
229
  category: "Pane Management",
228
- description: "Share the focused pane.",
230
+ description: "Share the focused pane: post a picture to chat or copy its link.",
229
231
  defaults: ["CmdOrCtrl+Shift+S"],
230
232
  },
233
+ {
234
+ id: "pane-ask",
235
+ category: "Pane Management",
236
+ description: "Ask Gloom about the focused pane, in a new conversation with the pane attached.",
237
+ // A for ask. Alt+A first, because it reaches most terminals, where
238
+ // Ctrl+Shift+A is often the terminal's own select all; the desktop app
239
+ // advertises the chord on its platform modifier.
240
+ defaults: ["Alt+A", "CmdOrCtrl+Shift+A"],
241
+ },
231
242
  {
232
243
  id: "layout-gallery",
233
244
  category: "Pane Management",
@@ -16,8 +16,8 @@ import {
16
16
  } from "../../components/layout/shell/visible-layout";
17
17
  import { applyPluginToggles } from "../../plugins/ownership";
18
18
  import { setLayoutManagerDispatch } from "../../plugins/builtin/layout-manager";
19
- import { setMarketplaceHost } from "../../plugins/builtin/plugin-marketplace/store";
20
- import type { InstalledPlugin } from "../../plugins/builtin/plugin-marketplace/model";
19
+ import { setMarketplaceHost } from "../../plugins/marketplace/store";
20
+ import type { InstalledPlugin } from "../../plugins/marketplace/model";
21
21
  import {
22
22
  listExternalPlugins,
23
23
  removeExternalPlugin,