gloomberb 0.18.2 → 0.18.4

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 (954) hide show
  1. package/README.md +8 -8
  2. package/README.zh-CN.md +11 -11
  3. package/bin/{gloomberb → gloom} +3 -1
  4. package/package.json +6 -2
  5. package/patches/electrobun@1.18.1.patch +106 -5
  6. package/src/account/checkout-handoff.tsx +225 -0
  7. package/src/account/device-signin-dialog.tsx +2 -2
  8. package/src/account/device-signin.ts +2 -2
  9. package/src/account/upgrade-dialog.tsx +1 -1
  10. package/src/api-client/askg.ts +2 -2
  11. package/src/api-client/auth.ts +2 -2
  12. package/src/api-client/central-bank-rates.ts +6 -0
  13. package/src/api-client/collections.ts +5 -1
  14. package/src/api-client/cot.ts +2 -0
  15. package/src/api-client/crypto-etf-flows.ts +37 -0
  16. package/src/api-client/crypto-markets.ts +60 -0
  17. package/src/api-client/data.ts +99 -5
  18. package/src/api-client/doe.ts +15 -0
  19. package/src/api-client/equity-screener.ts +28 -0
  20. package/src/api-client/exchange-announcements.ts +38 -0
  21. package/src/api-client/fund-facts.ts +39 -0
  22. package/src/api-client/futures-curve.ts +9 -1
  23. package/src/api-client/hiring.ts +301 -0
  24. package/src/api-client/index.ts +24 -5
  25. package/src/api-client/market-discovery.ts +14 -0
  26. package/src/api-client/members.ts +6 -0
  27. package/src/api-client/mna.ts +6 -0
  28. package/src/api-client/paths.ts +18 -1
  29. package/src/api-client/request.ts +26 -7
  30. package/src/api-client/short-side-publications.ts +37 -0
  31. package/src/api-client/socket.ts +64 -4
  32. package/src/api-client/swap-curve.ts +35 -0
  33. package/src/api-client/telemetry.ts +17 -0
  34. package/src/api-client/themes.ts +7 -1
  35. package/src/api-client/types.ts +90 -2
  36. package/src/app/global-shortcuts.ts +1 -16
  37. package/src/app/pane-runtime/plugin-bindings.ts +9 -2
  38. package/src/app/runtime/desktop-deeplink.ts +5 -5
  39. package/src/app/runtime/plugin-bindings.ts +2 -2
  40. package/src/app/runtime/startup.ts +13 -0
  41. package/src/app/runtime/update.ts +28 -8
  42. package/src/app/star-prompt/status-line.tsx +2 -2
  43. package/src/architecture/core-builtin-allowlist.json +5 -2
  44. package/src/architecture/pane-tabs-allowlist.json +65 -0
  45. package/src/architecture/ui-literals-allowlist.json +3 -3
  46. package/src/architecture/ui-tokens-allowlist.json +1 -1
  47. package/src/brokers/broker-portfolio-sync.ts +37 -0
  48. package/src/brokers/directory.ts +11 -0
  49. package/src/brokers/logos.ts +3 -1
  50. package/src/brokers/signed-in/adapter.ts +304 -26
  51. package/src/brokers/signed-in/client.ts +14 -2
  52. package/src/brokers/signed-in/connect.ts +10 -2
  53. package/src/brokers/sync-broker-instance.ts +9 -1
  54. package/src/capabilities/chart-series.ts +22 -6
  55. package/src/cli/bank-section.ts +1 -1
  56. package/src/cli/base-converter.ts +23 -14
  57. package/src/cli/central-bank-events.ts +1 -1
  58. package/src/cli/command-options.ts +59 -4
  59. package/src/cli/commands/api.ts +9 -6
  60. package/src/cli/commands/broker.ts +2 -2
  61. package/src/cli/commands/command-utils.ts +2 -2
  62. package/src/cli/commands/crypto-hints.ts +7 -20
  63. package/src/cli/commands/fred-series.ts +4 -2
  64. package/src/cli/commands/keybindings.ts +2 -2
  65. package/src/cli/commands/market.ts +1189 -296
  66. package/src/cli/commands/news-hints.ts +2 -2
  67. package/src/cli/commands/news-search.ts +59 -6
  68. package/src/cli/commands/options-leaps.ts +41 -26
  69. package/src/cli/commands/overview.ts +121 -48
  70. package/src/cli/commands/plugins.ts +9 -9
  71. package/src/cli/commands/remote.ts +13 -10
  72. package/src/cli/commands/search.ts +64 -44
  73. package/src/cli/commands/system.ts +27 -19
  74. package/src/cli/commands/themes.ts +1 -1
  75. package/src/cli/commands/ticker.ts +272 -70
  76. package/src/cli/context.ts +3 -2
  77. package/src/cli/desktop-pane-shot-view.ts +2 -2
  78. package/src/cli/desktop-pane-shot.ts +1 -1
  79. package/src/cli/earnings-calendar.ts +4 -4
  80. package/src/cli/entry.ts +18 -1
  81. package/src/cli/errors.ts +20 -2
  82. package/src/cli/exit-codes.ts +1 -1
  83. package/src/cli/export-source.ts +10 -4
  84. package/src/cli/freshness.ts +2 -8
  85. package/src/cli/fx-forward.ts +130 -0
  86. package/src/cli/fx-pair.ts +10 -9
  87. package/src/cli/glossary.ts +64 -20
  88. package/src/cli/help.ts +20 -14
  89. package/src/cli/history-export.ts +126 -0
  90. package/src/cli/history-rows.ts +196 -43
  91. package/src/cli/index-roots.ts +5 -45
  92. package/src/cli/index.ts +32 -18
  93. package/src/cli/issuer-membership.ts +103 -0
  94. package/src/cli/known-gaps.ts +118 -25
  95. package/src/cli/listing-arg.ts +315 -43
  96. package/src/cli/name-entries.ts +73 -22
  97. package/src/cli/native-smoke.ts +2 -0
  98. package/src/cli/not-a-ticker.ts +19 -9
  99. package/src/cli/opentui-libc.ts +5 -0
  100. package/src/cli/options.ts +12 -0
  101. package/src/cli/pane-functions/capabilities.ts +77 -20
  102. package/src/cli/pane-functions/catalog.ts +40 -23
  103. package/src/cli/pane-functions/discovery.ts +1 -1
  104. package/src/cli/pane-functions/dom.ts +12 -8
  105. package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
  106. package/src/cli/pane-functions/freshness.ts +174 -23
  107. package/src/cli/pane-functions/function-help.ts +66 -27
  108. package/src/cli/pane-functions/headless.ts +48 -16
  109. package/src/cli/pane-functions/index.ts +82 -21
  110. package/src/cli/pane-functions/options.ts +22 -2
  111. package/src/cli/pane-functions/report-notices.ts +12 -4
  112. package/src/cli/pane-functions/report.ts +5 -5
  113. package/src/cli/pane-functions/resolver.ts +65 -14
  114. package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
  115. package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
  116. package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
  117. package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
  118. package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
  119. package/src/cli/pane-functions/screenshot-payload.ts +453 -0
  120. package/src/cli/pane-functions/screenshot-render.ts +316 -0
  121. package/src/cli/pane-functions/screenshot-types.ts +162 -0
  122. package/src/cli/pane-functions/shot-options.ts +8 -3
  123. package/src/cli/peso-dollar-rates.ts +79 -0
  124. package/src/cli/quote-answer.ts +38 -3
  125. package/src/cli/report-tables.ts +190 -27
  126. package/src/cli/restore-plugins.ts +29 -14
  127. package/src/cli/result.ts +122 -25
  128. package/src/cli/series-search.ts +5 -5
  129. package/src/cli/statement-filings.ts +19 -0
  130. package/src/cli/suffixed-listing-rows.ts +49 -0
  131. package/src/cli/symbol-args.ts +50 -15
  132. package/src/cli/symbol-cells.ts +120 -0
  133. package/src/cli/symbol-list.ts +226 -60
  134. package/src/cli/symbol-rows.ts +131 -25
  135. package/src/cli/ticker-resolution.ts +108 -11
  136. package/src/cli/treasury-yields.ts +5 -5
  137. package/src/cli/types.ts +2 -0
  138. package/src/cli/uncovered-instrument.ts +3 -3
  139. package/src/cli/unknown-command.ts +6 -6
  140. package/src/components/chart/composite/chart-layout.ts +131 -0
  141. package/src/components/chart/composite/composite-chart.tsx +387 -21
  142. package/src/components/chart/composite/drawing-store.ts +26 -6
  143. package/src/components/chart/composite/interactions.ts +9 -3
  144. package/src/components/chart/composite/legend.tsx +75 -3
  145. package/src/components/chart/composite/levels.ts +5 -0
  146. package/src/components/chart/composite/panel-gestures.ts +41 -0
  147. package/src/components/chart/composite/panel-labels.ts +2 -1
  148. package/src/components/chart/composite/panel-surface.tsx +316 -11
  149. package/src/components/chart/composite/price-axis-labels.tsx +27 -3
  150. package/src/components/chart/composite/rasterizer.ts +44 -19
  151. package/src/components/chart/composite/scene.ts +16 -4
  152. package/src/components/chart/composite/text-renderer.ts +48 -21
  153. package/src/components/chart/composite/toolbar.tsx +52 -5
  154. package/src/components/chart/composite/types.ts +19 -0
  155. package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
  156. package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
  157. package/src/components/chart/composite/use-composite-viewport.ts +12 -3
  158. package/src/components/chart/composite/value-scale.ts +149 -0
  159. package/src/components/chart/composite/volume-profile-paint.ts +6 -3
  160. package/src/components/chart/core/pointer.ts +2 -0
  161. package/src/components/chart-table/index.ts +2 -0
  162. package/src/components/chart-table/read.tsx +74 -0
  163. package/src/components/command-bar/commands/collection-list.ts +41 -19
  164. package/src/components/command-bar/commands/collection.ts +9 -3
  165. package/src/components/command-bar/commands/direct/index.ts +1 -1
  166. package/src/components/command-bar/commands/direct/runtime.ts +3 -2
  167. package/src/components/command-bar/pane-templates/items.ts +59 -6
  168. package/src/components/command-bar/pane-templates/workflow.ts +10 -1
  169. package/src/components/command-bar/routes/root/command-items.ts +32 -6
  170. package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
  171. package/src/components/command-bar/routes/root/provider-search.ts +42 -11
  172. package/src/components/command-bar/routes/root/results.ts +18 -4
  173. package/src/components/command-bar/routes/root/runtime.ts +15 -3
  174. package/src/components/command-bar/routes/root/search-providers.ts +25 -2
  175. package/src/components/command-bar/routes/root/selection.ts +6 -1
  176. package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
  177. package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
  178. package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
  179. package/src/components/command-bar/selection-runtime.ts +50 -10
  180. package/src/components/command-bar/surface/index.tsx +24 -2
  181. package/src/components/command-bar/view-model.ts +7 -0
  182. package/src/components/command-bar/workflow/broker.ts +2 -2
  183. package/src/components/command-bar/workflow/collection-actions.ts +46 -7
  184. package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
  185. package/src/components/command-bar/workflow/fields.ts +8 -2
  186. package/src/components/command-bar/workflow/ops.ts +18 -4
  187. package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
  188. package/src/components/command-bar/workflow/submit.ts +3 -2
  189. package/src/components/command-bar/workflow/tickers.ts +5 -1
  190. package/src/components/company-logo.tsx +39 -0
  191. package/src/components/data-table/sections.ts +4 -2
  192. package/src/components/data-table/view.tsx +23 -3
  193. package/src/components/form-modal/confirm.tsx +2 -1
  194. package/src/components/form-modal/request.ts +5 -0
  195. package/src/components/form-modal/routes.ts +4 -1
  196. package/src/components/index.ts +13 -6
  197. package/src/components/layout/detached-pane-shell.tsx +1 -0
  198. package/src/components/layout/floating-pane.tsx +1 -0
  199. package/src/components/layout/header.tsx +234 -60
  200. package/src/components/layout/market-summary.ts +9 -6
  201. package/src/components/layout/pane/capture-status.ts +1 -1
  202. package/src/components/layout/pane/footer/model.ts +11 -5
  203. package/src/components/layout/pane/header.tsx +10 -3
  204. package/src/components/layout/pane/index.tsx +1 -0
  205. package/src/components/layout/pane/pane-tabs.tsx +9 -1
  206. package/src/components/layout/shell/chrome.ts +19 -6
  207. package/src/components/layout/shell/index.tsx +2 -1
  208. package/src/components/layout/shell/pane/layers.tsx +19 -1
  209. package/src/components/layout/status-bar.tsx +2 -2
  210. package/src/components/market-board/index.tsx +11 -3
  211. package/src/components/onboarding/onboarding-wizard.tsx +1 -0
  212. package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
  213. package/src/components/onboarding/wizard-broker-sync.ts +4 -1
  214. package/src/components/pane-settings-dialog/desktop.tsx +20 -7
  215. package/src/components/pane-settings-dialog/tui.tsx +17 -9
  216. package/src/components/pane-settings-dialog/value.ts +8 -1
  217. package/src/components/pane-settings-dialog.tsx +44 -13
  218. package/src/components/sign-in-code-panel.tsx +27 -19
  219. package/src/components/ui/column-grid.tsx +48 -4
  220. package/src/components/ui/country-flag-art.tsx +180 -0
  221. package/src/components/ui/country-flag.tsx +118 -12
  222. package/src/components/ui/data-table/opentui/index.tsx +61 -2
  223. package/src/components/ui/data-table/opentui/model.ts +109 -2
  224. package/src/components/ui/data-table/types.ts +1 -1
  225. package/src/components/ui/display.tsx +5 -1
  226. package/src/components/ui/index.ts +3 -1
  227. package/src/components/ui/logo-mark.tsx +11 -2
  228. package/src/components/ui/query-bar.tsx +1 -1
  229. package/src/components/ui/row-notes.ts +79 -0
  230. package/src/components/ui/stat-grid.tsx +28 -3
  231. package/src/components/ui/status.tsx +3 -1
  232. package/src/core/app-services.ts +4 -0
  233. package/src/core/state/app/layout.ts +4 -4
  234. package/src/data/cached-query.ts +8 -1
  235. package/src/data/config/chart-settings.ts +3 -3
  236. package/src/data/config/home.ts +10 -2
  237. package/src/data/config/layout.ts +4 -1
  238. package/src/data/config/store/node.ts +4 -0
  239. package/src/data/config/store/normalize.ts +13 -3
  240. package/src/data/config/store/portfolio-as-of-column.ts +2 -2
  241. package/src/data/json-storage.ts +2 -0
  242. package/src/data/saved-copies.ts +84 -0
  243. package/src/docs/snapshot.json +65 -32
  244. package/src/i18n/es.ts +51 -12
  245. package/src/i18n/ja.ts +51 -12
  246. package/src/i18n/ko.ts +51 -12
  247. package/src/i18n/zh-cn.ts +51 -12
  248. package/src/i18n/zh-tw.ts +51 -12
  249. package/src/layout/desks.ts +1 -1
  250. package/src/layout/launch-layout.ts +1 -1
  251. package/src/layout/pane-manager/floating-actions.ts +5 -3
  252. package/src/layout/pane-manager/floating.ts +43 -1
  253. package/src/layout/pane-manager/index.ts +2 -0
  254. package/src/layout/selected-ticker.ts +74 -0
  255. package/src/market-data/depositary-pair.ts +251 -0
  256. package/src/market-data/futures-board.ts +1 -1
  257. package/src/market-data/futures-contract.ts +124 -40
  258. package/src/market-data/fx-closes.ts +17 -2
  259. package/src/market-data/hooks.tsx +19 -11
  260. package/src/market-data/market/change-basis.ts +49 -7
  261. package/src/market-data/market/freshness.ts +34 -5
  262. package/src/market-data/market/period-return.ts +163 -0
  263. package/src/market-data/market/trading-sessions.ts +13 -0
  264. package/src/market-data/market/year-to-date.ts +8 -13
  265. package/src/market-data/performance.ts +20 -14
  266. package/src/market-data/perpetual-premium.ts +32 -0
  267. package/src/market-data/published-apac-sessions.ts +2 -1
  268. package/src/market-data/published-futures-sessions.ts +69 -0
  269. package/src/market-data/quotes/contributions.ts +5 -1
  270. package/src/market-data/quotes/freshness.ts +42 -0
  271. package/src/market-data/quotes/intraday-bar.ts +37 -0
  272. package/src/market-data/quotes/regular-session-valuation.ts +13 -8
  273. package/src/market-data/quotes/resolution.ts +4 -2
  274. package/src/market-data/tax-equivalent.ts +1 -1
  275. package/src/market-data/ticker-price-returns.ts +3 -1
  276. package/src/news/aggregator.ts +5 -1
  277. package/src/news/news-model.ts +4 -0
  278. package/src/news/types.ts +11 -0
  279. package/src/notifications/app-notifier.ts +1 -1
  280. package/src/plugins/auto-update.ts +2 -2
  281. package/src/plugins/builtin/account-management/index.tsx +1 -0
  282. package/src/plugins/builtin/account-management/pane.tsx +9 -8
  283. package/src/plugins/builtin/alerts/alert-engine.ts +30 -18
  284. package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
  285. package/src/plugins/builtin/alerts/cli.ts +485 -76
  286. package/src/plugins/builtin/alerts/command.ts +5 -10
  287. package/src/plugins/builtin/alerts/event-rows.ts +9 -5
  288. package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
  289. package/src/plugins/builtin/alerts/events.ts +108 -5
  290. package/src/plugins/builtin/alerts/fired-log.ts +78 -0
  291. package/src/plugins/builtin/alerts/format.ts +2 -1
  292. package/src/plugins/builtin/alerts/headless.ts +100 -39
  293. package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
  294. package/src/plugins/builtin/alerts/history-rows.ts +89 -0
  295. package/src/plugins/builtin/alerts/index.tsx +45 -18
  296. package/src/plugins/builtin/alerts/iv-level.ts +365 -0
  297. package/src/plugins/builtin/alerts/levels.ts +3 -3
  298. package/src/plugins/builtin/alerts/pane.tsx +97 -29
  299. package/src/plugins/builtin/alerts/price.ts +35 -0
  300. package/src/plugins/builtin/alerts/quotes.ts +24 -0
  301. package/src/plugins/builtin/alerts/research-builder.ts +84 -11
  302. package/src/plugins/builtin/alerts/research-rules.ts +77 -3
  303. package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
  304. package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
  305. package/src/plugins/builtin/alerts/scheduled.ts +188 -29
  306. package/src/plugins/builtin/alerts/storage.ts +13 -10
  307. package/src/plugins/builtin/alerts/targets.ts +12 -3
  308. package/src/plugins/builtin/analytics/index.tsx +8 -2
  309. package/src/plugins/builtin/analytics/metrics.ts +1 -1
  310. package/src/plugins/builtin/analytics/risk-book.ts +215 -0
  311. package/src/plugins/builtin/analytics/risk-client.ts +13 -6
  312. package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
  313. package/src/plugins/builtin/analytics/risk-math.ts +6 -3
  314. package/src/plugins/builtin/analytics/risk-model.ts +297 -104
  315. package/src/plugins/builtin/analytics/risk-options.ts +17 -2
  316. package/src/plugins/builtin/analytics/risk-pane.tsx +107 -43
  317. package/src/plugins/builtin/attention/pane.tsx +22 -16
  318. package/src/plugins/builtin/awards/headless.ts +7 -3
  319. package/src/plugins/builtin/awards/model.ts +18 -0
  320. package/src/plugins/builtin/awards/pane.tsx +12 -9
  321. package/src/plugins/builtin/backtest/export.ts +1 -1
  322. package/src/plugins/builtin/backtest/headless.ts +3 -3
  323. package/src/plugins/builtin/backtest/rules.ts +41 -5
  324. package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
  325. package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
  326. package/src/plugins/builtin/broker-manager/footer.ts +27 -11
  327. package/src/plugins/builtin/broker-manager/index.tsx +21 -12
  328. package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
  329. package/src/plugins/builtin/broker-manager/model.ts +12 -2
  330. package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
  331. package/src/plugins/builtin/broker-manager/table.ts +28 -12
  332. package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
  333. package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
  334. package/src/plugins/builtin/broker-trading/controller.ts +45 -13
  335. package/src/plugins/builtin/broker-trading/dock.tsx +24 -4
  336. package/src/plugins/builtin/broker-trading/headless.ts +2 -1
  337. package/src/plugins/builtin/broker-trading/index.tsx +7 -1
  338. package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
  339. package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
  340. package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
  341. package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
  342. package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
  343. package/src/plugins/builtin/broker-trading/pane.tsx +115 -26
  344. package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
  345. package/src/plugins/builtin/broker-trading/ticket.tsx +122 -36
  346. package/src/plugins/builtin/buildout/cells.tsx +4 -0
  347. package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
  348. package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
  349. package/src/plugins/builtin/buildout/pane/index.tsx +34 -18
  350. package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
  351. package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
  352. package/src/plugins/builtin/catalysts/client.ts +2 -2
  353. package/src/plugins/builtin/catalysts/detail.tsx +3 -2
  354. package/src/plugins/builtin/catalysts/index.tsx +1 -1
  355. package/src/plugins/builtin/catalysts/model.ts +49 -4
  356. package/src/plugins/builtin/catalysts/pane.tsx +9 -11
  357. package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
  358. package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
  359. package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
  360. package/src/plugins/builtin/changelog/index.tsx +1 -0
  361. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
  362. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
  363. package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
  364. package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
  365. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
  366. package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
  367. package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
  368. package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
  369. package/src/plugins/builtin/chart-composer/headless.ts +253 -35
  370. package/src/plugins/builtin/chart-composer/index.tsx +12 -2
  371. package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
  372. package/src/plugins/builtin/chart-composer/pane.tsx +128 -28
  373. package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
  374. package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
  375. package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
  376. package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
  377. package/src/plugins/builtin/chart-composer/settings.ts +31 -19
  378. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
  379. package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
  380. package/src/plugins/builtin/chat/attachments/model.ts +3 -1
  381. package/src/plugins/builtin/chat/content/index.tsx +1 -1
  382. package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
  383. package/src/plugins/builtin/chat/people.ts +1 -1
  384. package/src/plugins/builtin/clinical-trials/client.ts +5 -2
  385. package/src/plugins/builtin/clinical-trials/model.ts +13 -4
  386. package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
  387. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
  388. package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
  389. package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
  390. package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
  391. package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
  392. package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
  393. package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
  394. package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
  395. package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
  396. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  397. package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
  398. package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
  399. package/src/plugins/builtin/commodity-balances/pane.tsx +14 -8
  400. package/src/plugins/builtin/company-attention/app-rank.tsx +11 -10
  401. package/src/plugins/builtin/company-attention/building-model.ts +222 -0
  402. package/src/plugins/builtin/company-attention/building.tsx +172 -0
  403. package/src/plugins/builtin/company-attention/client.ts +117 -1
  404. package/src/plugins/builtin/company-attention/evidence.ts +16 -3
  405. package/src/plugins/builtin/company-attention/headless.ts +101 -5
  406. package/src/plugins/builtin/company-attention/index.tsx +6 -3
  407. package/src/plugins/builtin/company-attention/model.ts +33 -7
  408. package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
  409. package/src/plugins/builtin/company-attention/moves.tsx +159 -0
  410. package/src/plugins/builtin/company-attention/pane.tsx +89 -31
  411. package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
  412. package/src/plugins/builtin/company-attention/signals.tsx +160 -0
  413. package/src/plugins/builtin/company-kpis/headless.ts +3 -2
  414. package/src/plugins/builtin/company-kpis/model.ts +2 -2
  415. package/src/plugins/builtin/company-kpis/pane.tsx +5 -4
  416. package/src/plugins/builtin/composite-plugins.ts +2 -1
  417. package/src/plugins/builtin/congress-trades/headless.ts +1 -1
  418. package/src/plugins/builtin/connections/index.ts +1 -0
  419. package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
  420. package/src/plugins/builtin/correlation/headless.ts +7 -4
  421. package/src/plugins/builtin/correlation/relationship/model.ts +1 -0
  422. package/src/plugins/builtin/correlation/settings.ts +1 -0
  423. package/src/plugins/builtin/cot/headless.ts +28 -6
  424. package/src/plugins/builtin/cot/model.ts +12 -0
  425. package/src/plugins/builtin/cot/pane.tsx +7 -5
  426. package/src/plugins/builtin/cpi/headless.ts +5 -1
  427. package/src/plugins/builtin/cpi/pane.tsx +11 -9
  428. package/src/plugins/builtin/credit-boards/model.ts +2 -0
  429. package/src/plugins/builtin/credit-documents/headless.ts +1 -1
  430. package/src/plugins/builtin/credit-documents/pane.tsx +8 -7
  431. package/src/plugins/builtin/crypto-board/client.ts +86 -0
  432. package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
  433. package/src/plugins/builtin/crypto-board/defi.ts +239 -0
  434. package/src/plugins/builtin/crypto-board/headless.ts +117 -6
  435. package/src/plugins/builtin/crypto-board/index.tsx +8 -3
  436. package/src/plugins/builtin/crypto-board/model.ts +40 -8
  437. package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
  438. package/src/plugins/builtin/crypto-board/series.ts +19 -1
  439. package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
  440. package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
  441. package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
  442. package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
  443. package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
  444. package/src/plugins/builtin/debt-maturities/pane.tsx +4 -3
  445. package/src/plugins/builtin/debug/index.tsx +1 -0
  446. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  447. package/src/plugins/builtin/docs/index.tsx +1 -1
  448. package/src/plugins/builtin/docs/pane.tsx +2 -2
  449. package/src/plugins/builtin/docs/targets.ts +1 -1
  450. package/src/plugins/builtin/doe/client.ts +5 -1
  451. package/src/plugins/builtin/doe/headless.ts +12 -6
  452. package/src/plugins/builtin/doe/model.ts +43 -6
  453. package/src/plugins/builtin/doe/pane.tsx +19 -12
  454. package/src/plugins/builtin/earnings/board-model.ts +13 -6
  455. package/src/plugins/builtin/earnings/board-table.ts +4 -1
  456. package/src/plugins/builtin/earnings/board.tsx +253 -50
  457. package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
  458. package/src/plugins/builtin/earnings/calendar.tsx +338 -0
  459. package/src/plugins/builtin/earnings/client.ts +4 -3
  460. package/src/plugins/builtin/earnings/headless.ts +53 -15
  461. package/src/plugins/builtin/earnings/history-model.ts +53 -36
  462. package/src/plugins/builtin/earnings/index.tsx +15 -22
  463. package/src/plugins/builtin/earnings/model.ts +17 -12
  464. package/src/plugins/builtin/earnings/scope.ts +89 -0
  465. package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
  466. package/src/plugins/builtin/earnings-calls/data.ts +146 -2
  467. package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
  468. package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
  469. package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
  470. package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
  471. package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
  472. package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
  473. package/src/plugins/builtin/econ/calendar-model.ts +132 -20
  474. package/src/plugins/builtin/econ/detail-view.tsx +48 -10
  475. package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
  476. package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
  477. package/src/plugins/builtin/econ/index.tsx +112 -25
  478. package/src/plugins/builtin/econ/print-watch.ts +2 -1
  479. package/src/plugins/builtin/econ/types.ts +32 -1
  480. package/src/plugins/builtin/econ-statistics/client.ts +16 -3
  481. package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
  482. package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
  483. package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
  484. package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
  485. package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
  486. package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
  487. package/src/plugins/builtin/econ-statistics/view.ts +16 -1
  488. package/src/plugins/builtin/equity-screener/client.ts +21 -3
  489. package/src/plugins/builtin/equity-screener/headless.ts +77 -5
  490. package/src/plugins/builtin/equity-screener/live.ts +1 -1
  491. package/src/plugins/builtin/equity-screener/model.ts +34 -0
  492. package/src/plugins/builtin/equity-screener/pane.tsx +148 -106
  493. package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
  494. package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
  495. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
  496. package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
  497. package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
  498. package/src/plugins/builtin/exposure/headless.ts +51 -6
  499. package/src/plugins/builtin/exposure/index.tsx +28 -2
  500. package/src/plugins/builtin/exposure/model.ts +7 -0
  501. package/src/plugins/builtin/exposure/pane.tsx +16 -10
  502. package/src/plugins/builtin/fear-greed/index.tsx +1 -1
  503. package/src/plugins/builtin/filing-events/index.tsx +1 -1
  504. package/src/plugins/builtin/futures/model.ts +10 -9
  505. package/src/plugins/builtin/futures/returns.ts +8 -36
  506. package/src/plugins/builtin/futures/table.tsx +1 -1
  507. package/src/plugins/builtin/futures-curve/client.ts +40 -9
  508. package/src/plugins/builtin/futures-curve/headless.ts +39 -17
  509. package/src/plugins/builtin/futures-curve/model.ts +258 -69
  510. package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
  511. package/src/plugins/builtin/fx-matrix/client.ts +15 -8
  512. package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
  513. package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
  514. package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
  515. package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
  516. package/src/plugins/builtin/gpu/board.tsx +4 -1
  517. package/src/plugins/builtin/gpu/changes.tsx +10 -10
  518. package/src/plugins/builtin/gpu/equities.tsx +4 -1
  519. package/src/plugins/builtin/gpu/headless.ts +9 -4
  520. package/src/plugins/builtin/gpu/history.tsx +4 -2
  521. package/src/plugins/builtin/gpu/pane.tsx +5 -3
  522. package/src/plugins/builtin/help/index.tsx +13 -3
  523. package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
  524. package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
  525. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  526. package/src/plugins/builtin/holders/client.ts +15 -2
  527. package/src/plugins/builtin/holders/format.ts +28 -17
  528. package/src/plugins/builtin/holders/headless.ts +48 -8
  529. package/src/plugins/builtin/holders/index-holders.ts +264 -0
  530. package/src/plugins/builtin/holders/pane.tsx +79 -15
  531. package/src/plugins/builtin/holders/report-rows.ts +35 -7
  532. package/src/plugins/builtin/holders/table-model.ts +2 -1
  533. package/src/plugins/builtin/holders/thirteenf-match.ts +3 -1
  534. package/src/plugins/builtin/holders/treemap.tsx +2 -2
  535. package/src/plugins/builtin/insider/base-values.ts +11 -7
  536. package/src/plugins/builtin/insider/client.ts +3 -0
  537. package/src/plugins/builtin/insider/headless.ts +20 -7
  538. package/src/plugins/builtin/insider/index.tsx +17 -8
  539. package/src/plugins/builtin/insider/issuer.ts +34 -4
  540. package/src/plugins/builtin/insider/signals-client.ts +3 -3
  541. package/src/plugins/builtin/insider/signals.tsx +1 -1
  542. package/src/plugins/builtin/insider/table-model.ts +35 -13
  543. package/src/plugins/builtin/insider/table.tsx +5 -2
  544. package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
  545. package/src/plugins/builtin/iv-history/client.ts +20 -0
  546. package/src/plugins/builtin/iv-history/events.ts +145 -0
  547. package/src/plugins/builtin/iv-history/format.ts +3 -0
  548. package/src/plugins/builtin/iv-history/headless.ts +91 -7
  549. package/src/plugins/builtin/iv-history/index.tsx +1 -1
  550. package/src/plugins/builtin/iv-history/model.ts +13 -4
  551. package/src/plugins/builtin/iv-history/series.ts +3 -1
  552. package/src/plugins/builtin/jobs/lock-note.ts +1 -1
  553. package/src/plugins/builtin/jobs/model.ts +4 -15
  554. package/src/plugins/builtin/jobs/pane.tsx +7 -5
  555. package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
  556. package/src/plugins/builtin/jodi/pane.tsx +14 -8
  557. package/src/plugins/builtin/layout-manager/index.tsx +1 -0
  558. package/src/plugins/builtin/macro-day/headless.ts +20 -7
  559. package/src/plugins/builtin/macro-day/index.tsx +3 -2
  560. package/src/plugins/builtin/macro-day/model.ts +29 -8
  561. package/src/plugins/builtin/macro-day/pane.tsx +46 -10
  562. package/src/plugins/builtin/macro-day/releases.ts +55 -13
  563. package/src/plugins/builtin/market-heatmap/data.ts +9 -2
  564. package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
  565. package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
  566. package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
  567. package/src/plugins/builtin/market-heatmap/model.ts +10 -7
  568. package/src/plugins/builtin/market-movers/client.ts +36 -21
  569. package/src/plugins/builtin/market-movers/headless.ts +8 -2
  570. package/src/plugins/builtin/market-movers/index.tsx +16 -10
  571. package/src/plugins/builtin/market-movers/screener.ts +33 -11
  572. package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
  573. package/src/plugins/builtin/market-movers/session-table.ts +4 -2
  574. package/src/plugins/builtin/market-movers/table.ts +4 -1
  575. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  576. package/src/plugins/builtin/market-valuation/view.ts +5 -0
  577. package/src/plugins/builtin/members/headless.ts +6 -5
  578. package/src/plugins/builtin/members/pane.tsx +11 -4
  579. package/src/plugins/builtin/mna/client.ts +1 -0
  580. package/src/plugins/builtin/mna/detail.tsx +20 -32
  581. package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
  582. package/src/plugins/builtin/mna/distress/model.ts +3 -2
  583. package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
  584. package/src/plugins/builtin/mna/headless.ts +6 -13
  585. package/src/plugins/builtin/mna/model.ts +93 -15
  586. package/src/plugins/builtin/mna/pane.tsx +5 -4
  587. package/src/plugins/builtin/news/headless.ts +12 -6
  588. package/src/plugins/builtin/news/index.tsx +10 -1
  589. package/src/plugins/builtin/news/wire/index.tsx +3 -2
  590. package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
  591. package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
  592. package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
  593. package/src/plugins/builtin/notes/cli.ts +50 -15
  594. package/src/plugins/builtin/notes/export.ts +17 -6
  595. package/src/plugins/builtin/notes/files.ts +16 -5
  596. package/src/plugins/builtin/openfda/pane.tsx +1 -1
  597. package/src/plugins/builtin/options/carry.ts +2 -2
  598. package/src/plugins/builtin/options/enrichment-model.ts +10 -9
  599. package/src/plugins/builtin/options/index.tsx +1 -1
  600. package/src/plugins/builtin/options/model-spot.ts +70 -4
  601. package/src/plugins/builtin/options/view.tsx +51 -23
  602. package/src/plugins/builtin/options-calculator/headless.ts +46 -7
  603. package/src/plugins/builtin/options-calculator/pane.tsx +3 -2
  604. package/src/plugins/builtin/options-positioning/headless.ts +11 -3
  605. package/src/plugins/builtin/options-positioning/model.ts +24 -0
  606. package/src/plugins/builtin/options-positioning/pane.tsx +10 -12
  607. package/src/plugins/builtin/options-scenario/client.ts +142 -29
  608. package/src/plugins/builtin/options-scenario/collar.ts +8 -6
  609. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
  610. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
  611. package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
  612. package/src/plugins/builtin/options-scenario/csp.ts +101 -21
  613. package/src/plugins/builtin/options-scenario/headless.ts +49 -21
  614. package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
  615. package/src/plugins/builtin/options-scenario/index.tsx +28 -3
  616. package/src/plugins/builtin/options-scenario/model.ts +13 -0
  617. package/src/plugins/builtin/options-scenario/pane.tsx +22 -10
  618. package/src/plugins/builtin/perps/equity-row.tsx +11 -3
  619. package/src/plugins/builtin/perps/freshness.ts +8 -5
  620. package/src/plugins/builtin/perps/headless.ts +3 -1
  621. package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
  622. package/src/plugins/builtin/perps/live-rows.ts +161 -0
  623. package/src/plugins/builtin/perps/markets-section.tsx +154 -0
  624. package/src/plugins/builtin/perps/pane.tsx +36 -17
  625. package/src/plugins/builtin/perps/venue-markets.ts +96 -0
  626. package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
  627. package/src/plugins/builtin/plugin-marketplace/pane.tsx +145 -60
  628. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +78 -27
  629. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
  630. package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
  631. package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
  632. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
  633. package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
  634. package/src/plugins/builtin/portfolio-list/income.ts +13 -2
  635. package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
  636. package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
  637. package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
  638. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
  639. package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
  640. package/src/plugins/builtin/power/client.ts +6 -3
  641. package/src/plugins/builtin/power/evidence.ts +22 -7
  642. package/src/plugins/builtin/power/gas.tsx +5 -1
  643. package/src/plugins/builtin/power/pane.tsx +44 -32
  644. package/src/plugins/builtin/power/prices.tsx +10 -3
  645. package/src/plugins/builtin/research/analyst-headless.ts +25 -8
  646. package/src/plugins/builtin/research/analyst-model.ts +68 -3
  647. package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
  648. package/src/plugins/builtin/research/event-model.ts +3 -1
  649. package/src/plugins/builtin/research/event-sources.ts +12 -4
  650. package/src/plugins/builtin/research/index.tsx +2 -1
  651. package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
  652. package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
  653. package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
  654. package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
  655. package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
  656. package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
  657. package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
  658. package/src/plugins/builtin/reverse-dcf/client.ts +2 -1
  659. package/src/plugins/builtin/reverse-dcf/model.ts +10 -5
  660. package/src/plugins/builtin/risk-factors/index.tsx +2 -2
  661. package/src/plugins/builtin/scanner/lock-note.ts +1 -1
  662. package/src/plugins/builtin/seasonality/client.ts +2 -1
  663. package/src/plugins/builtin/sec/forms.ts +13 -0
  664. package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
  665. package/src/plugins/builtin/sec/fund-facts.ts +68 -8
  666. package/src/plugins/builtin/sec/headless.ts +85 -8
  667. package/src/plugins/builtin/sec/index.tsx +58 -12
  668. package/src/plugins/builtin/sectors/client.ts +6 -4
  669. package/src/plugins/builtin/sectors/sector-model.ts +11 -15
  670. package/src/plugins/builtin/series-inventory.ts +2 -0
  671. package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
  672. package/src/plugins/builtin/shared/cloud-resource.ts +15 -2
  673. package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
  674. package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
  675. package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
  676. package/src/plugins/builtin/shared/earnings-report.ts +3 -3
  677. package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
  678. package/src/plugins/builtin/shared/job-posting.ts +129 -0
  679. package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
  680. package/src/plugins/builtin/shared/report-freshness.ts +3 -0
  681. package/src/plugins/builtin/shared/research-trading.tsx +23 -0
  682. package/src/plugins/builtin/shared/series-cache.ts +2 -0
  683. package/src/plugins/builtin/shared/series-list-detail.tsx +3 -1
  684. package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
  685. package/src/plugins/builtin/shared/volatility/options.ts +2 -1
  686. package/src/plugins/builtin/short-interest/client.ts +2 -0
  687. package/src/plugins/builtin/short-interest/headless.ts +41 -12
  688. package/src/plugins/builtin/short-interest/index.tsx +23 -1
  689. package/src/plugins/builtin/short-interest/model.ts +70 -19
  690. package/src/plugins/builtin/short-interest/pane.tsx +19 -2
  691. package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
  692. package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
  693. package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
  694. package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
  695. package/src/plugins/builtin/short-interest/schedule.ts +35 -2
  696. package/src/plugins/builtin/short-interest/surface.tsx +11 -4
  697. package/src/plugins/builtin/short-interest/types.ts +9 -0
  698. package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
  699. package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
  700. package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
  701. package/src/plugins/builtin/social-mentions/client.ts +2 -1
  702. package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
  703. package/src/plugins/builtin/supply-chain/model.ts +51 -3
  704. package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
  705. package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
  706. package/src/plugins/builtin/themes/headless.ts +8 -5
  707. package/src/plugins/builtin/themes/model.ts +14 -4
  708. package/src/plugins/builtin/themes/pane.tsx +24 -5
  709. package/src/plugins/builtin/thirteenf/headless.ts +5 -5
  710. package/src/plugins/builtin/thirteenf/signals.ts +3 -1
  711. package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
  712. package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
  713. package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
  714. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
  715. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
  716. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
  717. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
  718. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
  719. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
  720. package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
  721. package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
  722. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
  723. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
  724. package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
  725. package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
  726. package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
  727. package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
  728. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
  729. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
  730. package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
  731. package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
  732. package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
  733. package/src/plugins/builtin/vol-surface/client.ts +28 -7
  734. package/src/plugins/builtin/vol-surface/headless.ts +43 -15
  735. package/src/plugins/builtin/vol-surface/model.ts +34 -12
  736. package/src/plugins/builtin/vol-surface/pane.tsx +33 -13
  737. package/src/plugins/builtin/vol-surface/stored.ts +34 -3
  738. package/src/plugins/builtin/vol-surface/tables.ts +14 -0
  739. package/src/plugins/builtin/volatility/model.ts +5 -10
  740. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
  741. package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
  742. package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
  743. package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
  744. package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
  745. package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
  746. package/src/plugins/builtin/world-venue-map/index.ts +3 -26
  747. package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
  748. package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
  749. package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
  750. package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
  751. package/src/plugins/builtin/yield-curve/client.ts +25 -0
  752. package/src/plugins/builtin/yield-curve/curves.ts +7 -4
  753. package/src/plugins/builtin/yield-curve/headless.ts +38 -4
  754. package/src/plugins/builtin/yield-curve/history.ts +4 -3
  755. package/src/plugins/builtin/yield-curve/index.tsx +12 -6
  756. package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
  757. package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
  758. package/src/plugins/bundle.ts +1 -1
  759. package/src/plugins/catalog-browser.ts +2 -1
  760. package/src/plugins/compat.ts +3 -3
  761. package/src/plugins/dependencies.ts +75 -14
  762. package/src/plugins/extracted-plugins.ts +132 -34
  763. package/src/plugins/host-link.ts +149 -34
  764. package/src/plugins/installer.ts +35 -10
  765. package/src/plugins/loader.ts +206 -38
  766. package/src/plugins/manager-node.ts +2 -2
  767. package/src/plugins/marketplace/deactivation.ts +22 -0
  768. package/src/plugins/marketplace/model.ts +2 -2
  769. package/src/plugins/marketplace/packs.ts +1 -1
  770. package/src/plugins/ownership.ts +1 -1
  771. package/src/plugins/peer-retry.ts +155 -0
  772. package/src/plugins/registry/contributions.ts +3 -1
  773. package/src/plugins/registry/index.ts +4 -3
  774. package/src/plugins/registry/plugin-state.ts +3 -0
  775. package/src/plugins/seed-notice.ts +20 -0
  776. package/src/plugins/shortcut-argument.ts +39 -0
  777. package/src/portfolio/allocation.ts +1 -1
  778. package/src/portfolio/collection-name.ts +31 -0
  779. package/src/portfolio/column-values.ts +10 -8
  780. package/src/portfolio/cost-fx.ts +296 -19
  781. package/src/portfolio/manual-lots.ts +75 -0
  782. package/src/portfolio/mutations.ts +60 -22
  783. package/src/portfolio/suffixed-listings.ts +209 -0
  784. package/src/portfolio/totals-currency.ts +24 -0
  785. package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
  786. package/src/public/time-series.ts +11 -8
  787. package/src/remote/schema.ts +1 -1
  788. package/src/renderers/browser/config-host.ts +3 -0
  789. package/src/renderers/browser/main.tsx +23 -3
  790. package/src/renderers/dom/boot-frame-page.ts +187 -0
  791. package/src/renderers/dom/boot-frame.ts +237 -0
  792. package/src/renderers/dom/build-assets.ts +46 -8
  793. package/src/renderers/dom/desktop/controls.tsx +1 -1
  794. package/src/renderers/dom/desktop/query-bar.tsx +2 -0
  795. package/src/renderers/dom/dom-ui-host.tsx +4 -29
  796. package/src/renderers/dom/host/ascii-text.ts +16 -2
  797. package/src/renderers/dom/host/box.tsx +43 -2
  798. package/src/renderers/dom/host/chart-surface.tsx +2 -0
  799. package/src/renderers/dom/host/hls.chunk.ts +3 -0
  800. package/src/renderers/dom/host/image-surface.tsx +49 -0
  801. package/src/renderers/dom/host/media-surface.tsx +24 -18
  802. package/src/renderers/dom/host/mouse.ts +30 -0
  803. package/src/renderers/dom/host/size-observer.ts +1 -1
  804. package/src/renderers/dom/host/style.ts +1 -1
  805. package/src/renderers/dom/host/tabs.tsx +16 -5
  806. package/src/renderers/dom/host/top-surface.ts +127 -0
  807. package/src/renderers/dom/styles.css +115 -0
  808. package/src/renderers/dom/test-utils.tsx +2 -1
  809. package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
  810. package/src/renderers/electrobun/bun/core-capabilities.ts +9 -1
  811. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
  812. package/src/renderers/electrobun/bun/desktop/backend.ts +56 -3
  813. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
  814. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
  815. package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
  816. package/src/renderers/electrobun/bun/desktop/update.ts +210 -30
  817. package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
  818. package/src/renderers/electrobun/bun/index.ts +11 -1
  819. package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
  820. package/src/renderers/electrobun/bun/window/create.ts +4 -1
  821. package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
  822. package/src/renderers/electrobun/shared/protocol.ts +6 -1
  823. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
  824. package/src/renderers/electrobun/view/config-host.ts +3 -0
  825. package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
  826. package/src/renderers/electrobun/view/main.tsx +30 -4
  827. package/src/renderers/electrobun/view/news-source.ts +9 -7
  828. package/src/renderers/electrobun/view/remote/asset-data-client.ts +9 -2
  829. package/src/renderers/electrobun/view/ui-host.tsx +1 -1
  830. package/src/renderers/opentui/browser-open.ts +88 -0
  831. package/src/renderers/opentui/host.tsx +5 -14
  832. package/src/renderers/opentui/image/loader.ts +3 -2
  833. package/src/renderers/opentui/native-smoke.ts +10 -1
  834. package/src/renderers/opentui/pane-image/index.ts +2 -1
  835. package/src/renderers/opentui/render-lib.ts +253 -0
  836. package/src/renderers/opentui/render-timing-smoke.ts +1 -1
  837. package/src/renderers/opentui/start.tsx +8 -1
  838. package/src/renderers/share/layout-view.tsx +2 -2
  839. package/src/renderers/share/main.tsx +4 -4
  840. package/src/renderers/share/view.tsx +1 -1
  841. package/src/series/resolve.ts +22 -6
  842. package/src/series/standalone.ts +30 -2
  843. package/src/series/types.ts +8 -1
  844. package/src/shares/api.ts +4 -1
  845. package/src/shares/pane.ts +1 -1
  846. package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
  847. package/src/sources/gloomberb-cloud/index.ts +39 -16
  848. package/src/sources/gloomberb-cloud/news.ts +39 -0
  849. package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
  850. package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
  851. package/src/sources/listing-symbols.ts +37 -0
  852. package/src/sources/provider-errors.ts +16 -2
  853. package/src/sources/provider-router/financial-routes.ts +21 -3
  854. package/src/sources/provider-router/financials.ts +15 -2
  855. package/src/sources/provider-router/history.ts +30 -8
  856. package/src/sources/provider-router/index.ts +16 -0
  857. package/src/sources/provider-router/primary.ts +1 -1
  858. package/src/state/app/bootstrap.ts +23 -0
  859. package/src/state/hooks/inline-tickers.ts +30 -5
  860. package/src/sync/controller.ts +1 -1
  861. package/src/sync/core-contributors.ts +46 -14
  862. package/src/team/collections-sync.ts +2 -1
  863. package/src/team/collections.ts +178 -17
  864. package/src/telemetry/crash-reports.ts +21 -4
  865. package/src/telemetry/update-failures-node.ts +59 -0
  866. package/src/telemetry/update-failures.ts +307 -0
  867. package/src/test-support/builtin-panes.ts +1 -1
  868. package/src/theme/colors.ts +3 -30
  869. package/src/theme/ui-tokens.ts +37 -1
  870. package/src/tickers/company-name-listing.ts +215 -36
  871. package/src/tickers/company-name.ts +43 -0
  872. package/src/tickers/index-roots.ts +47 -0
  873. package/src/tickers/instrument-label.ts +5 -1
  874. package/src/tickers/listing-fate.ts +30 -0
  875. package/src/tickers/metadata.ts +10 -0
  876. package/src/tickers/perpetual-listing.ts +5 -2
  877. package/src/tickers/search/home-listing.ts +75 -0
  878. package/src/tickers/search/index.ts +76 -27
  879. package/src/tickers/search/ranking.ts +54 -4
  880. package/src/tickers/search/upsert.ts +29 -0
  881. package/src/tickers/terminal-codes.ts +416 -40
  882. package/src/time-series/bar-aggregation.ts +243 -0
  883. package/src/time-series/base-series.ts +307 -0
  884. package/src/time-series/chart-bounds.ts +349 -0
  885. package/src/time-series/chart-seed.ts +142 -0
  886. package/src/time-series/economic.ts +5 -0
  887. package/src/time-series/fundamentals.ts +18 -3
  888. package/src/time-series/history-acquisition.ts +499 -0
  889. package/src/time-series/leverage.ts +100 -0
  890. package/src/time-series/market-resolution.ts +4 -2
  891. package/src/time-series/market.ts +2 -1
  892. package/src/time-series/price-comparison.ts +175 -30
  893. package/src/time-series/range.ts +9 -1
  894. package/src/time-series/resolution.ts +174 -16
  895. package/src/time-series/resolve-context.ts +157 -0
  896. package/src/time-series/resolve.ts +126 -1577
  897. package/src/time-series/series-name.ts +38 -0
  898. package/src/time-series/series-presentation.ts +208 -0
  899. package/src/time-series/spec.ts +11 -6
  900. package/src/time-series/studies.ts +109 -12
  901. package/src/time-series/tail-reconcile.ts +121 -0
  902. package/src/time-series/types.ts +29 -2
  903. package/src/time-series/use-chart-resolution.ts +4 -5
  904. package/src/types/broker.ts +10 -0
  905. package/src/types/config.ts +14 -0
  906. package/src/types/data-provider.ts +20 -0
  907. package/src/types/exchange-rate.ts +6 -0
  908. package/src/types/financials.ts +104 -7
  909. package/src/types/headless.ts +83 -6
  910. package/src/types/instrument.ts +3 -0
  911. package/src/types/issuer-listings.ts +28 -0
  912. package/src/types/plugin.ts +65 -8
  913. package/src/types/price-history.ts +2 -0
  914. package/src/types/ticker.ts +13 -0
  915. package/src/types/trading.ts +59 -1
  916. package/src/ui/ascii-font.ts +13 -1
  917. package/src/ui/host.tsx +6 -1
  918. package/src/updater/command-names.ts +175 -0
  919. package/src/updater/failure.ts +163 -0
  920. package/src/updater/index.ts +97 -28
  921. package/src/utils/calendar-date.ts +32 -15
  922. package/src/utils/cash-runway.ts +241 -0
  923. package/src/utils/central-banks.ts +42 -0
  924. package/src/utils/cli-output.ts +259 -80
  925. package/src/utils/contract-month.ts +16 -0
  926. package/src/utils/crypto-pair.ts +61 -3
  927. package/src/utils/currency-pair.ts +26 -0
  928. package/src/utils/currency-units.ts +29 -0
  929. package/src/utils/datetime-format.ts +10 -0
  930. package/src/utils/debug-log.ts +1 -1
  931. package/src/utils/decimal-comma.ts +39 -6
  932. package/src/utils/exchange-announcements.ts +71 -0
  933. package/src/utils/exchange-rate-snapshot.ts +10 -0
  934. package/src/utils/financial-statements.ts +83 -4
  935. package/src/utils/format.ts +34 -16
  936. package/src/utils/fundamentals.ts +150 -34
  937. package/src/utils/fx-market-hours.ts +10 -1
  938. package/src/utils/latest-financial-period.ts +8 -0
  939. package/src/utils/linux-libc.ts +54 -0
  940. package/src/utils/market-capitalization.ts +111 -15
  941. package/src/utils/max-drawdown.ts +64 -0
  942. package/src/utils/network-failure.ts +83 -0
  943. package/src/utils/option-expiry.ts +139 -7
  944. package/src/utils/price-earnings.ts +11 -5
  945. package/src/utils/price-history.ts +18 -8
  946. package/src/utils/price-window.ts +131 -0
  947. package/src/utils/release-date.ts +47 -0
  948. package/src/utils/sec.ts +71 -0
  949. package/src/utils/throttled-fetch.ts +11 -4
  950. package/src/utils/trailing-eps.ts +67 -0
  951. package/src/utils/typed-text.ts +21 -0
  952. package/src/utils/utc-time.ts +24 -1
  953. package/src/version.ts +6 -0
  954. package/src/cli/pane-functions/screenshot.ts +0 -2122
@@ -1,15 +1,23 @@
1
1
  import { logFailure } from "../utils/log-failure";
2
2
  import { readdir } from "fs/promises";
3
- import { basename, join } from "path";
4
- import { existsSync, lstatSync, readFileSync, statSync } from "fs";
3
+ import { basename, dirname, join } from "path";
4
+ import { existsSync, lstatSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs";
5
5
  import { getGloomberbDirs } from "../data/config/home";
6
6
  import type { GloomPlugin, PluginTarget } from "../types/plugin";
7
7
  import { debugLog } from "../utils/debug-log";
8
8
  import { reportCrash } from "../telemetry/crash-reports";
9
+ import { VERSION } from "../version";
9
10
  import { findAbsorbedPlugin, type AbsorbedPlugin } from "./absorbed";
10
11
  import { checkPluginCompatibility, explainPluginLoadError, findMissingHostExport, pluginSourceFiles, readPluginManifest } from "./compat";
11
- import { installPluginDependencies, missingPluginDependencies } from "./dependencies";
12
- import { isLinkedPeerModule, linkHostPackages } from "./host-link";
12
+ import {
13
+ describeDependencyInstalls,
14
+ installPluginDependencies,
15
+ missingPluginDependencies,
16
+ settleDependencyInstalls,
17
+ } from "./dependencies";
18
+ import { declaredPeerPlugins, describePeerLink, isLinkedPeerModule, linkHostPackages, relinkPeerPlugin } from "./host-link";
19
+ import { refreshResolverFolders, rekeyedEntry, withoutRetryQuery } from "./peer-retry";
20
+ import { pluginDirectoryNames } from "./plugin-names";
13
21
  import { pluginFromModule, pluginSupportsTarget } from "./plugin-export";
14
22
 
15
23
  const loaderLog = debugLog.createLogger("plugin-loader");
@@ -31,7 +39,7 @@ export interface LoadedExternalPlugin {
31
39
  commit?: string;
32
40
  /** `owner/repo` of the checkout's GitHub origin; usage counts trust only gloom-sh's. */
33
41
  repo?: string;
34
- /** A symlink to a local checkout (`gloomberb plugin link`) rather than a clone. */
42
+ /** A symlink to a local checkout (`gloom plugin link`) rather than a clone. */
35
43
  linked?: boolean;
36
44
  /**
37
45
  * The plugin's logo as a `data:` URL (plugin-icon.ts), for the desktop and
@@ -67,8 +75,8 @@ export function getPluginCacheDir(): string {
67
75
  * Whether a directory inside the plugins folder is a plugin at all.
68
76
  *
69
77
  * Dot-directories are bookkeeping, not plugins: the desktop bundle cache used
70
- * to be written to `plugins/.cache`, and it showed up in `gloomberb plugins`
71
- * as an installed plugin and in `gloomberb update` as a repo to pull. The
78
+ * to be written to `plugins/.cache`, and it showed up in `gloom plugins`
79
+ * as an installed plugin and in `gloom update` as a repo to pull. The
72
80
  * cache has moved out, but old installs still have that directory, so this
73
81
  * stays as the single rule every reader shares.
74
82
  */
@@ -176,7 +184,7 @@ export function findAbsorbedCheckout(pluginDir: string): AbsorbedPlugin | null {
176
184
 
177
185
  function skipsAbsorbedCheckout(pluginDir: string, absorbed: AbsorbedPlugin | null = findAbsorbedCheckout(pluginDir)): boolean {
178
186
  if (!absorbed) return false;
179
- loaderLog.debug(`Skipped ${basename(pluginDir)}: ${absorbed.name} is built into Gloomberb now`);
187
+ loaderLog.debug(`Skipped ${basename(pluginDir)}: ${absorbed.name} is built into Gloom now`);
180
188
  return true;
181
189
  }
182
190
 
@@ -243,6 +251,119 @@ function hasStaleModules(pluginDir: string, commit: string | null): boolean {
243
251
  }
244
252
  }
245
253
 
254
+ /**
255
+ * The entry a plugin was imported from on a retry, by plugin folder. A later
256
+ * load of the same plugin that is not fresh imports it from there again, so
257
+ * it gets the modules that loaded instead of the failed ones.
258
+ */
259
+ const retriedEntries = new Map<string, string>();
260
+
261
+ /** Plugin folders whose recovery this process already reported; once is enough to explain it. */
262
+ const reportedRecoveries = new Set<string>();
263
+
264
+ /** Loads running now, which a crash report counts: two at once share the links they rewrite. */
265
+ let loadsInFlight = 0;
266
+
267
+ /**
268
+ * Whether this process is the first to load plugins since this version was
269
+ * installed, null until the first full load records it. Read from a marker
270
+ * in the plugin cache, which the first startup load of a new version writes.
271
+ */
272
+ let firstLaunchOfVersion: boolean | null = null;
273
+
274
+ function recordLaunchedVersion(): void {
275
+ if (firstLaunchOfVersion !== null) return;
276
+ const marker = join(PLUGIN_CACHE_DIR, "loaded-version");
277
+ try {
278
+ const previous = existsSync(marker) ? readFileSync(marker, "utf-8").trim() : null;
279
+ firstLaunchOfVersion = previous !== VERSION;
280
+ if (firstLaunchOfVersion) {
281
+ mkdirSync(PLUGIN_CACHE_DIR, { recursive: true });
282
+ writeFileSync(marker, VERSION);
283
+ }
284
+ } catch (error) {
285
+ logFailure("plugin-loader", "Recording the loaded version failed")(error);
286
+ }
287
+ }
288
+
289
+ function errorMessage(err: unknown): string {
290
+ return err instanceof Error ? err.message : String(err);
291
+ }
292
+
293
+ /** The sibling plugin a failed import named, when the plugin declares it as a peer. */
294
+ function failedPeer(pluginDir: string, specifier: string | undefined): string | null {
295
+ if (!specifier) return null;
296
+ return declaredPeerPlugins(pluginDir).find((peer) => specifier === peer || specifier.startsWith(`${peer}/`)) ?? null;
297
+ }
298
+
299
+ /**
300
+ * The state of the link to `peer` and around it, for the crash report of an
301
+ * import that failed on it: whether the sibling's folder is there, what the
302
+ * link is and where it points, whether the retry rewrote it, how often this
303
+ * process wrote it before, which `bun install` runs this process made, how
304
+ * many loads ran at once, and whether this is the first launch of the version.
305
+ */
306
+ function describePeerFailure(pluginDir: string, peer: string, relinked: string, retry: string): string {
307
+ const link = describePeerLink(pluginDir, peer);
308
+ const now = Date.now();
309
+ const installs = describeDependencyInstalls(now);
310
+ const fields = [
311
+ `retry=${retry}`,
312
+ `peer=${peer}`,
313
+ `dir=${link.directory ?? "missing"}`,
314
+ `link=${link.link}${link.target ? `->${link.target}` : ""}${link.linked ? "" : "(not-resolving)"}`,
315
+ `relinked=${relinked}`,
316
+ `link-writes=${link.writes}${link.lastWriteAt ? `@${((now - link.lastWriteAt) / 1000).toFixed(1)}s` : ""}`,
317
+ ...(link.lastError ? [`link-error=${link.lastError}`] : []),
318
+ `installs=${installs.length > 0 ? installs.slice(0, 4).join(",") : "none"}`,
319
+ `loads=${loadsInFlight}`,
320
+ `first-launch=${firstLaunchOfVersion === null ? "unknown" : firstLaunchOfVersion ? "yes" : "no"}`,
321
+ ...(typeof Bun !== "undefined" ? [`bun=${Bun.version}`] : []),
322
+ ];
323
+ return fields.join(" ");
324
+ }
325
+
326
+ type PeerRetry =
327
+ | { module: unknown; detail: string }
328
+ | { error: unknown; detail: string };
329
+
330
+ /**
331
+ * The import that failed on `peer`, once more after linking the sibling
332
+ * again: past Bun's cached view of the plugin's folders and under new module
333
+ * keys (see peer-retry.ts), so it really resolves the sibling again rather
334
+ * than replaying the failure.
335
+ */
336
+ async function retryPeerImport(pluginDir: string, entryFile: string, peer: string): Promise<PeerRetry> {
337
+ // A `bun install` still running in the plugin or the sibling prunes the
338
+ // link it is about to need.
339
+ const peerDirs = pluginDirectoryNames(peer).map((name) => join(dirname(pluginDir), name));
340
+ await settleDependencyInstalls([pluginDir, ...peerDirs], 15_000);
341
+ // Windows refuses a new junction where one is still being deleted until
342
+ // every handle on the old one closes; that passes in moments.
343
+ const attempts = [relinkPeerPlugin(pluginDir, peer)];
344
+ for (const delayMs of [250, 1_000]) {
345
+ if (!attempts.at(-1)!.startsWith("failed")) break;
346
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
347
+ attempts.push(relinkPeerPlugin(pluginDir, peer));
348
+ }
349
+ const relinked = attempts.join(",");
350
+ // An install that finished during the wait pruned `gloomberb` and `react`
351
+ // as well. After the sibling's own relink, so `relinked` says what that did.
352
+ linkHostPackages(pluginDir);
353
+ refreshResolverFolders(pluginDir, [peer]);
354
+ const specifier = rekeyedEntry(entryFile, pluginDir);
355
+ if (!specifier) {
356
+ return { error: new Error("This process cannot import a plugin again."), detail: describePeerFailure(pluginDir, peer, relinked, "unavailable") };
357
+ }
358
+ try {
359
+ const module = await import(specifier);
360
+ retriedEntries.set(pluginDir, specifier);
361
+ return { module, detail: describePeerFailure(pluginDir, peer, relinked, "loaded") };
362
+ } catch (error) {
363
+ return { error, detail: describePeerFailure(pluginDir, peer, relinked, "failed") };
364
+ }
365
+ }
366
+
246
367
  /**
247
368
  * Loads one plugin directory. Never throws: a broken plugin comes back with
248
369
  * `error` set. Null for a folder that is not a plugin, and for a leftover
@@ -253,6 +374,19 @@ export async function loadExternalPlugin(
253
374
  pluginDir: string,
254
375
  target: PluginTarget = "cli",
255
376
  options: LoadExternalPluginOptions = {},
377
+ ): Promise<LoadedExternalPlugin | null> {
378
+ loadsInFlight += 1;
379
+ try {
380
+ return await loadPluginDirectory(pluginDir, target, options);
381
+ } finally {
382
+ loadsInFlight -= 1;
383
+ }
384
+ }
385
+
386
+ async function loadPluginDirectory(
387
+ pluginDir: string,
388
+ target: PluginTarget,
389
+ options: LoadExternalPluginOptions,
256
390
  ): Promise<LoadedExternalPlugin | null> {
257
391
  const directory = basename(pluginDir);
258
392
  missingHostExportFailures.delete(directory);
@@ -303,9 +437,68 @@ export async function loadExternalPlugin(
303
437
  const restart = hasStaleModules(pluginDir, commit) ? { needsRestart: true } : {};
304
438
  if (!importedCommits.has(pluginDir)) importedCommits.set(pluginDir, commit);
305
439
 
440
+ const failed = (err: unknown, retry?: Extract<PeerRetry, { error: unknown }>): LoadedExternalPlugin => {
441
+ const message = errorMessage(err);
442
+ let detail: string | undefined;
443
+ if (retry) {
444
+ // As plain text: escaping would double a Windows path's backslashes,
445
+ // and the home folder would no longer be recognized to remove.
446
+ const retryMessage = withoutRetryQuery(errorMessage(retry.error));
447
+ detail = retryMessage === message ? retry.detail : `${retry.detail} retry-error=${retryMessage.slice(0, 200)}`;
448
+ // The sibling is installed and linked, and a second import that
449
+ // looked again still failed. A new process imports everything fresh,
450
+ // so the plugin asks for a restart, and the report says why it got here.
451
+ const unresolved = unresolvedSpecifier(err, message);
452
+ if (unresolved && isLinkedPeerModule(pluginDir, unresolved)) {
453
+ loaderLog.info(`${directory} loads after a restart: ${message} [${detail}]`);
454
+ reportCrash(err, { kind: "plugin", plugin: directory, detail });
455
+ return { ...base, plugin: placeholder, needsRestart: true };
456
+ }
457
+ }
458
+ // An update that links against modules this process imported at the old
459
+ // commit, which Bun keeps until a restart. The row already asks for one,
460
+ // and the next launch imports everything fresh; a plugin that is really
461
+ // broken fails there, and is reported there. A host export the running
462
+ // Gloomberb lacks is a different failure and stays one.
463
+ if (restart.needsRestart && !findMissingHostExport(message) && STALE_LINK_FAILURE.test(message)) {
464
+ loaderLog.info(`${directory} loads after a restart: ${message}`);
465
+ return { ...base, plugin: placeholder, needsRestart: true };
466
+ }
467
+ loaderLog.error(`Failed to load plugin from ${pluginDir}: ${err}${detail ? ` [${detail}]` : ""}`);
468
+ reportCrash(err, { kind: "plugin", plugin: directory, ...(detail ? { detail } : {}) });
469
+ if (findMissingHostExport(message)) missingHostExportFailures.add(directory);
470
+ return {
471
+ ...base,
472
+ ...restart,
473
+ plugin: placeholder,
474
+ error: explainPluginLoadError(message),
475
+ };
476
+ };
477
+
478
+ let module: unknown;
306
479
  try {
307
- const specifier = options.fresh ? `${entryFile}?reload=${Date.now()}` : entryFile;
308
- const plugin = pluginFromModule(await import(specifier));
480
+ const retried = options.fresh ? undefined : retriedEntries.get(pluginDir);
481
+ module = await import(retried ?? (options.fresh ? `${entryFile}?reload=${Date.now()}` : entryFile));
482
+ } catch (err) {
483
+ // A sibling plugin it imports that did not resolve: not linked yet, or
484
+ // its link was being rewritten. Bun keeps that failure for the process,
485
+ // so the plugin is linked and imported again in a way that looks again.
486
+ const peer = failedPeer(pluginDir, unresolvedSpecifier(err, errorMessage(err)));
487
+ if (!peer) return failed(err);
488
+ const retry = await retryPeerImport(pluginDir, entryFile, peer);
489
+ if ("error" in retry) return failed(err, retry);
490
+ // Loaded, but the failure it recovered from is still a bug somewhere:
491
+ // the report carries the link state that explains it.
492
+ loaderLog.info(`Loaded ${directory} on a second import: ${errorMessage(err)} [${retry.detail}]`);
493
+ if (!reportedRecoveries.has(pluginDir)) {
494
+ reportedRecoveries.add(pluginDir);
495
+ reportCrash(err, { kind: "plugin", plugin: directory, detail: retry.detail });
496
+ }
497
+ module = retry.module;
498
+ }
499
+
500
+ try {
501
+ const plugin = pluginFromModule(module);
309
502
  if (!plugin) {
310
503
  const error = "Plugin did not export a valid GloomPlugin (missing id or name).";
311
504
  reportCrash(error, { kind: "plugin", plugin: directory });
@@ -325,33 +518,7 @@ export async function loadExternalPlugin(
325
518
  loaderLog.info(`Loaded external plugin: ${plugin.id} v${plugin.version ?? "0.0.0"}`);
326
519
  return { ...base, ...restart, plugin };
327
520
  } catch (err) {
328
- const message = err instanceof Error ? err.message : String(err);
329
- // A sibling plugin it imports that is linked now but was not when this
330
- // process first resolved it. Bun keeps that failure until a restart, which
331
- // is all the plugin needs: not a crash.
332
- const unresolved = unresolvedSpecifier(err, message);
333
- if (unresolved && isLinkedPeerModule(pluginDir, unresolved)) {
334
- loaderLog.info(`${directory} loads after a restart: ${message}`);
335
- return { ...base, plugin: placeholder, needsRestart: true };
336
- }
337
- // An update that links against modules this process imported at the old
338
- // commit, which Bun keeps until a restart. The row already asks for one,
339
- // and the next launch imports everything fresh; a plugin that is really
340
- // broken fails there, and is reported there. A host export the running
341
- // Gloomberb lacks is a different failure and stays one.
342
- if (restart.needsRestart && !findMissingHostExport(message) && STALE_LINK_FAILURE.test(message)) {
343
- loaderLog.info(`${directory} loads after a restart: ${message}`);
344
- return { ...base, plugin: placeholder, needsRestart: true };
345
- }
346
- loaderLog.error(`Failed to load plugin from ${pluginDir}: ${err}`);
347
- reportCrash(err, { kind: "plugin", plugin: directory });
348
- if (findMissingHostExport(message)) missingHostExportFailures.add(directory);
349
- return {
350
- ...base,
351
- ...restart,
352
- plugin: placeholder,
353
- error: explainPluginLoadError(message),
354
- };
521
+ return failed(err);
355
522
  }
356
523
  }
357
524
 
@@ -382,6 +549,7 @@ export async function listPluginDirectories(pluginsDir: string = PLUGINS_DIR): P
382
549
  }
383
550
 
384
551
  export async function loadExternalPlugins(target: PluginTarget = "cli"): Promise<LoadedExternalPlugin[]> {
552
+ recordLaunchedVersion();
385
553
  const results: LoadedExternalPlugin[] = [];
386
554
  for (const pluginDir of await listPluginDirectories()) {
387
555
  const loaded = await loadExternalPlugin(pluginDir, target);
@@ -399,7 +567,7 @@ function isSymlink(path: string): boolean {
399
567
  }
400
568
  }
401
569
 
402
- /** A linked plugin (`gloomberb plugin link`) is a symlink, which `readdir` does not report as a directory. */
570
+ /** A linked plugin (`gloom plugin link`) is a symlink, which `readdir` does not report as a directory. */
403
571
  export function isDirectoryOrLink(entry: { isDirectory(): boolean; isSymbolicLink(): boolean }, path: string): boolean {
404
572
  if (entry.isDirectory()) return true;
405
573
  if (!entry.isSymbolicLink()) return false;
@@ -6,7 +6,7 @@ import type { PluginTarget } from "../types/plugin";
6
6
  /**
7
7
  * The plugin manager for a process that can run git and bun: the terminal,
8
8
  * and the desktop's Bun side on behalf of its view. Wraps the installer so
9
- * the marketplace and `gloomberb install` do exactly the same thing, and
9
+ * the marketplace and `gloom install` do exactly the same thing, and
10
10
  * turns its failures into results the pane can show next to the row.
11
11
  */
12
12
 
@@ -41,7 +41,7 @@ export function createNodePluginManager(target: PluginTarget, hooks: NodePluginM
41
41
  }
42
42
 
43
43
  return {
44
- // Through the registry, like `gloomberb install`: a plugin that builds on
44
+ // Through the registry, like `gloom install`: a plugin that builds on
45
45
  // another brings it along instead of failing to load without it.
46
46
  install: (repo, pin) => attempt(async () => (await installer()).installListedPlugin(repo, { quiet: true, ...(pin ? { pin } : {}) })),
47
47
  update: (directory, pin) => attempt(async () => (await installer()).updatePlugin(directory, { quiet: true, pin })),
@@ -0,0 +1,22 @@
1
+ import type { PluginRegistry } from "../registry";
2
+ import { logFailure } from "../../utils/log-failure";
3
+
4
+ // unregister removes the registration even when cleanup throws. A later
5
+ // no-op cannot confirm that its background work stopped. Keep that uncertainty
6
+ // with this runtime, across pane remounts, until a fresh registry starts.
7
+ const failedStops = new WeakMap<PluginRegistry, Set<string>>();
8
+
9
+ export function deactivatePluginForRemoval(registry: PluginRegistry, pluginId: string): void {
10
+ const failure = "Plugin could not be stopped. Restart before removing it.";
11
+ if (failedStops.get(registry)?.has(pluginId)) throw new Error(failure);
12
+ if (!registry.allPlugins.has(pluginId)) return;
13
+ try {
14
+ registry.unregister(pluginId);
15
+ } catch (error) {
16
+ const failed = failedStops.get(registry) ?? new Set<string>();
17
+ failed.add(pluginId);
18
+ failedStops.set(registry, failed);
19
+ logFailure("plugin-removal", "Plugin cleanup before removal failed")(error);
20
+ throw new Error(failure);
21
+ }
22
+ }
@@ -72,7 +72,7 @@ export interface InstalledPlugin {
72
72
  path?: string;
73
73
  /** Checked-out commit, when the install is a git checkout. */
74
74
  commit?: string;
75
- /** A dev link (`gloomberb plugin link`) rather than a clone. */
75
+ /** A dev link (`gloom plugin link`) rather than a clone. */
76
76
  linked?: boolean;
77
77
  /** Set when the plugin is installed but cannot run on this renderer. */
78
78
  unsupportedTarget?: PluginTarget;
@@ -180,7 +180,7 @@ function isFeatured(id: string, bundled: boolean, feedFeatured: boolean | undefi
180
180
  * plugin can be installed but inert because this renderer cannot run it. The
181
181
  * merge keeps all three visible rather than showing whichever list is handy.
182
182
  */
183
- /** The folder `gloomberb install owner/repo` creates, which is the repository name. */
183
+ /** The folder `gloom install owner/repo` creates, which is the repository name. */
184
184
  function repoDirectory(repo: string | undefined): string | null {
185
185
  const name = repo?.split("/")[1]?.replace(/\.git$/, "");
186
186
  return name ? name.toLowerCase() : null;
@@ -37,7 +37,7 @@ export const STARTER_PACKS: readonly StarterPack[] = [
37
37
  {
38
38
  id: "everything",
39
39
  name: "Everything",
40
- tagline: "Every research plugin on, as Gloomberb ships.",
40
+ tagline: "Every research plugin on, as Gloom ships.",
41
41
  plugins: PACK_PLUGIN_IDS,
42
42
  },
43
43
  {
@@ -110,7 +110,7 @@ export function builtinPluginGroupMembers(pluginId: string): readonly string[] |
110
110
  /**
111
111
  * `disabledPlugins` after switching plugins on or off in one go, or null when
112
112
  * nothing changes. A retired group id switches every member, the way
113
- * `gloomberb plugin enable|disable` does. Changes apply in order, so a later
113
+ * `gloom plugin enable|disable` does. Changes apply in order, so a later
114
114
  * one wins for a plugin two groups share.
115
115
  */
116
116
  export function applyPluginToggles(
@@ -0,0 +1,155 @@
1
+ import { readdirSync, readFileSync, type Dirent } from "fs";
2
+ import { dirname, extname, isAbsolute, join, relative } from "path";
3
+
4
+ /**
5
+ * A second import of a plugin whose first one failed on a sibling plugin it
6
+ * imports (IBKR Gateway imports Interactive Brokers), that really looks again.
7
+ *
8
+ * Bun keeps both halves of that failure for the rest of the process. Its
9
+ * resolver remembers each folder it read, so `node_modules` stays without the
10
+ * sibling after the link is made. And the module that failed stays failed
11
+ * under its path, so importing the entry again, even under a fresh query,
12
+ * reaches the same error through the entry's own `./plugin` import. Until
13
+ * now only a restart cleared it, which is why the gateway failed on a launch
14
+ * and worked on the next one.
15
+ *
16
+ * The retry undoes both. It makes Bun read the plugin's folders again (a
17
+ * lookup that misses in a folder Bun had read drops that folder from its
18
+ * cache), and it imports every file of the plugin under a new module key, so
19
+ * nothing from the failed attempt is reused. Imports that leave the plugin,
20
+ * the sibling's files included, resolve to the same modules as always, so the
21
+ * plugin shares the sibling's state as on a normal load.
22
+ */
23
+
24
+ /** The query that gives a plugin's files their new module keys. */
25
+ const RETRY_PARAM = "gloom-plugin-retry";
26
+ const RETRY_QUERY = new RegExp(`[?&]${RETRY_PARAM}=(\\d+)(?:&|$)`);
27
+ const SOURCE_LOADERS: Readonly<Record<string, "ts" | "tsx" | "js" | "jsx">> = {
28
+ ".ts": "ts",
29
+ ".mts": "ts",
30
+ ".tsx": "tsx",
31
+ ".js": "js",
32
+ ".mjs": "js",
33
+ ".jsx": "jsx",
34
+ };
35
+ /** A file name that is never there: looking it up is what clears a folder. */
36
+ const MISSING_FILE = "./.gloom-resolver-refresh";
37
+ const SKIPPED_FOLDERS = new Set(["node_modules", ".git", "dist"]);
38
+
39
+ /**
40
+ * `text` without the retry query Bun puts in the paths of a retried import's
41
+ * errors, so the retry's error reads like the first import's.
42
+ */
43
+ export function withoutRetryQuery(text: string): string {
44
+ return text.replace(new RegExp(`[?&]${RETRY_PARAM}=\\d+`, "g"), "");
45
+ }
46
+
47
+ /** The plugin folder each retry imports from, by retry number. */
48
+ const retryRoots = new Map<number, string>();
49
+ let retries = 0;
50
+ let installed = false;
51
+
52
+ function isInside(root: string, path: string): boolean {
53
+ const inside = relative(root, path);
54
+ return !!inside && !inside.startsWith("..") && !isAbsolute(inside);
55
+ }
56
+
57
+ /** The plugin's own folders, without dependencies or build output. */
58
+ function sourceFolders(dir: string, out: string[] = [], depth = 0): string[] {
59
+ out.push(dir);
60
+ if (depth > 8) return out;
61
+ let entries: Dirent[];
62
+ try {
63
+ entries = readdirSync(dir, { withFileTypes: true });
64
+ } catch {
65
+ // Intentional ignore: a folder that cannot be listed has nothing Bun could have cached.
66
+ return out;
67
+ }
68
+ for (const entry of entries) {
69
+ if (entry.isDirectory() && !SKIPPED_FOLDERS.has(entry.name)) sourceFolders(join(dir, entry.name), out, depth + 1);
70
+ }
71
+ return out;
72
+ }
73
+
74
+ /**
75
+ * Makes Bun read the plugin's folders and its links to `peers` from disk
76
+ * again. Bun drops a folder from its resolver cache when a lookup in it
77
+ * misses, so this looks up a file that is not there in each one. The
78
+ * bundler shares the cache, which is why the desktop's compile of the same
79
+ * plugin failed in the same session too.
80
+ */
81
+ export function refreshResolverFolders(pluginDir: string, peers: readonly string[]): void {
82
+ const modules = join(pluginDir, "node_modules");
83
+ const folders = [...sourceFolders(pluginDir), modules];
84
+ for (const peer of peers) {
85
+ if (peer.startsWith("@")) folders.push(join(modules, peer.split("/")[0]!));
86
+ folders.push(join(modules, peer));
87
+ }
88
+ for (const folder of folders) {
89
+ try {
90
+ Bun.resolveSync(MISSING_FILE, folder);
91
+ } catch {
92
+ // Intentional ignore: the miss is what drops the folder from the cache.
93
+ }
94
+ }
95
+ }
96
+
97
+ /**
98
+ * The plugin's file at `path` (with the retry query), its relative imports
99
+ * of other source files in the plugin given the same query, so they load
100
+ * under new keys as well. Imports that leave the plugin keep their keys.
101
+ */
102
+ function rekeyedSource(path: string): { contents: string; loader: "ts" | "tsx" | "js" | "jsx" } {
103
+ const match = RETRY_QUERY.exec(path);
104
+ const file = match ? path.slice(0, match.index) : path;
105
+ const loader = SOURCE_LOADERS[extname(file).toLowerCase()] ?? "js";
106
+ let contents = readFileSync(file, "utf8");
107
+ const root = match ? retryRoots.get(Number(match[1])) : undefined;
108
+ if (!match || !root) return { contents, loader };
109
+ const retry = Number(match[1]);
110
+ const specifiers = new Set(
111
+ new Bun.Transpiler({ loader }).scanImports(contents)
112
+ .map((entry) => entry.path)
113
+ .filter((specifier) => (specifier.startsWith("./") || specifier.startsWith("../")) && !specifier.includes("?")),
114
+ );
115
+ for (const specifier of specifiers) {
116
+ let target: string;
117
+ try {
118
+ target = Bun.resolveSync(specifier, dirname(file));
119
+ } catch {
120
+ // Intentional ignore: left as written, the import fails the way it would have.
121
+ continue;
122
+ }
123
+ if (!isInside(root, target) || !SOURCE_LOADERS[extname(target).toLowerCase()]) continue;
124
+ const rekeyed = `${specifier}?${RETRY_PARAM}=${retry}`;
125
+ for (const quote of ["\"", "'", "`"]) {
126
+ contents = contents.split(`${quote}${specifier}${quote}`).join(`${quote}${rekeyed}${quote}`);
127
+ }
128
+ }
129
+ return { contents, loader };
130
+ }
131
+
132
+ function installRekeyingLoader(): boolean {
133
+ if (installed) return true;
134
+ if (typeof Bun === "undefined" || typeof Bun.plugin !== "function") return false;
135
+ Bun.plugin({
136
+ name: "gloomberb-plugin-retry",
137
+ setup(build) {
138
+ build.onLoad({ filter: RETRY_QUERY }, (args) => rekeyedSource(args.path));
139
+ },
140
+ });
141
+ installed = true;
142
+ return true;
143
+ }
144
+
145
+ /**
146
+ * The specifier that imports `entryFile` and the rest of its plugin under
147
+ * new module keys, or null when this process cannot register the loader that
148
+ * does it. The same specifier imports the same modules again.
149
+ */
150
+ export function rekeyedEntry(entryFile: string, pluginDir: string): string | null {
151
+ if (!installRekeyingLoader()) return null;
152
+ retries += 1;
153
+ retryRoots.set(retries, pluginDir);
154
+ return `${entryFile}?${RETRY_PARAM}=${retries}`;
155
+ }
@@ -11,6 +11,7 @@ import type {
11
11
  TickerAction,
12
12
  TickerResearchTabDef,
13
13
  } from "../../types/plugin";
14
+ import { withFunctionShortcutArgument } from "../shortcut-argument";
14
15
 
15
16
  export interface ContextMenuProviderEntry {
16
17
  pluginId: string;
@@ -89,7 +90,8 @@ export class RegistryContributions {
89
90
  }
90
91
 
91
92
  registerPaneTemplate(pluginId: string, template: PaneTemplateDef, replace = false): () => void {
92
- return this.paneTemplatesMap.register(pluginId, template.id, template, replace);
93
+ const registered = withFunctionShortcutArgument(template, this.panesMap.get(template.paneId));
94
+ return this.paneTemplatesMap.register(pluginId, template.id, registered, replace);
93
95
  }
94
96
 
95
97
  registerCommand(pluginId: string, command: CommandDef): void {
@@ -69,6 +69,7 @@ import {
69
69
  bindPluginContextNamespaces,
70
70
  createPluginPaneSettingsState,
71
71
  createPluginResumeState,
72
+ resumeStateKey,
72
73
  type NamespacedPluginContext,
73
74
  } from "./plugin-state";
74
75
  import { createPluginSetupCommand, isPluginConfigured } from "./setup-command";
@@ -405,18 +406,18 @@ export class PluginRegistry implements PluginRuntimeAccess {
405
406
 
406
407
  getResumeState<T = unknown>(pluginId: string, key: string, schemaVersion?: number): T | null {
407
408
  const stateId = this.stateNamespace(pluginId);
408
- return this.persistence.pluginState.get<T>(stateId, `resume:${key}`, schemaVersion)?.value ?? null;
409
+ return this.persistence.pluginState.get<T>(stateId, resumeStateKey(key), schemaVersion)?.value ?? null;
409
410
  }
410
411
 
411
412
  setResumeState(pluginId: string, key: string, value: unknown, schemaVersion?: number): void {
412
413
  const stateId = this.stateNamespace(pluginId);
413
- this.persistence.pluginState.set(stateId, `resume:${key}`, value, schemaVersion);
414
+ this.persistence.pluginState.set(stateId, resumeStateKey(key), value, schemaVersion);
414
415
  this.resumeStateListeners.emit(stateId, key);
415
416
  }
416
417
 
417
418
  deleteResumeState(pluginId: string, key: string): void {
418
419
  const stateId = this.stateNamespace(pluginId);
419
- this.persistence.pluginState.delete(stateId, `resume:${key}`);
420
+ this.persistence.pluginState.delete(stateId, resumeStateKey(key));
420
421
  this.resumeStateListeners.emit(stateId, key);
421
422
  }
422
423
 
@@ -4,6 +4,9 @@ import type { LayoutConfig } from "../../types/config";
4
4
  import type { GloomPluginContext, PluginPaneSettingsState, PluginResumeState } from "../../types/plugin";
5
5
  import { deletePluginPaneStateValue, setPluginPaneStateValue } from "../../layout/pane-state";
6
6
 
7
+ /** Where a plugin's resume state (`ctx.resume`) is kept in the device's plugin state store. */
8
+ export const resumeStateKey = (key: string) => `resume:${key}`;
9
+
7
10
  export class RegistryResumeStateListeners {
8
11
  private listeners = new Map<string, Set<() => void>>();
9
12
 
@@ -0,0 +1,20 @@
1
+ import type { PluginSeedNotice } from "./extracted-plugins";
2
+
3
+ /**
4
+ * What the launch's plugin seed could not install, said once the app is up.
5
+ * The seed runs before the app renders (in the terminal's process, or the
6
+ * desktop's Bun process, which hands it to its main window), so it leaves the
7
+ * notice here and the app takes it.
8
+ */
9
+ let pending: PluginSeedNotice | null = null;
10
+
11
+ export function setPluginSeedNotice(notice: PluginSeedNotice | null): void {
12
+ pending = notice;
13
+ }
14
+
15
+ /** The notice, once: a second call returns null. */
16
+ export function takePluginSeedNotice(): PluginSeedNotice | null {
17
+ const notice = pending;
18
+ pending = null;
19
+ return notice;
20
+ }