gloomberb 0.18.4 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (600) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/package.json +1 -1
  4. package/patches/electrobun@1.18.1.patch +169 -5
  5. package/src/account/auth-model.ts +7 -3
  6. package/src/api-client/auth.ts +9 -4
  7. package/src/api-client/catalysts.ts +2 -1
  8. package/src/api-client/cot.ts +6 -2
  9. package/src/api-client/credit-documents.ts +6 -0
  10. package/src/api-client/data.ts +31 -6
  11. package/src/api-client/equity-screener.ts +24 -0
  12. package/src/api-client/fund-facts.ts +45 -4
  13. package/src/api-client/index.ts +171 -11
  14. package/src/api-client/live-scan.ts +91 -0
  15. package/src/api-client/market-discovery.ts +10 -0
  16. package/src/api-client/market-movers.ts +7 -0
  17. package/src/api-client/members.ts +13 -1
  18. package/src/api-client/perps.ts +43 -0
  19. package/src/api-client/request.ts +222 -41
  20. package/src/api-client/research-activity.ts +6 -12
  21. package/src/api-client/types.ts +74 -0
  22. package/src/app/keybindings/index.ts +3 -0
  23. package/src/app/keybindings/labels.ts +18 -1
  24. package/src/app/keybindings/resolve.ts +14 -0
  25. package/src/app/pane-runtime/plugin-bindings.ts +9 -5
  26. package/src/app/runtime/broker-import.ts +42 -27
  27. package/src/app/runtime/plugin-bindings.ts +73 -56
  28. package/src/architecture/core-builtin-allowlist.json +1 -1
  29. package/src/architecture/pane-tabs-allowlist.json +3 -0
  30. package/src/architecture/ttl-caches-allowlist.json +19 -0
  31. package/src/brokers/sync-broker-instance.ts +2 -8
  32. package/src/capabilities/chart-series.ts +1 -1
  33. package/src/cli/commands/crypto-hints.ts +40 -24
  34. package/src/cli/commands/fred-series.ts +5 -0
  35. package/src/cli/commands/keybindings.ts +23 -0
  36. package/src/cli/commands/market.ts +138 -46
  37. package/src/cli/commands/options-chain.ts +107 -10
  38. package/src/cli/commands/options-leaps.ts +9 -3
  39. package/src/cli/commands/overview.ts +176 -39
  40. package/src/cli/commands/search.ts +39 -3
  41. package/src/cli/commands/themes.ts +11 -2
  42. package/src/cli/commands/ticker.ts +57 -35
  43. package/src/cli/company-name-hint.ts +41 -0
  44. package/src/cli/earnings-calendar.ts +1 -1
  45. package/src/cli/errors.ts +10 -2
  46. package/src/cli/export-source.ts +29 -1
  47. package/src/cli/glossary.ts +73 -1
  48. package/src/cli/history-rows.ts +87 -16
  49. package/src/cli/index.ts +2 -0
  50. package/src/cli/known-gaps.ts +5 -2
  51. package/src/cli/listing-arg.ts +195 -56
  52. package/src/cli/output-file.ts +68 -0
  53. package/src/cli/pane-functions/capabilities.ts +3 -0
  54. package/src/cli/pane-functions/catalog.ts +80 -7
  55. package/src/cli/pane-functions/dom.ts +13 -3
  56. package/src/cli/pane-functions/freshness.ts +111 -16
  57. package/src/cli/pane-functions/function-help.ts +23 -13
  58. package/src/cli/pane-functions/headless.ts +56 -12
  59. package/src/cli/pane-functions/index.ts +58 -16
  60. package/src/cli/pane-functions/market-session.ts +81 -9
  61. package/src/cli/pane-functions/options.ts +19 -1
  62. package/src/cli/pane-functions/report.ts +5 -1
  63. package/src/cli/pane-functions/resolver.ts +35 -8
  64. package/src/cli/pane-functions/screenshot-assessment.ts +6 -4
  65. package/src/cli/pane-functions/screenshot-types.ts +5 -0
  66. package/src/cli/quote-answer.ts +30 -13
  67. package/src/cli/report-tables.ts +18 -7
  68. package/src/cli/restore-plugins.ts +13 -1
  69. package/src/cli/result.ts +57 -5
  70. package/src/cli/ticker-resolution.ts +3 -2
  71. package/src/components/chart/composite/composite-chart.tsx +26 -4
  72. package/src/components/chart/composite/format.ts +27 -0
  73. package/src/components/chart/composite/interactions.ts +6 -0
  74. package/src/components/chart/composite/legend.tsx +45 -7
  75. package/src/components/chart/composite/levels.ts +2 -0
  76. package/src/components/chart/composite/panel-gestures.ts +33 -0
  77. package/src/components/chart/composite/panel-series.ts +1 -0
  78. package/src/components/chart/composite/panel-surface.tsx +61 -5
  79. package/src/components/chart/composite/range-statistics.ts +62 -0
  80. package/src/components/chart/composite/rasterizer.ts +24 -13
  81. package/src/components/chart/composite/scene.ts +46 -7
  82. package/src/components/chart/composite/series-axis-tags.tsx +16 -9
  83. package/src/components/chart/composite/series-cues.ts +14 -0
  84. package/src/components/chart/composite/text-renderer.ts +9 -2
  85. package/src/components/chart/composite/tool-catalog.ts +36 -0
  86. package/src/components/chart/composite/tools.ts +203 -44
  87. package/src/components/chart/composite/types.ts +4 -0
  88. package/src/components/chart/composite/use-composite-chart-keyboard.ts +11 -4
  89. package/src/components/command-bar/assist/inventory.ts +2 -1
  90. package/src/components/command-bar/commands/direct/index.ts +28 -13
  91. package/src/components/command-bar/pane-templates/items.ts +3 -2
  92. package/src/components/command-bar/panel/prompt-binding.ts +0 -8
  93. package/src/components/command-bar/workflow/alert.ts +1 -1
  94. package/src/components/command-bar/workflow/collection-actions.ts +3 -3
  95. package/src/components/layout/header.tsx +26 -40
  96. package/src/components/layout/pane/footer/index.tsx +1 -0
  97. package/src/components/layout/pane/footer/model.ts +27 -0
  98. package/src/components/onboarding/onboarding-frame.tsx +1 -1
  99. package/src/components/onboarding/onboarding-wizard.tsx +4 -1
  100. package/src/components/onboarding/portfolio-step/positions-panel.tsx +14 -9
  101. package/src/components/onboarding/wizard-broker-sync.ts +0 -1
  102. package/src/components/onboarding/wizard-positions.ts +3 -3
  103. package/src/components/ticker/list-table-view.tsx +4 -1
  104. package/src/components/ui/choice-dialog.tsx +23 -18
  105. package/src/components/ui/choice-groups.ts +18 -0
  106. package/src/components/ui/data-table/opentui/index.tsx +9 -7
  107. package/src/components/ui/data-table/opentui/model.ts +26 -1
  108. package/src/components/ui/data-table/types.ts +2 -0
  109. package/src/components/ui/display.tsx +5 -1
  110. package/src/components/ui/list-view.tsx +8 -4
  111. package/src/components/ui/query-bar-keys.tsx +2 -0
  112. package/src/components/ui/query-bar.tsx +1 -0
  113. package/src/components/ui/select-button.tsx +5 -1
  114. package/src/components/ui/select-field.tsx +1 -0
  115. package/src/components/ui/table-layout.ts +8 -5
  116. package/src/core/app-runtime.ts +2 -0
  117. package/src/core/app-services.ts +2 -2
  118. package/src/core/state/app/layout.ts +2 -0
  119. package/src/core/state/app/state.ts +9 -0
  120. package/src/core/state/app/types.ts +3 -0
  121. package/src/data/config/chart-settings.ts +1 -1
  122. package/src/data/json-ticker-repository.ts +17 -8
  123. package/src/data/saved-copies.ts +55 -16
  124. package/src/data/ticker-repository.ts +16 -9
  125. package/src/data/ticker-writes.ts +81 -0
  126. package/src/data/ttl-cache.ts +165 -0
  127. package/src/docs/snapshot.json +427 -216
  128. package/src/i18n/es.ts +19 -3
  129. package/src/i18n/ja.ts +19 -3
  130. package/src/i18n/ko.ts +19 -3
  131. package/src/i18n/zh-cn.ts +19 -3
  132. package/src/i18n/zh-tw.ts +19 -3
  133. package/src/market-data/coordinator/financials.ts +10 -2
  134. package/src/market-data/coordinator/index.ts +3 -1
  135. package/src/market-data/coordinator/quotes.ts +4 -2
  136. package/src/market-data/depositary-pair.ts +2 -2
  137. package/src/market-data/fund-facts.ts +50 -0
  138. package/src/market-data/market/change-basis.ts +48 -7
  139. package/src/market-data/market/dated-previous-close.ts +203 -0
  140. package/src/market-data/market/format.ts +25 -0
  141. package/src/market-data/market/freshness.ts +2 -1
  142. package/src/market-data/market/futures-week.ts +68 -0
  143. package/src/market-data/market/status.ts +16 -4
  144. package/src/market-data/options-alternatives.ts +141 -4
  145. package/src/market-data/quotes/contributions.ts +20 -2
  146. package/src/market-data/quotes/resolution.ts +3 -0
  147. package/src/market-data/selectors.ts +3 -0
  148. package/src/news/aggregator.ts +113 -9
  149. package/src/news/cloud-session.ts +21 -0
  150. package/src/news/hooks.ts +1 -0
  151. package/src/news/news-model.ts +1 -0
  152. package/src/news/types.ts +11 -0
  153. package/src/notifications/notification-log.ts +6 -4
  154. package/src/plugins/builtin/alerts/alert-engine.ts +25 -2
  155. package/src/plugins/builtin/alerts/alert-log.ts +33 -0
  156. package/src/plugins/builtin/alerts/calendar-events.ts +57 -6
  157. package/src/plugins/builtin/alerts/cli-forms.ts +216 -0
  158. package/src/plugins/builtin/alerts/cli.ts +380 -82
  159. package/src/plugins/builtin/alerts/command.ts +31 -0
  160. package/src/plugins/builtin/alerts/constants.ts +1 -1
  161. package/src/plugins/builtin/alerts/events-pane.tsx +19 -4
  162. package/src/plugins/builtin/alerts/fired-log.ts +113 -8
  163. package/src/plugins/builtin/alerts/format.ts +80 -4
  164. package/src/plugins/builtin/alerts/headless.ts +30 -7
  165. package/src/plugins/builtin/alerts/history-rows.ts +7 -3
  166. package/src/plugins/builtin/alerts/history.ts +2 -0
  167. package/src/plugins/builtin/alerts/index.tsx +135 -22
  168. package/src/plugins/builtin/alerts/live.ts +3 -3
  169. package/src/plugins/builtin/alerts/metric-command.ts +134 -0
  170. package/src/plugins/builtin/alerts/metric-data.ts +111 -0
  171. package/src/plugins/builtin/alerts/metric-model.ts +324 -0
  172. package/src/plugins/builtin/alerts/metric-parity-fixture.json +725 -0
  173. package/src/plugins/builtin/alerts/pane.tsx +90 -39
  174. package/src/plugins/builtin/alerts/quotes.ts +6 -0
  175. package/src/plugins/builtin/alerts/storage.ts +37 -10
  176. package/src/plugins/builtin/alerts/types.ts +7 -0
  177. package/src/plugins/builtin/analytics/index.tsx +2 -1
  178. package/src/plugins/builtin/analytics/risk-client.ts +16 -5
  179. package/src/plugins/builtin/analytics/risk-fx.ts +70 -15
  180. package/src/plugins/builtin/analytics/risk-headless.ts +27 -0
  181. package/src/plugins/builtin/analytics/risk-model.ts +55 -9
  182. package/src/plugins/builtin/analytics/risk-pane.tsx +8 -2
  183. package/src/plugins/builtin/attention/index.tsx +2 -1
  184. package/src/plugins/builtin/attention/listing.ts +14 -0
  185. package/src/plugins/builtin/backtest/headless.ts +10 -5
  186. package/src/plugins/builtin/backtest/pane.tsx +9 -4
  187. package/src/plugins/builtin/backtest/presets.ts +29 -3
  188. package/src/plugins/builtin/broker-manager/index.tsx +10 -5
  189. package/src/plugins/builtin/broker-manager/model.ts +6 -1
  190. package/src/plugins/builtin/broker-trading/controller.ts +22 -12
  191. package/src/plugins/builtin/broker-trading/index.tsx +13 -1
  192. package/src/plugins/builtin/broker-trading/order-feed.ts +9 -4
  193. package/src/plugins/builtin/broker-trading/pane.tsx +1 -1
  194. package/src/plugins/builtin/buildout/cells.tsx +12 -4
  195. package/src/plugins/builtin/buildout/format.ts +38 -0
  196. package/src/plugins/builtin/buildout/model/normalizers.ts +36 -1
  197. package/src/plugins/builtin/buildout/pane/index.tsx +4 -1
  198. package/src/plugins/builtin/buildout/table-model.ts +23 -2
  199. package/src/plugins/builtin/builtin-plugin-meta.ts +7 -3
  200. package/src/plugins/builtin/catalysts/model.ts +2 -1
  201. package/src/plugins/builtin/changelog/index.tsx +9 -6
  202. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +6 -1
  203. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +1 -1
  204. package/src/plugins/builtin/chart-composer/cli-options.ts +9 -5
  205. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +12 -2
  206. package/src/plugins/builtin/chart-composer/editor/controller.ts +4 -2
  207. package/src/plugins/builtin/chart-composer/editor/model.ts +2 -0
  208. package/src/plugins/builtin/chart-composer/editor.tsx +7 -5
  209. package/src/plugins/builtin/chart-composer/formula.ts +71 -18
  210. package/src/plugins/builtin/chart-composer/headless-schema.ts +21 -4
  211. package/src/plugins/builtin/chart-composer/headless.ts +19 -3
  212. package/src/plugins/builtin/chart-composer/index.tsx +1 -1
  213. package/src/plugins/builtin/chart-composer/pane.tsx +53 -9
  214. package/src/plugins/builtin/chart-composer/presets.ts +50 -15
  215. package/src/plugins/builtin/chart-composer/quick-add.tsx +40 -25
  216. package/src/plugins/builtin/chart-composer/session-history.ts +18 -9
  217. package/src/plugins/builtin/chart-composer/settings.ts +27 -0
  218. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +40 -26
  219. package/src/plugins/builtin/chat/content/command-suggestions.ts +93 -0
  220. package/src/plugins/builtin/chat/content/composer.tsx +13 -6
  221. package/src/plugins/builtin/chat/content/footer.tsx +6 -3
  222. package/src/plugins/builtin/chat/content/index.tsx +50 -21
  223. package/src/plugins/builtin/chat/content/open-targets.ts +14 -3
  224. package/src/plugins/builtin/chat/controller/session-runtime.ts +4 -2
  225. package/src/plugins/builtin/chat/index.tsx +23 -0
  226. package/src/plugins/builtin/chat/message/desktop.tsx +1 -0
  227. package/src/plugins/builtin/chat/message/inline-tokens.tsx +23 -0
  228. package/src/plugins/builtin/chat/message/pane-chip.tsx +50 -20
  229. package/src/plugins/builtin/chat/pane-links/commands.ts +271 -0
  230. package/src/plugins/builtin/chat/pane-links/model.ts +12 -3
  231. package/src/plugins/builtin/chat/pane-links/open.ts +8 -1
  232. package/src/plugins/builtin/chat/unread-inbox-pane.tsx +10 -1
  233. package/src/plugins/builtin/clinical-trials/model.ts +0 -9
  234. package/src/plugins/builtin/clinical-trials/pane.tsx +15 -22
  235. package/src/plugins/builtin/clinical-trials/sponsor-tickers.ts +8 -6
  236. package/src/plugins/builtin/cloud/askg/manifest.ts +2 -0
  237. package/src/plugins/builtin/cloud/plugin.tsx +1 -1
  238. package/src/plugins/builtin/company-attention/building.tsx +5 -1
  239. package/src/plugins/builtin/company-attention/client.ts +8 -9
  240. package/src/plugins/builtin/company-attention/evidence.ts +4 -1
  241. package/src/plugins/builtin/company-attention/moves.tsx +5 -1
  242. package/src/plugins/builtin/company-attention/pane.tsx +9 -2
  243. package/src/plugins/builtin/company-attention/signals.tsx +5 -1
  244. package/src/plugins/builtin/correlation/headless.ts +13 -5
  245. package/src/plugins/builtin/correlation/history.ts +22 -0
  246. package/src/plugins/builtin/cot/client.ts +22 -18
  247. package/src/plugins/builtin/cot/headless.ts +15 -10
  248. package/src/plugins/builtin/cot/model.ts +14 -1
  249. package/src/plugins/builtin/cot/pane.tsx +22 -14
  250. package/src/plugins/builtin/credit-boards/client.ts +6 -10
  251. package/src/plugins/builtin/credit-conditions/headless.ts +8 -2
  252. package/src/plugins/builtin/credit-conditions/index.tsx +5 -1
  253. package/src/plugins/builtin/credit-conditions/model.ts +4 -0
  254. package/src/plugins/builtin/credit-conditions/series.ts +3 -1
  255. package/src/plugins/builtin/credit-documents/detail.tsx +2 -2
  256. package/src/plugins/builtin/credit-documents/export.ts +173 -0
  257. package/src/plugins/builtin/credit-documents/headless.ts +7 -7
  258. package/src/plugins/builtin/credit-documents/model.ts +104 -14
  259. package/src/plugins/builtin/credit-documents/pane.tsx +12 -5
  260. package/src/plugins/builtin/custom-view/sources.ts +2 -0
  261. package/src/plugins/builtin/dividend-yield/client.ts +131 -23
  262. package/src/plugins/builtin/dividend-yield/headless.ts +44 -16
  263. package/src/plugins/builtin/dividend-yield/model.ts +8 -5
  264. package/src/plugins/builtin/dividend-yield/pane.tsx +38 -13
  265. package/src/plugins/builtin/dividend-yield/ranking.ts +37 -14
  266. package/src/plugins/builtin/dividend-yield/types.ts +20 -2
  267. package/src/plugins/builtin/dividend-yield/view.ts +30 -2
  268. package/src/plugins/builtin/docs/targets.ts +5 -1
  269. package/src/plugins/builtin/earnings/board-model.ts +16 -15
  270. package/src/plugins/builtin/earnings/board.tsx +62 -71
  271. package/src/plugins/builtin/earnings/headless.ts +40 -4
  272. package/src/plugins/builtin/earnings/scope.ts +31 -43
  273. package/src/plugins/builtin/earnings-calls/calendar.tsx +2 -2
  274. package/src/plugins/builtin/earnings-calls/format.ts +31 -2
  275. package/src/plugins/builtin/earnings-calls/headless.ts +7 -2
  276. package/src/plugins/builtin/earnings-calls/model.ts +6 -1
  277. package/src/plugins/builtin/earnings-calls/pane.tsx +5 -4
  278. package/src/plugins/builtin/econ/calendar-model.ts +14 -9
  279. package/src/plugins/builtin/econ/figures.ts +72 -0
  280. package/src/plugins/builtin/econ/index.tsx +33 -3
  281. package/src/plugins/builtin/econ/types.ts +4 -0
  282. package/src/plugins/builtin/econ-statistics/defs.ts +6 -0
  283. package/src/plugins/builtin/econ-statistics/headless.ts +85 -35
  284. package/src/plugins/builtin/econ-statistics/stats.ts +37 -9
  285. package/src/plugins/builtin/econ-statistics/view.ts +3 -0
  286. package/src/plugins/builtin/equity-screener/categories.ts +179 -0
  287. package/src/plugins/builtin/equity-screener/client.ts +4 -2
  288. package/src/plugins/builtin/equity-screener/headless.ts +144 -13
  289. package/src/plugins/builtin/equity-screener/ideas.ts +49 -0
  290. package/src/plugins/builtin/equity-screener/model.ts +99 -10
  291. package/src/plugins/builtin/equity-screener/pane.tsx +70 -15
  292. package/src/plugins/builtin/exposure/charts.tsx +2 -2
  293. package/src/plugins/builtin/exposure/model.ts +13 -1
  294. package/src/plugins/builtin/exposure/pane.tsx +4 -4
  295. package/src/plugins/builtin/fixed-income/pane.tsx +2 -1
  296. package/src/plugins/builtin/futures/index.tsx +1 -0
  297. package/src/plugins/builtin/futures/model.ts +2 -1
  298. package/src/plugins/builtin/futures/table.tsx +2 -2
  299. package/src/plugins/builtin/futures/use-board-terms.ts +42 -28
  300. package/src/plugins/builtin/futures/use-front-returns.ts +45 -28
  301. package/src/plugins/builtin/fx-matrix/client.ts +11 -3
  302. package/src/plugins/builtin/fx-matrix/headless.ts +6 -3
  303. package/src/plugins/builtin/fx-matrix/index.tsx +16 -4
  304. package/src/plugins/builtin/fx-matrix/live-legs.ts +54 -3
  305. package/src/plugins/builtin/gpu/headless.ts +8 -2
  306. package/src/plugins/builtin/help/function-index.ts +4 -1
  307. package/src/plugins/builtin/help/index.tsx +1 -0
  308. package/src/plugins/builtin/help/keybindings-editor.tsx +18 -14
  309. package/src/plugins/builtin/help/shortcut-model.ts +1 -1
  310. package/src/plugins/builtin/holders/fund-holders.ts +51 -0
  311. package/src/plugins/builtin/holders/headless.ts +18 -1
  312. package/src/plugins/builtin/iv-history/client.ts +52 -11
  313. package/src/plugins/builtin/iv-history/format.ts +36 -23
  314. package/src/plugins/builtin/iv-history/headless.ts +36 -18
  315. package/src/plugins/builtin/iv-history/index.tsx +2 -2
  316. package/src/plugins/builtin/iv-history/model.ts +163 -27
  317. package/src/plugins/builtin/iv-history/pane.tsx +10 -6
  318. package/src/plugins/builtin/iv-history/screen-pane.tsx +22 -15
  319. package/src/plugins/builtin/iv-history/universe.ts +5 -1
  320. package/src/plugins/builtin/jobs/client.ts +25 -29
  321. package/src/plugins/builtin/kelly-sizer/model.ts +12 -8
  322. package/src/plugins/builtin/kelly-sizer/pane.tsx +9 -9
  323. package/src/plugins/builtin/kelly-sizer/sections.tsx +19 -10
  324. package/src/plugins/builtin/kelly-sizer/types.ts +10 -4
  325. package/src/plugins/builtin/macro-day/pane.tsx +7 -5
  326. package/src/plugins/builtin/macro-day/release-table.ts +2 -2
  327. package/src/plugins/builtin/market-heatmap/data.ts +8 -33
  328. package/src/plugins/builtin/market-movers/client.ts +25 -7
  329. package/src/plugins/builtin/market-movers/footer.ts +2 -2
  330. package/src/plugins/builtin/market-movers/headless.ts +32 -12
  331. package/src/plugins/builtin/market-movers/index.tsx +26 -14
  332. package/src/plugins/builtin/market-movers/min-float.ts +74 -0
  333. package/src/plugins/builtin/market-movers/model.ts +4 -1
  334. package/src/plugins/builtin/market-movers/screener.ts +14 -0
  335. package/src/plugins/builtin/market-movers/session-body.tsx +13 -8
  336. package/src/plugins/builtin/market-movers/session-table.ts +4 -3
  337. package/src/plugins/builtin/market-movers/table.ts +17 -5
  338. package/src/plugins/builtin/members/breadth-pane.tsx +82 -0
  339. package/src/plugins/builtin/members/client.ts +19 -4
  340. package/src/plugins/builtin/members/headless.ts +20 -7
  341. package/src/plugins/builtin/members/index.tsx +9 -9
  342. package/src/plugins/builtin/members/model.ts +23 -4
  343. package/src/plugins/builtin/members/pane.tsx +25 -15
  344. package/src/plugins/builtin/news/index.tsx +1 -0
  345. package/src/plugins/builtin/news/wire/categories.ts +19 -3
  346. package/src/plugins/builtin/news/wire/industry-pane.tsx +1 -0
  347. package/src/plugins/builtin/news/wire/news/footer.ts +31 -5
  348. package/src/plugins/builtin/news/wire/news/preset-pane.tsx +6 -1
  349. package/src/plugins/builtin/news/wire/news/table.tsx +2 -2
  350. package/src/plugins/builtin/openfda/client.ts +14 -2
  351. package/src/plugins/builtin/openfda/index.tsx +3 -2
  352. package/src/plugins/builtin/openfda/model.ts +9 -0
  353. package/src/plugins/builtin/openfda/pane.tsx +42 -6
  354. package/src/plugins/builtin/options/analytics.ts +54 -6
  355. package/src/plugins/builtin/options/enrichment.ts +17 -5
  356. package/src/plugins/builtin/options/model-spot.ts +5 -2
  357. package/src/plugins/builtin/options/strike-window.ts +2 -1
  358. package/src/plugins/builtin/options/table.ts +6 -9
  359. package/src/plugins/builtin/options/types.ts +2 -0
  360. package/src/plugins/builtin/options/view.tsx +42 -12
  361. package/src/plugins/builtin/options-positioning/client.ts +30 -0
  362. package/src/plugins/builtin/options-positioning/headless.ts +74 -21
  363. package/src/plugins/builtin/options-positioning/index.tsx +4 -4
  364. package/src/plugins/builtin/options-positioning/model.ts +122 -14
  365. package/src/plugins/builtin/options-positioning/pane.tsx +87 -42
  366. package/src/plugins/builtin/options-scenario/client.ts +116 -47
  367. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +142 -10
  368. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +206 -55
  369. package/src/plugins/builtin/options-scenario/csp-screen.ts +63 -23
  370. package/src/plugins/builtin/options-scenario/csp.ts +8 -2
  371. package/src/plugins/builtin/options-scenario/index.tsx +9 -7
  372. package/src/plugins/builtin/options-scenario/strategy-screen.ts +532 -0
  373. package/src/plugins/builtin/pe-band/model.ts +12 -49
  374. package/src/plugins/builtin/perps/cascade-tabs.tsx +161 -0
  375. package/src/plugins/builtin/perps/cascade.ts +236 -0
  376. package/src/plugins/builtin/perps/client.ts +56 -2
  377. package/src/plugins/builtin/perps/freshness.ts +12 -10
  378. package/src/plugins/builtin/perps/headless.ts +65 -9
  379. package/src/plugins/builtin/perps/index.tsx +7 -5
  380. package/src/plugins/builtin/perps/live-rows.ts +10 -3
  381. package/src/plugins/builtin/perps/model.ts +18 -4
  382. package/src/plugins/builtin/perps/pane.tsx +32 -31
  383. package/src/plugins/builtin/perps/status-line.ts +25 -0
  384. package/src/plugins/builtin/plugin-module.ts +5 -1
  385. package/src/plugins/builtin/portfolio-list/cached-account.ts +3 -1
  386. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +2 -8
  387. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +4 -4
  388. package/src/plugins/builtin/portfolio-list/cli/render.ts +12 -7
  389. package/src/plugins/builtin/portfolio-list/headless.ts +1 -1
  390. package/src/plugins/builtin/portfolio-list/pane/futures-front.ts +40 -0
  391. package/src/plugins/builtin/portfolio-list/pane/index.tsx +4 -1
  392. package/src/plugins/builtin/portfolio-list/pane/streaming.ts +5 -2
  393. package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +3 -2
  394. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +3 -1
  395. package/src/plugins/builtin/portfolio-list/summary/index.tsx +11 -8
  396. package/src/plugins/builtin/portfolio-list/table.tsx +11 -3
  397. package/src/plugins/builtin/primary-dealers/client.ts +13 -38
  398. package/src/plugins/builtin/rate-path/pane.tsx +2 -2
  399. package/src/plugins/builtin/realized-vol/index.tsx +2 -2
  400. package/src/plugins/builtin/realized-vol/pane.tsx +3 -3
  401. package/src/plugins/builtin/relative-rotation/client.ts +18 -4
  402. package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
  403. package/src/plugins/builtin/relative-rotation/index.tsx +2 -1
  404. package/src/plugins/builtin/relative-rotation/model.ts +16 -40
  405. package/src/plugins/builtin/relative-rotation/pane.tsx +3 -2
  406. package/src/plugins/builtin/research/corporate-actions-pane.tsx +3 -2
  407. package/src/plugins/builtin/research/event-model.ts +10 -8
  408. package/src/plugins/builtin/research/headless.ts +1 -1
  409. package/src/plugins/builtin/research/relative-valuation-headless.ts +5 -1
  410. package/src/plugins/builtin/research/relative-valuation-model.ts +31 -3
  411. package/src/plugins/builtin/research/relative-valuation-pane.tsx +11 -9
  412. package/src/plugins/builtin/reverse-dcf/headless.ts +5 -3
  413. package/src/plugins/builtin/reverse-dcf/model.ts +61 -6
  414. package/src/plugins/builtin/reverse-dcf/pane.tsx +7 -4
  415. package/src/plugins/builtin/scanner/feed.ts +2 -2
  416. package/src/plugins/builtin/scanner/flow-model.ts +50 -4
  417. package/src/plugins/builtin/scanner/flow-pane.tsx +367 -65
  418. package/src/plugins/builtin/scanner/flow-session.ts +146 -0
  419. package/src/plugins/builtin/scanner/headless.ts +204 -35
  420. package/src/plugins/builtin/scanner/index.ts +40 -6
  421. package/src/plugins/builtin/scanner/live-condition-editor.tsx +222 -0
  422. package/src/plugins/builtin/scanner/live-feed.ts +168 -0
  423. package/src/plugins/builtin/scanner/live-headless.ts +138 -0
  424. package/src/plugins/builtin/scanner/live-model.ts +362 -0
  425. package/src/plugins/builtin/scanner/live-pane.tsx +677 -0
  426. package/src/plugins/builtin/scanner/live-track.ts +186 -0
  427. package/src/plugins/builtin/scanner/lock-note.ts +3 -2
  428. package/src/plugins/builtin/seasonality/headless.ts +10 -1
  429. package/src/plugins/builtin/sec/fund-facts-view.tsx +5 -2
  430. package/src/plugins/builtin/sec/fund-facts.ts +116 -34
  431. package/src/plugins/builtin/sec/headless.ts +2 -1
  432. package/src/plugins/builtin/series-inventory.ts +3 -0
  433. package/src/plugins/builtin/shared/cloud-resource.ts +3 -2
  434. package/src/plugins/builtin/shared/cloud-upgrade.ts +4 -3
  435. package/src/plugins/builtin/shared/earnings-calendar.ts +6 -2
  436. package/src/plugins/builtin/shared/earnings-report.ts +2 -2
  437. package/src/plugins/builtin/shared/job-posting.ts +1 -0
  438. package/src/plugins/builtin/shared/macro-releases.ts +65 -0
  439. package/src/plugins/builtin/shared/members-menu.tsx +3 -2
  440. package/src/plugins/builtin/shared/pro-lock-note.ts +12 -12
  441. package/src/plugins/builtin/shared/report-freshness.ts +3 -2
  442. package/src/plugins/builtin/shared/scanner-capture.ts +3 -0
  443. package/src/plugins/builtin/shared/ticker-choice.tsx +2 -1
  444. package/src/plugins/builtin/shared/ticker-company.ts +77 -0
  445. package/src/plugins/builtin/shared/use-quote-board.ts +10 -3
  446. package/src/plugins/builtin/shared/volatility/live-session.ts +34 -8
  447. package/src/plugins/builtin/shared/volatility/pricing.ts +26 -1
  448. package/src/plugins/builtin/shared/wall-view-lifecycle.ts +3 -1
  449. package/src/plugins/builtin/themes/headless.ts +6 -4
  450. package/src/plugins/builtin/themes/model.ts +17 -8
  451. package/src/plugins/builtin/themes/pane.tsx +7 -7
  452. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +43 -18
  453. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +3 -2
  454. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +62 -0
  455. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +83 -46
  456. package/src/plugins/builtin/ticker-detail/headless.ts +31 -16
  457. package/src/plugins/builtin/ticker-detail/overview/model.ts +1 -1
  458. package/src/plugins/builtin/ticker-detail/pane.tsx +3 -2
  459. package/src/plugins/builtin/ticker-detail/quote-footer.ts +6 -1
  460. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +2 -1
  461. package/src/plugins/builtin/ticker-detail/settings.ts +1 -0
  462. package/src/plugins/builtin/time-sales/pane.tsx +31 -19
  463. package/src/plugins/builtin/treasury-daily/client.ts +41 -5
  464. package/src/plugins/builtin/treasury-daily/headless.ts +2 -2
  465. package/src/plugins/builtin/treasury-daily/index.tsx +1 -1
  466. package/src/plugins/builtin/treasury-daily/model.ts +50 -3
  467. package/src/plugins/builtin/treasury-daily/pane.tsx +81 -2
  468. package/src/plugins/builtin/vol-surface/charts.tsx +9 -4
  469. package/src/plugins/builtin/vol-surface/client.ts +9 -17
  470. package/src/plugins/builtin/vol-surface/headless.ts +63 -14
  471. package/src/plugins/builtin/vol-surface/index.tsx +2 -2
  472. package/src/plugins/builtin/vol-surface/model.ts +22 -7
  473. package/src/plugins/builtin/vol-surface/pane.tsx +48 -9
  474. package/src/plugins/builtin/vol-surface/tables.ts +31 -3
  475. package/src/plugins/builtin/volatility/dvol.ts +46 -0
  476. package/src/plugins/builtin/volatility/index.tsx +2 -2
  477. package/src/plugins/builtin/volatility/pane.tsx +4 -4
  478. package/src/plugins/builtin/volatility/series.ts +26 -0
  479. package/src/plugins/builtin/world-indices/footer.ts +1 -1
  480. package/src/plugins/builtin/world-venue-map/headless.ts +3 -3
  481. package/src/plugins/catalog-browser.ts +13 -8
  482. package/src/plugins/catalog-manifest.ts +2 -1
  483. package/src/plugins/marketplace/model.ts +18 -5
  484. package/src/portfolio/column-values.ts +5 -5
  485. package/src/portfolio/futures-positions.ts +6 -3
  486. package/src/portfolio/position-quantity.ts +15 -9
  487. package/src/public/__snapshots__/public-api.test.ts.snap +1 -0
  488. package/src/remote/resources.ts +2 -1
  489. package/src/renderers/browser/app-services.ts +1 -7
  490. package/src/renderers/browser/config-host.ts +2 -55
  491. package/src/renderers/browser/main.tsx +7 -57
  492. package/src/renderers/dom/data-table/row.tsx +26 -0
  493. package/src/renderers/dom/desktop/list-view.tsx +13 -10
  494. package/src/renderers/dom/desktop/query-bar.tsx +4 -2
  495. package/src/renderers/dom/desktop/select-field.tsx +4 -2
  496. package/src/renderers/dom/host/chart-surface.tsx +21 -0
  497. package/src/renderers/electrobun/bun/desktop/app-name.ts +222 -0
  498. package/src/renderers/electrobun/bun/desktop/backend.ts +29 -7
  499. package/src/renderers/electrobun/bun/desktop/host-requests.ts +7 -0
  500. package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -0
  501. package/src/renderers/electrobun/bun/desktop/relaunch.ts +74 -25
  502. package/src/renderers/electrobun/bun/desktop/state-broadcaster.ts +1 -0
  503. package/src/renderers/electrobun/bun/desktop/update.ts +173 -5
  504. package/src/renderers/electrobun/bun/desktop/view-ids.ts +52 -0
  505. package/src/renderers/electrobun/bun/desktop/workspace/index.ts +2 -0
  506. package/src/renderers/electrobun/bun/index.ts +25 -1
  507. package/src/renderers/electrobun/shared/app-name.ts +30 -0
  508. package/src/renderers/electrobun/shared/protocol.ts +10 -0
  509. package/src/renderers/electrobun/view/backend-rpc.ts +6 -0
  510. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +3 -3
  511. package/src/renderers/electrobun/view/desktop/window/snapshot.ts +1 -0
  512. package/src/renderers/electrobun/view/main.tsx +24 -1
  513. package/src/renderers/electrobun/view/news-source.ts +3 -1
  514. package/src/renderers/electrobun/view/remote/ticker-repository.ts +14 -7
  515. package/src/renderers/electrobun/view/view-ids.ts +85 -0
  516. package/src/renderers/opentui/start.tsx +5 -0
  517. package/src/renderers/opentui/toast-host.tsx +71 -43
  518. package/src/series/registry.ts +1 -0
  519. package/src/series/types.ts +6 -0
  520. package/src/series/validate.ts +1 -0
  521. package/src/sources/gloomberb-cloud/index.ts +1 -0
  522. package/src/sources/gloomberb-cloud/news.ts +47 -7
  523. package/src/sources/gloomberb-cloud/normalizers.ts +2 -0
  524. package/src/sources/provider-router/batches.ts +10 -2
  525. package/src/sources/provider-router/financial-routes.ts +3 -3
  526. package/src/sources/provider-router/financials.ts +15 -3
  527. package/src/sources/provider-router/history.ts +28 -7
  528. package/src/sources/provider-router/index.ts +149 -10
  529. package/src/sources/provider-router/search.ts +13 -2
  530. package/src/state/app/context/index.tsx +3 -0
  531. package/src/state/ticker-cleanup.ts +50 -0
  532. package/src/sync/auth-transition.ts +19 -9
  533. package/src/sync/baseline.ts +10 -4
  534. package/src/sync/controller.ts +70 -19
  535. package/src/sync/core-contributors.ts +90 -31
  536. package/src/sync/react.ts +4 -1
  537. package/src/sync/types.ts +3 -0
  538. package/src/telemetry/stall-reports-dom.ts +38 -0
  539. package/src/telemetry/stall-reports-node.ts +75 -0
  540. package/src/telemetry/stall-reports.ts +214 -0
  541. package/src/telemetry/usage-counts.ts +0 -18
  542. package/src/test-support/preload.ts +14 -0
  543. package/src/theme/colors.ts +8 -0
  544. package/src/theme/themes.ts +10 -0
  545. package/src/tickers/company-name.ts +103 -3
  546. package/src/tickers/listing-venues.ts +38 -3
  547. package/src/tickers/search/bare-symbol.ts +36 -0
  548. package/src/tickers/search/index.ts +36 -7
  549. package/src/tickers/search/ranking.ts +10 -1
  550. package/src/tickers/search/types.ts +5 -0
  551. package/src/tickers/terminal-codes.ts +19 -0
  552. package/src/time-series/alignment.ts +1 -1
  553. package/src/time-series/base-series.ts +13 -5
  554. package/src/time-series/daily-valuation.ts +62 -0
  555. package/src/time-series/economic.ts +18 -4
  556. package/src/time-series/field-catalog.ts +2 -4
  557. package/src/time-series/filed-trailing-eps.ts +197 -0
  558. package/src/time-series/forward-valuation.ts +32 -0
  559. package/src/time-series/fundamentals.ts +198 -7
  560. package/src/time-series/hooks.ts +1 -0
  561. package/src/time-series/ice-credit.ts +3 -0
  562. package/src/time-series/price-comparison.ts +30 -2
  563. package/src/time-series/price-units.ts +72 -2
  564. package/src/time-series/resolve-context.ts +7 -1
  565. package/src/time-series/resolve.ts +116 -15
  566. package/src/time-series/series-presentation.ts +40 -6
  567. package/src/time-series/session-bar.ts +11 -0
  568. package/src/time-series/spec.ts +5 -3
  569. package/src/time-series/studies.ts +278 -74
  570. package/src/time-series/total-return.ts +160 -0
  571. package/src/time-series/transforms.ts +3 -3
  572. package/src/time-series/types.ts +27 -1
  573. package/src/time-series/valuation-releases.ts +39 -0
  574. package/src/types/data-provider.ts +9 -1
  575. package/src/types/desktop-window.ts +2 -0
  576. package/src/types/financials.ts +73 -2
  577. package/src/types/headless.ts +61 -5
  578. package/src/types/instrument.ts +3 -0
  579. package/src/types/news-source.ts +1 -0
  580. package/src/types/plugin.ts +10 -1
  581. package/src/ui/host.tsx +3 -0
  582. package/src/updater/command-names.ts +12 -7
  583. package/src/updater/failure.ts +4 -1
  584. package/src/utils/cli-output.ts +42 -1
  585. package/src/utils/crypto-pair.ts +44 -0
  586. package/src/utils/financial-statements.ts +6 -1
  587. package/src/utils/forward-dividend.ts +2 -0
  588. package/src/utils/fundamentals.ts +24 -3
  589. package/src/utils/fx-market-hours.ts +26 -3
  590. package/src/utils/main-thread-stall.ts +35 -2
  591. package/src/utils/market-capitalization.ts +24 -1
  592. package/src/utils/network-failure.ts +9 -6
  593. package/src/utils/option-expiry.ts +48 -1
  594. package/src/utils/options.ts +10 -0
  595. package/src/utils/plugin-proxy-hosts.json +1 -0
  596. package/src/utils/price-history.ts +12 -1
  597. package/src/utils/shell-word.ts +8 -0
  598. package/src/utils/trailing-dividend.ts +53 -4
  599. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +0 -17
  600. package/src/renderers/browser/first-screen.ts +0 -193
@@ -57,6 +57,7 @@ import type { ContextMenuItem } from "../../../../types/context-menu";
57
57
  import { usePluginAppActions } from "../../../runtime";
58
58
  import { openTeamPane } from "../../../../team/pane-request";
59
59
  import { openChatPaneLink } from "../pane-links/open";
60
+ import { runChatCommand, useChatFunctions } from "../pane-links/commands";
60
61
  import type { ChatMessagePaneLink } from "../pane-links/model";
61
62
  import { splitComposerDraft, type ComposerShareLink } from "../pane-links/composer";
62
63
  import { teamStore } from "../../../../team/store";
@@ -71,6 +72,7 @@ import {
71
72
  detectChatMentionTrigger,
72
73
  filterMentionSuggestions,
73
74
  } from "./mentions";
75
+ import { applyCommandSuggestion, detectChatCommandTrigger, filterCommandSuggestions } from "./command-suggestions";
74
76
  import { getComposerCursorOffset } from "./composer-cursor";
75
77
  import { ChatHandlePrompt, chatHandlePromptRows, handleSavedMessage, useChatHandlePrompt } from "./handle-prompt";
76
78
 
@@ -321,12 +323,31 @@ export function ChatContent({
321
323
  if (!mentionTrigger || mentionTriggerKey === dismissedMentionKey) return [];
322
324
  return filterMentionSuggestions(recentMentionSuggestions, mentionTrigger.query);
323
325
  }, [dismissedMentionKey, mentionTrigger, mentionTriggerKey, recentMentionSuggestions]);
324
- const mentionSelectedIndexSafe = mentionSuggestions.length > 0
325
- ? Math.min(mentionSelectedIndex, mentionSuggestions.length - 1)
326
+ // Desktop and web: after a backtick the same list offers functions, which a message draws as chips there.
327
+ const commandTrigger = useMemo(() => (
328
+ nativePaneChrome && !mentionTrigger ? detectChatCommandTrigger(composerDraft, composerCursorOffset) : null
329
+ ), [composerCursorOffset, composerDraft, mentionTrigger, nativePaneChrome]);
330
+ const commandTriggerKey = commandTrigger
331
+ ? `${channelId}:code:${commandTrigger.start}:${commandTrigger.end}:${commandTrigger.query}`
332
+ : null;
333
+ const functions = useChatFunctions();
334
+ const commandSuggestions = useMemo(() => {
335
+ if (!commandTrigger || commandTriggerKey === dismissedMentionKey) return [];
336
+ return filterCommandSuggestions(functions, commandTrigger.query);
337
+ }, [commandTrigger, commandTriggerKey, dismissedMentionKey, functions]);
338
+ // One list at a time: people after @, functions after a backtick.
339
+ const suggestionTriggerKey = mentionTriggerKey ?? commandTriggerKey;
340
+ const suggestionCount = mentionSuggestions.length + commandSuggestions.length;
341
+ const composerSuggestions = useMemo(() => mentionSuggestions.length > 0
342
+ ? mentionSuggestions.map((suggestion) => ({ id: suggestion.username, label: `@${suggestion.username}` }))
343
+ : commandSuggestions.map((suggestion) => ({ id: suggestion.code, label: suggestion.code, detail: suggestion.name })),
344
+ [commandSuggestions, mentionSuggestions]);
345
+ const mentionSelectedIndexSafe = suggestionCount > 0
346
+ ? Math.min(mentionSelectedIndex, suggestionCount - 1)
326
347
  : 0;
327
348
  useEffect(() => {
328
349
  setMentionSelectedIndex(0);
329
- }, [mentionTriggerKey]);
350
+ }, [suggestionTriggerKey]);
330
351
  const {
331
352
  composerHeight,
332
353
  messageAreaHeight,
@@ -335,7 +356,7 @@ export function ChatContent({
335
356
  composerRows,
336
357
  editingMessage,
337
358
  height,
338
- mentionSuggestionCount: mentionSuggestions.length,
359
+ mentionSuggestionCount: suggestionCount,
339
360
  nativePaneChrome,
340
361
  replyTo,
341
362
  stackHeader: stackedNav && !channelListOpen,
@@ -568,12 +589,13 @@ export function ChatContent({
568
589
  if (controller.attachToChannel(channelIdRef.current, files.map(uploadFromTransferFile)) > 0) focusInput();
569
590
  }, [canAttach, controller, focusInput, imagesAvailable, notify]);
570
591
 
571
- // A chip under a message: the shared pane, or the story or calendar a Wire post names.
592
+ // A chip: the shared pane, the story or calendar a Wire post names, or a function written in a message.
572
593
  const openPaneLink = useCallback((link: ChatMessagePaneLink) => {
573
594
  openChatPaneLink(link, {
574
595
  createPaneFromTemplate,
575
596
  notify,
576
597
  openExternal: (url) => { void rendererHost.openExternal(url); },
598
+ runCommand: runChatCommand,
577
599
  });
578
600
  }, [createPaneFromTemplate, notify, rendererHost]);
579
601
 
@@ -821,41 +843,48 @@ export function ChatContent({
821
843
  }, [directMessageContext, messageUser, selectedMessageAuthor]);
822
844
 
823
845
  const moveMentionSelection = useCallback((direction: "up" | "down") => {
824
- if (mentionSuggestions.length === 0) return false;
846
+ if (suggestionCount === 0) return false;
825
847
  setMentionSelectedIndex((current) => {
826
- const safeCurrent = Math.max(0, Math.min(current, mentionSuggestions.length - 1));
848
+ const safeCurrent = Math.max(0, Math.min(current, suggestionCount - 1));
827
849
  if (direction === "up") {
828
- return safeCurrent <= 0 ? mentionSuggestions.length - 1 : safeCurrent - 1;
850
+ return safeCurrent <= 0 ? suggestionCount - 1 : safeCurrent - 1;
829
851
  }
830
- return safeCurrent >= mentionSuggestions.length - 1 ? 0 : safeCurrent + 1;
852
+ return safeCurrent >= suggestionCount - 1 ? 0 : safeCurrent + 1;
831
853
  });
832
854
  return true;
833
- }, [mentionSuggestions.length]);
855
+ }, [suggestionCount]);
834
856
 
835
857
  const dismissMentionSuggestions = useCallback(() => {
836
- if (!mentionTriggerKey || mentionSuggestions.length === 0) return false;
837
- setDismissedMentionKey(mentionTriggerKey);
858
+ if (!suggestionTriggerKey || suggestionCount === 0) return false;
859
+ setDismissedMentionKey(suggestionTriggerKey);
838
860
  return true;
839
- }, [mentionSuggestions.length, mentionTriggerKey]);
861
+ }, [suggestionCount, suggestionTriggerKey]);
840
862
 
841
863
  const commitMentionSelection = useCallback((index = mentionSelectedIndexSafe) => {
842
- if (!mentionTrigger || mentionSuggestions.length === 0) return false;
843
- const suggestion = mentionSuggestions[index] ?? mentionSuggestions[0];
844
- if (!suggestion) return false;
845
- const replacement = applyMentionSuggestion(composerDraft, mentionTrigger, suggestion);
864
+ let replacement: { draft: string; cursorOffset: number } | null = null;
865
+ if (mentionTrigger && mentionSuggestions.length > 0) {
866
+ const suggestion = mentionSuggestions[index] ?? mentionSuggestions[0]!;
867
+ replacement = applyMentionSuggestion(composerDraft, mentionTrigger, suggestion);
868
+ } else if (commandTrigger && commandSuggestions.length > 0) {
869
+ const suggestion = commandSuggestions[index] ?? commandSuggestions[0]!;
870
+ replacement = applyCommandSuggestion(composerDraft, commandTrigger, suggestion);
871
+ }
872
+ if (!replacement) return false;
846
873
  replaceComposerDraft(replacement.draft, replacement.cursorOffset);
847
874
  setMentionSelectedIndex(0);
848
- setDismissedMentionKey(mentionTriggerKey);
875
+ setDismissedMentionKey(suggestionTriggerKey);
849
876
  queueMicrotask(() => focusInput());
850
877
  return true;
851
878
  }, [
879
+ commandSuggestions,
880
+ commandTrigger,
852
881
  composerDraft,
853
882
  focusInput,
854
883
  mentionSelectedIndexSafe,
855
884
  mentionSuggestions,
856
885
  mentionTrigger,
857
- mentionTriggerKey,
858
886
  replaceComposerDraft,
887
+ suggestionTriggerKey,
859
888
  ]);
860
889
 
861
890
  const {
@@ -941,7 +970,7 @@ export function ChatContent({
941
970
  inputValueRef,
942
971
  loadingOlderMessages,
943
972
  messages,
944
- mentionMenuOpen: mentionSuggestions.length > 0,
973
+ mentionMenuOpen: suggestionCount > 0,
945
974
  moveMentionSelection,
946
975
  dismissMentionSuggestions,
947
976
  commitMentionSelection,
@@ -1193,7 +1222,7 @@ export function ChatContent({
1193
1222
  replyPreview={replyPreview}
1194
1223
  replyTo={replyTo}
1195
1224
  sendMessage={sendMessage}
1196
- mentionSuggestions={mentionSuggestions}
1225
+ suggestions={composerSuggestions}
1197
1226
  mentionSelectedIndex={mentionSelectedIndexSafe}
1198
1227
  onMentionCursorChange={syncComposerCursor}
1199
1228
  onMentionSelect={commitMentionSelection}
@@ -4,6 +4,7 @@ import { chatMessageTokens } from "../markdown";
4
4
  import { chatImageLabel } from "../attachments/model";
5
5
  import { wirePaneTarget, type ChatMessagePaneLink } from "../pane-links/model";
6
6
  import { chatPaneLinkPane, peekSharePreview } from "../pane-links/previews";
7
+ import { resolveChatCommand, type ChatFunction } from "../pane-links/commands";
7
8
 
8
9
  export type ChatOpenTarget =
9
10
  | { kind: "pane"; link: ChatMessagePaneLink; label: string }
@@ -11,8 +12,9 @@ export type ChatOpenTarget =
11
12
  | { kind: "link"; url: string; label: string }
12
13
  | { kind: "image"; index: number; url: string; label: string };
13
14
 
14
- /** What the Open list calls a chip: the share's title once read, else its link; a Wire post's pane. */
15
+ /** What the Open list calls a chip: the share's title once read, else its link; a Wire post's pane; a function as written. */
15
16
  function paneLinkLabel(link: ChatMessagePaneLink): string {
17
+ if (link.kind === "command") return link.query;
16
18
  if (link.kind === "share") {
17
19
  const preview = peekSharePreview(link.id);
18
20
  return preview.status === "ready" ? preview.title : link.url;
@@ -27,13 +29,16 @@ function paneLinkLabel(link: ChatMessagePaneLink): string {
27
29
  * share links and Wire link open), the ticker badges its text draws (a symbol
28
30
  * the catalog does not know stays plain text), its links, then its images.
29
31
  * `content` is the text the message draws, without the links its chips stand
30
- * for. Code is text, so nothing in it is offered.
32
+ * for. Code is text, so nothing in it is offered, except where `functions` is
33
+ * given (the desktop and the web): there a function written in backticks is a
34
+ * chip, offered where the text names it.
31
35
  */
32
36
  export function chatMessageOpenTargets(
33
37
  content: string,
34
38
  catalog: Record<string, InlineTickerCatalogEntry>,
35
39
  attachments: readonly ChatAttachment[] = [],
36
40
  paneLinks: readonly ChatMessagePaneLink[] = [],
41
+ functions?: ReadonlyMap<string, ChatFunction>,
37
42
  ): ChatOpenTarget[] {
38
43
  const targets: ChatOpenTarget[] = paneLinks.map((link) => ({ kind: "pane", link, label: paneLinkLabel(link) }));
39
44
  const seen = new Set<string>();
@@ -45,7 +50,13 @@ export function chatMessageOpenTargets(
45
50
  continue;
46
51
  }
47
52
  open = null;
48
- if (token.kind === "ticker") {
53
+ const command = functions && token.kind === "text" && token.style?.code ? resolveChatCommand(token.value, functions) : null;
54
+ if (command) {
55
+ if (seen.has(`command:${command.query}`)) continue;
56
+ seen.add(`command:${command.query}`);
57
+ const link = { kind: "command", query: command.query, name: command.fn.name } as const;
58
+ targets.push({ kind: "pane", link, label: paneLinkLabel(link) });
59
+ } else if (token.kind === "ticker") {
49
60
  const entry = catalog[token.symbol];
50
61
  if (!entry || entry.status === "missing" || seen.has(`ticker:${token.symbol}`)) continue;
51
62
  seen.add(`ticker:${token.symbol}`);
@@ -121,7 +121,7 @@ export async function refreshChatControllerSession({
121
121
  stopVerificationPolling,
122
122
  syncVerificationPolling,
123
123
  }: RefreshChatControllerSessionOptions): Promise<void> {
124
- session.sessionToken = apiClient.getSessionToken();
124
+ const cachedToken = session.sessionToken;
125
125
  const apiSession = await apiClient.getSession(isCurrent);
126
126
  if (!isCurrent()) return;
127
127
  if (!apiSession) {
@@ -133,7 +133,9 @@ export async function refreshChatControllerSession({
133
133
  // startup from signing the user out.
134
134
  if (persistedToken) {
135
135
  session.sessionToken = persistedToken;
136
- session.user = session.user ?? normalizeSessionUser(apiClient.getCurrentUser());
136
+ // A failed sign-in can install another token before its user arrives.
137
+ // Only the credential stored with a cached user can restore that user.
138
+ session.user = (cachedToken === persistedToken ? session.user : null) ?? normalizeSessionUser(apiClient.getCurrentUser());
137
139
  // getSession() clears the API client's cached user when the endpoint
138
140
  // answers null. Keep both session views aligned while the protected
139
141
  // request validates the preserved native credential.
@@ -23,6 +23,8 @@ import { ChatStatusWidget } from "./status-widget";
23
23
  import { UnreadInboxPane } from "./unread-inbox-pane";
24
24
  import { installPaneChatSharing } from "./share/flow";
25
25
  import { attachChatPaneLinkPanes } from "./pane-links/previews";
26
+ import { attachChatCommands, cachedChatFunctions, chatFunctionsChanged } from "./pane-links/commands";
27
+ import { getSharedRegistry } from "../../registry";
26
28
  import { UNREAD_INBOX_PANE_ID, UNREAD_INBOX_TEMPLATE_ID } from "./unread-inbox";
27
29
  import { watchUnreadBadge } from "./unread-badge";
28
30
  import { getAppBadgeHost } from "../../../notifications/app-badge";
@@ -54,6 +56,7 @@ function isPrivateConversation(channelId: unknown): boolean {
54
56
 
55
57
  let disposePaneChatSharing: (() => void) | undefined;
56
58
  let detachPaneLinkPanes: (() => void) | undefined;
59
+ let detachCommands: (() => void) | undefined;
57
60
  let disposeUnreadBadge: (() => void) | undefined;
58
61
 
59
62
  export const chatModule: PluginModule = {
@@ -154,6 +157,24 @@ export const chatModule: PluginModule = {
154
157
  // A chip names the pane it opens (any plugin's) and its letter.
155
158
  detachPaneLinkPanes?.();
156
159
  detachPaneLinkPanes = attachChatPaneLinkPanes((paneId) => ctx.getPaneDef(paneId));
160
+ // A function written in a message is a chip for the codes this app runs, and runs in its command bar.
161
+ detachCommands?.();
162
+ detachCommands = attachChatCommands({
163
+ functions: () => {
164
+ const registry = getSharedRegistry();
165
+ if (!registry) return cachedChatFunctions(null);
166
+ const disabledPlugins = ctx.getConfig().disabledPlugins ?? [];
167
+ return cachedChatFunctions({
168
+ paneTemplates: registry.paneTemplates,
169
+ commands: registry.commands,
170
+ disabledPlugins,
171
+ isTemplateOff: (templateId) => !!registry.getDisabledPaneTemplateOwner(templateId, disabledPlugins),
172
+ });
173
+ },
174
+ run: (query) => getSharedRegistry()?.runCommandBarQuery(query),
175
+ });
176
+ // Messages drawn before a plugin came in, or with one since switched off, draw its codes again.
177
+ for (const event of ["plugin:registered", "plugin:unregistered", "config:changed"] as const) ctx.on(event, chatFunctionsChanged);
157
178
  chatController.attachPersistence(ctx.persistence, ctx.resume);
158
179
  chatSidebarStore.attach(ctx.persistence);
159
180
  chatHandlePromptStore.attach(ctx.persistence);
@@ -198,6 +219,8 @@ export const chatModule: PluginModule = {
198
219
  disposePaneChatSharing = undefined;
199
220
  detachPaneLinkPanes?.();
200
221
  detachPaneLinkPanes = undefined;
222
+ detachCommands?.();
223
+ detachCommands = undefined;
201
224
  // Before the controller drops its listeners, so the badge is cleared with the plugin.
202
225
  disposeUnreadBadge?.();
203
226
  disposeUnreadBadge = undefined;
@@ -206,6 +206,7 @@ export const DesktopChatMessage = memo(function DesktopChatMessage({
206
206
  textColor={state.bodyColor}
207
207
  mutedColor={state.bodyMutedColor}
208
208
  openTicker={openTicker}
209
+ openPaneLink={openPaneLink}
209
210
  userByUsername={userByUsername}
210
211
  onUserHover={onUserHover}
211
212
  onUserHoverEnd={onUserHoverEnd}
@@ -9,6 +9,9 @@ import type { ChatUserSummary } from "../../../../api-client";
9
9
  import { parseMarkdownLines, type MarkdownLine } from "../../../../utils/markdown";
10
10
  import { chatBadgeTextWidth, type ChatBodyLine } from "../layout";
11
11
  import { chatInlineTokens, type ChatInlineToken, type ChatTextStyle } from "../markdown";
12
+ import { resolveChatCommand, useChatFunctions } from "../pane-links/commands";
13
+ import type { ChatMessagePaneLink } from "../pane-links/model";
14
+ import { DesktopChatPaneChip } from "./pane-chip";
12
15
  import type { ChatUserAnchor, ChatUserContextMenuEvent } from "./types";
13
16
 
14
17
  interface ChatUserHandlers {
@@ -25,6 +28,11 @@ interface ChatTextProps extends ChatUserHandlers {
25
28
  /** Code, list markers, a quote's bar and a link's host. */
26
29
  mutedColor: string;
27
30
  openTicker: (symbol: string) => void;
31
+ /**
32
+ * Desktop and web: opens a function written in backticks, which then draws
33
+ * as a chip. Without it, as in the terminal, the code stays text.
34
+ */
35
+ openPaneLink?: (link: ChatMessagePaneLink) => void;
28
36
  }
29
37
 
30
38
  /** Desktop and web: a run of text inside a line, which wraps with the line. */
@@ -111,6 +119,7 @@ function ChatTokens({
111
119
  hoveredSymbol,
112
120
  setHoveredSymbol,
113
121
  userByUsername,
122
+ openPaneLink,
114
123
  ...userHandlers
115
124
  }: ChatTextProps & {
116
125
  tokens: readonly ChatInlineToken[];
@@ -122,12 +131,26 @@ function ChatTokens({
122
131
  setHoveredSymbol: (update: (current: string | null) => string | null) => void;
123
132
  }) {
124
133
  const { nativeContextMenu } = useUiCapabilities();
134
+ const allFunctions = useChatFunctions();
135
+ const functions = inline && openPaneLink ? allFunctions : null;
125
136
  return (
126
137
  <>
127
138
  {tokens.map((token, index) => {
128
139
  const key = `${keyPrefix}:${index}`;
129
140
  if (token.kind === "text") {
130
141
  if (!token.value) return null;
142
+ const command = functions && token.style?.code ? resolveChatCommand(token.value, functions) : null;
143
+ if (command && openPaneLink) {
144
+ return (
145
+ <Box key={key} justifyContent="center" style={INLINE_CHIP_STYLE}>
146
+ <DesktopChatPaneChip
147
+ link={{ kind: "command", query: command.query, name: command.fn.name }}
148
+ dimmed={false}
149
+ onOpen={openPaneLink}
150
+ />
151
+ </Box>
152
+ );
153
+ }
131
154
  const fg = styleColor(token.style, textColor, mutedColor);
132
155
  const attributes = styleAttributes(token.style) || undefined;
133
156
  return inline
@@ -14,8 +14,9 @@ import { DESKTOP_DRAFT_STRIP_STYLE } from "../attachments/desktop";
14
14
  /**
15
15
  * A chip for something a message opens in the terminal: a shared pane (its
16
16
  * title and the pane it is, with the picture its sender posted when there is
17
- * one) or a Gloom Wire post's story or calendar. It always takes the same
18
- * room, before and after the share is read, so the transcript never moves.
17
+ * one), a Gloom Wire post's story or calendar, or a function written in
18
+ * backticks, drawn in its line of text. It always takes the same room, before
19
+ * and after the share is read, so the transcript never moves.
19
20
  */
20
21
 
21
22
  interface ChatPaneChipContent {
@@ -30,6 +31,7 @@ interface ChatPaneChipContent {
30
31
  function useChatPaneChipContent(link: ChatMessagePaneLink): ChatPaneChipContent {
31
32
  const shareId = link.kind === "share" ? link.id : "";
32
33
  const preview = useSharePreview(shareId);
34
+ if (link.kind === "command") return { title: link.query, detail: link.name, icon: "" };
33
35
  if (link.kind === "share") {
34
36
  if (preview.status !== "ready") return { title: link.url, detail: "", icon: "" };
35
37
  const pane = chatPaneLinkPane(preview.paneId);
@@ -87,6 +89,52 @@ export function DesktopChatPaneChip({
87
89
  const height = compact ? COMPACT_CHIP_HEIGHT : preview ? PICTURE_CHIP_HEIGHT : SHARE_CHIP_HEIGHT;
88
90
  const border = hovered ? themeColors.borderFocused : blendHex(themeColors.border, themeColors.bg, 0.35);
89
91
  const surface = blendHex(themeColors.panel, themeColors.bg, hovered ? 0.2 : 0.5);
92
+ const label = [content.title, content.detail].filter(Boolean).join(", ");
93
+ const pressable = {
94
+ "aria-label": label || undefined,
95
+ // A share's link, and what a function written in a message is called.
96
+ title: link.kind === "share" ? link.url : link.kind === "command" ? link.name : undefined,
97
+ onMouseEnter: () => setHovered(true),
98
+ onMouseLeave: () => setHovered(false),
99
+ // A press on the chip is not a press on the row behind it.
100
+ onMouseDown: (event: DomEventLike) => event.stopPropagation(),
101
+ onClick: (event: DomEventLike) => {
102
+ event.stopPropagation();
103
+ onOpen(link);
104
+ },
105
+ };
106
+ const buttonReset = { cursor: "pointer", font: "inherit", color: "inherit", textAlign: "left" };
107
+ const dataAttributes = {
108
+ "data-gloom-role": "chat-pane-chip",
109
+ "data-gloom-pane-link": link.kind === "share" ? `share:${link.id}` : link.kind === "command" ? `command:${link.query}` : link.link.kind,
110
+ };
111
+ if (link.kind === "command") {
112
+ // The same frame at the height of the line of text it is written in: the
113
+ // kit's chip, 16px in an 18px row, as the ticker chips beside it.
114
+ return createElement("button", {
115
+ type: "button",
116
+ ...dataAttributes,
117
+ ...pressable,
118
+ style: {
119
+ ...buttonReset,
120
+ boxSizing: "border-box",
121
+ display: "inline-flex",
122
+ alignItems: "center",
123
+ height: "calc(100% - 2px)",
124
+ maxWidth: "100%",
125
+ padding: "0 var(--gloom-space-sm)",
126
+ border: `1px solid ${border}`,
127
+ borderRadius: "var(--gloom-radius-sm)",
128
+ background: surface,
129
+ opacity: dimmed ? 0.6 : 1,
130
+ overflow: "hidden",
131
+ textOverflow: "ellipsis",
132
+ whiteSpace: "pre",
133
+ color: themeColors.textBright,
134
+ fontWeight: "var(--gloom-weight-bold)",
135
+ },
136
+ }, content.title);
137
+ }
90
138
  const showPicture = !!preview && failedUrl !== preview.url;
91
139
  const leadSize = compact ? 18 : ICON_SIZE;
92
140
  const lead = showPicture
@@ -144,7 +192,6 @@ export function DesktopChatPaneChip({
144
192
  fontSize: tone === "title" ? undefined : "0.92em",
145
193
  },
146
194
  }, text);
147
- const label = [content.title, content.detail].filter(Boolean).join(", ");
148
195
  const text = compact
149
196
  ? createElement("span", {
150
197
  key: "text",
@@ -172,23 +219,6 @@ export function DesktopChatPaneChip({
172
219
  opacity: dimmed ? 0.6 : 1,
173
220
  overflow: "hidden",
174
221
  };
175
- const pressable = {
176
- "aria-label": label || undefined,
177
- title: link.kind === "share" ? link.url : undefined,
178
- onMouseEnter: () => setHovered(true),
179
- onMouseLeave: () => setHovered(false),
180
- // A press on the chip is not a press on the row behind it.
181
- onMouseDown: (event: DomEventLike) => event.stopPropagation(),
182
- onClick: (event: DomEventLike) => {
183
- event.stopPropagation();
184
- onOpen(link);
185
- },
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
222
  if (!onRemove) {
193
223
  return createElement("button", { type: "button", ...dataAttributes, ...pressable, style: { ...frame, ...buttonReset } }, lead, text);
194
224
  }