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
@@ -0,0 +1,222 @@
1
+ import { constants } from "fs";
2
+ import { access, lstat, readFile, readlink, rename, rm, symlink } from "fs/promises";
3
+ import { basename, dirname, isAbsolute, join, relative, resolve } from "path";
4
+ import { HOMEBREW_PREFIXES, macCommandFolders } from "../../../../updater/command-names";
5
+ import { logFailure } from "../../../../utils/log-failure";
6
+ import { DESKTOP_APP_NAME, isDesktopAppIdentifier, LEGACY_DESKTOP_APP_NAME } from "../../shared/app-name";
7
+
8
+ /**
9
+ * A Mac install from before the rename is `Gloomberb.app`, and its updater
10
+ * puts each new build in that same bundle. So the new build, when it starts
11
+ * from `Gloomberb.app`, renames its bundle to `Gloom.app` and opens again from
12
+ * there, and the `gloom` and `gloomberb` links the install script made into
13
+ * the old bundle follow it. Run from `Gloom.app`, it removes a
14
+ * `Gloomberb.app` left beside it.
15
+ *
16
+ * Homebrew installs are left to Homebrew: its record names the bundle it
17
+ * installed, and a bundle renamed under it makes `brew upgrade` fail. The cask
18
+ * moves it to `Gloom.app` at the next `brew upgrade --cask gloomberb`.
19
+ *
20
+ * Nothing moves when a link into the old bundle sits in a folder this user
21
+ * cannot write, since that command would stop working; the app runs under the
22
+ * old name and tries again at the next start.
23
+ */
24
+ const APP_BUNDLE = `${DESKTOP_APP_NAME}.app`;
25
+ const LEGACY_APP_BUNDLE = `${LEGACY_DESKTOP_APP_NAME}.app`;
26
+ /** The terminal commands an installer links into the bundle's Resources. */
27
+ const COMMAND_NAMES = ["gloom", "gloomberb"];
28
+
29
+ export interface MacAppNameOptions {
30
+ /** The running app's executable, inside `<bundle>/Contents/MacOS`. */
31
+ execPath: string;
32
+ platform: string;
33
+ homeDir: string;
34
+ /** PATH as the app sees it. */
35
+ pathEnv: string;
36
+ /** Where Homebrew may keep its Caskroom; tests pass their own. */
37
+ homebrewPrefixes?: readonly string[];
38
+ /** Homebrew's command folders; tests pass their own. */
39
+ homebrewBins?: readonly string[];
40
+ }
41
+
42
+ export type MacAppRename =
43
+ /** Not a Mac bundle under the old name. */
44
+ | { kind: "none" }
45
+ | { kind: "skipped"; reason: "homebrew" | "read-only-location" | "name-taken" | "command-folder-not-writable" }
46
+ | { kind: "failed" }
47
+ /** Renamed: the app opens again from `bundle`. */
48
+ | { kind: "renamed"; bundle: string; relinked: string[] };
49
+
50
+ interface BundleLink {
51
+ /** The link, in a command folder. */
52
+ path: string;
53
+ /** What it points at, as written. */
54
+ target: string;
55
+ /** Where in the bundle it points, from the bundle's folder down. */
56
+ inside: string;
57
+ }
58
+
59
+ function runningBundle(execPath: string): string | null {
60
+ return /^(.*?\.app)\/Contents\/MacOS\/[^/]+$/.exec(execPath)?.[1] ?? null;
61
+ }
62
+
63
+ async function exists(path: string): Promise<boolean> {
64
+ try {
65
+ await lstat(path);
66
+ return true;
67
+ } catch {
68
+ // Intentional ignore: a missing path, or one this user cannot see; either way there is nothing to move there.
69
+ return false;
70
+ }
71
+ }
72
+
73
+ /** The bundle identifier a build of this app writes in its version.json, or null for anything else. */
74
+ async function bundleIdentifier(bundle: string): Promise<string | null> {
75
+ try {
76
+ const info = JSON.parse(await readFile(join(bundle, "Contents", "Resources", "version.json"), "utf8")) as { identifier?: unknown };
77
+ return typeof info.identifier === "string" ? info.identifier : null;
78
+ } catch {
79
+ // Intentional ignore: no readable version.json means the bundle is not one of ours.
80
+ return null;
81
+ }
82
+ }
83
+
84
+ async function managedByHomebrew(prefixes: readonly string[]): Promise<boolean> {
85
+ const found = await Promise.all(prefixes.map((prefix) => exists(join(prefix, "Caskroom", "gloomberb"))));
86
+ return found.includes(true);
87
+ }
88
+
89
+ /** The `gloom` and `gloomberb` links in the command folders that point into `bundle`. */
90
+ async function linksInto(bundle: string, folders: readonly string[]): Promise<BundleLink[]> {
91
+ const found = await Promise.all(folders.flatMap((folder) => COMMAND_NAMES.map(async (name): Promise<BundleLink | null> => {
92
+ const path = join(folder, name);
93
+ let target: string;
94
+ try {
95
+ target = await readlink(path);
96
+ } catch {
97
+ // Intentional ignore: not there, or not a link; either way it does not lead into the bundle.
98
+ return null;
99
+ }
100
+ const absolute = resolve(folder, target);
101
+ if (absolute !== bundle && !absolute.startsWith(`${bundle}/`)) return null;
102
+ return { path, target, inside: absolute.slice(bundle.length) };
103
+ })));
104
+ return found.filter((link): link is BundleLink => link !== null);
105
+ }
106
+
107
+ async function writable(folder: string): Promise<boolean> {
108
+ try {
109
+ await access(folder, constants.W_OK);
110
+ return true;
111
+ } catch {
112
+ // Intentional ignore: a folder this user cannot write keeps its link, so nothing is renamed.
113
+ return false;
114
+ }
115
+ }
116
+
117
+ /** Points `link` at the same file inside `bundle`, written the same way (absolute or relative). Resolves to whether it did. */
118
+ async function relink(link: BundleLink, bundle: string): Promise<boolean> {
119
+ const folder = dirname(link.path);
120
+ const absolute = `${bundle}${link.inside}`;
121
+ const target = isAbsolute(link.target) ? absolute : relative(folder, absolute);
122
+ // Made beside it and moved over it, so the command is never missing.
123
+ const temporary = `${link.path}.${process.pid}-relink`;
124
+ try {
125
+ await rm(temporary, { force: true });
126
+ await symlink(target, temporary);
127
+ await rename(temporary, link.path);
128
+ return true;
129
+ } catch (error) {
130
+ await rm(temporary, { force: true }).catch(logFailure("desktop-app-name", "Could not remove a half-made command link"));
131
+ logFailure("desktop-app-name", "Could not point a command at the renamed app")(error);
132
+ return false;
133
+ }
134
+ }
135
+
136
+ /**
137
+ * The name the copy moved out of the way takes: `Gloom.app.previous`, the
138
+ * name the updater's own copies take, so one that cannot be removed now goes
139
+ * with theirs at the next start (update.ts, `removeUpdateAsides`).
140
+ */
141
+ async function asidePath(bundle: string): Promise<string> {
142
+ const previous = `${bundle}.previous`;
143
+ if (!(await exists(previous))) return previous;
144
+ for (let attempt = 0; ; attempt += 1) {
145
+ const unique = `${previous}-${Date.now().toString(36)}${attempt ? `-${attempt}` : ""}`;
146
+ if (!(await exists(unique))) return unique;
147
+ }
148
+ }
149
+
150
+ /** The links into `bundle`, unless one of them sits in a folder this user cannot write. */
151
+ async function movableLinks(bundle: string, options: MacAppNameOptions): Promise<BundleLink[] | null> {
152
+ const links = await linksInto(bundle, macCommandFolders(options.homeDir, options.pathEnv, options.homebrewBins));
153
+ const folders = [...new Set(links.map((link) => dirname(link.path)))];
154
+ const allWritable = await Promise.all(folders.map(writable));
155
+ return allWritable.every(Boolean) ? links : null;
156
+ }
157
+
158
+ /**
159
+ * Renames the running app from `Gloomberb.app` to `Gloom.app` and points the
160
+ * command links that led into it at the new bundle. The caller relaunches from
161
+ * `bundle` when it says `renamed`. A `Gloom.app` of this app already there
162
+ * gives way to the running one, which is the build its updater just installed.
163
+ */
164
+ export async function renameLegacyMacApp(options: MacAppNameOptions): Promise<MacAppRename> {
165
+ if (options.platform !== "darwin") return { kind: "none" };
166
+ const bundle = runningBundle(options.execPath);
167
+ if (!bundle || basename(bundle) !== LEGACY_APP_BUNDLE) return { kind: "none" };
168
+ // A disk image, or the read-only copy App Translocation runs.
169
+ if (bundle.startsWith("/Volumes/") || bundle.includes("/AppTranslocation/")) return { kind: "skipped", reason: "read-only-location" };
170
+ if (await managedByHomebrew(options.homebrewPrefixes ?? HOMEBREW_PREFIXES)) return { kind: "skipped", reason: "homebrew" };
171
+
172
+ const renamed = join(dirname(bundle), APP_BUNDLE);
173
+ const occupied = await exists(renamed);
174
+ if (occupied && !isDesktopAppIdentifier(await bundleIdentifier(renamed))) return { kind: "skipped", reason: "name-taken" };
175
+ const links = await movableLinks(bundle, options);
176
+ if (!links) return { kind: "skipped", reason: "command-folder-not-writable" };
177
+
178
+ const aside = occupied ? await asidePath(renamed) : null;
179
+ try {
180
+ if (aside) await rename(renamed, aside);
181
+ try {
182
+ await rename(bundle, renamed);
183
+ } catch (error) {
184
+ if (aside) await rename(aside, renamed);
185
+ throw error;
186
+ }
187
+ } catch (error) {
188
+ logFailure("desktop-app-name", "Could not rename the app to its new name")(error);
189
+ return { kind: "failed" };
190
+ }
191
+ if (aside) await rm(aside, { recursive: true, force: true }).catch(logFailure("desktop-app-name", "Could not remove the copy of the app the rename replaced"));
192
+
193
+ const relinked: string[] = [];
194
+ for (const link of links) {
195
+ if (await relink(link, renamed)) relinked.push(link.path);
196
+ }
197
+ return { kind: "renamed", bundle: renamed, relinked };
198
+ }
199
+
200
+ /**
201
+ * Run from `Gloom.app`: removes a `Gloomberb.app` of this app beside it (an
202
+ * install from before the rename, next to one made from a new download) after
203
+ * pointing its command links at the running bundle. Left alone under
204
+ * Homebrew, or when a link into it cannot be moved. Resolves to the removed
205
+ * bundle, or null.
206
+ */
207
+ export async function removeLegacyMacApp(options: MacAppNameOptions): Promise<string | null> {
208
+ if (options.platform !== "darwin") return null;
209
+ const bundle = runningBundle(options.execPath);
210
+ if (!bundle || basename(bundle) !== APP_BUNDLE) return null;
211
+ const legacy = join(dirname(bundle), LEGACY_APP_BUNDLE);
212
+ if (!(await exists(legacy)) || !isDesktopAppIdentifier(await bundleIdentifier(legacy))) return null;
213
+ if (await managedByHomebrew(options.homebrewPrefixes ?? HOMEBREW_PREFIXES)) return null;
214
+ const links = await movableLinks(legacy, options);
215
+ if (!links) return null;
216
+ for (const link of links) {
217
+ // A command still leading into the old bundle keeps it: removing it would break that command.
218
+ if (!(await relink(link, bundle))) return null;
219
+ }
220
+ const removed = await rm(legacy, { recursive: true, force: true }).then(() => true, logFailure("desktop-app-name", "Could not remove the app's old copy", false));
221
+ return removed ? legacy : null;
222
+ }
@@ -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,
@@ -44,6 +47,7 @@ import {
44
47
  import { MAIN_WINDOW_RPC_KEY } from "../window/focus";
45
48
  import { handleDesktopBackendRequest } from "./backend-requests";
46
49
  import { detectDesktopInstallKind, removeUpdateAsides } from "./update";
50
+ import { removeLegacyMacApp } from "./app-name";
47
51
  import { DesktopCapabilityBridge } from "./capability-bridge";
48
52
  import { DesktopDetachedWindowManager } from "./detached-windows";
49
53
  import { handleDesktopHostRequest } from "./host-requests";
@@ -155,6 +159,10 @@ export class DesktopBackend {
155
159
  }));
156
160
  reviewLastUpdateAttempt();
157
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();
158
166
  }
159
167
  // The native menu shows the same accelerators the keys use, so a rebind
160
168
  // rebuilds it.
@@ -258,6 +266,10 @@ export class DesktopBackend {
258
266
  "host.restart": (message) => {
259
267
  this.restart(message);
260
268
  },
269
+ "runtime.stall": (message) => {
270
+ const event = parseStallEvent(message);
271
+ if (event) recordStall("window", event);
272
+ },
261
273
  },
262
274
  },
263
275
  });
@@ -412,20 +424,29 @@ export class DesktopBackend {
412
424
  /**
413
425
  * An install from before the rename updates its bundle in place and keeps
414
426
  * only the `gloomberb` command its installer linked, so the app adds `gloom`
415
- * beside it. That looks through PATH, which can hold a slow network folder,
416
- * so it runs a while after the main window is up and never in its way.
427
+ * beside it. First, a Mac `Gloomberb.app` left beside this `Gloom.app` goes,
428
+ * its links moved here. That looks through PATH, which can hold a slow
429
+ * network folder, so it runs a while after the main window is up and never
430
+ * in its way.
417
431
  */
418
432
  private scheduleCommandLinks(): void {
419
433
  if (this.commandLinksScheduled) return;
420
434
  this.commandLinksScheduled = true;
421
435
  const log = debugLog.createLogger("desktop-command");
436
+ const where = {
437
+ platform: process.platform,
438
+ homeDir: homedir(),
439
+ pathEnv: process.env.PATH ?? "",
440
+ };
422
441
  const timer = setTimeout(() => {
423
- void linkDesktopCommands({
424
- platform: process.platform,
425
- homeDir: homedir(),
426
- pathEnv: process.env.PATH ?? "",
442
+ void removeLegacyMacApp({ ...where, execPath: process.execPath }).then((removed) => {
443
+ if (removed) log.info("Removed the app's copy under its old name");
444
+ }, (error: unknown) => {
445
+ log.warn("Could not remove the app's copy under its old name", summarizeError(error));
446
+ }).then(() => linkDesktopCommands({
447
+ ...where,
427
448
  localAppData: process.env.LOCALAPPDATA,
428
- }).then((added) => {
449
+ })).then((added) => {
429
450
  if (added.length > 0) log.info(`Added the gloom command in ${added.length} folder(s)`);
430
451
  }, (error: unknown) => {
431
452
  log.warn("Could not add the gloom command", summarizeError(error));
@@ -554,6 +575,7 @@ export class DesktopBackend {
554
575
  case "host.notify":
555
576
  case "host.showContextMenu":
556
577
  case "host.saveBootFrame":
578
+ case "host.saveViewIds":
557
579
  case "host.setAppBadge":
558
580
  return handleDesktopHostRequest(this, rpc, request);
559
581
  case "update.check":
@@ -13,6 +13,7 @@ import { applyDesktopWindowControl } from "../window/controls";
13
13
  import { saveTextFileToDownloads } from "../../../../utils/save-text-file";
14
14
  import { setAppBadge } from "./app-badge";
15
15
  import { desktopBootFramePath, saveDesktopBootFrame } from "../window/boot-frame";
16
+ import { saveDesktopViewIds } from "./view-ids";
16
17
  import type { DesktopBackend, DesktopRpc } from "./backend";
17
18
 
18
19
  function normalizeText(value: unknown): string | undefined {
@@ -162,6 +163,12 @@ export async function handleDesktopHostRequest(
162
163
  session: backend.config !== null,
163
164
  });
164
165
  return null;
166
+ case "host.saveViewIds":
167
+ // The main window's view keeps them; its popped-out panes share its storage.
168
+ if (backend.rpcs.getRpcWindowKey(rpc) === MAIN_WINDOW_RPC_KEY && backend.config) {
169
+ saveDesktopViewIds(backend.config.dataDir, request.payload.ids);
170
+ }
171
+ return null;
165
172
  case "host.setAppBadge":
166
173
  // One badge for the app, from the main window; a popped-out pane's view
167
174
  // 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
 
@@ -1,5 +1,11 @@
1
1
  import { dirname } from "path";
2
2
 
3
+ /**
4
+ * The folders the relaunch script finds `sleep` in, after whatever PATH the
5
+ * app was started with: a terminal launch can hand it a PATH without them.
6
+ */
7
+ const SYSTEM_PATH = "/usr/bin:/bin:/usr/sbin:/sbin";
8
+
3
9
  function shellQuote(value: string): string {
4
10
  return `'${value.replaceAll("'", "'\\''")}'`;
5
11
  }
@@ -13,36 +19,79 @@ function findMacAppBundle(execPath: string): string | null {
13
19
  return null;
14
20
  }
15
21
 
16
- function spawnDetached(command: string[]): void {
17
- const child = Bun.spawn(command, {
18
- detached: true,
19
- stdio: ["ignore", "ignore", "ignore"],
20
- } as any);
21
- child.unref();
22
+ /** The running process, as far as opening it again goes. */
23
+ export interface RelaunchContext {
24
+ platform: string;
25
+ pid: number;
26
+ execPath: string;
27
+ /** What the app was started with, after the runtime (`process.argv.slice(1)`). */
28
+ args: string[];
29
+ cwd: string;
30
+ /** PATH as the app sees it. */
31
+ pathEnv: string;
32
+ }
33
+
34
+ interface RelaunchCommand {
35
+ cmd: string[];
36
+ /** Where it starts; unset keeps this process's folder. */
37
+ cwd?: string;
38
+ /** PATH for it; unset keeps this process's. */
39
+ pathEnv?: string;
40
+ }
41
+
42
+ function currentProcess(): RelaunchContext {
43
+ return {
44
+ platform: process.platform,
45
+ pid: process.pid,
46
+ execPath: process.execPath,
47
+ args: process.argv.slice(1),
48
+ cwd: process.cwd(),
49
+ pathEnv: process.env.PATH ?? "",
50
+ };
22
51
  }
23
52
 
24
- export function scheduleDesktopRelaunch(): void {
25
- const pid = process.pid;
26
- const macAppBundle = process.platform === "darwin" ? findMacAppBundle(process.execPath) : null;
53
+ /**
54
+ * What opens the app again once `context.pid` has exited. The script runs in
55
+ * `/` with the shell and `open` named by their full paths: the launcher starts
56
+ * the app inside its bundle's `Contents/MacOS`, which a rename to the app's
57
+ * new name takes away, and a spawn into a folder that is gone fails as if the
58
+ * shell were missing (`ENOENT, posix_spawn 'sh'`).
59
+ */
60
+ export function desktopRelaunchCommand(context: RelaunchContext, bundle?: string): RelaunchCommand {
61
+ const pathEnv = context.pathEnv ? `${context.pathEnv}:${SYSTEM_PATH}` : SYSTEM_PATH;
62
+ const waitForExit = `while kill -0 ${context.pid} 2>/dev/null; do sleep 0.25; done`;
63
+ const macAppBundle = context.platform === "darwin" ? bundle ?? findMacAppBundle(context.execPath) : null;
27
64
 
28
65
  if (macAppBundle) {
29
- spawnDetached([
30
- "sh",
31
- "-c",
32
- `while kill -0 ${pid} 2>/dev/null; do sleep 0.25; done; sleep 0.5; open ${shellQuote(macAppBundle)}`,
33
- ]);
34
- return;
66
+ return {
67
+ cmd: ["/bin/sh", "-c", `${waitForExit}; sleep 0.5; /usr/bin/open ${shellQuote(macAppBundle)}`],
68
+ cwd: "/",
69
+ pathEnv,
70
+ };
35
71
  }
36
72
 
37
- if (process.platform === "win32") {
38
- spawnDetached([process.execPath, ...process.argv.slice(1)]);
39
- return;
40
- }
73
+ if (context.platform === "win32") return { cmd: [context.execPath, ...context.args] };
74
+
75
+ const args = context.args.map(shellQuote).join(" ");
76
+ return {
77
+ cmd: ["/bin/sh", "-c", `${waitForExit}; cd ${shellQuote(context.cwd)} 2>/dev/null; ${shellQuote(context.execPath)}${args ? ` ${args}` : ""}`],
78
+ cwd: "/",
79
+ pathEnv,
80
+ };
81
+ }
41
82
 
42
- const args = process.argv.slice(1).map(shellQuote).join(" ");
43
- spawnDetached([
44
- "sh",
45
- "-c",
46
- `while kill -0 ${pid} 2>/dev/null; do sleep 0.25; done; cd ${shellQuote(process.cwd())}; ${shellQuote(process.execPath)}${args ? ` ${args}` : ""}`,
47
- ]);
83
+ /**
84
+ * Opens the app again once this process has exited. On a Mac, `bundle` opens
85
+ * that bundle instead of the one this process runs from: the app's own, under
86
+ * the name it was just given.
87
+ */
88
+ export function scheduleDesktopRelaunch(bundle?: string, context: RelaunchContext = currentProcess()): void {
89
+ const { cmd, cwd, pathEnv } = desktopRelaunchCommand(context, bundle);
90
+ const child = Bun.spawn(cmd, {
91
+ ...(cwd ? { cwd } : {}),
92
+ ...(pathEnv ? { env: { ...process.env, PATH: pathEnv } } : {}),
93
+ detached: true,
94
+ stdio: ["ignore", "ignore", "ignore"],
95
+ });
96
+ child.unref();
48
97
  }
@@ -28,6 +28,7 @@ function desktopStateKey(snapshot: DesktopSharedStateSnapshot): string {
28
28
  paneState: snapshot.paneState,
29
29
  focusedPaneId: snapshot.focusedPaneId,
30
30
  statusBarVisible: snapshot.statusBarVisible,
31
+ brokerSyncErrors: snapshot.brokerSyncErrors ?? {},
31
32
  });
32
33
  }
33
34