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
@@ -1,6 +1,6 @@
1
1
  import { logFailure } from "../utils/log-failure";
2
2
  import { httpFetch, isHttpFetchStreaming } from "../utils/http-transport";
3
- import { withDeadline } from "../utils/async-deadline";
3
+ import { OperationTimeoutError } from "../utils/async-deadline";
4
4
  import {
5
5
  ApiRequestError,
6
6
  parseApiErrorCode,
@@ -16,17 +16,59 @@ import {
16
16
  type ConnectionHealthRegistry,
17
17
  } from "../core/connection-health";
18
18
  import { SESSION_COOKIE_NAMES } from "./session-cookie";
19
- import { asDataServiceFailure } from "../utils/network-failure";
19
+ import { asDataServiceFailure, DataServiceUnreachableError } from "../utils/network-failure";
20
20
 
21
21
  /** The public Gloom Cloud API, which the web app's same-origin `/api` path forwards to. */
22
22
  export const DEFAULT_API_URL = "https://api.gloom.sh";
23
+ /**
24
+ * How long a request waits for the service to answer at all. Nothing back by
25
+ * then, and nothing else answered meanwhile, is a hung connection: the request
26
+ * fails as the data service being unreachable, as a refused one does.
27
+ */
23
28
  const DEFAULT_MARKET_REQUEST_TIMEOUT_MS = 10_000;
29
+ /**
30
+ * A search, which a command and a keystroke wait on, gives up on a connection
31
+ * that sends nothing back sooner. A slow search on a service that answers
32
+ * (some take five seconds) still gets the full market deadline.
33
+ */
34
+ const SEARCH_ANSWER_TIMEOUT_MS = 4_000;
35
+ /**
36
+ * Once a request went unanswered, later ones wait this long for an answer,
37
+ * until any answer comes back: a hung connection is not waited out in full by
38
+ * every request a command or a pane makes after it.
39
+ */
40
+ const UNREACHABLE_REQUEST_TIMEOUT_MS = 3_000;
41
+ /**
42
+ * Right after a request hung with nothing back, the requests that follow it
43
+ * (a fallback, the next step of a command) fail at once rather than each
44
+ * waiting out a connection that just proved dead. Past this they try again.
45
+ */
46
+ const HUNG_FAIL_FAST_MS = 5_000;
24
47
  const DEFAULT_RESEARCH_REQUEST_TIMEOUT_MS = 45_000;
48
+ /** Requests outside market reads (saves, uploads, drafts) may take the server this long once it is known to answer. */
49
+ const DEFAULT_SERVICE_REQUEST_LIMIT_MS = 120_000;
50
+ const UPLOAD_REQUEST_LIMIT_MS = 300_000;
51
+ /**
52
+ * How long the check that the service answers at all waits. It runs this long
53
+ * before a request's answer deadline, unless something answered meanwhile, so
54
+ * one slow request on a service that answers is waited for and a dead
55
+ * connection is not.
56
+ */
57
+ const SERVICE_PROBE_TIMEOUT_MS = 3_000;
58
+ const SERVICE_PROBE_PATH = "/health";
25
59
  // Research may fill missing sections after a primary read; quote/history reads remain latency bounded.
26
60
  const RESEARCH_MARKET_PATHS = new Set([
27
61
  "/market/dividends", "/market/short-interest", "/market/movers", "/market/trending",
28
62
  "/market/heatmap", "/market/earnings-calendar",
29
63
  ]);
64
+
65
+ /** When a request gives up: without any answer from the service, and in all. */
66
+ interface RequestDeadline {
67
+ answerMs: number;
68
+ limitMs: number;
69
+ /** When to check that the service answers at all, if nothing has by then; null when the deadline is too short for it. */
70
+ probeAtMs: number | null;
71
+ }
30
72
  /** Local status for "this runtime cannot stream", never returned by the server. */
31
73
  export const STREAMING_UNSUPPORTED_STATUS = 0;
32
74
 
@@ -74,6 +116,8 @@ type CloudApiUploadTransport = (request: CloudApiUploadRequest) => Promise<Cloud
74
116
  let cloudApiFetchTransport: CloudApiFetchTransport = httpFetch;
75
117
  let cloudApiUploadTransport: CloudApiUploadTransport | null = null;
76
118
  let cloudApiTransportInstalled = false;
119
+ /** Counts installed transports, so what a client learned of one connection is not applied to the next. */
120
+ let cloudApiTransportGeneration = 0;
77
121
  let cloudApiFetchStreaming = true;
78
122
  let cloudApiStreamFetch: CloudApiStreamFetch | null = null;
79
123
 
@@ -83,6 +127,7 @@ export function setCloudApiFetchTransport(
83
127
  ): void {
84
128
  cloudApiFetchTransport = transport ?? httpFetch;
85
129
  cloudApiTransportInstalled = !!transport;
130
+ cloudApiTransportGeneration += 1;
86
131
  cloudApiFetchStreaming = transport ? (options.streaming ?? false) : true;
87
132
  cloudApiStreamFetch = transport ? options.streamFetch ?? null : null;
88
133
  }
@@ -163,22 +208,6 @@ function throwIfRequestAborted(signal: AbortSignal | null | undefined): void {
163
208
  );
164
209
  }
165
210
 
166
- /**
167
- * Sends one request, saying the same thing whichever fetch failed to connect
168
- * (Bun's "Unable to connect", a browser's "Failed to fetch", a refused proxy):
169
- * every command, pane and status line then reads "Gloom couldn't reach its
170
- * data service", and code that falls back to a saved copy can tell it apart.
171
- * A caller's abort stays an abort.
172
- */
173
- async function reachService<R>(fetch: () => Promise<R>, signal: AbortSignal | null | undefined): Promise<R> {
174
- try {
175
- return await fetch();
176
- } catch (error) {
177
- if (signal?.aborted) throw error;
178
- throw asDataServiceFailure(error);
179
- }
180
- }
181
-
182
211
  export class CloudApiRequestTransport {
183
212
  private sessionToken: string | null = null;
184
213
  private sessionCookieName: SessionCookieName | null = null;
@@ -188,6 +217,17 @@ export class CloudApiRequestTransport {
188
217
  private readonly marketRequestTimeoutMs: number;
189
218
  private readonly researchRequestTimeoutMs: number;
190
219
  private readonly connectionHealth: ConnectionHealthRegistry;
220
+ /** Answers received from the service, by any request: a request that sees this grow knows the connection works. */
221
+ private answers = 0;
222
+ /** The last request went unanswered (refused or hung) and nothing has answered since. */
223
+ private unreachable = false;
224
+ /** When a request last hung with nothing back, while nothing has answered since. */
225
+ private hungAt: number | null = null;
226
+ /** The installed transport the two above were learned on. */
227
+ private connectionGeneration = cloudApiTransportGeneration;
228
+ /** Requests waiting under a deadline: the check that the service answers runs only while one is. */
229
+ private pending = 0;
230
+ private probe: AbortController | null = null;
191
231
 
192
232
  readonly baseUrl = getCloudApiBaseUrl();
193
233
 
@@ -280,7 +320,7 @@ export class CloudApiRequestTransport {
280
320
  GLOOM_CLOUD_HTTP_CONNECTION_ID,
281
321
  operation,
282
322
  async () => {
283
- const response = await reachService(() => streamFetch(`${this.baseUrl}${path}`, {
323
+ const response = await this.reachService(() => streamFetch(`${this.baseUrl}${path}`, {
284
324
  ...options,
285
325
  headers,
286
326
  credentials: "include",
@@ -301,37 +341,178 @@ export class CloudApiRequestTransport {
301
341
  }
302
342
 
303
343
  async request<T>(path: string, options?: RequestInit, canApplySession: () => boolean = () => true): Promise<T> {
304
- if (!path.startsWith("/market/")) {
305
- return this.performRequest<T>(path, options, canApplySession);
306
- }
344
+ return this.withDeadline(path, this.deadlineFor(path), options?.signal, (signal) => this.performRequest<T>(path, {
345
+ ...options,
346
+ signal,
347
+ }, canApplySession));
348
+ }
307
349
 
308
- const timeoutMs = RESEARCH_MARKET_PATHS.has(path.split("?")[0]!)
309
- ? this.researchRequestTimeoutMs : this.marketRequestTimeoutMs;
350
+ /**
351
+ * Every request's deadline. A market read or a search waits about ten
352
+ * seconds, research and requests outside market data longer. With nothing
353
+ * back from the service, a request gives up at ten seconds, a search at
354
+ * four, and any request at three after one went unanswered, until something
355
+ * answers again. Three seconds before that, a request still unanswered
356
+ * checks that the service answers at all, so one slow request on a working
357
+ * connection is waited for and a dead connection is not.
358
+ */
359
+ private deadlineFor(path: string, limitMs?: number): RequestDeadline {
360
+ this.forgetOtherTransport();
361
+ const pathname = path.split("?")[0]!;
362
+ const market = pathname.startsWith("/market/");
363
+ const limit = limitMs ?? (!market ? DEFAULT_SERVICE_REQUEST_LIMIT_MS
364
+ : RESEARCH_MARKET_PATHS.has(pathname) ? this.researchRequestTimeoutMs : this.marketRequestTimeoutMs);
365
+ let answerMs = pathname === "/market/search"
366
+ ? Math.min(this.marketRequestTimeoutMs, SEARCH_ANSWER_TIMEOUT_MS)
367
+ : this.marketRequestTimeoutMs;
368
+ if (this.unreachable) answerMs = Math.min(answerMs, UNREACHABLE_REQUEST_TIMEOUT_MS);
369
+ return {
370
+ answerMs,
371
+ limitMs: Math.max(limit, answerMs),
372
+ probeAtMs: answerMs >= SERVICE_PROBE_TIMEOUT_MS ? answerMs - SERVICE_PROBE_TIMEOUT_MS : null,
373
+ };
374
+ }
375
+
376
+ /**
377
+ * Runs one request under its deadline. Without an answer from the service by
378
+ * `answerMs` (from this request, any other, or the check that the service
379
+ * answers at all), the connection is taken as hung: the request is aborted
380
+ * and fails as the data service being unreachable, as a refused connection
381
+ * does. A service that answers but is slow gets until `limitMs`, then the
382
+ * request times out. A caller's abort stays an abort.
383
+ */
384
+ private async withDeadline<T>(
385
+ path: string,
386
+ deadline: RequestDeadline,
387
+ callerSignal: AbortSignal | null | undefined,
388
+ run: (signal: AbortSignal) => Promise<T>,
389
+ ): Promise<T> {
310
390
  const controller = new AbortController();
311
- const callerSignal = options?.signal;
312
391
  const abortFromCaller = () => controller.abort(callerSignal?.reason);
313
392
  if (callerSignal?.aborted) {
314
393
  abortFromCaller();
315
394
  } else {
316
395
  callerSignal?.addEventListener("abort", abortFromCaller, { once: true });
317
396
  }
318
-
397
+ const answersAtStart = this.answers;
398
+ const answered = () => this.answers > answersAtStart;
399
+ const generation = cloudApiTransportGeneration;
400
+ const what = path.startsWith("/market/") ? "Cloud market request" : "Cloud request";
401
+ const timedOut = (ms: number) => new OperationTimeoutError(`${what} timed out after ${ms}ms: ${path.split("?")[0]}`);
402
+ const timers: Array<ReturnType<typeof setTimeout>> = [];
403
+ if (this.hungAt != null && Date.now() - this.hungAt < HUNG_FAIL_FAST_MS && !controller.signal.aborted) {
404
+ callerSignal?.removeEventListener("abort", abortFromCaller);
405
+ throw new DataServiceUnreachableError(new OperationTimeoutError(`${what} not sent: the last one got no answer: ${path.split("?")[0]}`));
406
+ }
407
+ this.pending += 1;
319
408
  try {
320
- const request = this.performRequest<T>(path, {
321
- ...options,
322
- signal: controller.signal,
323
- }, canApplySession);
324
- return await withDeadline(
325
- request,
326
- timeoutMs,
327
- `Cloud market request timed out after ${timeoutMs}ms: ${path}`,
328
- (error) => controller.abort(error),
329
- );
409
+ const work = run(controller.signal);
410
+ return await new Promise<T>((resolve, reject) => {
411
+ const fail = (error: Error) => {
412
+ reject(error);
413
+ controller.abort(error);
414
+ };
415
+ work.then(resolve, reject);
416
+ if (deadline.probeAtMs != null) {
417
+ timers.push(setTimeout(() => {
418
+ if (!answered()) this.checkServiceAnswers();
419
+ }, deadline.probeAtMs));
420
+ }
421
+ timers.push(setTimeout(() => {
422
+ // The caller gave up first: its abort settles the request, and says nothing of the connection.
423
+ if (callerSignal?.aborted) return;
424
+ if (!answered()) {
425
+ this.recordNoAnswer(generation, true);
426
+ fail(new DataServiceUnreachableError(timedOut(deadline.answerMs)));
427
+ } else if (deadline.limitMs > deadline.answerMs) {
428
+ timers.push(setTimeout(() => fail(timedOut(deadline.limitMs)), deadline.limitMs - deadline.answerMs));
429
+ } else {
430
+ fail(timedOut(deadline.answerMs));
431
+ }
432
+ }, deadline.answerMs));
433
+ });
330
434
  } finally {
435
+ for (const timer of timers) clearTimeout(timer);
331
436
  callerSignal?.removeEventListener("abort", abortFromCaller);
437
+ this.pending -= 1;
438
+ // Nothing waits on the check any more: it must not hold a command's process open.
439
+ if (this.pending === 0) this.probe?.abort();
332
440
  }
333
441
  }
334
442
 
443
+ /**
444
+ * Sends one request, saying the same thing whichever fetch failed to connect
445
+ * (Bun's "Unable to connect", a browser's "Failed to fetch", a refused proxy):
446
+ * every command, pane and status line then reads "Gloom couldn't reach its
447
+ * data service", and code that falls back to a saved copy can tell it apart.
448
+ * A caller's abort stays an abort. An answer of any status says the
449
+ * connection works, for the deadlines of the requests beside it.
450
+ */
451
+ private async reachService<R>(fetch: () => Promise<R>, signal: AbortSignal | null | undefined): Promise<R> {
452
+ const generation = cloudApiTransportGeneration;
453
+ let response: R;
454
+ try {
455
+ response = await fetch();
456
+ } catch (error) {
457
+ if (signal?.aborted) throw error;
458
+ const failure = asDataServiceFailure(error);
459
+ if (failure instanceof DataServiceUnreachableError) this.recordNoAnswer(generation, false);
460
+ throw failure;
461
+ }
462
+ this.recordAnswer();
463
+ return response;
464
+ }
465
+
466
+ /** A new transport installed is a new connection: what failed on the last one says nothing about it. */
467
+ private forgetOtherTransport(): void {
468
+ if (this.fetchTransport || this.connectionGeneration === cloudApiTransportGeneration) return;
469
+ this.connectionGeneration = cloudApiTransportGeneration;
470
+ this.unreachable = false;
471
+ this.hungAt = null;
472
+ }
473
+
474
+ /** Something came back from the service: the connection works. */
475
+ private recordAnswer(): void {
476
+ this.answers += 1;
477
+ this.unreachable = false;
478
+ this.hungAt = null;
479
+ }
480
+
481
+ /**
482
+ * A request sent on the transport installed as `generation` got no answer:
483
+ * refused, or `hung` with nothing back by its deadline. Once another
484
+ * transport is installed, what one sent on the last says nothing of it.
485
+ */
486
+ private recordNoAnswer(generation: number, hung: boolean): void {
487
+ if (!this.fetchTransport && generation !== cloudApiTransportGeneration) return;
488
+ this.unreachable = true;
489
+ if (hung) this.hungAt = Date.now();
490
+ }
491
+
492
+ /**
493
+ * Asks the service for anything at all, once at a time, so a request that
494
+ * is slow can tell a slow server (which answers this) from a dead
495
+ * connection (which does not). Any status counts as an answer. It stops
496
+ * when nothing waits on it any more.
497
+ */
498
+ private checkServiceAnswers(): void {
499
+ if (this.probe) return;
500
+ const controller = new AbortController();
501
+ const timer = setTimeout(() => controller.abort(), SERVICE_PROBE_TIMEOUT_MS);
502
+ const done = () => {
503
+ clearTimeout(timer);
504
+ if (this.probe === controller) this.probe = null;
505
+ };
506
+ // Done once given up on, even through a transport that ignores the abort.
507
+ controller.signal.addEventListener("abort", done, { once: true });
508
+ this.probe = controller;
509
+ (this.fetchTransport ?? cloudApiFetchTransport)(`${this.baseUrl}${SERVICE_PROBE_PATH}`, { signal: controller.signal })
510
+ .then(() => this.recordAnswer(), () => {
511
+ // Intentional ignore: an unanswered check only leaves the request it guards to its own deadline.
512
+ })
513
+ .finally(done);
514
+ }
515
+
335
516
  /**
336
517
  * POSTs raw bytes, such as an image, and parses the JSON answer like
337
518
  * `request`. Progress is reported where the installed upload transport can
@@ -355,17 +536,17 @@ export class CloudApiRequestTransport {
355
536
  url,
356
537
  body,
357
538
  headers: new Headers(init?.headers),
358
- signal: options.signal,
539
+ signal: init?.signal ?? options.signal,
359
540
  onProgress: options.onProgress,
360
541
  })
361
542
  : undefined;
362
- return this.performRequest<T>(path, {
543
+ return this.withDeadline(path, this.deadlineFor(path, UPLOAD_REQUEST_LIMIT_MS), options.signal, (signal) => this.performRequest<T>(path, {
363
544
  method: "POST",
364
545
  headers,
365
546
  // Typed arrays are valid fetch bodies; RequestInit's DOM typing lags behind.
366
547
  body: body as BodyInit,
367
- signal: options.signal,
368
- }, () => true, send);
548
+ signal,
549
+ }, () => true, send));
369
550
  }
370
551
 
371
552
  private async performRequest<T>(
@@ -389,7 +570,7 @@ export class CloudApiRequestTransport {
389
570
 
390
571
  const operation = `${options?.method ?? "GET"} ${path.split("?")[0]}`;
391
572
  const request = async () => {
392
- const res = await reachService(() => (send ?? this.fetchTransport ?? cloudApiFetchTransport)(
573
+ const res = await this.reachService(() => (send ?? this.fetchTransport ?? cloudApiFetchTransport)(
393
574
  `${this.baseUrl}${path}`,
394
575
  {
395
576
  ...options,
@@ -29,10 +29,7 @@ export type ResearchActivity =
29
29
  | "onboarding_signed_in"
30
30
  | "onboarding_pro_viewed"
31
31
  | "onboarding_completed"
32
- | "onboarding_skipped"
33
- // The first action of a web visitor counted in the first-screen experiment,
34
- // in that first session. Keep in sync with the server's list.
35
- | "first_screen_engaged";
32
+ | "onboarding_skipped";
36
33
  export type ResearchFeature =
37
34
  | "overview"
38
35
  | "chart"
@@ -49,8 +46,9 @@ const signinWallExperiment = createWallExperimentSession("wall_teaser_signin");
49
46
  const upgradeExperiment = createUpgradeExperimentSession();
50
47
  const WALL_VIEWS_SESSION_KEY = "gloomberb.wall-teaser.views";
51
48
 
52
- const ATTRIBUTION_STORAGE_KEY = "gloomberb.web.attribution";
53
- const ANONYMOUS_ID_STORAGE_KEY = "gloomberb.web.anonymous-id";
49
+ // The desktop app also keeps a copy of these two on disk (electrobun/view/view-ids.ts).
50
+ export const ATTRIBUTION_STORAGE_KEY = "gloomberb.web.attribution";
51
+ export const ANONYMOUS_ID_STORAGE_KEY = "gloomberb.web.anonymous-id";
54
52
  const HANDOFF_ID_KEY = "_gloom";
55
53
  const ATTRIBUTION_WINDOW_MS = 30 * 24 * 60 * 60 * 1000;
56
54
  /** Another device's clock may run slightly ahead; a touch from a minute in the future is still fresh. */
@@ -461,10 +459,7 @@ function webExperimentAttribution(): { experiments?: string } {
461
459
  * visitors on term.gloom.sh with an analytics id (no Do Not Track or Global
462
460
  * Privacy Control) and not driven by automation are asked. See web-experiments.ts.
463
461
  */
464
- export function exposeWebExperiment(
465
- experiment: string,
466
- { placement, signal }: { placement?: string; signal?: AbortSignal } = {},
467
- ): Promise<string | null> {
462
+ export function exposeWebExperiment(experiment: string): Promise<string | null> {
468
463
  if (!researchTelemetryAllowed()) return Promise.resolve(null);
469
464
  if (getCurrentPluginTarget() !== "web") return Promise.resolve(null);
470
465
  try {
@@ -481,8 +476,7 @@ export function exposeWebExperiment(
481
476
  attribution: attributionPayload(),
482
477
  experiment: key,
483
478
  variant,
484
- ...(placement && ACTIVITY_ID.test(placement) ? { placement } : {}),
485
- }, signal),
479
+ }),
486
480
  });
487
481
  } catch {
488
482
  return Promise.resolve(null);
@@ -516,6 +516,18 @@ export interface CloudEconEventPayload {
516
516
  referencePeriod?: string | null;
517
517
  /** Who publishes the release (Freddie Mac for the 30-year mortgage rate), and its page when one is named. */
518
518
  source?: { name: string; url?: string };
519
+ /**
520
+ * The indicator this release is of, the same from one release to the next
521
+ * (`us-unemployment-rate` on every month's row), where `id` names the one
522
+ * row. Absent from a server that names none; exports leave the column empty.
523
+ */
524
+ indicatorId?: string | null;
525
+ /**
526
+ * Where the forecast (the consensus) was read from, `week-feed` or
527
+ * `release-calendar`, and when that feed was read. Absent on a row with no
528
+ * forecast and on one kept before the read was recorded.
529
+ */
530
+ consensus?: { source: string; readAt: string } | null;
519
531
  }
520
532
 
521
533
  /** One currency's short-term rate, as GET /cloud/econ/short-rates serves it. */
@@ -885,6 +897,13 @@ export interface CloudEarningsCallPayload {
885
897
  * New York day). Absent from a server that predates it.
886
898
  */
887
899
  callTimeKnown?: boolean;
900
+ /**
901
+ * "other" for an event that is not an earnings call (a deal call, a
902
+ * conference, an investor day), named by eventLabel and with no fiscal
903
+ * period; null when unclear. Older servers omit both.
904
+ */
905
+ eventKind?: "earnings" | "other" | null;
906
+ eventLabel?: string | null;
888
907
  }
889
908
 
890
909
  interface CloudJobsSeriesPoint {
@@ -1249,6 +1268,13 @@ export interface CloudEarningsTranscriptPayload {
1249
1268
  companyName: string | null;
1250
1269
  fiscalYear: number | null;
1251
1270
  fiscalQuarter: number | null;
1271
+ /**
1272
+ * "other" for an event that is not an earnings call (a deal call, a
1273
+ * conference, an investor day), named by eventLabel and with no fiscal
1274
+ * period; null when unclear. Older servers omit both.
1275
+ */
1276
+ eventKind?: "earnings" | "other" | null;
1277
+ eventLabel?: string | null;
1252
1278
  callAt: string | null;
1253
1279
  timing: string | null;
1254
1280
  webcastUrl: string | null;
@@ -1530,6 +1556,8 @@ export interface CloudNewsPayload {
1530
1556
  export interface CloudNewsListResponse {
1531
1557
  items: CloudNewsPayload[];
1532
1558
  nextCursor: string | null;
1559
+ /** Which news the service answered with, when it says: the live wire, or the one held back for a free account. */
1560
+ access?: "realtime" | "delayed";
1533
1561
  }
1534
1562
 
1535
1563
  interface CloudTweetUserPayload {
@@ -1733,6 +1761,14 @@ export interface CloudMarketScreenerItem extends CloudMoverSessionFields {
1733
1761
  exchange: string;
1734
1762
  lastUpdated: number;
1735
1763
  dataSource: "live";
1764
+ /** The listing's float as the equity screener serves it; absent where it serves none. */
1765
+ floatShares?: number;
1766
+ /** Set with a float the source states no measurement date for: `partial`. */
1767
+ floatSharesState?: "partial";
1768
+ /** Why the float is partial, as the server says it. */
1769
+ floatSharesReason?: string;
1770
+ /** When the statistics the float is read from were retrieved (ISO). */
1771
+ floatSharesRetrievedAt?: string;
1736
1772
  }
1737
1773
 
1738
1774
  export interface CloudMarketScreenerPayload {
@@ -1927,6 +1963,44 @@ export interface ScannerFlowHistoryPage {
1927
1963
  hasMore: boolean;
1928
1964
  }
1929
1965
 
1966
+ /**
1967
+ * Premium of a slice of the session's recorded prints by where it traded: at
1968
+ * or above the ask (bought) or at or below the bid (sold). Mid and unknown
1969
+ * prints count as neither.
1970
+ */
1971
+ interface ScannerFlowSidePremium {
1972
+ callAsk: number;
1973
+ callBid: number;
1974
+ putAsk: number;
1975
+ putBid: number;
1976
+ }
1977
+
1978
+ /** The session's prints in one time bucket, which starts at `at`. */
1979
+ export interface ScannerFlowSessionBucket extends ScannerFlowSidePremium {
1980
+ at: number;
1981
+ }
1982
+
1983
+ /** What one name printed at one expiry and strike during the session. */
1984
+ export interface ScannerFlowSessionStrike extends ScannerFlowSidePremium {
1985
+ expiry: string;
1986
+ strike: number;
1987
+ /** Every call print's premium, mid and unknown included. */
1988
+ callPremium: number;
1989
+ putPremium: number;
1990
+ prints: number;
1991
+ }
1992
+
1993
+ /** The latest session's recorded prints under the FLOW pane's filters, summed. */
1994
+ export interface ScannerFlowSession {
1995
+ /** The New York date of the session; null before any print was recorded. */
1996
+ session: string | null;
1997
+ bucketMs: number;
1998
+ /** Buckets with a matching print, oldest first. */
1999
+ buckets: ScannerFlowSessionBucket[];
2000
+ /** Only when one name was asked for: most premium first. */
2001
+ strikes: ScannerFlowSessionStrike[] | null;
2002
+ }
2003
+
1930
2004
  export type ScannerPayload = ScannerHiloPayload | ScannerFlowPayload;
1931
2005
 
1932
2006
  /** What a scanner subscriber receives: data, or the entitlement refusal. */
@@ -14,6 +14,7 @@ export {
14
14
  type KeyChordEventLike,
15
15
  } from "./chord";
16
16
  export {
17
+ coreActionOnChord,
17
18
  describeKeybindingIssue,
18
19
  isPaneKeybindingAction,
19
20
  keyChordsOverlap,
@@ -32,6 +33,8 @@ export {
32
33
  formatChordForHost,
33
34
  menuAcceleratorFor,
34
35
  primaryModifierFor,
36
+ shortActionLabel,
37
+ takenChordMessage,
35
38
  } from "./labels";
36
39
  export { KeybindingsProvider, getDefaultKeybindings, useKeybindings, useResolvedKeybindings } from "./react";
37
40
  export {
@@ -3,8 +3,9 @@ import {
3
3
  type ShortcutDisplayMode,
4
4
  type ShortcutPlatform,
5
5
  } from "../../utils/shortcut-labels";
6
+ import { t, tf } from "../../i18n";
6
7
  import { formatKeyChord, serializeKeyChord, type KeyChord, type PrimaryModifier } from "./chord";
7
- import type { ResolvedKeybindings } from "./resolve";
8
+ import type { ResolvedKeybindingAction, ResolvedKeybindings } from "./resolve";
8
9
 
9
10
  /** What `CmdOrCtrl` is on this host: Control in a terminal, Command on a Mac desktop. */
10
11
  export function primaryModifierFor(
@@ -85,3 +86,19 @@ export function menuAcceleratorFor(resolved: ResolvedKeybindings, actionId: stri
85
86
  const chord = resolved.actionsById.get(actionId)?.chords.find((entry) => entry.primary || entry.cmd);
86
87
  return chord ? serializeKeyChord(chord) : undefined;
87
88
  }
89
+
90
+ /** The first clause of a description, for messages that name an action mid-sentence. */
91
+ export function shortActionLabel(description: string): string {
92
+ const clause = description.split(/[,.](?:\s|$)/)[0] ?? description;
93
+ return clause.trim() || description.trim();
94
+ }
95
+
96
+ /**
97
+ * Why a chord a built-in action uses (coreActionOnChord) is refused, the
98
+ * same in the shortcuts editor and `config set keybindings`: "Ctrl+P is
99
+ * taken: Open the command bar. Press another key."
100
+ */
101
+ export function takenChordMessage(chord: string, action: ResolvedKeybindingAction): string {
102
+ const name = action.def ? t(action.def.description) : action.pluginShortcut?.description ?? action.id;
103
+ return tf("{chord} is taken: {target}. Press another key.", { chord, target: shortActionLabel(name) });
104
+ }
@@ -249,6 +249,20 @@ export function matchKeybinding(resolved: ResolvedKeybindings, event: KeyChordEv
249
249
  return null;
250
250
  }
251
251
 
252
+ /**
253
+ * The built-in action already on a chord, on this host, other than `exceptId`:
254
+ * one whose chord fires on the same keypress, a digit under the layout
255
+ * switcher's 1-9 included. Capture refuses such a chord, so a new binding never
256
+ * leaves a core key (the command bar, close pane, quit) dead. Null when no
257
+ * built-in action has it; a plugin shortcut or a bound command does not count.
258
+ */
259
+ export function coreActionOnChord(resolved: ResolvedKeybindings, chord: KeyChord, exceptId?: string): ResolvedKeybindingAction | null {
260
+ return resolved.actions.find((action) => action.def && action.id !== exceptId
261
+ && action.chords.some((existing) => keyChordsOverlap(existing, chord)
262
+ || (existing.key === "digit" && /^[1-9]$/.test(chord.key) && keyChordsOverlap({ ...existing, key: chord.key }, chord))))
263
+ ?? null;
264
+ }
265
+
252
266
  export function matchesKeybindingAction(resolved: ResolvedKeybindings, id: string, event: KeyChordEventLike): boolean {
253
267
  const action = resolved.actionsById.get(id);
254
268
  return !!action && action.chords.some((chord) => matchesKeyChord(chord, event));
@@ -513,13 +513,17 @@ export function bindAppPanePluginRegistry({
513
513
  removeExternalPlugin(pluginId, directory);
514
514
  },
515
515
  contributions: (pluginId) => {
516
+ // An unlisted function (`listed: false`) and a pane only it opens are left out, as of every list.
517
+ const registered = pluginRegistry.getPluginPaneTemplateIds(pluginId)
518
+ .map((id) => ({ id, template: pluginRegistry.paneTemplates.get(id) }));
519
+ const listedPaneIds = new Set(registered.flatMap(({ template }) => template && template.listed !== false ? [template.paneId] : []));
520
+ const unlistedPaneIds = new Set(registered.flatMap(({ template }) => template?.listed === false && !listedPaneIds.has(template.paneId) ? [template.paneId] : []));
516
521
  const panes = pluginRegistry.getPluginPaneIds(pluginId)
522
+ .filter((id) => !unlistedPaneIds.has(id))
517
523
  .map((id) => ({ id, name: pluginRegistry.panes.get(id)?.name ?? id }));
518
- const templates = pluginRegistry.getPluginPaneTemplateIds(pluginId)
519
- .map((id) => {
520
- const template = pluginRegistry.paneTemplates.get(id);
521
- return { id, label: template?.label ?? id, ...(template?.shortcut?.prefix ? { prefix: template.shortcut.prefix } : {}) };
522
- });
524
+ const templates = registered
525
+ .filter(({ template }) => template?.listed !== false)
526
+ .map(({ id, template }) => ({ id, label: template?.label ?? id, ...(template?.shortcut?.prefix ? { prefix: template.shortcut.prefix } : {}) }));
523
527
  const commands = [...pluginRegistry.commands.entries()]
524
528
  .filter(([id]) => pluginRegistry.getCommandPluginId(id) === pluginId && !id.endsWith(":setup"))
525
529
  .map(([id, command]) => ({ id, label: command.label, ...(command.shortcut ? { shortcut: command.shortcut } : {}) }));