@gloom-sh/terminal 0.18.5 → 0.19.1

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 (570) 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 +163 -8
  5. package/src/api-client/app-attention.ts +3 -0
  6. package/src/api-client/beneficial-owners.ts +3 -0
  7. package/src/api-client/company-kpis.ts +3 -0
  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 +19 -7
  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/hiring.ts +3 -0
  14. package/src/api-client/index.ts +15 -0
  15. package/src/api-client/ipo.ts +24 -1
  16. package/src/api-client/market-discovery.ts +10 -0
  17. package/src/api-client/market-movers.ts +7 -0
  18. package/src/api-client/members.ts +1 -1
  19. package/src/api-client/mna.ts +3 -0
  20. package/src/api-client/paths.ts +9 -1
  21. package/src/api-client/perps.ts +43 -0
  22. package/src/api-client/research-activity.ts +3 -2
  23. package/src/api-client/roadmap.ts +85 -0
  24. package/src/api-client/types.ts +82 -2
  25. package/src/app/pane-runtime/plugin-bindings.ts +9 -5
  26. package/src/app/runtime/broker-import.ts +0 -2
  27. package/src/app/runtime/plugin-bindings.ts +73 -56
  28. package/src/architecture/core-builtin-allowlist.json +2 -2
  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/market.ts +107 -38
  35. package/src/cli/commands/news-search.ts +22 -0
  36. package/src/cli/commands/options-chain.ts +48 -7
  37. package/src/cli/commands/options-leaps.ts +9 -3
  38. package/src/cli/commands/overview.ts +147 -32
  39. package/src/cli/commands/search.ts +21 -1
  40. package/src/cli/commands/themes.ts +11 -2
  41. package/src/cli/commands/ticker.ts +87 -36
  42. package/src/cli/company-name-hint.ts +41 -0
  43. package/src/cli/earnings-calendar.ts +1 -1
  44. package/src/cli/errors.ts +25 -2
  45. package/src/cli/glossary.ts +31 -2
  46. package/src/cli/history-rows.ts +57 -9
  47. package/src/cli/index-roots.ts +0 -7
  48. package/src/cli/index.ts +2 -0
  49. package/src/cli/listing-arg.ts +235 -60
  50. package/src/cli/output-file.ts +68 -0
  51. package/src/cli/pane-functions/capabilities.ts +4 -0
  52. package/src/cli/pane-functions/catalog.ts +80 -7
  53. package/src/cli/pane-functions/discovery.ts +21 -1
  54. package/src/cli/pane-functions/dom.ts +13 -3
  55. package/src/cli/pane-functions/freshness.ts +93 -4
  56. package/src/cli/pane-functions/function-help.ts +20 -10
  57. package/src/cli/pane-functions/headless.ts +17 -7
  58. package/src/cli/pane-functions/index.ts +54 -16
  59. package/src/cli/pane-functions/market-session.ts +66 -4
  60. package/src/cli/pane-functions/options.ts +19 -1
  61. package/src/cli/pane-functions/resolver.ts +19 -8
  62. package/src/cli/pane-functions/screenshot-assessment.ts +6 -4
  63. package/src/cli/pane-functions/screenshot-types.ts +5 -0
  64. package/src/cli/quote-answer.ts +22 -11
  65. package/src/cli/saved-copy-persistence.ts +88 -0
  66. package/src/cli/ticker-resolution.ts +3 -2
  67. package/src/components/chart/composite/composite-chart.tsx +4 -0
  68. package/src/components/chart/composite/interactions.ts +6 -0
  69. package/src/components/chart/composite/legend.tsx +45 -7
  70. package/src/components/chart/composite/panel-gestures.ts +33 -0
  71. package/src/components/chart/composite/panel-surface.tsx +52 -3
  72. package/src/components/chart/composite/rasterizer.ts +24 -13
  73. package/src/components/chart/composite/scene.ts +39 -4
  74. package/src/components/chart/composite/series-cues.ts +14 -0
  75. package/src/components/chart/composite/text-renderer.ts +9 -2
  76. package/src/components/chart/composite/tool-catalog.ts +36 -0
  77. package/src/components/chart/composite/tools.ts +203 -44
  78. package/src/components/chart/composite/use-composite-chart-keyboard.ts +11 -4
  79. package/src/components/command-bar/assist/inventory.ts +2 -1
  80. package/src/components/command-bar/commands/direct/index.ts +28 -13
  81. package/src/components/command-bar/list/model.ts +5 -0
  82. package/src/components/command-bar/pane-templates/items.ts +3 -2
  83. package/src/components/command-bar/routes/root/runtime.ts +6 -7
  84. package/src/components/command-bar/selection-runtime.ts +52 -3
  85. package/src/components/command-bar/surface/index.tsx +2 -0
  86. package/src/components/command-bar/workflow/collection-actions.ts +3 -3
  87. package/src/components/layout/pane/capture-stamp.ts +2 -2
  88. package/src/components/layout/pane/footer/index.tsx +22 -6
  89. package/src/components/layout/pane/footer/model.ts +83 -15
  90. package/src/components/layout/pane/status-footer.ts +35 -2
  91. package/src/components/layout/status-widget-space.ts +9 -0
  92. package/src/components/onboarding/onboarding-wizard.tsx +4 -1
  93. package/src/components/onboarding/portfolio-step/positions-panel.tsx +12 -7
  94. package/src/components/onboarding/wizard-broker-sync.ts +0 -1
  95. package/src/components/onboarding/wizard-positions.ts +3 -3
  96. package/src/components/ticker/list-table-view.tsx +8 -21
  97. package/src/components/ui/choice-dialog.tsx +23 -18
  98. package/src/components/ui/choice-groups.ts +18 -0
  99. package/src/components/ui/data-table/opentui/index.tsx +9 -7
  100. package/src/components/ui/data-table/opentui/model.ts +26 -1
  101. package/src/components/ui/data-table/types.ts +2 -0
  102. package/src/components/ui/display.tsx +18 -3
  103. package/src/components/ui/icon.tsx +4 -1
  104. package/src/components/ui/list-view.tsx +8 -4
  105. package/src/components/ui/query-bar-keys.tsx +2 -0
  106. package/src/components/ui/query-bar.tsx +1 -0
  107. package/src/components/ui/select-button.tsx +5 -1
  108. package/src/components/ui/select-field.tsx +1 -0
  109. package/src/components/ui/table-layout.ts +8 -5
  110. package/src/core/app-runtime.ts +2 -0
  111. package/src/core/app-services.ts +2 -2
  112. package/src/data/config/chart-settings.ts +1 -1
  113. package/src/data/json-ticker-repository.ts +17 -8
  114. package/src/data/plugin-cache.ts +5 -3
  115. package/src/data/saved-copies.ts +8 -0
  116. package/src/data/ticker-repository.ts +16 -9
  117. package/src/data/ticker-writes.ts +81 -0
  118. package/src/data/ttl-cache.ts +165 -0
  119. package/src/docs/snapshot.json +103 -142
  120. package/src/i18n/es.ts +20 -6
  121. package/src/i18n/ja.ts +20 -6
  122. package/src/i18n/ko.ts +20 -6
  123. package/src/i18n/zh-cn.ts +20 -6
  124. package/src/i18n/zh-tw.ts +20 -6
  125. package/src/market-data/depositary-pair.ts +27 -3
  126. package/src/market-data/fund-facts.ts +50 -0
  127. package/src/market-data/market/change-basis.ts +16 -3
  128. package/src/market-data/market/format.ts +25 -0
  129. package/src/market-data/market/freshness.ts +2 -1
  130. package/src/market-data/options-alternatives.ts +81 -4
  131. package/src/market-data/quotes/metadata.ts +7 -0
  132. package/src/news/aggregator.ts +119 -9
  133. package/src/news/cloud-session.ts +21 -0
  134. package/src/news/hooks.ts +1 -0
  135. package/src/news/news-model.ts +1 -0
  136. package/src/news/types.ts +17 -0
  137. package/src/plugins/builtin/alerts/alert-engine.ts +20 -1
  138. package/src/plugins/builtin/alerts/alert-log.ts +33 -0
  139. package/src/plugins/builtin/alerts/calendar-events.ts +10 -4
  140. package/src/plugins/builtin/alerts/cli-forms.ts +216 -0
  141. package/src/plugins/builtin/alerts/cli.ts +362 -80
  142. package/src/plugins/builtin/alerts/command.ts +25 -1
  143. package/src/plugins/builtin/alerts/event-rows.ts +24 -3
  144. package/src/plugins/builtin/alerts/events-pane.tsx +34 -10
  145. package/src/plugins/builtin/alerts/fired-log.ts +73 -9
  146. package/src/plugins/builtin/alerts/format.ts +75 -5
  147. package/src/plugins/builtin/alerts/headless.ts +34 -12
  148. package/src/plugins/builtin/alerts/history-rows.ts +3 -2
  149. package/src/plugins/builtin/alerts/history.ts +1 -1
  150. package/src/plugins/builtin/alerts/index.tsx +79 -16
  151. package/src/plugins/builtin/alerts/metric-command.ts +77 -4
  152. package/src/plugins/builtin/alerts/metric-data.ts +54 -13
  153. package/src/plugins/builtin/alerts/metric-model.ts +163 -14
  154. package/src/plugins/builtin/alerts/metric-parity-fixture.json +1 -1
  155. package/src/plugins/builtin/alerts/pane.tsx +61 -23
  156. package/src/plugins/builtin/alerts/quotes.ts +6 -0
  157. package/src/plugins/builtin/alerts/storage.ts +12 -8
  158. package/src/plugins/builtin/alerts/types.ts +4 -0
  159. package/src/plugins/builtin/analytics/index.tsx +2 -1
  160. package/src/plugins/builtin/analytics/risk-client.ts +16 -5
  161. package/src/plugins/builtin/analytics/risk-fx.ts +70 -15
  162. package/src/plugins/builtin/analytics/risk-headless.ts +27 -0
  163. package/src/plugins/builtin/analytics/risk-model.ts +55 -9
  164. package/src/plugins/builtin/analytics/risk-pane.tsx +8 -2
  165. package/src/plugins/builtin/attention/index.tsx +2 -1
  166. package/src/plugins/builtin/attention/listing.ts +14 -0
  167. package/src/plugins/builtin/broker-manager/index.tsx +7 -3
  168. package/src/plugins/builtin/buildout/cells.tsx +12 -4
  169. package/src/plugins/builtin/buildout/format.ts +38 -0
  170. package/src/plugins/builtin/buildout/model/normalizers.ts +36 -1
  171. package/src/plugins/builtin/buildout/pane/index.tsx +4 -1
  172. package/src/plugins/builtin/buildout/table-model.ts +23 -2
  173. package/src/plugins/builtin/builtin-plugin-meta.ts +6 -2
  174. package/src/plugins/builtin/cds/client.ts +142 -30
  175. package/src/plugins/builtin/cds/headless.ts +35 -8
  176. package/src/plugins/builtin/cds/model.ts +145 -18
  177. package/src/plugins/builtin/cds/pane.tsx +16 -5
  178. package/src/plugins/builtin/changelog/index.tsx +9 -6
  179. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +3 -0
  180. package/src/plugins/builtin/chart-composer/cli-options.ts +4 -0
  181. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +7 -0
  182. package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -2
  183. package/src/plugins/builtin/chart-composer/follow-binding.ts +14 -2
  184. package/src/plugins/builtin/chart-composer/headless-schema.ts +7 -1
  185. package/src/plugins/builtin/chart-composer/headless.ts +6 -1
  186. package/src/plugins/builtin/chart-composer/index.tsx +5 -6
  187. package/src/plugins/builtin/chart-composer/pane.tsx +37 -8
  188. package/src/plugins/builtin/chart-composer/settings.ts +27 -0
  189. package/src/plugins/builtin/chat/content/command-suggestions.ts +1 -0
  190. package/src/plugins/builtin/chat/controller/index.ts +5 -1
  191. package/src/plugins/builtin/chat/controller/notifications.ts +33 -3
  192. package/src/plugins/builtin/chat/controller/state.ts +25 -2
  193. package/src/plugins/builtin/chat/controller/unread-people.ts +89 -23
  194. package/src/plugins/builtin/chat/controller/utils.ts +7 -2
  195. package/src/plugins/builtin/chat/pane-links/commands.ts +7 -1
  196. package/src/plugins/builtin/chat/status-preview.ts +79 -0
  197. package/src/plugins/builtin/chat/status-widget.tsx +147 -10
  198. package/src/plugins/builtin/chat/unread-badge.ts +51 -10
  199. package/src/plugins/builtin/clinical-trials/client.ts +49 -4
  200. package/src/plugins/builtin/clinical-trials/model.ts +86 -31
  201. package/src/plugins/builtin/clinical-trials/pane.tsx +61 -49
  202. package/src/plugins/builtin/clinical-trials/sponsor-listing.ts +90 -0
  203. package/src/plugins/builtin/clinical-trials/sponsor-tickers.ts +95 -15
  204. package/src/plugins/builtin/clinical-trials/trial-pages.ts +50 -0
  205. package/src/plugins/builtin/cloud/askg/manifest.ts +2 -0
  206. package/src/plugins/builtin/company-attention/building.tsx +5 -1
  207. package/src/plugins/builtin/company-attention/client.ts +8 -9
  208. package/src/plugins/builtin/company-attention/evidence.ts +4 -1
  209. package/src/plugins/builtin/company-attention/headless.ts +2 -1
  210. package/src/plugins/builtin/company-attention/moves.tsx +5 -1
  211. package/src/plugins/builtin/company-attention/pane.tsx +12 -2
  212. package/src/plugins/builtin/company-attention/signals.tsx +5 -1
  213. package/src/plugins/builtin/company-kpis/headless.ts +8 -3
  214. package/src/plugins/builtin/company-kpis/model.ts +73 -5
  215. package/src/plugins/builtin/company-kpis/pane.tsx +15 -7
  216. package/src/plugins/builtin/composite-plugins.ts +2 -1
  217. package/src/plugins/builtin/correlation/headless.ts +13 -5
  218. package/src/plugins/builtin/correlation/history.ts +22 -0
  219. package/src/plugins/builtin/cot/client.ts +22 -18
  220. package/src/plugins/builtin/cot/headless.ts +15 -10
  221. package/src/plugins/builtin/cot/model.ts +14 -1
  222. package/src/plugins/builtin/cot/pane.tsx +22 -14
  223. package/src/plugins/builtin/credit-boards/client.ts +6 -10
  224. package/src/plugins/builtin/credit-conditions/headless.ts +8 -2
  225. package/src/plugins/builtin/credit-conditions/index.tsx +5 -1
  226. package/src/plugins/builtin/credit-conditions/model.ts +4 -0
  227. package/src/plugins/builtin/credit-conditions/series.ts +3 -1
  228. package/src/plugins/builtin/credit-documents/detail.tsx +2 -2
  229. package/src/plugins/builtin/credit-documents/export.ts +173 -0
  230. package/src/plugins/builtin/credit-documents/headless.ts +10 -10
  231. package/src/plugins/builtin/credit-documents/model.ts +104 -14
  232. package/src/plugins/builtin/credit-documents/pane.tsx +12 -5
  233. package/src/plugins/builtin/custom-view/sources.ts +2 -0
  234. package/src/plugins/builtin/dividend-yield/client.ts +131 -23
  235. package/src/plugins/builtin/dividend-yield/headless.ts +44 -16
  236. package/src/plugins/builtin/dividend-yield/model.ts +8 -5
  237. package/src/plugins/builtin/dividend-yield/pane.tsx +38 -13
  238. package/src/plugins/builtin/dividend-yield/ranking.ts +37 -14
  239. package/src/plugins/builtin/dividend-yield/types.ts +20 -2
  240. package/src/plugins/builtin/dividend-yield/view.ts +30 -2
  241. package/src/plugins/builtin/docs/targets.ts +5 -1
  242. package/src/plugins/builtin/doe/headless.ts +3 -2
  243. package/src/plugins/builtin/doe/pane.tsx +13 -3
  244. package/src/plugins/builtin/earnings/board-model.ts +16 -15
  245. package/src/plugins/builtin/earnings/board.tsx +62 -71
  246. package/src/plugins/builtin/earnings/headless.ts +40 -4
  247. package/src/plugins/builtin/earnings/scope.ts +31 -43
  248. package/src/plugins/builtin/earnings-calls/calendar.tsx +2 -2
  249. package/src/plugins/builtin/earnings-calls/data.ts +18 -6
  250. package/src/plugins/builtin/earnings-calls/format.ts +31 -2
  251. package/src/plugins/builtin/earnings-calls/headless.ts +20 -5
  252. package/src/plugins/builtin/earnings-calls/model.ts +6 -1
  253. package/src/plugins/builtin/earnings-calls/pane.tsx +12 -4
  254. package/src/plugins/builtin/econ/calendar-model.ts +48 -1
  255. package/src/plugins/builtin/econ/calendar-source.ts +4 -2
  256. package/src/plugins/builtin/econ/detail-view.tsx +2 -2
  257. package/src/plugins/builtin/econ/figures.ts +48 -0
  258. package/src/plugins/builtin/econ/index.tsx +14 -5
  259. package/src/plugins/builtin/econ/print-watch.ts +3 -1
  260. package/src/plugins/builtin/econ/types.ts +2 -0
  261. package/src/plugins/builtin/econ-statistics/client.ts +11 -0
  262. package/src/plugins/builtin/econ-statistics/defs.ts +6 -0
  263. package/src/plugins/builtin/econ-statistics/headless.ts +16 -6
  264. package/src/plugins/builtin/econ-statistics/pane.tsx +8 -4
  265. package/src/plugins/builtin/econ-statistics/stats.ts +39 -9
  266. package/src/plugins/builtin/equity-screener/categories.ts +179 -0
  267. package/src/plugins/builtin/equity-screener/client.ts +4 -2
  268. package/src/plugins/builtin/equity-screener/headless.ts +144 -13
  269. package/src/plugins/builtin/equity-screener/ideas.ts +49 -0
  270. package/src/plugins/builtin/equity-screener/model.ts +99 -10
  271. package/src/plugins/builtin/equity-screener/pane.tsx +68 -13
  272. package/src/plugins/builtin/fixed-income/pane.tsx +2 -1
  273. package/src/plugins/builtin/futures/use-board-terms.ts +42 -28
  274. package/src/plugins/builtin/futures/use-front-returns.ts +45 -28
  275. package/src/plugins/builtin/fx-matrix/client.ts +6 -3
  276. package/src/plugins/builtin/fx-matrix/headless.ts +1 -1
  277. package/src/plugins/builtin/fx-matrix/index.tsx +4 -2
  278. package/src/plugins/builtin/fx-matrix/live-legs.ts +42 -3
  279. package/src/plugins/builtin/gpu/headless.ts +8 -2
  280. package/src/plugins/builtin/help/function-index.ts +4 -1
  281. package/src/plugins/builtin/help/index.tsx +62 -59
  282. package/src/plugins/builtin/help/shortcut-model.ts +1 -1
  283. package/src/plugins/builtin/help/shortcut-table.tsx +5 -6
  284. package/src/plugins/builtin/help/table-cells.tsx +13 -2
  285. package/src/plugins/builtin/holders/beneficial-client.ts +5 -1
  286. package/src/plugins/builtin/holders/beneficial-view.tsx +3 -0
  287. package/src/plugins/builtin/holders/fund-holders.ts +51 -0
  288. package/src/plugins/builtin/holders/headless.ts +22 -3
  289. package/src/plugins/builtin/holders/pane.tsx +3 -0
  290. package/src/plugins/builtin/holders/report-rows.ts +4 -1
  291. package/src/plugins/builtin/insider/headless.ts +2 -2
  292. package/src/plugins/builtin/ipo-calendar/client.ts +18 -2
  293. package/src/plugins/builtin/ipo-calendar/headless.ts +75 -11
  294. package/src/plugins/builtin/ipo-calendar/listing-ipo.ts +160 -0
  295. package/src/plugins/builtin/ipo-calendar/model.ts +98 -2
  296. package/src/plugins/builtin/iv-history/client.ts +52 -11
  297. package/src/plugins/builtin/iv-history/format.ts +36 -23
  298. package/src/plugins/builtin/iv-history/headless.ts +33 -18
  299. package/src/plugins/builtin/iv-history/index.tsx +2 -2
  300. package/src/plugins/builtin/iv-history/model.ts +163 -27
  301. package/src/plugins/builtin/iv-history/pane.tsx +10 -6
  302. package/src/plugins/builtin/iv-history/screen-pane.tsx +22 -15
  303. package/src/plugins/builtin/iv-history/universe.ts +5 -1
  304. package/src/plugins/builtin/jobs/client.ts +25 -29
  305. package/src/plugins/builtin/kelly-sizer/model.ts +12 -8
  306. package/src/plugins/builtin/kelly-sizer/pane.tsx +9 -9
  307. package/src/plugins/builtin/kelly-sizer/sections.tsx +19 -10
  308. package/src/plugins/builtin/kelly-sizer/types.ts +10 -4
  309. package/src/plugins/builtin/macro-day/headless.ts +12 -5
  310. package/src/plugins/builtin/macro-day/index.tsx +1 -1
  311. package/src/plugins/builtin/macro-day/model.ts +39 -5
  312. package/src/plugins/builtin/macro-day/pane.tsx +27 -19
  313. package/src/plugins/builtin/macro-day/release-table.ts +2 -2
  314. package/src/plugins/builtin/market-heatmap/data.ts +8 -33
  315. package/src/plugins/builtin/market-movers/client.ts +27 -7
  316. package/src/plugins/builtin/market-movers/headless.ts +34 -12
  317. package/src/plugins/builtin/market-movers/index.tsx +26 -14
  318. package/src/plugins/builtin/market-movers/min-float.ts +74 -0
  319. package/src/plugins/builtin/market-movers/model.ts +4 -1
  320. package/src/plugins/builtin/market-movers/screener.ts +22 -4
  321. package/src/plugins/builtin/market-movers/session-body.tsx +13 -8
  322. package/src/plugins/builtin/market-movers/session-table.ts +4 -3
  323. package/src/plugins/builtin/market-movers/table.ts +17 -5
  324. package/src/plugins/builtin/members/breadth-pane.tsx +2 -1
  325. package/src/plugins/builtin/mna/headless.ts +2 -0
  326. package/src/plugins/builtin/mna/pane.tsx +3 -1
  327. package/src/plugins/builtin/news/headless.ts +3 -1
  328. package/src/plugins/builtin/news/index.tsx +4 -0
  329. package/src/plugins/builtin/news/wire/categories.ts +19 -3
  330. package/src/plugins/builtin/news/wire/industry-pane.tsx +1 -0
  331. package/src/plugins/builtin/news/wire/news/footer.ts +31 -5
  332. package/src/plugins/builtin/news/wire/news/preset-pane.tsx +6 -1
  333. package/src/plugins/builtin/news/wire/news/table.tsx +2 -2
  334. package/src/plugins/builtin/openfda/client.ts +14 -2
  335. package/src/plugins/builtin/openfda/index.tsx +3 -2
  336. package/src/plugins/builtin/openfda/model.ts +9 -0
  337. package/src/plugins/builtin/openfda/pane.tsx +42 -6
  338. package/src/plugins/builtin/options/analytics.ts +29 -5
  339. package/src/plugins/builtin/options/enrichment.ts +17 -5
  340. package/src/plugins/builtin/options/table.ts +5 -2
  341. package/src/plugins/builtin/options/types.ts +2 -0
  342. package/src/plugins/builtin/options/view.tsx +17 -4
  343. package/src/plugins/builtin/options-positioning/client.ts +11 -0
  344. package/src/plugins/builtin/options-positioning/headless.ts +21 -8
  345. package/src/plugins/builtin/options-positioning/index.tsx +1 -1
  346. package/src/plugins/builtin/options-positioning/model.ts +78 -9
  347. package/src/plugins/builtin/options-positioning/pane.tsx +21 -6
  348. package/src/plugins/builtin/options-scenario/client.ts +116 -47
  349. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +142 -10
  350. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +206 -55
  351. package/src/plugins/builtin/options-scenario/csp-screen.ts +63 -23
  352. package/src/plugins/builtin/options-scenario/csp.ts +8 -2
  353. package/src/plugins/builtin/options-scenario/index.tsx +9 -7
  354. package/src/plugins/builtin/options-scenario/strategy-screen.ts +532 -0
  355. package/src/plugins/builtin/pe-band/model.ts +12 -49
  356. package/src/plugins/builtin/perps/cascade-tabs.tsx +161 -0
  357. package/src/plugins/builtin/perps/cascade.ts +236 -0
  358. package/src/plugins/builtin/perps/client.ts +56 -2
  359. package/src/plugins/builtin/perps/headless.ts +65 -9
  360. package/src/plugins/builtin/perps/index.tsx +7 -5
  361. package/src/plugins/builtin/perps/model.ts +18 -4
  362. package/src/plugins/builtin/perps/pane.tsx +19 -22
  363. package/src/plugins/builtin/perps/status-line.ts +25 -0
  364. package/src/plugins/builtin/plugin-module.ts +5 -1
  365. package/src/plugins/builtin/portfolio-list/cached-account.ts +3 -1
  366. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +2 -8
  367. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +4 -4
  368. package/src/plugins/builtin/portfolio-list/cli/render.ts +7 -5
  369. package/src/plugins/builtin/portfolio-list/pane/futures-front.ts +40 -0
  370. package/src/plugins/builtin/portfolio-list/pane/index.tsx +6 -7
  371. package/src/plugins/builtin/portfolio-list/pane/streaming.ts +5 -2
  372. package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +3 -2
  373. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +0 -14
  374. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +5 -2
  375. package/src/plugins/builtin/portfolio-list/table.tsx +15 -9
  376. package/src/plugins/builtin/primary-dealers/client.ts +13 -38
  377. package/src/plugins/builtin/realized-vol/client.ts +13 -5
  378. package/src/plugins/builtin/realized-vol/evidence.ts +29 -4
  379. package/src/plugins/builtin/realized-vol/headless.ts +8 -4
  380. package/src/plugins/builtin/realized-vol/index.tsx +2 -2
  381. package/src/plugins/builtin/realized-vol/model.ts +37 -6
  382. package/src/plugins/builtin/realized-vol/pane.tsx +11 -9
  383. package/src/plugins/builtin/relative-rotation/client.ts +18 -4
  384. package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
  385. package/src/plugins/builtin/relative-rotation/index.tsx +2 -1
  386. package/src/plugins/builtin/relative-rotation/model.ts +16 -40
  387. package/src/plugins/builtin/relative-rotation/pane.tsx +3 -2
  388. package/src/plugins/builtin/research/corporate-actions-pane.tsx +3 -2
  389. package/src/plugins/builtin/research/event-model.ts +40 -12
  390. package/src/plugins/builtin/research/headless.ts +1 -1
  391. package/src/plugins/builtin/research/index.tsx +7 -3
  392. package/src/plugins/builtin/research/relative-valuation-headless.ts +13 -26
  393. package/src/plugins/builtin/research/relative-valuation-model.ts +31 -3
  394. package/src/plugins/builtin/research/relative-valuation-pane.tsx +59 -20
  395. package/src/plugins/builtin/research/relative-valuation-peers.ts +217 -20
  396. package/src/plugins/builtin/research/relative-valuation-settings.ts +44 -0
  397. package/src/plugins/builtin/reverse-dcf/headless.ts +5 -3
  398. package/src/plugins/builtin/reverse-dcf/model.ts +61 -6
  399. package/src/plugins/builtin/reverse-dcf/pane.tsx +7 -4
  400. package/src/plugins/builtin/risk-factors/data.ts +4 -2
  401. package/src/plugins/builtin/risk-factors/headless.ts +5 -2
  402. package/src/plugins/builtin/roadmap/index.tsx +28 -0
  403. package/src/plugins/builtin/roadmap/model.ts +67 -0
  404. package/src/plugins/builtin/roadmap/pane.tsx +244 -0
  405. package/src/plugins/builtin/scanner/flow-model.ts +50 -4
  406. package/src/plugins/builtin/scanner/flow-pane.tsx +367 -65
  407. package/src/plugins/builtin/scanner/flow-session.ts +146 -0
  408. package/src/plugins/builtin/scanner/headless.ts +204 -35
  409. package/src/plugins/builtin/scanner/index.ts +16 -5
  410. package/src/plugins/builtin/scanner/live-headless.ts +48 -5
  411. package/src/plugins/builtin/scanner/live-model.ts +11 -0
  412. package/src/plugins/builtin/scanner/live-pane.tsx +3 -3
  413. package/src/plugins/builtin/scanner/lock-note.ts +3 -2
  414. package/src/plugins/builtin/seasonality/headless.ts +10 -1
  415. package/src/plugins/builtin/sec/fund-facts-view.tsx +5 -2
  416. package/src/plugins/builtin/sec/fund-facts.ts +116 -34
  417. package/src/plugins/builtin/sec/headless.ts +4 -2
  418. package/src/plugins/builtin/sec/index.tsx +3 -0
  419. package/src/plugins/builtin/series-inventory.ts +2 -0
  420. package/src/plugins/builtin/shared/cloud-resource.ts +16 -7
  421. package/src/plugins/builtin/shared/cloud-upgrade.ts +4 -3
  422. package/src/plugins/builtin/shared/earnings-calendar.ts +6 -2
  423. package/src/plugins/builtin/shared/earnings-report.ts +2 -2
  424. package/src/plugins/builtin/shared/headless-market-data.ts +2 -2
  425. package/src/plugins/builtin/shared/job-posting.ts +1 -0
  426. package/src/plugins/builtin/shared/members-menu.tsx +3 -2
  427. package/src/plugins/builtin/shared/pro-lock-note.ts +12 -12
  428. package/src/plugins/builtin/shared/report-freshness.ts +11 -2
  429. package/src/plugins/builtin/shared/research-cells.tsx +1 -1
  430. package/src/plugins/builtin/shared/series-cache.ts +4 -4
  431. package/src/plugins/builtin/shared/ticker-choice.tsx +2 -1
  432. package/src/plugins/builtin/shared/ticker-company.ts +77 -0
  433. package/src/plugins/builtin/shared/use-quote-board.ts +2 -1
  434. package/src/plugins/builtin/shared/volatility/live-session.ts +34 -8
  435. package/src/plugins/builtin/shared/volatility/pricing.ts +19 -0
  436. package/src/plugins/builtin/shared/wall-view-lifecycle.ts +3 -1
  437. package/src/plugins/builtin/themes/model.ts +16 -7
  438. package/src/plugins/builtin/themes/pane.tsx +5 -5
  439. package/src/plugins/builtin/thirteenf/api.ts +12 -1
  440. package/src/plugins/builtin/thirteenf/data.ts +7 -7
  441. package/src/plugins/builtin/thirteenf/headless.ts +31 -4
  442. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +43 -18
  443. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +3 -2
  444. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +62 -0
  445. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +83 -46
  446. package/src/plugins/builtin/ticker-detail/headless.ts +31 -16
  447. package/src/plugins/builtin/ticker-detail/overview/model.ts +11 -3
  448. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +2 -1
  449. package/src/plugins/builtin/ticker-detail/pane.tsx +14 -8
  450. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +2 -1
  451. package/src/plugins/builtin/ticker-detail/settings.ts +1 -0
  452. package/src/plugins/builtin/time-sales/pane.tsx +31 -19
  453. package/src/plugins/builtin/treasury-auctions/headless.ts +21 -12
  454. package/src/plugins/builtin/treasury-auctions/pane.tsx +9 -3
  455. package/src/plugins/builtin/treasury-daily/client.ts +41 -5
  456. package/src/plugins/builtin/treasury-daily/headless.ts +2 -2
  457. package/src/plugins/builtin/treasury-daily/index.tsx +1 -1
  458. package/src/plugins/builtin/treasury-daily/model.ts +50 -3
  459. package/src/plugins/builtin/treasury-daily/pane.tsx +81 -2
  460. package/src/plugins/builtin/vol-surface/client.ts +3 -13
  461. package/src/plugins/builtin/vol-surface/headless.ts +3 -3
  462. package/src/plugins/builtin/vol-surface/index.tsx +1 -1
  463. package/src/plugins/builtin/vol-surface/pane.tsx +7 -5
  464. package/src/plugins/builtin/volatility/index.tsx +2 -2
  465. package/src/plugins/builtin/volatility/pane.tsx +7 -4
  466. package/src/plugins/builtin/world-venue-map/headless.ts +3 -3
  467. package/src/plugins/builtin/yield-curve/client.ts +61 -1
  468. package/src/plugins/builtin/yield-curve/headless.ts +9 -6
  469. package/src/plugins/builtin/yield-curve/index.tsx +34 -10
  470. package/src/plugins/builtin/yield-curve/swaps.tsx +9 -5
  471. package/src/plugins/catalog-browser.ts +2 -1
  472. package/src/plugins/catalog-manifest.ts +2 -1
  473. package/src/plugins/host-link.ts +1 -1
  474. package/src/plugins/marketplace/model.ts +18 -5
  475. package/src/portfolio/column-values.ts +11 -7
  476. package/src/portfolio/futures-positions.ts +6 -3
  477. package/src/portfolio/position-quantity.ts +15 -9
  478. package/src/remote/resources.ts +2 -1
  479. package/src/renderers/dom/data-table/row.tsx +26 -0
  480. package/src/renderers/dom/desktop/icons.tsx +7 -0
  481. package/src/renderers/dom/desktop/list-view.tsx +13 -10
  482. package/src/renderers/dom/desktop/query-bar.tsx +4 -2
  483. package/src/renderers/dom/desktop/select-field.tsx +4 -2
  484. package/src/renderers/dom/host/chart-surface.tsx +21 -0
  485. package/src/renderers/electrobun/bun/desktop/app-name.ts +3 -3
  486. package/src/renderers/electrobun/bun/desktop/backend.ts +21 -10
  487. package/src/renderers/electrobun/bun/desktop/host-requests.ts +15 -0
  488. package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -0
  489. package/src/renderers/electrobun/bun/desktop/installer-folder.ts +731 -0
  490. package/src/renderers/electrobun/bun/desktop/relaunch.ts +102 -10
  491. package/src/renderers/electrobun/bun/desktop/update.ts +115 -14
  492. package/src/renderers/electrobun/bun/desktop/view-ids.ts +52 -0
  493. package/src/renderers/electrobun/bun/desktop/windows-script.ts +92 -0
  494. package/src/renderers/electrobun/bun/index.ts +26 -2
  495. package/src/renderers/electrobun/bun/window/create.ts +43 -4
  496. package/src/renderers/electrobun/bun/window/events.ts +20 -0
  497. package/src/renderers/electrobun/bun/window/windows-custom-chrome.ts +9 -2
  498. package/src/renderers/electrobun/bun/window/windows-native.ts +78 -0
  499. package/src/renderers/electrobun/bun/window/windows-quit.ts +57 -0
  500. package/src/renderers/electrobun/shared/app-name.ts +13 -0
  501. package/src/renderers/electrobun/shared/protocol.ts +12 -0
  502. package/src/renderers/electrobun/view/backend-rpc.ts +6 -0
  503. package/src/renderers/electrobun/view/main.tsx +24 -1
  504. package/src/renderers/electrobun/view/news-source.ts +5 -1
  505. package/src/renderers/electrobun/view/remote/ticker-repository.ts +14 -7
  506. package/src/renderers/electrobun/view/ui-host.tsx +8 -0
  507. package/src/renderers/electrobun/view/view-ids.ts +85 -0
  508. package/src/renderers/opentui/start.tsx +5 -0
  509. package/src/series/registry.ts +1 -0
  510. package/src/series/types.ts +6 -0
  511. package/src/series/validate.ts +1 -0
  512. package/src/sources/gloomberb-cloud/fred-series.ts +3 -1
  513. package/src/sources/gloomberb-cloud/index.ts +43 -8
  514. package/src/sources/gloomberb-cloud/news.ts +47 -7
  515. package/src/sources/provider-router/financials.ts +15 -3
  516. package/src/sources/provider-router/index.ts +8 -5
  517. package/src/state/ticker-cleanup.ts +50 -0
  518. package/src/sync/controller.ts +4 -3
  519. package/src/sync/core-contributors.ts +90 -31
  520. package/src/telemetry/stall-reports-dom.ts +38 -0
  521. package/src/telemetry/stall-reports-node.ts +75 -0
  522. package/src/telemetry/stall-reports.ts +214 -0
  523. package/src/test-support/preload.ts +14 -0
  524. package/src/theme/themes.ts +10 -0
  525. package/src/tickers/company-name-listing.ts +53 -13
  526. package/src/tickers/company-name.ts +50 -4
  527. package/src/tickers/index-roots.ts +7 -0
  528. package/src/tickers/listing-fate.ts +2 -2
  529. package/src/tickers/listing-venues.ts +15 -3
  530. package/src/tickers/search/index.ts +6 -2
  531. package/src/tickers/search/ranking.ts +5 -1
  532. package/src/tickers/search/upsert.ts +13 -0
  533. package/src/tickers/terminal-codes.ts +19 -0
  534. package/src/tickers/ticker-changes.ts +8 -4
  535. package/src/time-series/alignment.ts +1 -1
  536. package/src/time-series/economic.ts +18 -4
  537. package/src/time-series/field-catalog.ts +1 -1
  538. package/src/time-series/filed-trailing-eps.ts +197 -0
  539. package/src/time-series/fundamentals.ts +44 -1
  540. package/src/time-series/ice-credit.ts +3 -0
  541. package/src/time-series/price-comparison.ts +30 -2
  542. package/src/time-series/resolve-context.ts +3 -1
  543. package/src/time-series/resolve.ts +56 -4
  544. package/src/time-series/session-bar.ts +11 -0
  545. package/src/time-series/spec.ts +3 -2
  546. package/src/time-series/studies.ts +8 -2
  547. package/src/time-series/total-return.ts +160 -0
  548. package/src/time-series/transforms.ts +2 -3
  549. package/src/time-series/types.ts +22 -1
  550. package/src/types/company-from.ts +40 -0
  551. package/src/types/data-provider.ts +7 -0
  552. package/src/types/financials.ts +59 -1
  553. package/src/types/headless.ts +27 -3
  554. package/src/types/news-source.ts +1 -0
  555. package/src/types/plugin.ts +9 -0
  556. package/src/ui/host.tsx +3 -0
  557. package/src/updater/failure.ts +4 -1
  558. package/src/utils/cli-output.ts +42 -1
  559. package/src/utils/crypto-pair.ts +165 -7
  560. package/src/utils/declared-dividends.ts +1 -1
  561. package/src/utils/forward-dividend.ts +2 -0
  562. package/src/utils/fundamentals.ts +60 -8
  563. package/src/utils/fx-market-hours.ts +26 -3
  564. package/src/utils/main-thread-stall.ts +35 -2
  565. package/src/utils/market-capitalization.ts +24 -1
  566. package/src/utils/price-history.ts +7 -1
  567. package/src/utils/shell-word.ts +8 -0
  568. package/src/utils/trailing-dividend.ts +53 -4
  569. package/src/version.ts +2 -2
  570. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +0 -17
@@ -23,21 +23,27 @@ function tradesInWholeUnits(ticker: TickerRecord): boolean {
23
23
  }
24
24
 
25
25
  /**
26
- * Why a typed size cannot be stored as read: a dot and three digits (`1.250`)
27
- * on a listing held in whole units, where it is far likelier the thousands
28
- * grouping many locales write (1,250 shares) than a quarter of a share, so the
29
- * command asks which, as it does for `1,250`. Null for any other size, and
30
- * for a listing that may be held in fractions, where `1.250` is 1.25.
26
+ * Why a typed size cannot be stored as read: a dot and three digits (`1.000`,
27
+ * `1.250`), which is as likely the thousands grouping many locales write
28
+ * (1,000 shares, as cash reads `1.000`) as a fraction of a share, so the
29
+ * command asks which, as it does for `1,250`. On a listing held in whole
30
+ * units the thousands reading is the only one that can be held, and the
31
+ * message says so. Null for any other size (`0.500`, `12.25`).
31
32
  */
32
- export function wholeUnitQuantityProblem(
33
+ export function ambiguousQuantityProblem(
33
34
  typed: string,
34
35
  ticker: TickerRecord,
35
36
  options: { label?: PositionQuantityLabel; listing?: string } = {},
36
37
  ): string | null {
37
38
  const reading = thousandsDotReadings(typed);
38
- if (!reading || !tradesInWholeUnits(ticker)) return null;
39
+ if (!reading) return null;
39
40
  const label = options.label ?? positionQuantityLabel(ticker);
40
41
  const listing = options.listing ?? ticker.metadata.ticker;
41
- const because = `${listing} trades in whole ${label === "Contracts" ? "contracts" : "shares"}`;
42
- return `${label} ${ambiguousNumberMessage(typed, reading, { because })}.`;
42
+ const because = tradesInWholeUnits(ticker)
43
+ ? `${listing} trades in whole ${label === "Contracts" ? "contracts" : "shares"}`
44
+ : undefined;
45
+ // The fraction typed so it does not read two ways itself: 1.234 asks again, 1.2340 does not.
46
+ const fraction = String(reading.decimal);
47
+ const decimalAs = thousandsDotReadings(fraction) ? `${fraction}0` : fraction;
48
+ return `${label} ${ambiguousNumberMessage(typed, reading, { because, decimalAs })}.`;
43
49
  }
@@ -110,7 +110,8 @@ export function createRemoteResources({
110
110
  }));
111
111
  }
112
112
  if (resource === "app://pane-templates") {
113
- return [...pluginRegistry.paneTemplates.values()].map((template) => ({
113
+ // An unlisted function (`listed: false`) is left out, as of every list.
114
+ return [...pluginRegistry.paneTemplates.values()].filter((template) => template.listed !== false).map((template) => ({
114
115
  id: template.id,
115
116
  paneId: template.paneId,
116
117
  label: template.label,
@@ -457,6 +457,32 @@ function WebDataTableRowInner<
457
457
 
458
458
  function CellText({ cell, column, color }: { cell: DataTableCell; column: DataTableColumn; color: string }) {
459
459
  const style = clippedCellTextStyle(column, color, cell.attributes ?? TextAttributes.NONE);
460
+ if (cell.note) {
461
+ const text = (
462
+ <div
463
+ style={{
464
+ display: "flex",
465
+ flexWrap: "wrap",
466
+ alignContent: "flex-start",
467
+ justifyContent: contentJustifyForAlign(column.align),
468
+ columnGap: "var(--gloom-space-sm)",
469
+ width: "100%",
470
+ height: "100%",
471
+ minWidth: 0,
472
+ overflow: "hidden",
473
+ }}
474
+ >
475
+ <span title={cell.text} style={{ ...style, width: "auto", flex: "0 1 auto", minWidth: 0 }}>{cell.text}</span>
476
+ <span data-gloom-role="data-table-cell-note" style={{ ...cellTextStyle(CSS_TEXT_DIM, TextAttributes.NONE), flex: "none" }}>{cell.note}</span>
477
+ </div>
478
+ );
479
+ return cell.leading === undefined ? text : (
480
+ <div style={{ display: "flex", alignItems: "center", gap: LABEL_GAP_PX, width: "100%", height: "100%", minWidth: 0, overflow: "hidden" }}>
481
+ <Leading>{cell.leading}</Leading>
482
+ {text}
483
+ </div>
484
+ );
485
+ }
460
486
  if (cell.leading === undefined) return <span title={cell.text} style={style}>{cell.text}</span>;
461
487
  return (
462
488
  <div
@@ -165,6 +165,13 @@ const ICONS: Record<IconName, ReactNode> = {
165
165
  <path d="M7.3 2.9l1.8 1.8" stroke="currentColor" strokeWidth="1.1" />
166
166
  </>
167
167
  ),
168
+ // An envelope: a message written to you.
169
+ mail: (
170
+ <>
171
+ <rect x="1.5" y="2.75" width="9" height="6.5" rx="1.1" stroke="currentColor" strokeWidth="1.1" />
172
+ <path d="M2 3.4 6 6.5l4-3.1" stroke="currentColor" strokeWidth="1.1" strokeLinecap="round" strokeLinejoin="round" />
173
+ </>
174
+ ),
168
175
  restore: (
169
176
  <>
170
177
  <rect x="2" y="4" width="6" height="6" rx="0.8" stroke="currentColor" strokeWidth="1.1" />
@@ -27,6 +27,7 @@ function DefaultDesktopRow({
27
27
  stacked: boolean;
28
28
  }) {
29
29
  const colors = useThemeColors();
30
+ if (item.kind === "heading") return <Text fg={colors.textMuted}>{item.label}</Text>;
30
31
  return (
31
32
  <Box
32
33
  flexDirection="row"
@@ -142,6 +143,7 @@ export function WebListView({
142
143
  const rowHoverBg = hoverBgColor ?? hoverBg(colors);
143
144
  const selectedItem = selectedIndex >= 0 ? items[selectedIndex] : undefined;
144
145
  const activeScrollIndex = scrollIndex ?? selectedIndex;
146
+ const headingAboveSelection = items[activeScrollIndex - 1]?.kind === "heading";
145
147
  const rowStride = rowHeight + rowGap;
146
148
  const tabStopIndex = selectedIndex >= 0 && items[selectedIndex] && !items[selectedIndex].disabled
147
149
  ? selectedIndex : items.findIndex((item) => !item.disabled);
@@ -176,14 +178,14 @@ export function WebListView({
176
178
  if (!scrollBox) return;
177
179
  const safeIndex = Math.min(activeScrollIndex, items.length - 1);
178
180
  const viewportHeight = Math.max(scrollBox.viewport?.height ?? 0, 1);
179
- const rowTop = safeIndex * rowStride;
180
- const rowBottom = rowTop + rowHeight;
181
+ const rowTop = Math.max(0, safeIndex - (headingAboveSelection ? 1 : 0)) * rowStride;
182
+ const rowBottom = safeIndex * rowStride + rowHeight;
181
183
  if (rowTop < scrollBox.scrollTop) {
182
184
  scrollBox.scrollTo(rowTop);
183
185
  } else if (rowBottom > scrollBox.scrollTop + viewportHeight) {
184
186
  scrollBox.scrollTo(rowBottom - viewportHeight);
185
187
  }
186
- }, [activeScrollIndex, autoScrollToIndex, items.length, rowHeight, rowStride, scrolls]);
188
+ }, [activeScrollIndex, autoScrollToIndex, headingAboveSelection, items.length, rowHeight, rowStride, scrolls]);
187
189
 
188
190
  useEffect(() => {
189
191
  if (!scrolls) return;
@@ -202,7 +204,7 @@ export function WebListView({
202
204
  const list = document.getElementById(listDomId);
203
205
  const active = document.activeElement;
204
206
  if (!list || !active || !list.contains(active) || isEditableKeyboardTarget(active)) return;
205
- const row = list.querySelectorAll<HTMLElement>('[role="option"]')[selectedIndex];
207
+ const row = list.querySelector<HTMLElement>(`[data-gloom-list-index="${selectedIndex}"]`);
206
208
  if (row && !row.contains(active)) row.focus({ preventScroll: scrolls });
207
209
  }, [listDomId, scrolls, selectedIndex]);
208
210
 
@@ -246,10 +248,11 @@ export function WebListView({
246
248
  onActivate?.(item, index);
247
249
  }}
248
250
  data-gloom-role="desktop-list-row"
249
- role="option"
250
- aria-selected={selected}
251
- aria-disabled={disabled || undefined}
252
- tabIndex={index === tabStopIndex ? 0 : -1}
251
+ data-gloom-list-index={index}
252
+ role={item.kind === "heading" ? "presentation" : "option"}
253
+ aria-selected={item.kind === "heading" ? undefined : selected}
254
+ aria-disabled={item.kind === "heading" ? undefined : disabled || undefined}
255
+ tabIndex={item.kind === "heading" ? undefined : index === tabStopIndex ? 0 : -1}
253
256
  onKeyDown={(event: React.KeyboardEvent<HTMLElement>) => {
254
257
  if (disabled) return;
255
258
  if (event.key === " " || (event.key === "Enter" && !checkboxRows)) {
@@ -267,8 +270,8 @@ export function WebListView({
267
270
  while (items[nextIndex]?.disabled) nextIndex += direction;
268
271
  if (!items[nextIndex]) return;
269
272
  onSelect?.(nextIndex);
270
- const rows = event.currentTarget.parentElement?.querySelectorAll<HTMLElement>('[role="option"]');
271
- rows?.[nextIndex]?.focus();
273
+ const row = event.currentTarget.parentElement?.querySelector<HTMLElement>(`[data-gloom-list-index="${nextIndex}"]`);
274
+ row?.focus();
272
275
  }}
273
276
  style={listRowStyle(selected, disabled, colors, selection === "frame")}
274
277
  >
@@ -1,6 +1,7 @@
1
1
  /** @jsxImportSource react */
2
2
  import { useCallback, useContext, useEffect, useLayoutEffect, useRef, useState, type CSSProperties, type ReactNode } from "react";
3
3
  import type { HostQueryBarItem, HostQueryBarProps } from "../../../ui/host";
4
+ import { withChoiceGroupHeadings } from "../../../components/ui/choice-groups";
4
5
  import { WebPopover } from "./popover";
5
6
  import { WebMenu } from "./menu";
6
7
  import { useHorizontalOverflow } from "../host/overflow-fade";
@@ -75,15 +76,16 @@ function QueryMenu({ item, onClose }: { item: HostQueryBarItem; onClose: () => v
75
76
  <WebMenu
76
77
  label={item.label}
77
78
  selection={item.kind === "multi" ? "multi" : "single"}
78
- items={item.options.map((option) => ({
79
+ items={withChoiceGroupHeadings(item.options.map((option) => ({
79
80
  id: option.value,
80
81
  label: option.label,
82
+ group: option.group,
81
83
  description: option.description,
82
84
  disabled: option.disabled,
83
85
  selected: item.kind === "select" ? option.selected : undefined,
84
86
  checked: item.kind === "multi" ? option.selected : undefined,
85
87
  color: option.color,
86
- }))}
88
+ })))}
87
89
  onSelect={(value) => {
88
90
  item.onSelect(value);
89
91
  if (item.kind === "select") onClose();
@@ -5,6 +5,7 @@ import { WEB_CELL_HEIGHT } from "../../../theme/font-scale";
5
5
  import { Box } from "../../../ui";
6
6
  import { MenuPopover } from "../../../components/ui/menu";
7
7
  import type { SelectFieldHandle, SelectFieldProps } from "../../../components/ui/select-field";
8
+ import { withChoiceGroupHeadings } from "../../../components/ui/choice-groups";
8
9
  import { WebIcon } from "./icons";
9
10
  import { isInsideDialogSurface } from "../host/focus-scope";
10
11
 
@@ -136,13 +137,14 @@ export function WebSelectField({
136
137
  minWidth={typeof resolvedWidth === "number" ? Math.max(160, resolvedWidth) : 170}
137
138
  items={[
138
139
  ...(showUnset ? [{ id: UNSET_VALUE, label: "Unset", selected: true, disabled: true }] : []),
139
- ...options.map((option) => ({
140
+ ...withChoiceGroupHeadings(options.map((option) => ({
140
141
  id: option.value,
141
142
  label: option.label,
143
+ group: option.group,
142
144
  description: option.description,
143
145
  disabled: option.disabled,
144
146
  selected: option.value === value,
145
- })),
147
+ }))),
146
148
  ]}
147
149
  onSelect={(id) => {
148
150
  if (id !== UNSET_VALUE && id !== value) onChange(id);
@@ -168,6 +168,27 @@ const ChartVectors = memo(function ChartVectors({ vectors }: { vectors: readonly
168
168
  />
169
169
  ))
170
170
  : [])}
171
+ {vectors.map((shape) => shape.label && shape.points[0]
172
+ ? (
173
+ <div
174
+ key={`${shape.id}:label`}
175
+ style={{
176
+ position: "absolute",
177
+ left: `${shape.points[0].x * 100}%`,
178
+ top: `${shape.points[0].y * 100}%`,
179
+ transform: "translate(2px, -100%)",
180
+ color: shape.color,
181
+ fontSize: "var(--gloom-type-caption)",
182
+ lineHeight: 1.2,
183
+ whiteSpace: "nowrap",
184
+ pointerEvents: "none",
185
+ zIndex: 10,
186
+ }}
187
+ >
188
+ {shape.label}
189
+ </div>
190
+ )
191
+ : null)}
171
192
  </>
172
193
  );
173
194
  });
@@ -3,7 +3,7 @@ import { access, lstat, readFile, readlink, rename, rm, symlink } from "fs/promi
3
3
  import { basename, dirname, isAbsolute, join, relative, resolve } from "path";
4
4
  import { HOMEBREW_PREFIXES, macCommandFolders } from "../../../../updater/command-names";
5
5
  import { logFailure } from "../../../../utils/log-failure";
6
- import { DESKTOP_APP_IDENTIFIER, DESKTOP_APP_NAME, LEGACY_DESKTOP_APP_NAME } from "../../shared/app-name";
6
+ import { DESKTOP_APP_NAME, isDesktopAppIdentifier, LEGACY_DESKTOP_APP_NAME } from "../../shared/app-name";
7
7
 
8
8
  /**
9
9
  * A Mac install from before the rename is `Gloomberb.app`, and its updater
@@ -171,7 +171,7 @@ export async function renameLegacyMacApp(options: MacAppNameOptions): Promise<Ma
171
171
 
172
172
  const renamed = join(dirname(bundle), APP_BUNDLE);
173
173
  const occupied = await exists(renamed);
174
- if (occupied && await bundleIdentifier(renamed) !== DESKTOP_APP_IDENTIFIER) return { kind: "skipped", reason: "name-taken" };
174
+ if (occupied && !isDesktopAppIdentifier(await bundleIdentifier(renamed))) return { kind: "skipped", reason: "name-taken" };
175
175
  const links = await movableLinks(bundle, options);
176
176
  if (!links) return { kind: "skipped", reason: "command-folder-not-writable" };
177
177
 
@@ -209,7 +209,7 @@ export async function removeLegacyMacApp(options: MacAppNameOptions): Promise<st
209
209
  const bundle = runningBundle(options.execPath);
210
210
  if (!bundle || basename(bundle) !== APP_BUNDLE) return null;
211
211
  const legacy = join(dirname(bundle), LEGACY_APP_BUNDLE);
212
- if (!(await exists(legacy)) || await bundleIdentifier(legacy) !== DESKTOP_APP_IDENTIFIER) return null;
212
+ if (!(await exists(legacy)) || !isDesktopAppIdentifier(await bundleIdentifier(legacy))) return null;
213
213
  if (await managedByHomebrew(options.homebrewPrefixes ?? HOMEBREW_PREFIXES)) return null;
214
214
  const links = await movableLinks(legacy, options);
215
215
  if (!links) return null;
@@ -16,11 +16,14 @@ import { startRemoteControlServer, type RemoteControlServer } from "../../../../
16
16
  import type { RemoteControlRequest, RemoteControlResponse } from "../../../../remote/types";
17
17
  import { installCrashReporter } from "../../../../telemetry/crash-reports";
18
18
  import { createNodeCrashReporterHost } from "../../../../telemetry/crash-reports-node";
19
+ import { installStallReporter, parseStallEvent, recordStall } from "../../../../telemetry/stall-reports";
20
+ import { createNodeStallReporterHost } from "../../../../telemetry/stall-reports-node";
19
21
  import { installUpdateFailureReporter, reviewLastUpdateAttempt } from "../../../../telemetry/update-failures";
20
22
  import { createNodeUpdateFailureHost } from "../../../../telemetry/update-failures-node";
21
23
  import type { AppConfig } from "../../../../types/config";
22
24
  import { linkDesktopCommands } from "../../../../updater/command-names";
23
25
  import { debugLog } from "../../../../utils/debug-log";
26
+ import { setStallSink, startMainThreadStallMonitor } from "../../../../utils/main-thread-stall";
24
27
  import type { DesktopSharedStateSnapshot } from "../../../../types/desktop-window";
25
28
  import type {
26
29
  ContextMenuSelectMessage,
@@ -156,6 +159,10 @@ export class DesktopBackend {
156
159
  }));
157
160
  reviewLastUpdateAttempt();
158
161
  void removeUpdateAsides();
162
+ // Desktop has no Debug Log: freezes of this process and of its windows go to the stall log in the data folder.
163
+ installStallReporter(createNodeStallReporterHost({ getDataDir: () => this.config?.dataDir ?? null }));
164
+ setStallSink((event) => recordStall("app", event));
165
+ startMainThreadStallMonitor();
159
166
  }
160
167
  // The native menu shows the same accelerators the keys use, so a rebind
161
168
  // rebuilds it.
@@ -259,6 +266,10 @@ export class DesktopBackend {
259
266
  "host.restart": (message) => {
260
267
  this.restart(message);
261
268
  },
269
+ "runtime.stall": (message) => {
270
+ const event = parseStallEvent(message);
271
+ if (event) recordStall("window", event);
272
+ },
262
273
  },
263
274
  },
264
275
  });
@@ -341,16 +352,14 @@ export class DesktopBackend {
341
352
  execPath: process.execPath,
342
353
  argv: process.argv,
343
354
  });
344
- try {
345
- scheduleDesktopRelaunch();
346
- } catch (error) {
347
- this.restartInProgress = false;
348
- console.error("[desktop-recovery] failed to schedule restart", summarizeError(error));
349
- throw error;
350
- }
351
- this.detachedWindows.closeAll();
352
- this.teardownServices();
353
- Utils.quit();
355
+ scheduleDesktopRelaunch().then(
356
+ // As a quit does: an app whose windows are gone ends at once on Windows.
357
+ () => this.quit(),
358
+ (error: unknown) => {
359
+ this.restartInProgress = false;
360
+ console.error("[desktop-recovery] failed to schedule restart", summarizeError(error));
361
+ },
362
+ );
354
363
  }
355
364
 
356
365
  private syncConfigAccessors(): void {
@@ -555,6 +564,7 @@ export class DesktopBackend {
555
564
  case "host.exit":
556
565
  case "host.windowControl":
557
566
  case "host.windowFullscreen":
567
+ case "host.startWindowDrag":
558
568
  case "host.openExternal":
559
569
  case "host.copyText":
560
570
  case "host.focusWindow":
@@ -564,6 +574,7 @@ export class DesktopBackend {
564
574
  case "host.notify":
565
575
  case "host.showContextMenu":
566
576
  case "host.saveBootFrame":
577
+ case "host.saveViewIds":
567
578
  case "host.setAppBadge":
568
579
  return handleDesktopHostRequest(this, rpc, request);
569
580
  case "update.check":
@@ -10,9 +10,11 @@ import { safeExternalUrl } from "../../../../utils/external-url";
10
10
  import { getContextMenuRequestId, normalizeContextMenuItems } from "../context-menu/normalize";
11
11
  import { MAIN_WINDOW_RPC_KEY } from "../window/focus";
12
12
  import { applyDesktopWindowControl } from "../window/controls";
13
+ import { startSystemWindowMove } from "../window/windows-native";
13
14
  import { saveTextFileToDownloads } from "../../../../utils/save-text-file";
14
15
  import { setAppBadge } from "./app-badge";
15
16
  import { desktopBootFramePath, saveDesktopBootFrame } from "../window/boot-frame";
17
+ import { saveDesktopViewIds } from "./view-ids";
16
18
  import type { DesktopBackend, DesktopRpc } from "./backend";
17
19
 
18
20
  function normalizeText(value: unknown): string | undefined {
@@ -110,6 +112,13 @@ export async function handleDesktopHostRequest(
110
112
  }
111
113
  case "host.windowFullscreen":
112
114
  return isWindowFullscreen(backend, backend.rpcs.getRpcWindowKey(rpc));
115
+ case "host.startWindowDrag": {
116
+ const targetWindow = windowForRpcKey(backend, backend.rpcs.getRpcWindowKey(rpc));
117
+ if (!targetWindow?.ptr || !startSystemWindowMove(targetWindow.ptr)) {
118
+ throw new Error("This window cannot be moved by the system.");
119
+ }
120
+ return null;
121
+ }
113
122
  case "host.openExternal": {
114
123
  if (typeof request.payload.url !== "string") {
115
124
  throw new Error("host.openExternal requires a URL.");
@@ -162,6 +171,12 @@ export async function handleDesktopHostRequest(
162
171
  session: backend.config !== null,
163
172
  });
164
173
  return null;
174
+ case "host.saveViewIds":
175
+ // The main window's view keeps them; its popped-out panes share its storage.
176
+ if (backend.rpcs.getRpcWindowKey(rpc) === MAIN_WINDOW_RPC_KEY && backend.config) {
177
+ saveDesktopViewIds(backend.config.dataDir, request.payload.ids);
178
+ }
179
+ return null;
165
180
  case "host.setAppBadge":
166
181
  // One badge for the app, from the main window; a popped-out pane's view
167
182
  // has its own chat state and must not overwrite it.
@@ -24,6 +24,7 @@ import type { CapabilityRegistry } from "../../../../capabilities";
24
24
  import { telemetryOptedOut } from "../../../../telemetry/crash-reports";
25
25
  import { describeNodeOs, readOrCreateInstallId } from "../../../../telemetry/crash-reports-node";
26
26
  import type { DesktopBackend, DesktopRpc } from "./backend";
27
+ import { readDesktopViewIds } from "./view-ids";
27
28
 
28
29
  interface DesktopWindowTarget {
29
30
  kind: "main" | "detached";
@@ -94,6 +95,7 @@ function buildInitializationPayload(
94
95
  homeDir: homedir(),
95
96
  optedOut: telemetryOptedOut(process.env),
96
97
  },
98
+ viewIds: readDesktopViewIds(config.dataDir),
97
99
  };
98
100
  }
99
101