gloomberb 0.18.3 → 0.18.5

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 (1018) 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 +32 -1
  6. package/src/account/auth-model.ts +7 -3
  7. package/src/account/checkout-handoff.tsx +225 -0
  8. package/src/account/device-signin-dialog.tsx +2 -2
  9. package/src/account/device-signin.ts +2 -2
  10. package/src/account/upgrade-dialog.tsx +1 -1
  11. package/src/api-client/askg.ts +2 -2
  12. package/src/api-client/auth.ts +11 -6
  13. package/src/api-client/catalysts.ts +2 -1
  14. package/src/api-client/central-bank-rates.ts +6 -0
  15. package/src/api-client/collections.ts +5 -1
  16. package/src/api-client/cot.ts +2 -0
  17. package/src/api-client/crypto-etf-flows.ts +37 -0
  18. package/src/api-client/crypto-markets.ts +60 -0
  19. package/src/api-client/data.ts +98 -5
  20. package/src/api-client/doe.ts +15 -0
  21. package/src/api-client/equity-screener.ts +28 -0
  22. package/src/api-client/exchange-announcements.ts +38 -0
  23. package/src/api-client/fund-facts.ts +39 -0
  24. package/src/api-client/futures-curve.ts +9 -1
  25. package/src/api-client/hiring.ts +301 -0
  26. package/src/api-client/index.ts +182 -16
  27. package/src/api-client/live-scan.ts +91 -0
  28. package/src/api-client/market-discovery.ts +14 -0
  29. package/src/api-client/members.ts +18 -0
  30. package/src/api-client/mna.ts +6 -0
  31. package/src/api-client/paths.ts +18 -1
  32. package/src/api-client/request.ts +224 -26
  33. package/src/api-client/research-activity.ts +3 -10
  34. package/src/api-client/short-side-publications.ts +37 -0
  35. package/src/api-client/socket.ts +64 -4
  36. package/src/api-client/swap-curve.ts +35 -0
  37. package/src/api-client/themes.ts +7 -1
  38. package/src/api-client/types.ts +96 -2
  39. package/src/app/keybindings/index.ts +3 -0
  40. package/src/app/keybindings/labels.ts +18 -1
  41. package/src/app/keybindings/resolve.ts +14 -0
  42. package/src/app/pane-runtime/plugin-bindings.ts +9 -2
  43. package/src/app/runtime/broker-import.ts +43 -26
  44. package/src/app/runtime/desktop-deeplink.ts +5 -5
  45. package/src/app/runtime/plugin-bindings.ts +2 -2
  46. package/src/app/runtime/startup.ts +13 -0
  47. package/src/app/star-prompt/status-line.tsx +2 -2
  48. package/src/architecture/core-builtin-allowlist.json +5 -2
  49. package/src/architecture/ui-literals-allowlist.json +3 -3
  50. package/src/architecture/ui-tokens-allowlist.json +1 -1
  51. package/src/brokers/broker-portfolio-sync.ts +37 -0
  52. package/src/brokers/directory.ts +11 -0
  53. package/src/brokers/logos.ts +3 -1
  54. package/src/brokers/signed-in/adapter.ts +304 -26
  55. package/src/brokers/signed-in/client.ts +14 -2
  56. package/src/brokers/signed-in/connect.ts +10 -2
  57. package/src/brokers/sync-broker-instance.ts +9 -1
  58. package/src/capabilities/chart-series.ts +22 -6
  59. package/src/cli/bank-section.ts +1 -1
  60. package/src/cli/base-converter.ts +23 -14
  61. package/src/cli/central-bank-events.ts +1 -1
  62. package/src/cli/command-options.ts +59 -4
  63. package/src/cli/commands/api.ts +9 -6
  64. package/src/cli/commands/broker.ts +2 -2
  65. package/src/cli/commands/command-utils.ts +2 -2
  66. package/src/cli/commands/crypto-hints.ts +7 -20
  67. package/src/cli/commands/fred-series.ts +9 -2
  68. package/src/cli/commands/keybindings.ts +25 -2
  69. package/src/cli/commands/market.ts +1177 -278
  70. package/src/cli/commands/news-hints.ts +2 -2
  71. package/src/cli/commands/news-search.ts +59 -6
  72. package/src/cli/commands/options-chain.ts +59 -3
  73. package/src/cli/commands/options-leaps.ts +41 -26
  74. package/src/cli/commands/overview.ts +222 -61
  75. package/src/cli/commands/plugins.ts +9 -9
  76. package/src/cli/commands/remote.ts +13 -10
  77. package/src/cli/commands/search.ts +82 -46
  78. package/src/cli/commands/system.ts +27 -19
  79. package/src/cli/commands/themes.ts +1 -1
  80. package/src/cli/commands/ticker.ts +194 -48
  81. package/src/cli/context.ts +3 -2
  82. package/src/cli/desktop-pane-shot-view.ts +2 -2
  83. package/src/cli/desktop-pane-shot.ts +1 -1
  84. package/src/cli/earnings-calendar.ts +4 -4
  85. package/src/cli/entry.ts +18 -1
  86. package/src/cli/errors.ts +21 -3
  87. package/src/cli/exit-codes.ts +1 -1
  88. package/src/cli/export-source.ts +38 -4
  89. package/src/cli/freshness.ts +2 -8
  90. package/src/cli/fx-forward.ts +130 -0
  91. package/src/cli/fx-pair.ts +10 -9
  92. package/src/cli/glossary.ts +113 -20
  93. package/src/cli/help.ts +19 -13
  94. package/src/cli/history-export.ts +126 -0
  95. package/src/cli/history-rows.ts +226 -50
  96. package/src/cli/index-roots.ts +5 -45
  97. package/src/cli/index.ts +24 -18
  98. package/src/cli/known-gaps.ts +123 -27
  99. package/src/cli/listing-arg.ts +316 -46
  100. package/src/cli/name-entries.ts +30 -18
  101. package/src/cli/native-smoke.ts +2 -0
  102. package/src/cli/not-a-ticker.ts +19 -9
  103. package/src/cli/opentui-libc.ts +5 -0
  104. package/src/cli/options.ts +12 -0
  105. package/src/cli/pane-functions/capabilities.ts +75 -20
  106. package/src/cli/pane-functions/catalog.ts +24 -23
  107. package/src/cli/pane-functions/discovery.ts +1 -1
  108. package/src/cli/pane-functions/dom.ts +10 -7
  109. package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
  110. package/src/cli/pane-functions/freshness.ts +193 -30
  111. package/src/cli/pane-functions/function-help.ts +76 -30
  112. package/src/cli/pane-functions/headless.ts +59 -12
  113. package/src/cli/pane-functions/index.ts +28 -19
  114. package/src/cli/pane-functions/market-session.ts +15 -5
  115. package/src/cli/pane-functions/options.ts +22 -2
  116. package/src/cli/pane-functions/report-notices.ts +12 -4
  117. package/src/cli/pane-functions/report.ts +10 -6
  118. package/src/cli/pane-functions/resolver.ts +64 -11
  119. package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
  120. package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
  121. package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
  122. package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
  123. package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
  124. package/src/cli/pane-functions/screenshot-payload.ts +453 -0
  125. package/src/cli/pane-functions/screenshot-render.ts +316 -0
  126. package/src/cli/pane-functions/screenshot-types.ts +162 -0
  127. package/src/cli/pane-functions/shot-options.ts +8 -3
  128. package/src/cli/peso-dollar-rates.ts +79 -0
  129. package/src/cli/quote-answer.ts +45 -4
  130. package/src/cli/report-tables.ts +75 -19
  131. package/src/cli/restore-plugins.ts +42 -15
  132. package/src/cli/result.ts +164 -23
  133. package/src/cli/series-search.ts +5 -5
  134. package/src/cli/statement-filings.ts +19 -0
  135. package/src/cli/suffixed-listing-rows.ts +49 -0
  136. package/src/cli/symbol-args.ts +50 -15
  137. package/src/cli/symbol-cells.ts +120 -0
  138. package/src/cli/symbol-list.ts +198 -68
  139. package/src/cli/symbol-rows.ts +131 -25
  140. package/src/cli/ticker-resolution.ts +108 -11
  141. package/src/cli/treasury-yields.ts +5 -5
  142. package/src/cli/types.ts +2 -0
  143. package/src/cli/uncovered-instrument.ts +3 -3
  144. package/src/cli/unknown-command.ts +6 -6
  145. package/src/components/chart/composite/chart-layout.ts +131 -0
  146. package/src/components/chart/composite/composite-chart.tsx +395 -20
  147. package/src/components/chart/composite/format.ts +27 -0
  148. package/src/components/chart/composite/interactions.ts +7 -2
  149. package/src/components/chart/composite/legend.tsx +75 -3
  150. package/src/components/chart/composite/levels.ts +7 -0
  151. package/src/components/chart/composite/panel-gestures.ts +41 -0
  152. package/src/components/chart/composite/panel-labels.ts +2 -1
  153. package/src/components/chart/composite/panel-series.ts +1 -0
  154. package/src/components/chart/composite/panel-surface.tsx +314 -13
  155. package/src/components/chart/composite/price-axis-labels.tsx +27 -3
  156. package/src/components/chart/composite/range-statistics.ts +62 -0
  157. package/src/components/chart/composite/rasterizer.ts +44 -19
  158. package/src/components/chart/composite/scene.ts +20 -4
  159. package/src/components/chart/composite/series-axis-tags.tsx +16 -9
  160. package/src/components/chart/composite/text-renderer.ts +48 -21
  161. package/src/components/chart/composite/toolbar.tsx +52 -5
  162. package/src/components/chart/composite/types.ts +17 -0
  163. package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
  164. package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
  165. package/src/components/chart/composite/use-composite-viewport.ts +12 -3
  166. package/src/components/chart/composite/value-scale.ts +149 -0
  167. package/src/components/chart/composite/volume-profile-paint.ts +6 -3
  168. package/src/components/chart/core/pointer.ts +2 -0
  169. package/src/components/chart-table/index.ts +2 -0
  170. package/src/components/chart-table/read.tsx +74 -0
  171. package/src/components/command-bar/commands/collection-list.ts +41 -19
  172. package/src/components/command-bar/commands/collection.ts +9 -3
  173. package/src/components/command-bar/commands/direct/index.ts +1 -1
  174. package/src/components/command-bar/commands/direct/runtime.ts +3 -2
  175. package/src/components/command-bar/pane-templates/items.ts +59 -6
  176. package/src/components/command-bar/pane-templates/workflow.ts +10 -1
  177. package/src/components/command-bar/panel/prompt-binding.ts +0 -8
  178. package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
  179. package/src/components/command-bar/routes/root/provider-search.ts +42 -11
  180. package/src/components/command-bar/routes/root/results.ts +18 -4
  181. package/src/components/command-bar/routes/root/runtime.ts +15 -3
  182. package/src/components/command-bar/routes/root/search-providers.ts +25 -2
  183. package/src/components/command-bar/routes/root/selection.ts +6 -1
  184. package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
  185. package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
  186. package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
  187. package/src/components/command-bar/selection-runtime.ts +50 -10
  188. package/src/components/command-bar/surface/index.tsx +24 -2
  189. package/src/components/command-bar/view-model.ts +7 -0
  190. package/src/components/command-bar/workflow/alert.ts +1 -1
  191. package/src/components/command-bar/workflow/broker.ts +2 -2
  192. package/src/components/command-bar/workflow/collection-actions.ts +46 -7
  193. package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
  194. package/src/components/command-bar/workflow/fields.ts +8 -2
  195. package/src/components/command-bar/workflow/ops.ts +18 -4
  196. package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
  197. package/src/components/command-bar/workflow/submit.ts +3 -2
  198. package/src/components/command-bar/workflow/tickers.ts +5 -1
  199. package/src/components/company-logo.tsx +39 -0
  200. package/src/components/data-table/sections.ts +4 -2
  201. package/src/components/form-modal/confirm.tsx +2 -1
  202. package/src/components/form-modal/request.ts +5 -0
  203. package/src/components/form-modal/routes.ts +4 -1
  204. package/src/components/index.ts +12 -6
  205. package/src/components/layout/header.tsx +33 -46
  206. package/src/components/layout/market-summary.ts +9 -6
  207. package/src/components/layout/pane/capture-status.ts +1 -1
  208. package/src/components/layout/pane/footer/index.tsx +1 -0
  209. package/src/components/layout/pane/footer/model.ts +38 -5
  210. package/src/components/layout/shell/chrome.ts +19 -6
  211. package/src/components/layout/shell/index.tsx +2 -1
  212. package/src/components/layout/shell/pane/layers.tsx +19 -1
  213. package/src/components/layout/status-bar.tsx +2 -2
  214. package/src/components/market-board/index.tsx +11 -3
  215. package/src/components/onboarding/onboarding-frame.tsx +1 -1
  216. package/src/components/onboarding/onboarding-wizard.tsx +1 -0
  217. package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
  218. package/src/components/onboarding/portfolio-step/positions-panel.tsx +2 -2
  219. package/src/components/onboarding/wizard-broker-sync.ts +4 -1
  220. package/src/components/pane-settings-dialog/desktop.tsx +20 -7
  221. package/src/components/pane-settings-dialog/tui.tsx +17 -9
  222. package/src/components/pane-settings-dialog/value.ts +8 -1
  223. package/src/components/pane-settings-dialog.tsx +44 -13
  224. package/src/components/sign-in-code-panel.tsx +27 -19
  225. package/src/components/ui/column-grid.tsx +48 -4
  226. package/src/components/ui/country-flag-art.tsx +180 -0
  227. package/src/components/ui/country-flag.tsx +118 -12
  228. package/src/components/ui/data-table/opentui/index.tsx +61 -2
  229. package/src/components/ui/data-table/opentui/model.ts +109 -2
  230. package/src/components/ui/data-table/types.ts +1 -1
  231. package/src/components/ui/display.tsx +10 -2
  232. package/src/components/ui/index.ts +3 -1
  233. package/src/components/ui/logo-mark.tsx +11 -2
  234. package/src/components/ui/query-bar.tsx +1 -1
  235. package/src/components/ui/row-notes.ts +79 -0
  236. package/src/core/state/app/layout.ts +6 -4
  237. package/src/core/state/app/state.ts +9 -0
  238. package/src/core/state/app/types.ts +3 -0
  239. package/src/data/cached-query.ts +8 -1
  240. package/src/data/config/chart-settings.ts +3 -3
  241. package/src/data/config/home.ts +10 -2
  242. package/src/data/config/layout.ts +4 -1
  243. package/src/data/config/store/node.ts +4 -0
  244. package/src/data/config/store/normalize.ts +13 -3
  245. package/src/data/config/store/portfolio-as-of-column.ts +2 -2
  246. package/src/data/json-storage.ts +2 -0
  247. package/src/data/saved-copies.ts +123 -0
  248. package/src/docs/snapshot.json +422 -112
  249. package/src/i18n/es.ts +30 -13
  250. package/src/i18n/ja.ts +30 -13
  251. package/src/i18n/ko.ts +30 -13
  252. package/src/i18n/zh-cn.ts +30 -13
  253. package/src/i18n/zh-tw.ts +30 -13
  254. package/src/layout/desks.ts +1 -1
  255. package/src/layout/launch-layout.ts +1 -1
  256. package/src/layout/pane-manager/floating-actions.ts +5 -3
  257. package/src/layout/pane-manager/floating.ts +43 -1
  258. package/src/layout/pane-manager/index.ts +2 -0
  259. package/src/layout/selected-ticker.ts +74 -0
  260. package/src/market-data/coordinator/financials.ts +10 -2
  261. package/src/market-data/coordinator/index.ts +3 -1
  262. package/src/market-data/coordinator/quotes.ts +4 -2
  263. package/src/market-data/depositary-pair.ts +251 -0
  264. package/src/market-data/futures-board.ts +1 -1
  265. package/src/market-data/futures-contract.ts +124 -40
  266. package/src/market-data/fx-closes.ts +17 -2
  267. package/src/market-data/hooks.tsx +19 -11
  268. package/src/market-data/market/change-basis.ts +81 -11
  269. package/src/market-data/market/dated-previous-close.ts +203 -0
  270. package/src/market-data/market/freshness.ts +34 -5
  271. package/src/market-data/market/futures-week.ts +68 -0
  272. package/src/market-data/market/period-return.ts +163 -0
  273. package/src/market-data/market/status.ts +16 -4
  274. package/src/market-data/market/trading-sessions.ts +13 -0
  275. package/src/market-data/market/year-to-date.ts +8 -13
  276. package/src/market-data/options-alternatives.ts +60 -0
  277. package/src/market-data/performance.ts +20 -14
  278. package/src/market-data/perpetual-premium.ts +32 -0
  279. package/src/market-data/published-apac-sessions.ts +2 -1
  280. package/src/market-data/published-futures-sessions.ts +69 -0
  281. package/src/market-data/quotes/contributions.ts +25 -3
  282. package/src/market-data/quotes/freshness.ts +42 -0
  283. package/src/market-data/quotes/intraday-bar.ts +37 -0
  284. package/src/market-data/quotes/regular-session-valuation.ts +13 -8
  285. package/src/market-data/quotes/resolution.ts +7 -2
  286. package/src/market-data/selectors.ts +3 -0
  287. package/src/market-data/tax-equivalent.ts +1 -1
  288. package/src/market-data/ticker-price-returns.ts +3 -1
  289. package/src/news/aggregator.ts +5 -1
  290. package/src/news/news-model.ts +4 -0
  291. package/src/news/types.ts +11 -0
  292. package/src/notifications/app-notifier.ts +1 -1
  293. package/src/notifications/notification-log.ts +6 -4
  294. package/src/plugins/auto-update.ts +2 -2
  295. package/src/plugins/builtin/account-management/index.tsx +1 -0
  296. package/src/plugins/builtin/account-management/pane.tsx +9 -8
  297. package/src/plugins/builtin/alerts/alert-engine.ts +34 -20
  298. package/src/plugins/builtin/alerts/calendar-events.ts +429 -0
  299. package/src/plugins/builtin/alerts/cli.ts +533 -85
  300. package/src/plugins/builtin/alerts/command.ts +12 -10
  301. package/src/plugins/builtin/alerts/constants.ts +1 -1
  302. package/src/plugins/builtin/alerts/event-rows.ts +9 -5
  303. package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
  304. package/src/plugins/builtin/alerts/events.ts +107 -5
  305. package/src/plugins/builtin/alerts/fired-log.ts +119 -0
  306. package/src/plugins/builtin/alerts/format.ts +10 -3
  307. package/src/plugins/builtin/alerts/headless.ts +107 -41
  308. package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
  309. package/src/plugins/builtin/alerts/history-rows.ts +92 -0
  310. package/src/plugins/builtin/alerts/history.ts +2 -0
  311. package/src/plugins/builtin/alerts/index.tsx +107 -30
  312. package/src/plugins/builtin/alerts/iv-level.ts +365 -0
  313. package/src/plugins/builtin/alerts/levels.ts +3 -3
  314. package/src/plugins/builtin/alerts/live.ts +3 -3
  315. package/src/plugins/builtin/alerts/metric-command.ts +61 -0
  316. package/src/plugins/builtin/alerts/metric-data.ts +70 -0
  317. package/src/plugins/builtin/alerts/metric-model.ts +175 -0
  318. package/src/plugins/builtin/alerts/metric-parity-fixture.json +725 -0
  319. package/src/plugins/builtin/alerts/pane.tsx +130 -49
  320. package/src/plugins/builtin/alerts/price.ts +35 -0
  321. package/src/plugins/builtin/alerts/quotes.ts +24 -0
  322. package/src/plugins/builtin/alerts/research-builder.ts +84 -11
  323. package/src/plugins/builtin/alerts/research-rules.ts +76 -3
  324. package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
  325. package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
  326. package/src/plugins/builtin/alerts/scheduled.ts +188 -29
  327. package/src/plugins/builtin/alerts/storage.ts +38 -12
  328. package/src/plugins/builtin/alerts/targets.ts +12 -3
  329. package/src/plugins/builtin/alerts/types.ts +3 -0
  330. package/src/plugins/builtin/analytics/index.tsx +8 -2
  331. package/src/plugins/builtin/analytics/metrics.ts +1 -1
  332. package/src/plugins/builtin/analytics/risk-book.ts +215 -0
  333. package/src/plugins/builtin/analytics/risk-client.ts +13 -6
  334. package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
  335. package/src/plugins/builtin/analytics/risk-math.ts +6 -3
  336. package/src/plugins/builtin/analytics/risk-model.ts +297 -104
  337. package/src/plugins/builtin/analytics/risk-options.ts +17 -2
  338. package/src/plugins/builtin/analytics/risk-pane.tsx +97 -36
  339. package/src/plugins/builtin/attention/pane.tsx +6 -2
  340. package/src/plugins/builtin/awards/headless.ts +7 -3
  341. package/src/plugins/builtin/awards/model.ts +18 -0
  342. package/src/plugins/builtin/awards/pane.tsx +6 -3
  343. package/src/plugins/builtin/backtest/headless.ts +13 -8
  344. package/src/plugins/builtin/backtest/pane.tsx +9 -4
  345. package/src/plugins/builtin/backtest/presets.ts +29 -3
  346. package/src/plugins/builtin/backtest/rules.ts +41 -5
  347. package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
  348. package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
  349. package/src/plugins/builtin/broker-manager/footer.ts +27 -11
  350. package/src/plugins/builtin/broker-manager/index.tsx +24 -14
  351. package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
  352. package/src/plugins/builtin/broker-manager/model.ts +18 -3
  353. package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
  354. package/src/plugins/builtin/broker-manager/table.ts +28 -12
  355. package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
  356. package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
  357. package/src/plugins/builtin/broker-trading/controller.ts +66 -24
  358. package/src/plugins/builtin/broker-trading/dock.tsx +22 -4
  359. package/src/plugins/builtin/broker-trading/headless.ts +2 -1
  360. package/src/plugins/builtin/broker-trading/index.tsx +19 -1
  361. package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
  362. package/src/plugins/builtin/broker-trading/order-feed.ts +83 -10
  363. package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
  364. package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
  365. package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
  366. package/src/plugins/builtin/broker-trading/pane.tsx +111 -24
  367. package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
  368. package/src/plugins/builtin/broker-trading/ticket.tsx +112 -31
  369. package/src/plugins/builtin/buildout/cells.tsx +4 -0
  370. package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
  371. package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
  372. package/src/plugins/builtin/buildout/pane/index.tsx +25 -12
  373. package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
  374. package/src/plugins/builtin/builtin-plugin-meta.ts +2 -2
  375. package/src/plugins/builtin/catalysts/detail.tsx +3 -2
  376. package/src/plugins/builtin/catalysts/index.tsx +1 -1
  377. package/src/plugins/builtin/catalysts/model.ts +51 -5
  378. package/src/plugins/builtin/catalysts/pane.tsx +6 -8
  379. package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
  380. package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
  381. package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
  382. package/src/plugins/builtin/changelog/index.tsx +1 -0
  383. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +4 -1
  384. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +3 -2
  385. package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
  386. package/src/plugins/builtin/chart-composer/cli-options.ts +7 -10
  387. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +7 -3
  388. package/src/plugins/builtin/chart-composer/editor/controller.ts +4 -0
  389. package/src/plugins/builtin/chart-composer/editor/model.ts +2 -0
  390. package/src/plugins/builtin/chart-composer/editor.tsx +9 -4
  391. package/src/plugins/builtin/chart-composer/formula.ts +71 -18
  392. package/src/plugins/builtin/chart-composer/headless-schema.ts +42 -29
  393. package/src/plugins/builtin/chart-composer/headless.ts +266 -37
  394. package/src/plugins/builtin/chart-composer/index.tsx +12 -2
  395. package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
  396. package/src/plugins/builtin/chart-composer/pane.tsx +144 -30
  397. package/src/plugins/builtin/chart-composer/presets.ts +50 -15
  398. package/src/plugins/builtin/chart-composer/quick-add.tsx +40 -25
  399. package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
  400. package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
  401. package/src/plugins/builtin/chart-composer/session-history.ts +31 -28
  402. package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
  403. package/src/plugins/builtin/chart-composer/settings.ts +31 -19
  404. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +44 -31
  405. package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
  406. package/src/plugins/builtin/chat/attachments/model.ts +3 -1
  407. package/src/plugins/builtin/chat/content/command-suggestions.ts +92 -0
  408. package/src/plugins/builtin/chat/content/composer.tsx +13 -6
  409. package/src/plugins/builtin/chat/content/footer.tsx +6 -3
  410. package/src/plugins/builtin/chat/content/index.tsx +51 -22
  411. package/src/plugins/builtin/chat/content/open-targets.ts +14 -3
  412. package/src/plugins/builtin/chat/controller/session-runtime.ts +4 -2
  413. package/src/plugins/builtin/chat/index.tsx +23 -0
  414. package/src/plugins/builtin/chat/message/desktop.tsx +1 -0
  415. package/src/plugins/builtin/chat/message/inline-tokens.tsx +23 -0
  416. package/src/plugins/builtin/chat/message/pane-chip.tsx +50 -20
  417. package/src/plugins/builtin/chat/pane-links/commands.ts +265 -0
  418. package/src/plugins/builtin/chat/pane-links/model.ts +12 -3
  419. package/src/plugins/builtin/chat/pane-links/open.ts +9 -2
  420. package/src/plugins/builtin/chat/people.ts +1 -1
  421. package/src/plugins/builtin/chat/unread-inbox-pane.tsx +10 -1
  422. package/src/plugins/builtin/clinical-trials/client.ts +5 -2
  423. package/src/plugins/builtin/clinical-trials/model.ts +13 -4
  424. package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
  425. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
  426. package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
  427. package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
  428. package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
  429. package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
  430. package/src/plugins/builtin/cloud/plugin.tsx +1 -1
  431. package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
  432. package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
  433. package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
  434. package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
  435. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  436. package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
  437. package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
  438. package/src/plugins/builtin/commodity-balances/pane.tsx +11 -4
  439. package/src/plugins/builtin/company-attention/app-rank.tsx +7 -5
  440. package/src/plugins/builtin/company-attention/building-model.ts +222 -0
  441. package/src/plugins/builtin/company-attention/building.tsx +172 -0
  442. package/src/plugins/builtin/company-attention/client.ts +117 -1
  443. package/src/plugins/builtin/company-attention/evidence.ts +16 -3
  444. package/src/plugins/builtin/company-attention/headless.ts +101 -5
  445. package/src/plugins/builtin/company-attention/index.tsx +6 -3
  446. package/src/plugins/builtin/company-attention/model.ts +33 -7
  447. package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
  448. package/src/plugins/builtin/company-attention/moves.tsx +159 -0
  449. package/src/plugins/builtin/company-attention/pane.tsx +79 -23
  450. package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
  451. package/src/plugins/builtin/company-attention/signals.tsx +160 -0
  452. package/src/plugins/builtin/company-kpis/headless.ts +3 -2
  453. package/src/plugins/builtin/company-kpis/model.ts +2 -2
  454. package/src/plugins/builtin/company-kpis/pane.tsx +1 -1
  455. package/src/plugins/builtin/composite-plugins.ts +2 -1
  456. package/src/plugins/builtin/congress-trades/headless.ts +1 -1
  457. package/src/plugins/builtin/connections/index.ts +1 -0
  458. package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
  459. package/src/plugins/builtin/correlation/headless.ts +5 -3
  460. package/src/plugins/builtin/cot/headless.ts +28 -6
  461. package/src/plugins/builtin/cot/model.ts +12 -0
  462. package/src/plugins/builtin/cot/pane.tsx +3 -2
  463. package/src/plugins/builtin/cpi/headless.ts +5 -1
  464. package/src/plugins/builtin/cpi/pane.tsx +11 -9
  465. package/src/plugins/builtin/credit-boards/model.ts +2 -0
  466. package/src/plugins/builtin/credit-documents/headless.ts +1 -1
  467. package/src/plugins/builtin/crypto-board/client.ts +86 -0
  468. package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
  469. package/src/plugins/builtin/crypto-board/defi.ts +239 -0
  470. package/src/plugins/builtin/crypto-board/headless.ts +117 -6
  471. package/src/plugins/builtin/crypto-board/index.tsx +8 -3
  472. package/src/plugins/builtin/crypto-board/model.ts +40 -8
  473. package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
  474. package/src/plugins/builtin/crypto-board/series.ts +19 -1
  475. package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
  476. package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
  477. package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
  478. package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
  479. package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
  480. package/src/plugins/builtin/debug/index.tsx +1 -0
  481. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  482. package/src/plugins/builtin/docs/index.tsx +1 -1
  483. package/src/plugins/builtin/docs/pane.tsx +2 -2
  484. package/src/plugins/builtin/docs/targets.ts +1 -1
  485. package/src/plugins/builtin/doe/client.ts +5 -1
  486. package/src/plugins/builtin/doe/headless.ts +12 -6
  487. package/src/plugins/builtin/doe/model.ts +43 -6
  488. package/src/plugins/builtin/doe/pane.tsx +18 -11
  489. package/src/plugins/builtin/earnings/board-model.ts +13 -6
  490. package/src/plugins/builtin/earnings/board-table.ts +4 -1
  491. package/src/plugins/builtin/earnings/board.tsx +253 -50
  492. package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
  493. package/src/plugins/builtin/earnings/calendar.tsx +338 -0
  494. package/src/plugins/builtin/earnings/client.ts +4 -3
  495. package/src/plugins/builtin/earnings/headless.ts +53 -15
  496. package/src/plugins/builtin/earnings/history-model.ts +53 -36
  497. package/src/plugins/builtin/earnings/index.tsx +15 -22
  498. package/src/plugins/builtin/earnings/model.ts +17 -12
  499. package/src/plugins/builtin/earnings/scope.ts +89 -0
  500. package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
  501. package/src/plugins/builtin/earnings-calls/data.ts +146 -2
  502. package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
  503. package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
  504. package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
  505. package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
  506. package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
  507. package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
  508. package/src/plugins/builtin/econ/calendar-model.ts +144 -27
  509. package/src/plugins/builtin/econ/detail-view.tsx +48 -10
  510. package/src/plugins/builtin/econ/figures.ts +72 -0
  511. package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
  512. package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
  513. package/src/plugins/builtin/econ/index.tsx +144 -27
  514. package/src/plugins/builtin/econ/print-watch.ts +2 -1
  515. package/src/plugins/builtin/econ/types.ts +34 -1
  516. package/src/plugins/builtin/econ-statistics/client.ts +16 -3
  517. package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
  518. package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
  519. package/src/plugins/builtin/econ-statistics/headless.ts +87 -28
  520. package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
  521. package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
  522. package/src/plugins/builtin/econ-statistics/stats.ts +104 -0
  523. package/src/plugins/builtin/econ-statistics/view.ts +19 -1
  524. package/src/plugins/builtin/equity-screener/client.ts +21 -3
  525. package/src/plugins/builtin/equity-screener/headless.ts +68 -6
  526. package/src/plugins/builtin/equity-screener/live.ts +1 -1
  527. package/src/plugins/builtin/equity-screener/model.ts +6 -0
  528. package/src/plugins/builtin/equity-screener/pane.tsx +47 -12
  529. package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
  530. package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
  531. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
  532. package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
  533. package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
  534. package/src/plugins/builtin/exposure/charts.tsx +2 -2
  535. package/src/plugins/builtin/exposure/headless.ts +51 -6
  536. package/src/plugins/builtin/exposure/index.tsx +28 -2
  537. package/src/plugins/builtin/exposure/model.ts +20 -1
  538. package/src/plugins/builtin/exposure/pane.tsx +10 -5
  539. package/src/plugins/builtin/fear-greed/index.tsx +1 -1
  540. package/src/plugins/builtin/filing-events/index.tsx +1 -1
  541. package/src/plugins/builtin/futures/index.tsx +1 -0
  542. package/src/plugins/builtin/futures/model.ts +12 -10
  543. package/src/plugins/builtin/futures/returns.ts +8 -36
  544. package/src/plugins/builtin/futures/table.tsx +3 -3
  545. package/src/plugins/builtin/futures-curve/client.ts +40 -9
  546. package/src/plugins/builtin/futures-curve/headless.ts +39 -17
  547. package/src/plugins/builtin/futures-curve/model.ts +258 -69
  548. package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
  549. package/src/plugins/builtin/fx-matrix/client.ts +20 -8
  550. package/src/plugins/builtin/fx-matrix/headless.ts +37 -16
  551. package/src/plugins/builtin/fx-matrix/index.tsx +25 -13
  552. package/src/plugins/builtin/fx-matrix/live-legs.ts +34 -0
  553. package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
  554. package/src/plugins/builtin/gpu/headless.ts +9 -4
  555. package/src/plugins/builtin/help/index.tsx +13 -3
  556. package/src/plugins/builtin/help/keybindings-editor.tsx +18 -14
  557. package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
  558. package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
  559. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  560. package/src/plugins/builtin/holders/client.ts +13 -1
  561. package/src/plugins/builtin/holders/format.ts +28 -17
  562. package/src/plugins/builtin/holders/headless.ts +46 -7
  563. package/src/plugins/builtin/holders/index-holders.ts +264 -0
  564. package/src/plugins/builtin/holders/pane.tsx +79 -15
  565. package/src/plugins/builtin/holders/report-rows.ts +35 -7
  566. package/src/plugins/builtin/holders/table-model.ts +2 -1
  567. package/src/plugins/builtin/holders/treemap.tsx +2 -2
  568. package/src/plugins/builtin/insider/headless.ts +1 -1
  569. package/src/plugins/builtin/insider/signals-client.ts +1 -1
  570. package/src/plugins/builtin/insider/signals.tsx +1 -1
  571. package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
  572. package/src/plugins/builtin/iv-history/client.ts +20 -0
  573. package/src/plugins/builtin/iv-history/headless.ts +7 -4
  574. package/src/plugins/builtin/iv-history/index.tsx +1 -1
  575. package/src/plugins/builtin/iv-history/model.ts +13 -4
  576. package/src/plugins/builtin/iv-history/series.ts +3 -1
  577. package/src/plugins/builtin/jobs/lock-note.ts +1 -1
  578. package/src/plugins/builtin/jobs/model.ts +4 -15
  579. package/src/plugins/builtin/jobs/pane.tsx +7 -5
  580. package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
  581. package/src/plugins/builtin/jodi/pane.tsx +10 -4
  582. package/src/plugins/builtin/layout-manager/index.tsx +1 -0
  583. package/src/plugins/builtin/macro-day/headless.ts +20 -7
  584. package/src/plugins/builtin/macro-day/index.tsx +3 -2
  585. package/src/plugins/builtin/macro-day/model.ts +29 -8
  586. package/src/plugins/builtin/macro-day/pane.tsx +51 -13
  587. package/src/plugins/builtin/macro-day/releases.ts +55 -13
  588. package/src/plugins/builtin/market-heatmap/data.ts +9 -2
  589. package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
  590. package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
  591. package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
  592. package/src/plugins/builtin/market-heatmap/model.ts +10 -7
  593. package/src/plugins/builtin/market-movers/client.ts +33 -19
  594. package/src/plugins/builtin/market-movers/footer.ts +2 -2
  595. package/src/plugins/builtin/market-movers/headless.ts +8 -2
  596. package/src/plugins/builtin/market-movers/index.tsx +16 -10
  597. package/src/plugins/builtin/market-movers/screener.ts +29 -8
  598. package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
  599. package/src/plugins/builtin/market-movers/session-table.ts +4 -2
  600. package/src/plugins/builtin/market-movers/table.ts +4 -1
  601. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  602. package/src/plugins/builtin/market-valuation/view.ts +5 -0
  603. package/src/plugins/builtin/members/breadth-pane.tsx +81 -0
  604. package/src/plugins/builtin/members/client.ts +19 -4
  605. package/src/plugins/builtin/members/headless.ts +24 -10
  606. package/src/plugins/builtin/members/index.tsx +9 -9
  607. package/src/plugins/builtin/members/model.ts +23 -4
  608. package/src/plugins/builtin/members/pane.tsx +31 -14
  609. package/src/plugins/builtin/mna/client.ts +1 -0
  610. package/src/plugins/builtin/mna/detail.tsx +20 -32
  611. package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
  612. package/src/plugins/builtin/mna/distress/model.ts +3 -2
  613. package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
  614. package/src/plugins/builtin/mna/headless.ts +6 -13
  615. package/src/plugins/builtin/mna/model.ts +93 -15
  616. package/src/plugins/builtin/mna/pane.tsx +5 -4
  617. package/src/plugins/builtin/news/headless.ts +12 -6
  618. package/src/plugins/builtin/news/index.tsx +10 -1
  619. package/src/plugins/builtin/news/wire/index.tsx +3 -2
  620. package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
  621. package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
  622. package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
  623. package/src/plugins/builtin/notes/cli.ts +49 -14
  624. package/src/plugins/builtin/openfda/pane.tsx +1 -1
  625. package/src/plugins/builtin/options/analytics.ts +26 -2
  626. package/src/plugins/builtin/options/carry.ts +2 -2
  627. package/src/plugins/builtin/options/index.tsx +1 -1
  628. package/src/plugins/builtin/options/model-spot.ts +5 -2
  629. package/src/plugins/builtin/options/strike-window.ts +2 -1
  630. package/src/plugins/builtin/options/table.ts +1 -7
  631. package/src/plugins/builtin/options/view.tsx +30 -13
  632. package/src/plugins/builtin/options-calculator/headless.ts +46 -7
  633. package/src/plugins/builtin/options-positioning/client.ts +19 -0
  634. package/src/plugins/builtin/options-positioning/headless.ts +54 -14
  635. package/src/plugins/builtin/options-positioning/index.tsx +3 -3
  636. package/src/plugins/builtin/options-positioning/model.ts +47 -8
  637. package/src/plugins/builtin/options-positioning/pane.tsx +68 -38
  638. package/src/plugins/builtin/options-scenario/client.ts +123 -28
  639. package/src/plugins/builtin/options-scenario/collar.ts +8 -6
  640. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
  641. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
  642. package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
  643. package/src/plugins/builtin/options-scenario/csp.ts +101 -21
  644. package/src/plugins/builtin/options-scenario/headless.ts +36 -15
  645. package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
  646. package/src/plugins/builtin/options-scenario/index.tsx +28 -3
  647. package/src/plugins/builtin/options-scenario/model.ts +13 -0
  648. package/src/plugins/builtin/options-scenario/pane.tsx +9 -5
  649. package/src/plugins/builtin/perps/equity-row.tsx +11 -3
  650. package/src/plugins/builtin/perps/freshness.ts +14 -9
  651. package/src/plugins/builtin/perps/headless.ts +3 -1
  652. package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
  653. package/src/plugins/builtin/perps/live-rows.ts +168 -0
  654. package/src/plugins/builtin/perps/markets-section.tsx +154 -0
  655. package/src/plugins/builtin/perps/pane.tsx +49 -26
  656. package/src/plugins/builtin/perps/venue-markets.ts +96 -0
  657. package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
  658. package/src/plugins/builtin/plugin-marketplace/pane.tsx +143 -59
  659. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +72 -24
  660. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
  661. package/src/plugins/builtin/portfolio-list/cli/render.ts +54 -22
  662. package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
  663. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
  664. package/src/plugins/builtin/portfolio-list/headless.ts +7 -4
  665. package/src/plugins/builtin/portfolio-list/income.ts +13 -2
  666. package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
  667. package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
  668. package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
  669. package/src/plugins/builtin/portfolio-list/summary/index.tsx +11 -8
  670. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
  671. package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
  672. package/src/plugins/builtin/power/client.ts +4 -1
  673. package/src/plugins/builtin/power/evidence.ts +22 -7
  674. package/src/plugins/builtin/power/gas.tsx +5 -1
  675. package/src/plugins/builtin/power/pane.tsx +8 -1
  676. package/src/plugins/builtin/power/prices.tsx +10 -3
  677. package/src/plugins/builtin/rate-path/pane.tsx +2 -2
  678. package/src/plugins/builtin/research/analyst-headless.ts +25 -8
  679. package/src/plugins/builtin/research/analyst-model.ts +68 -3
  680. package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
  681. package/src/plugins/builtin/research/event-model.ts +3 -1
  682. package/src/plugins/builtin/research/event-sources.ts +12 -4
  683. package/src/plugins/builtin/research/index.tsx +2 -1
  684. package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
  685. package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
  686. package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
  687. package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
  688. package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
  689. package/src/plugins/builtin/research/relative-valuation-pane.tsx +80 -13
  690. package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
  691. package/src/plugins/builtin/reverse-dcf/model.ts +6 -2
  692. package/src/plugins/builtin/risk-factors/index.tsx +2 -2
  693. package/src/plugins/builtin/scanner/feed.ts +2 -2
  694. package/src/plugins/builtin/scanner/index.ts +24 -1
  695. package/src/plugins/builtin/scanner/live-condition-editor.tsx +222 -0
  696. package/src/plugins/builtin/scanner/live-feed.ts +168 -0
  697. package/src/plugins/builtin/scanner/live-headless.ts +114 -0
  698. package/src/plugins/builtin/scanner/live-model.ts +351 -0
  699. package/src/plugins/builtin/scanner/live-pane.tsx +677 -0
  700. package/src/plugins/builtin/scanner/live-track.ts +186 -0
  701. package/src/plugins/builtin/scanner/lock-note.ts +1 -1
  702. package/src/plugins/builtin/sec/forms.ts +13 -0
  703. package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
  704. package/src/plugins/builtin/sec/fund-facts.ts +68 -8
  705. package/src/plugins/builtin/sec/headless.ts +85 -8
  706. package/src/plugins/builtin/sec/index.tsx +58 -12
  707. package/src/plugins/builtin/sectors/client.ts +2 -1
  708. package/src/plugins/builtin/sectors/sector-model.ts +11 -15
  709. package/src/plugins/builtin/series-inventory.ts +3 -0
  710. package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
  711. package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
  712. package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
  713. package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
  714. package/src/plugins/builtin/shared/earnings-report.ts +3 -3
  715. package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
  716. package/src/plugins/builtin/shared/job-posting.ts +129 -0
  717. package/src/plugins/builtin/shared/macro-releases.ts +65 -0
  718. package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
  719. package/src/plugins/builtin/shared/report-freshness.ts +3 -0
  720. package/src/plugins/builtin/shared/research-trading.tsx +21 -0
  721. package/src/plugins/builtin/shared/scanner-capture.ts +3 -0
  722. package/src/plugins/builtin/shared/series-cache.ts +2 -0
  723. package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
  724. package/src/plugins/builtin/shared/use-quote-board.ts +8 -2
  725. package/src/plugins/builtin/shared/volatility/pricing.ts +7 -1
  726. package/src/plugins/builtin/short-interest/client.ts +2 -0
  727. package/src/plugins/builtin/short-interest/headless.ts +41 -12
  728. package/src/plugins/builtin/short-interest/index.tsx +23 -1
  729. package/src/plugins/builtin/short-interest/model.ts +70 -19
  730. package/src/plugins/builtin/short-interest/pane.tsx +19 -2
  731. package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
  732. package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
  733. package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
  734. package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
  735. package/src/plugins/builtin/short-interest/schedule.ts +35 -2
  736. package/src/plugins/builtin/short-interest/surface.tsx +11 -4
  737. package/src/plugins/builtin/short-interest/types.ts +9 -0
  738. package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
  739. package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
  740. package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
  741. package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
  742. package/src/plugins/builtin/supply-chain/model.ts +51 -3
  743. package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
  744. package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
  745. package/src/plugins/builtin/themes/headless.ts +11 -6
  746. package/src/plugins/builtin/themes/model.ts +15 -5
  747. package/src/plugins/builtin/themes/pane.tsx +27 -8
  748. package/src/plugins/builtin/thirteenf/headless.ts +5 -5
  749. package/src/plugins/builtin/thirteenf/signals.ts +3 -1
  750. package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
  751. package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
  752. package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
  753. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
  754. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
  755. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
  756. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
  757. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
  758. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
  759. package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
  760. package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
  761. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
  762. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
  763. package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
  764. package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
  765. package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
  766. package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
  767. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
  768. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
  769. package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
  770. package/src/plugins/builtin/ticker-detail/quote-footer.ts +14 -4
  771. package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
  772. package/src/plugins/builtin/vol-surface/charts.tsx +9 -4
  773. package/src/plugins/builtin/vol-surface/client.ts +7 -4
  774. package/src/plugins/builtin/vol-surface/headless.ts +71 -13
  775. package/src/plugins/builtin/vol-surface/index.tsx +2 -2
  776. package/src/plugins/builtin/vol-surface/model.ts +26 -9
  777. package/src/plugins/builtin/vol-surface/pane.tsx +44 -7
  778. package/src/plugins/builtin/vol-surface/tables.ts +31 -3
  779. package/src/plugins/builtin/volatility/dvol.ts +46 -0
  780. package/src/plugins/builtin/volatility/model.ts +5 -10
  781. package/src/plugins/builtin/volatility/pane.tsx +2 -2
  782. package/src/plugins/builtin/volatility/series.ts +26 -0
  783. package/src/plugins/builtin/world-indices/footer.ts +1 -1
  784. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
  785. package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
  786. package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
  787. package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
  788. package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
  789. package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
  790. package/src/plugins/builtin/world-venue-map/index.ts +3 -26
  791. package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
  792. package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
  793. package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
  794. package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
  795. package/src/plugins/builtin/yield-curve/client.ts +25 -0
  796. package/src/plugins/builtin/yield-curve/curves.ts +7 -4
  797. package/src/plugins/builtin/yield-curve/headless.ts +38 -4
  798. package/src/plugins/builtin/yield-curve/history.ts +4 -3
  799. package/src/plugins/builtin/yield-curve/index.tsx +12 -6
  800. package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
  801. package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
  802. package/src/plugins/bundle.ts +1 -1
  803. package/src/plugins/catalog-browser.ts +15 -9
  804. package/src/plugins/compat.ts +3 -3
  805. package/src/plugins/dependencies.ts +75 -14
  806. package/src/plugins/extracted-plugins.ts +132 -34
  807. package/src/plugins/host-link.ts +149 -34
  808. package/src/plugins/installer.ts +35 -10
  809. package/src/plugins/loader.ts +206 -38
  810. package/src/plugins/manager-node.ts +2 -2
  811. package/src/plugins/marketplace/deactivation.ts +22 -0
  812. package/src/plugins/marketplace/model.ts +2 -2
  813. package/src/plugins/marketplace/packs.ts +1 -1
  814. package/src/plugins/ownership.ts +1 -1
  815. package/src/plugins/peer-retry.ts +155 -0
  816. package/src/plugins/registry/contributions.ts +3 -1
  817. package/src/plugins/registry/index.ts +4 -3
  818. package/src/plugins/registry/plugin-state.ts +3 -0
  819. package/src/plugins/seed-notice.ts +20 -0
  820. package/src/plugins/shortcut-argument.ts +39 -0
  821. package/src/portfolio/allocation.ts +1 -1
  822. package/src/portfolio/collection-name.ts +31 -0
  823. package/src/portfolio/column-values.ts +15 -13
  824. package/src/portfolio/cost-fx.ts +296 -19
  825. package/src/portfolio/manual-lots.ts +75 -0
  826. package/src/portfolio/mutations.ts +60 -22
  827. package/src/portfolio/suffixed-listings.ts +209 -0
  828. package/src/portfolio/totals-currency.ts +24 -0
  829. package/src/public/__snapshots__/public-api.test.ts.snap +15 -0
  830. package/src/public/time-series.ts +11 -8
  831. package/src/remote/schema.ts +1 -1
  832. package/src/renderers/browser/app-services.ts +1 -7
  833. package/src/renderers/browser/config-host.ts +5 -55
  834. package/src/renderers/browser/main.tsx +30 -60
  835. package/src/renderers/dom/boot-frame-page.ts +187 -0
  836. package/src/renderers/dom/boot-frame.ts +237 -0
  837. package/src/renderers/dom/build-assets.ts +46 -8
  838. package/src/renderers/dom/dom-ui-host.tsx +4 -29
  839. package/src/renderers/dom/host/ascii-text.ts +16 -2
  840. package/src/renderers/dom/host/box.tsx +43 -2
  841. package/src/renderers/dom/host/chart-surface.tsx +2 -0
  842. package/src/renderers/dom/host/hls.chunk.ts +3 -0
  843. package/src/renderers/dom/host/image-surface.tsx +49 -0
  844. package/src/renderers/dom/host/media-surface.tsx +24 -18
  845. package/src/renderers/dom/host/mouse.ts +30 -0
  846. package/src/renderers/dom/host/size-observer.ts +1 -1
  847. package/src/renderers/dom/host/style.ts +1 -1
  848. package/src/renderers/dom/styles.css +76 -0
  849. package/src/renderers/dom/test-utils.tsx +2 -1
  850. package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
  851. package/src/renderers/electrobun/bun/desktop/app-name.ts +222 -0
  852. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
  853. package/src/renderers/electrobun/bun/desktop/backend.ts +56 -3
  854. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
  855. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
  856. package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
  857. package/src/renderers/electrobun/bun/desktop/relaunch.ts +74 -25
  858. package/src/renderers/electrobun/bun/desktop/state-broadcaster.ts +1 -0
  859. package/src/renderers/electrobun/bun/desktop/update.ts +70 -3
  860. package/src/renderers/electrobun/bun/desktop/workspace/index.ts +2 -0
  861. package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
  862. package/src/renderers/electrobun/bun/index.ts +36 -2
  863. package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
  864. package/src/renderers/electrobun/bun/window/create.ts +4 -1
  865. package/src/renderers/electrobun/shared/app-name.ts +17 -0
  866. package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
  867. package/src/renderers/electrobun/shared/protocol.ts +6 -1
  868. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
  869. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +3 -3
  870. package/src/renderers/electrobun/view/config-host.ts +3 -0
  871. package/src/renderers/electrobun/view/desktop/window/snapshot.ts +1 -0
  872. package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
  873. package/src/renderers/electrobun/view/main.tsx +30 -4
  874. package/src/renderers/electrobun/view/news-source.ts +5 -5
  875. package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -1
  876. package/src/renderers/electrobun/view/ui-host.tsx +1 -1
  877. package/src/renderers/opentui/browser-open.ts +88 -0
  878. package/src/renderers/opentui/host.tsx +5 -14
  879. package/src/renderers/opentui/image/loader.ts +3 -2
  880. package/src/renderers/opentui/native-smoke.ts +10 -1
  881. package/src/renderers/opentui/pane-image/index.ts +2 -1
  882. package/src/renderers/opentui/render-lib.ts +253 -0
  883. package/src/renderers/opentui/render-timing-smoke.ts +1 -1
  884. package/src/renderers/opentui/start.tsx +1 -1
  885. package/src/renderers/opentui/toast-host.tsx +71 -43
  886. package/src/renderers/share/layout-view.tsx +2 -2
  887. package/src/renderers/share/main.tsx +4 -4
  888. package/src/renderers/share/view.tsx +1 -1
  889. package/src/series/resolve.ts +22 -6
  890. package/src/series/standalone.ts +30 -2
  891. package/src/series/types.ts +8 -1
  892. package/src/shares/api.ts +4 -1
  893. package/src/shares/pane.ts +1 -1
  894. package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
  895. package/src/sources/gloomberb-cloud/index.ts +32 -16
  896. package/src/sources/gloomberb-cloud/news.ts +39 -0
  897. package/src/sources/gloomberb-cloud/normalizers.ts +16 -1
  898. package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
  899. package/src/sources/listing-symbols.ts +37 -0
  900. package/src/sources/provider-errors.ts +16 -2
  901. package/src/sources/provider-router/batches.ts +10 -2
  902. package/src/sources/provider-router/financial-routes.ts +21 -3
  903. package/src/sources/provider-router/financials.ts +15 -2
  904. package/src/sources/provider-router/history.ts +58 -15
  905. package/src/sources/provider-router/index.ts +146 -10
  906. package/src/sources/provider-router/primary.ts +1 -1
  907. package/src/sources/provider-router/search.ts +13 -2
  908. package/src/state/app/bootstrap.ts +23 -0
  909. package/src/state/app/context/index.tsx +3 -0
  910. package/src/state/hooks/inline-tickers.ts +30 -5
  911. package/src/sync/auth-transition.ts +19 -9
  912. package/src/sync/baseline.ts +10 -4
  913. package/src/sync/controller.ts +67 -17
  914. package/src/sync/core-contributors.ts +46 -14
  915. package/src/sync/react.ts +4 -1
  916. package/src/sync/types.ts +3 -0
  917. package/src/team/collections-sync.ts +2 -1
  918. package/src/team/collections.ts +178 -17
  919. package/src/telemetry/crash-reports.ts +17 -4
  920. package/src/telemetry/usage-counts.ts +0 -18
  921. package/src/test-support/builtin-panes.ts +1 -1
  922. package/src/theme/colors.ts +11 -30
  923. package/src/theme/ui-tokens.ts +37 -1
  924. package/src/tickers/company-name-listing.ts +210 -33
  925. package/src/tickers/company-name.ts +59 -0
  926. package/src/tickers/index-roots.ts +47 -0
  927. package/src/tickers/instrument-label.ts +5 -1
  928. package/src/tickers/listing-venues.ts +23 -0
  929. package/src/tickers/metadata.ts +10 -0
  930. package/src/tickers/perpetual-listing.ts +5 -2
  931. package/src/tickers/search/bare-symbol.ts +36 -0
  932. package/src/tickers/search/home-listing.ts +75 -0
  933. package/src/tickers/search/index.ts +111 -33
  934. package/src/tickers/search/ranking.ts +64 -5
  935. package/src/tickers/search/types.ts +5 -0
  936. package/src/tickers/search/upsert.ts +29 -0
  937. package/src/tickers/terminal-codes.ts +416 -40
  938. package/src/time-series/bar-aggregation.ts +243 -0
  939. package/src/time-series/base-series.ts +315 -0
  940. package/src/time-series/chart-bounds.ts +349 -0
  941. package/src/time-series/chart-seed.ts +142 -0
  942. package/src/time-series/daily-valuation.ts +62 -0
  943. package/src/time-series/economic.ts +5 -0
  944. package/src/time-series/field-catalog.ts +1 -3
  945. package/src/time-series/forward-valuation.ts +32 -0
  946. package/src/time-series/fundamentals.ts +173 -10
  947. package/src/time-series/history-acquisition.ts +499 -0
  948. package/src/time-series/hooks.ts +1 -0
  949. package/src/time-series/leverage.ts +100 -0
  950. package/src/time-series/market-resolution.ts +4 -2
  951. package/src/time-series/market.ts +2 -1
  952. package/src/time-series/price-comparison.ts +175 -30
  953. package/src/time-series/price-units.ts +72 -2
  954. package/src/time-series/range.ts +9 -1
  955. package/src/time-series/resolution.ts +174 -16
  956. package/src/time-series/resolve-context.ts +161 -0
  957. package/src/time-series/resolve.ts +185 -1587
  958. package/src/time-series/series-name.ts +38 -0
  959. package/src/time-series/series-presentation.ts +242 -0
  960. package/src/time-series/spec.ts +13 -7
  961. package/src/time-series/studies.ts +377 -82
  962. package/src/time-series/tail-reconcile.ts +121 -0
  963. package/src/time-series/transforms.ts +1 -0
  964. package/src/time-series/types.ts +34 -2
  965. package/src/time-series/use-chart-resolution.ts +4 -5
  966. package/src/time-series/valuation-releases.ts +39 -0
  967. package/src/types/broker.ts +10 -0
  968. package/src/types/config.ts +14 -0
  969. package/src/types/data-provider.ts +23 -1
  970. package/src/types/desktop-window.ts +2 -0
  971. package/src/types/exchange-rate.ts +6 -0
  972. package/src/types/financials.ts +145 -8
  973. package/src/types/headless.ts +117 -9
  974. package/src/types/instrument.ts +6 -0
  975. package/src/types/plugin.ts +66 -9
  976. package/src/types/price-history.ts +2 -0
  977. package/src/types/ticker.ts +13 -0
  978. package/src/types/trading.ts +59 -1
  979. package/src/ui/ascii-font.ts +13 -1
  980. package/src/ui/host.tsx +6 -1
  981. package/src/updater/command-names.ts +180 -0
  982. package/src/updater/index.ts +10 -5
  983. package/src/utils/calendar-date.ts +32 -15
  984. package/src/utils/cash-runway.ts +241 -0
  985. package/src/utils/central-banks.ts +42 -0
  986. package/src/utils/cli-output.ts +259 -80
  987. package/src/utils/contract-month.ts +16 -0
  988. package/src/utils/crypto-pair.ts +61 -3
  989. package/src/utils/currency-units.ts +29 -0
  990. package/src/utils/datetime-format.ts +10 -0
  991. package/src/utils/debug-log.ts +1 -1
  992. package/src/utils/decimal-comma.ts +39 -6
  993. package/src/utils/exchange-announcements.ts +71 -0
  994. package/src/utils/exchange-rate-snapshot.ts +10 -0
  995. package/src/utils/financial-statements.ts +89 -5
  996. package/src/utils/format.ts +34 -16
  997. package/src/utils/fundamentals.ts +150 -34
  998. package/src/utils/fx-market-hours.ts +10 -1
  999. package/src/utils/latest-financial-period.ts +8 -0
  1000. package/src/utils/linux-libc.ts +54 -0
  1001. package/src/utils/market-capitalization.ts +111 -15
  1002. package/src/utils/max-drawdown.ts +64 -0
  1003. package/src/utils/network-failure.ts +86 -0
  1004. package/src/utils/option-expiry.ts +186 -7
  1005. package/src/utils/options.ts +10 -0
  1006. package/src/utils/plugin-proxy-hosts.json +1 -0
  1007. package/src/utils/price-earnings.ts +11 -5
  1008. package/src/utils/price-history.ts +23 -8
  1009. package/src/utils/price-window.ts +131 -0
  1010. package/src/utils/release-date.ts +47 -0
  1011. package/src/utils/sec.ts +3 -0
  1012. package/src/utils/throttled-fetch.ts +11 -4
  1013. package/src/utils/trailing-eps.ts +67 -0
  1014. package/src/utils/typed-text.ts +21 -0
  1015. package/src/utils/utc-time.ts +24 -1
  1016. package/src/version.ts +6 -0
  1017. package/src/cli/pane-functions/screenshot.ts +0 -2122
  1018. package/src/renderers/browser/first-screen.ts +0 -193
@@ -69,12 +69,57 @@ import {
69
69
  MembersSection,
70
70
  SettingsSection,
71
71
  } from "./pane-sections";
72
- import { Muted, PaneButton, TeamPaneFocusContext, type TeamPaneFocus } from "./pane-ui";
72
+ import { Muted, PaneButton, RowReason, RowStatus, TeamPaneFocusContext, type TeamPaneFocus, type TeamRowState } from "./pane-ui";
73
73
  import { teamStore } from "../../../../team/store";
74
74
  import { logFailure } from "../../../../utils/log-failure";
75
+ import { useRowNotes } from "../../../../components/ui/row-notes";
76
+ import { wrapTextLines } from "../../../../utils/text-wrap";
75
77
 
76
78
  type Message = { tone: "info" | "success" | "error"; text: string } | null;
77
79
 
80
+ /**
81
+ * What the last action on one row (a member, an invitation, a link, a
82
+ * channel, an invitation to me) came to, said on that row: `status` in its
83
+ * status cell, `text` under it while one of its controls holds the ring.
84
+ * Keyed `member:<id>`, `invitation:<id>`, `link:<token>`, `channel:<id>`,
85
+ * `received:<id>`.
86
+ */
87
+ interface RowNote {
88
+ status: string;
89
+ text: string;
90
+ tone: "negative" | "warning";
91
+ }
92
+
93
+ /** An action on one row: its key, what its status cell says while it runs (none when its button says it), and if it fails. */
94
+ interface RowAction {
95
+ row: string;
96
+ verb?: string;
97
+ failure: string;
98
+ }
99
+
100
+ type TeamForm = "invite" | "link" | "channel";
101
+
102
+ const NO_ROWS: readonly string[] = [];
103
+ const rowKey = (row: string) => row;
104
+
105
+ /** The row a control of the ring belongs to: `remove:m-1` is the member m-1's. */
106
+ const FIELD_ROWS: Readonly<Record<string, string>> = {
107
+ role: "member",
108
+ remove: "member",
109
+ "cancel-invitation": "invitation",
110
+ "copy-link": "link",
111
+ "revoke-link": "link",
112
+ "open-channel": "channel",
113
+ "delete-channel": "channel",
114
+ accept: "received",
115
+ decline: "received",
116
+ };
117
+ function fieldRow(field: string | null): string | null {
118
+ const split = field?.indexOf(":") ?? -1;
119
+ const kind = field && split > 0 ? FIELD_ROWS[field.slice(0, split)] : undefined;
120
+ return kind ? `${kind}:${field!.slice(split + 1)}` : null;
121
+ }
122
+
78
123
  const TEAM_RING_SCOPE = "team-pane:ring";
79
124
 
80
125
  function errorText(error: unknown, fallback: string): string {
@@ -173,38 +218,50 @@ function InvitationBanner({
173
218
  invitation,
174
219
  width,
175
220
  busy,
221
+ state,
176
222
  onAccept,
177
223
  onDecline,
178
224
  }: {
179
225
  invitation: TeamReceivedInvitation;
180
226
  width: number;
181
227
  busy: boolean;
228
+ state?: TeamRowState;
182
229
  onAccept: () => void;
183
230
  onDecline: () => void;
184
231
  }) {
185
232
  const accent = teamAccentHex(invitation.team.accentColor);
233
+ // One shape with or without a reason, so the banner's own box is never restyled into its wrapper.
186
234
  return (
187
- <Box
188
- flexDirection="row"
189
- width={width}
190
- height={1}
191
- alignItems="center"
192
- gap={1}
193
- backgroundColor={colors.panel}
194
- paddingX={1}
195
- >
196
- <Text fg={accent} attributes={TextAttributes.BOLD}>{`${teamPrefix(invitation.team)} ${invitation.team.name}`}</Text>
197
- <Text fg={colors.text}>
198
- {`${userHandle(invitation.inviter)} invited you · ${describeMemberCount(invitation.team.memberCount)} · ${describeExpiry(invitation.expiresAt)}`}
199
- </Text>
200
- <Box flexGrow={1} />
201
- {/* In the keyboard ring, ahead of the section below. */}
202
- <PaneButton id={`accept:${invitation.id}`} label={busy ? "Joining…" : "Accept"} variant="primary" compact disabled={busy} onPress={onAccept} />
203
- <PaneButton id={`decline:${invitation.id}`} label="Decline" variant="ghost" compact disabled={busy} onPress={onDecline} />
235
+ <Box flexDirection="column" width={width}>
236
+ <Box
237
+ flexDirection="row"
238
+ width={width}
239
+ height={1}
240
+ alignItems="center"
241
+ gap={1}
242
+ backgroundColor={colors.panel}
243
+ paddingX={1}
244
+ >
245
+ <Text fg={accent} attributes={TextAttributes.BOLD}>{`${teamPrefix(invitation.team)} ${invitation.team.name}`}</Text>
246
+ <Text fg={colors.text}>
247
+ {`${userHandle(invitation.inviter)} invited you · ${describeMemberCount(invitation.team.memberCount)} · ${describeExpiry(invitation.expiresAt)}`}
248
+ </Text>
249
+ <Box flexGrow={1} />
250
+ <RowStatus state={state} />
251
+ {/* In the keyboard ring, ahead of the section below. */}
252
+ <PaneButton id={`accept:${invitation.id}`} label={busy ? "Joining…" : "Accept"} variant="primary" compact disabled={busy} onPress={onAccept} />
253
+ <PaneButton id={`decline:${invitation.id}`} label="Decline" variant="ghost" compact disabled={busy} onPress={onDecline} />
254
+ </Box>
255
+ <RowReason state={state} width={width} indent={1} />
204
256
  </Box>
205
257
  );
206
258
  }
207
259
 
260
+ /** The lines a banner takes: itself, and its reason while shown. */
261
+ function bannerRows(state: TeamRowState | undefined, width: number): number {
262
+ return 1 + (state?.reason ? wrapTextLines(state.reason, Math.max(8, width - 1)).length : 0);
263
+ }
264
+
208
265
  export function TeamPane({ focused, width, height, close }: PaneProps) {
209
266
  const { createPaneFromTemplate, notify } = usePluginAppActions();
210
267
  const rendererHost = useRendererHost();
@@ -230,6 +287,15 @@ export function TeamPane({ focused, width, height, close }: PaneProps) {
230
287
  const [channelName, setChannelName] = useState("");
231
288
  const [busy, setBusy] = useState<string | null>(null);
232
289
  const [message, setMessage] = useState<Message>(null);
290
+ // What an action on one row is doing, and what the last one came to (RowNote): said on that row.
291
+ const [busyRow, setBusyRow] = useState<{ row: string; verb?: string } | null>(null);
292
+ const { noteFor, setNote: setRowNote, clearNotes } = useRowNotes<string, RowNote>(NO_ROWS, { key: rowKey });
293
+ // What stopped the invite, a new link or a new channel, under its button.
294
+ const [formError, setFormError] = useState<{ form: TeamForm; text: string } | null>(null);
295
+ const resetMessages = useCallback(() => {
296
+ setMessage(null);
297
+ setFormError(null);
298
+ }, []);
233
299
  const [activeField, setActiveFieldState] = useState<string | null>(null);
234
300
  const actions = useRef(new Map<string, () => void>());
235
301
 
@@ -248,8 +314,8 @@ export function TeamPane({ focused, width, height, close }: PaneProps) {
248
314
  if (view.teamId) setTeamId(view.teamId);
249
315
  }
250
316
  if (view.section) setSection(view.section);
251
- setMessage(null);
252
- }, []);
317
+ resetMessages();
318
+ }, [resetMessages]);
253
319
  useEffect(() => subscribeRequestedTeamPaneView(applyView), [applyView]);
254
320
 
255
321
  // The settings draft follows the team until the person starts editing.
@@ -297,6 +363,21 @@ export function TeamPane({ focused, width, height, close }: PaneProps) {
297
363
  });
298
364
  }, [team]);
299
365
 
366
+ // The rows on screen, by note key: a failure on one of them is said on it, one that has left is a toast.
367
+ const listedRows = useRef<ReadonlySet<string>>(new Set());
368
+ listedRows.current = new Set([
369
+ ...details.members.map((member) => `member:${member.id}`),
370
+ ...details.invitations.map((invitation) => `invitation:${invitation.id}`),
371
+ ...details.links.map((link) => `link:${link.token}`),
372
+ ...channels.map((channel) => `channel:${channel.id}`),
373
+ ...snapshot.invitations.map((invitation) => `received:${invitation.id}`),
374
+ ]);
375
+ // Another team's rows are others; what was said on this one's goes with it.
376
+ useEffect(() => {
377
+ clearNotes();
378
+ setFormError(null);
379
+ }, [clearNotes, team?.id]);
380
+
300
381
  // Keyboard ring.
301
382
  const fieldIds = useMemo(() => sectionFieldIds({
302
383
  section: showCreate ? "create" : section,
@@ -348,7 +429,7 @@ export function TeamPane({ focused, width, height, close }: PaneProps) {
348
429
  const run = useCallback(async (key: string, work: () => Promise<Message>) => {
349
430
  if (busy) return;
350
431
  setBusy(key);
351
- setMessage(null);
432
+ resetMessages();
352
433
  try {
353
434
  report(await work());
354
435
  } catch (error) {
@@ -356,7 +437,44 @@ export function TeamPane({ focused, width, height, close }: PaneProps) {
356
437
  } finally {
357
438
  setBusy(null);
358
439
  }
359
- }, [busy, report]);
440
+ }, [busy, report, resetMessages]);
441
+
442
+ // An action on one row: its row says it is running and, if it fails while
443
+ // the row is listed, what it ran into. What `work` returns is what became of
444
+ // a row that has left the list (removed, revoked), a toast.
445
+ const runRow = useCallback(async (key: string, action: RowAction, work: () => Promise<Message>) => {
446
+ if (busy) return;
447
+ setBusy(key);
448
+ setBusyRow({ row: action.row, verb: action.verb });
449
+ setRowNote(action.row, null);
450
+ resetMessages();
451
+ try {
452
+ const gone = await work();
453
+ if (gone) notify({ body: gone.text, type: gone.tone });
454
+ } catch (error) {
455
+ const text = errorText(error, "That did not work.");
456
+ if (listedRows.current.has(action.row)) setRowNote(action.row, { status: action.failure, text, tone: "negative" });
457
+ else notify({ body: text, type: "error" });
458
+ } finally {
459
+ setBusy(null);
460
+ setBusyRow(null);
461
+ }
462
+ }, [busy, notify, resetMessages, setRowNote]);
463
+
464
+ // A form that adds a row (an invitation, a link, a channel): the new row is
465
+ // its result, and what stopped it goes under its button.
466
+ const runForm = useCallback(async (form: TeamForm, work: () => Promise<void>) => {
467
+ if (busy) return;
468
+ setBusy(form);
469
+ resetMessages();
470
+ try {
471
+ await work();
472
+ } catch (error) {
473
+ setFormError({ form, text: errorText(error, "That did not work.") });
474
+ } finally {
475
+ setBusy(null);
476
+ }
477
+ }, [busy, resetMessages]);
360
478
 
361
479
  const openChannel = useCallback((channel: ChatChannel | string) => {
362
480
  createPaneFromTemplate("new-chat-pane", { arg: typeof channel === "string" ? channel : channel.id });
@@ -394,7 +512,7 @@ export function TeamPane({ focused, width, height, close }: PaneProps) {
394
512
  if (!team) return;
395
513
  const username = inviteUsername.trim().replace(/^@/, "");
396
514
  if (!username) return;
397
- void run("invite", async () => {
515
+ void runForm("invite", async () => {
398
516
  const invitation = await apiClient.inviteTeamMemberByUsername(team.id, username);
399
517
  setInviteUsername("");
400
518
  setDetails((previous) => ({
@@ -412,47 +530,44 @@ export function TeamPane({ focused, width, height, close }: PaneProps) {
412
530
  ...previous.invitations.filter((entry) => entry.id !== invitation.id),
413
531
  ],
414
532
  }));
415
- return { tone: "success", text: `Invited ${userHandle(invitation.invitee)}. They have 7 days to accept.` };
416
533
  });
417
- }, [inviteUsername, run, selfUserId, setDetails, team]);
534
+ }, [inviteUsername, runForm, selfUserId, setDetails, team]);
418
535
 
536
+ /** A link copied is a toast, as every copy is; one that would not copy says so on its row, with the link to copy by hand. */
419
537
  const copyLink = useCallback(async (link: TeamInviteLink) => {
538
+ const row = `link:${link.token}`;
539
+ setRowNote(row, null);
420
540
  try {
421
541
  await rendererHost.copyText(link.url);
422
- report({ tone: "success", text: "Invite link copied." });
542
+ notify({ body: "Invite link copied.", type: "success" });
423
543
  } catch {
424
- report({ tone: "info", text: link.url });
544
+ setRowNote(row, { status: "Not copied", text: `Copy it from here: ${link.url}`, tone: "warning" });
425
545
  }
426
- }, [rendererHost, report]);
546
+ }, [notify, rendererHost, setRowNote]);
427
547
 
428
548
  const newLink = useCallback(() => {
429
549
  if (!team) return;
430
- void run("link", async () => {
550
+ void runForm("link", async () => {
431
551
  const link = await apiClient.createTeamInviteLink(team.id);
432
552
  setDetails((previous) => ({ ...previous, links: [link, ...previous.links] }));
433
- try {
434
- await rendererHost.copyText(link.url);
435
- return { tone: "success", text: `Link copied: ${link.url}` };
436
- } catch {
437
- return { tone: "info", text: link.url };
438
- }
553
+ await copyLink(link);
439
554
  });
440
- }, [rendererHost, run, setDetails, team]);
555
+ }, [copyLink, runForm, setDetails, team]);
441
556
 
442
557
  const createChannel = useCallback(() => {
443
558
  if (!team) return;
444
559
  const name = normalizeTeamChannelName(channelName);
445
560
  if (!name) return;
446
- void run("channel", async () => {
447
- const channel = await apiClient.createTeamChannel(team.id, name);
561
+ void runForm("channel", async () => {
562
+ await apiClient.createTeamChannel(team.id, name);
448
563
  setChannelName("");
449
564
  await chatController.refreshChatState()
450
565
  .catch(logFailure("cloud.team.pane", "Refresh chat channels after creating a channel failed"));
451
- return { tone: "success", text: `#${channel.name} is ready. Open it from the list.` };
452
566
  });
453
- }, [channelName, run, team]);
567
+ }, [channelName, runForm, team]);
454
568
 
455
- const acceptInvitation = useCallback((invitation: TeamReceivedInvitation) => run(`accept:${invitation.id}`, async () => {
569
+ // The banner is the invitation's row: its button says it is joining, and a failure stays on it.
570
+ const acceptInvitation = useCallback((invitation: TeamReceivedInvitation) => runRow(`accept:${invitation.id}`, { row: `received:${invitation.id}`, failure: "Join failed" }, async () => {
456
571
  const joined = await apiClient.acceptTeamInvitation(invitation.id);
457
572
  teamStore.removeInvitation(invitation.id);
458
573
  teamStore.upsertTeam(joined);
@@ -462,13 +577,13 @@ export function TeamPane({ focused, width, height, close }: PaneProps) {
462
577
  setTeamId(joined.id);
463
578
  setSection("members");
464
579
  return { tone: "success", text: `You joined ${joined.name}.` };
465
- }), [run]);
580
+ }), [runRow]);
466
581
 
467
- const declineInvitation = useCallback((invitation: TeamReceivedInvitation) => run(`decline:${invitation.id}`, async () => {
582
+ const declineInvitation = useCallback((invitation: TeamReceivedInvitation) => runRow(`decline:${invitation.id}`, { row: `received:${invitation.id}`, verb: "Declining…", failure: "Decline failed" }, async () => {
468
583
  await apiClient.rejectTeamInvitation(invitation.id);
469
584
  teamStore.removeInvitation(invitation.id);
470
585
  return { tone: "info", text: `Declined ${invitation.team.name}.` };
471
- }), [run]);
586
+ }), [runRow]);
472
587
 
473
588
  // The team strip is a row of tabs no key reaches (1-4 pick the section), so
474
589
  // [ and ] step through teams, from the create form too.
@@ -482,8 +597,8 @@ export function TeamPane({ focused, width, height, close }: PaneProps) {
482
597
  if (!next || (next.id === team?.id && !showCreate)) return;
483
598
  setCreating(false);
484
599
  setTeamId(next.id);
485
- setMessage(null);
486
- }, [showCreate, snapshot.teams, team?.id]);
600
+ resetMessages();
601
+ }, [resetMessages, showCreate, snapshot.teams, team?.id]);
487
602
  const canCycleTeams = snapshot.teams.length > (showCreate ? 0 : 1);
488
603
 
489
604
  // Tab, j/k and Enter on the ring; the keys below are the pane's own.
@@ -551,7 +666,7 @@ export function TeamPane({ focused, width, height, close }: PaneProps) {
551
666
  : [];
552
667
  }
553
668
  const list: PaneHint[] = [
554
- { id: "new", key: "n", label: "ew team", onPress: () => { setCreating(true); setMessage(null); } },
669
+ { id: "new", key: "n", label: "ew team", onPress: () => { setCreating(true); resetMessages(); } },
555
670
  ];
556
671
  if (team) {
557
672
  list.push({ id: "chat", key: "c", label: "hat", onPress: () => openChannel(teamChannelId(team.id)) });
@@ -564,9 +679,11 @@ export function TeamPane({ focused, width, height, close }: PaneProps) {
564
679
  return list;
565
680
  }, [dirty, draft, openChannel, saveSettings, section, showCreate, signedIn, snapshot.teams.length, team]);
566
681
  const result = message ?? (details.error ? { tone: "error" as const, text: details.error } : null);
682
+ // A row's action, or a form's, shows on its row or button; the footer has the team's own.
683
+ const teamBusy = !!busy && !busyRow && !["invite", "link", "channel"].includes(busy);
567
684
  usePaneFooter(TEAM_PANE_ID, () => ({
568
685
  info: [
569
- ...(busy ? [{ id: "busy", parts: [{ text: "working", tone: "muted" as const }] }] : []),
686
+ ...(teamBusy ? [{ id: "busy", parts: [{ text: "working", tone: "muted" as const }] }] : []),
570
687
  ...(details.loading && !busy ? [{ id: "loading", parts: [{ text: "syncing", tone: "muted" as const }] }] : []),
571
688
  ...(result && !busy ? [{
572
689
  id: "result",
@@ -577,7 +694,16 @@ export function TeamPane({ focused, width, height, close }: PaneProps) {
577
694
  } satisfies PaneFooterSegment] : []),
578
695
  ],
579
696
  hints,
580
- }), [busy, details.loading, hints, result]);
697
+ }), [busy, details.loading, hints, result, teamBusy]);
698
+
699
+ // While one of a row's controls holds the ring, the row's reason shows in full under it.
700
+ const selectedRow = fieldRow(activeField);
701
+ const rowState = useCallback((row: string): TeamRowState | undefined => {
702
+ if (busyRow?.row === row) return busyRow.verb ? { status: { text: busyRow.verb, tone: "warning" } } : undefined;
703
+ const note = noteFor(row);
704
+ return note ? { status: { text: note.status, tone: note.tone }, reason: selectedRow === row ? note.text : null } : undefined;
705
+ }, [busyRow, noteFor, selectedRow]);
706
+ const formErrorFor = useCallback((form: TeamForm) => (formError?.form === form ? formError.text : null), [formError]);
581
707
 
582
708
  const teamTabs = useMemo(() => [
583
709
  ...snapshot.teams.map((entry) => ({
@@ -594,12 +720,12 @@ export function TeamPane({ focused, width, height, close }: PaneProps) {
594
720
  setCreating(false);
595
721
  setTeamId(value);
596
722
  }
597
- setMessage(null);
598
- }, []);
723
+ resetMessages();
724
+ }, [resetMessages]);
599
725
  const startCreate = useCallback(() => {
600
726
  setCreating(true);
601
- setMessage(null);
602
- }, []);
727
+ resetMessages();
728
+ }, [resetMessages]);
603
729
  const { strip: tabStrip, rows: tabRows } = usePaneTabs(signedIn ? {
604
730
  tabs: teamTabs,
605
731
  activeValue: showCreate ? "__create" : team?.id ?? null,
@@ -620,7 +746,8 @@ export function TeamPane({ focused, width, height, close }: PaneProps) {
620
746
  const banners = snapshot.invitations;
621
747
  // The section bar or the teams status line; the create form has neither.
622
748
  const sectionRows = showCreate ? 0 : 1;
623
- const headerRows = sectionRows + tabRows + (banners.length > 0 ? banners.length + 1 : 0);
749
+ const bannerHeight = banners.reduce((rows, invitation) => rows + bannerRows(rowState(`received:${invitation.id}`), width), 0);
750
+ const headerRows = sectionRows + tabRows + (banners.length > 0 ? bannerHeight + 1 : 0);
624
751
  const bodyHeight = Math.max(3, height - headerRows);
625
752
 
626
753
  return (
@@ -632,6 +759,7 @@ export function TeamPane({ focused, width, height, close }: PaneProps) {
632
759
  invitation={invitation}
633
760
  width={width}
634
761
  busy={busy === `accept:${invitation.id}` || busy === `decline:${invitation.id}`}
762
+ state={rowState(`received:${invitation.id}`)}
635
763
  onAccept={() => { void acceptInvitation(invitation); }}
636
764
  onDecline={() => { void declineInvitation(invitation); }}
637
765
  />
@@ -650,7 +778,7 @@ export function TeamPane({ focused, width, height, close }: PaneProps) {
650
778
  inline: true,
651
779
  value: section,
652
780
  options: TEAM_PANE_SECTIONS,
653
- onChange: (value: TeamPaneSection) => { setSection(value); setMessage(null); },
781
+ onChange: (value: TeamPaneSection) => { setSection(value); resetMessages(); },
654
782
  }]}
655
783
  meta={team.role}
656
784
  />
@@ -687,15 +815,17 @@ export function TeamPane({ focused, width, height, close }: PaneProps) {
687
815
  selfUserId={selfUserId}
688
816
  width={contentWidth}
689
817
  busyId={busy}
818
+ rowState={rowState}
690
819
  onChangeRole={(member, role) => {
691
- void run(member.id, async () => {
820
+ // The row's role says the change took; nothing else does.
821
+ void runRow(member.id, { row: `member:${member.id}`, verb: "Changing…", failure: "Change failed" }, async () => {
692
822
  const members = await apiClient.updateTeamMemberRole(team.id, member.id, role);
693
823
  setDetails((previous) => ({ ...previous, members }));
694
- return { tone: "success", text: `${userHandle(member.user)} is now ${role === "admin" ? "an admin" : "a member"}.` };
824
+ return null;
695
825
  });
696
826
  }}
697
827
  onRemove={(member) => {
698
- void run(member.id, async () => {
828
+ void runRow(member.id, { row: `member:${member.id}`, verb: "Removing…", failure: "Remove failed" }, async () => {
699
829
  const members = await apiClient.removeTeamMember(team.id, member.id);
700
830
  setDetails((previous) => ({ ...previous, members }));
701
831
  void teamStore.refresh();
@@ -713,19 +843,24 @@ export function TeamPane({ focused, width, height, close }: PaneProps) {
713
843
  username={inviteUsername}
714
844
  width={contentWidth}
715
845
  busy={busy}
716
- onUsernameChange={setInviteUsername}
846
+ rowState={rowState}
847
+ formError={formErrorFor}
848
+ onUsernameChange={(value) => {
849
+ setInviteUsername(value);
850
+ if (formError?.form === "invite") setFormError(null);
851
+ }}
717
852
  onInvite={invite}
718
853
  onCancelInvitation={(invitation) => {
719
- void run(invitation.id, async () => {
854
+ void runRow(invitation.id, { row: `invitation:${invitation.id}`, verb: "Canceling…", failure: "Cancel failed" }, async () => {
720
855
  await apiClient.cancelTeamInvitation(team.id, invitation.id);
721
856
  setDetails((previous) => ({ ...previous, invitations: previous.invitations.filter((entry) => entry.id !== invitation.id) }));
722
- return { tone: "info", text: "Invitation canceled." };
857
+ return { tone: "info", text: invitation.invitee ? `Canceled the invitation to ${userHandle(invitation.invitee)}.` : "Invitation canceled." };
723
858
  });
724
859
  }}
725
860
  onNewLink={newLink}
726
861
  onCopyLink={(link) => { void copyLink(link); }}
727
862
  onRevokeLink={(link) => {
728
- void run(link.token, async () => {
863
+ void runRow(link.token, { row: `link:${link.token}`, verb: "Revoking…", failure: "Revoke failed" }, async () => {
729
864
  await apiClient.deleteTeamInviteLink(team.id, link.token);
730
865
  setDetails((previous) => ({ ...previous, links: previous.links.filter((entry) => entry.token !== link.token) }));
731
866
  return { tone: "info", text: "Link revoked." };
@@ -740,11 +875,16 @@ export function TeamPane({ focused, width, height, close }: PaneProps) {
740
875
  channelName={channelName}
741
876
  width={contentWidth}
742
877
  busy={busy}
743
- onChannelNameChange={setChannelName}
878
+ rowState={rowState}
879
+ formError={formErrorFor("channel")}
880
+ onChannelNameChange={(value) => {
881
+ setChannelName(value);
882
+ if (formError?.form === "channel") setFormError(null);
883
+ }}
744
884
  onCreate={createChannel}
745
885
  onOpen={openChannel}
746
886
  onDelete={(channel) => {
747
- void run(channel.id, async () => {
887
+ void runRow(channel.id, { row: `channel:${channel.id}`, verb: "Deleting…", failure: "Delete failed" }, async () => {
748
888
  await apiClient.deleteTeamChannel(team.id, channel.id);
749
889
  await chatController.refreshChatState()
750
890
  .catch(logFailure("cloud.team.pane", "Refresh chat channels after deleting a channel failed"));
@@ -52,7 +52,7 @@ type ThesisStoreClient = Pick<
52
52
  * readable offline from the last copy. Writes go through here so every pane
53
53
  * showing a thesis sees the saved version at once.
54
54
  */
55
- class ThesisStore {
55
+ export class ThesisStore {
56
56
  constructor(private readonly client: ThesisStoreClient = apiClient) {}
57
57
 
58
58
  private snapshot: ThesisStoreSnapshot = EMPTY;
@@ -62,6 +62,13 @@ class ThesisStore {
62
62
  private openThesis: ((thesisId: string) => void) | null = null;
63
63
  private disposers: Array<() => void> = [];
64
64
  private refreshPromise: Promise<void> | null = null;
65
+ /**
66
+ * Counts the times the store stopped or lost its account. A refresh keeps
67
+ * the count it started under and says nothing once it has moved on, so a
68
+ * request that outlives a dispose, a restart or a sign-out cannot write its
69
+ * answer, or its failure, over what the store holds now.
70
+ */
71
+ private generation = 0;
65
72
  private refreshTimer: ReturnType<typeof setTimeout> | null = null;
66
73
  private started = false;
67
74
  private readonly signalListeners = new Set<(thesisId: string) => void>();
@@ -104,9 +111,13 @@ class ThesisStore {
104
111
  const syncAuth = () => {
105
112
  if (this.client.isVerified()) {
106
113
  void this.refresh();
107
- } else if (this.snapshot.loaded || this.snapshot.theses.length > 0) {
108
- this.update({ ...EMPTY });
109
- this.persistence?.setState(CACHE_STATE_KEY, []);
114
+ } else {
115
+ // Whatever a refresh in flight is about to say belongs to the account that left.
116
+ this.abandonRefresh();
117
+ if (this.snapshot.loaded || this.snapshot.theses.length > 0) {
118
+ this.update({ ...EMPTY });
119
+ this.persistence?.setState(CACHE_STATE_KEY, []);
120
+ }
110
121
  }
111
122
  };
112
123
  this.disposers.push(this.client.subscribeCurrentUser(syncAuth));
@@ -121,7 +132,7 @@ class ThesisStore {
121
132
  if (this.refreshTimer) clearTimeout(this.refreshTimer);
122
133
  this.refreshTimer = null;
123
134
  this.started = false;
124
- this.refreshPromise = null;
135
+ this.abandonRefresh();
125
136
  }
126
137
 
127
138
  get(id: string | null | undefined): CloudThesis | null {
@@ -132,23 +143,35 @@ class ThesisStore {
132
143
  async refresh(): Promise<void> {
133
144
  if (this.refreshPromise) return this.refreshPromise;
134
145
  this.update({ loading: true, error: null });
135
- this.refreshPromise = (async () => {
136
- try {
137
- const theses = await this.client.listTheses({ scope: "all" });
138
- this.update({ theses, loaded: true, loading: false, error: null, offline: false });
139
- this.persistence?.setState(CACHE_STATE_KEY, theses);
140
- } catch (error) {
141
- this.update({
142
- loading: false,
143
- loaded: true,
144
- error: error instanceof Error ? error.message : "Could not load theses.",
145
- offline: this.snapshot.theses.length > 0,
146
- });
147
- } finally {
148
- this.refreshPromise = null;
149
- }
150
- })();
151
- return this.refreshPromise;
146
+ const run: Promise<void> = this.load(this.generation).finally(() => {
147
+ if (this.refreshPromise === run) this.refreshPromise = null;
148
+ });
149
+ this.refreshPromise = run;
150
+ return run;
151
+ }
152
+
153
+ private async load(generation: number): Promise<void> {
154
+ try {
155
+ const theses = await this.client.listTheses({ scope: "all" });
156
+ if (generation !== this.generation) return;
157
+ this.update({ theses, loaded: true, loading: false, error: null, offline: false });
158
+ this.persistence?.setState(CACHE_STATE_KEY, theses);
159
+ } catch (error) {
160
+ if (generation !== this.generation) return;
161
+ this.update({
162
+ loading: false,
163
+ loaded: true,
164
+ error: error instanceof Error ? error.message : "Could not load theses.",
165
+ offline: this.snapshot.theses.length > 0,
166
+ });
167
+ }
168
+ }
169
+
170
+ /** Drops the refresh in flight: its answer is ignored, and nothing is left loading on its account. */
171
+ private abandonRefresh(): void {
172
+ this.generation += 1;
173
+ this.refreshPromise = null;
174
+ if (this.snapshot.loading) this.update({ loading: false });
152
175
  }
153
176
 
154
177
  async create(input: Parameters<ThesisStoreClient["createThesis"]>[0]): Promise<CloudThesis> {
@@ -29,6 +29,7 @@ export function registerTwitterFeedFeature(ctx: GloomPluginContext): void {
29
29
  ctx.registerPane({
30
30
  id: TWITTER_FEED_PANE_ID,
31
31
  reportFreshness: { source: "X posts", status: "not-a-feed", basis: "posts" },
32
+ reportArgument: { kind: "free-text", placeholder: "query", optional: true, description: "An X advanced search." },
32
33
  name: "X Feed",
33
34
  icon: "X",
34
35
  component: TwitterFeedPane,
@@ -2,7 +2,7 @@ import { useCallback, useEffect, useState, type ComponentType } from "react";
2
2
  import { NestedPaneTabs, PaneFooterScope, usePaneTabs } from "../../../components";
3
3
  import { usePaneInstance, usePaneSettingValue, usePaneTitle } from "../../../state/app/context";
4
4
  import { Box } from "../../../ui";
5
- import type { PaneProps, PaneSettingsContext, PaneTemplateContext, PaneTemplateCreateOptions, PaneTemplateDef, PaneTemplateInstanceConfig } from "../../../types/plugin";
5
+ import type { PaneProps, PaneReportOptionDef, PaneSettingsContext, PaneTemplateContext, PaneTemplateCreateOptions, PaneTemplateDef, PaneTemplateInstanceConfig } from "../../../types/plugin";
6
6
  import { withPluginStateNamespace } from "../../runtime/context";
7
7
  import { useCommandTab, withCommandTab } from "../shared/command-tab";
8
8
  import { commodityBalancesModule } from "../commodity-balances";
@@ -22,6 +22,7 @@ import { COMMODITIES_VIEW_STATE } from "./view-state";
22
22
 
23
23
  const COMMODITIES_ENERGY_PANE_ID = "commodities-energy";
24
24
  const COMMODITIES_ENERGY_TITLE = "Commodities & Energy";
25
+ const TAB_STATE_KEY = "commodities-energy:tab";
25
26
 
26
27
  /**
27
28
  * The window's title: the curve it shows, by its root ("Curve \u00b7 BZ"), as a
@@ -43,6 +44,30 @@ const TABS = [
43
44
  ] as const;
44
45
  type WorkspaceTab = typeof TABS[number]["value"];
45
46
 
47
+ /** Where a tab FUT's --tab does not take lives: the curve and the oil and gas balances are functions of their own. */
48
+ const TAB_ELSEWHERE: Readonly<Record<string, string>> = {
49
+ curve: "The curve is its own function: gloom fn CTM <root>.",
50
+ balances: "Oil and gas balances: gloom fn JODI.",
51
+ oilgas: "Oil and gas balances: gloom fn JODI.",
52
+ };
53
+
54
+ /**
55
+ * FUT's report and shot open the workspace on one of its boards (`fn FUT --tab
56
+ * inventories`): written to the tab's pane state, which the workspace opens
57
+ * on, and to its setting, which sizes a shot and titles the window.
58
+ */
59
+ const TAB_REPORT_OPTION: PaneReportOptionDef = {
60
+ key: "tab",
61
+ type: "enum",
62
+ description: "The board to open on: futures markets, EIA inventories, CFTC positioning or USDA crop balances.",
63
+ values: [{ value: "markets" }, { value: "inventories" }, { value: "positioning" }, { value: "crops" }],
64
+ example: "--tab inventories",
65
+ exampleWithoutArgument: true,
66
+ settingKey: "workspaceTab",
67
+ pluginState: { pluginId: COMMODITIES_VIEW_STATE.workspace, key: TAB_STATE_KEY },
68
+ invalidValueHint: (value) => TAB_ELSEWHERE[value.trim().toLowerCase().replace(/[^a-z]/g, "")] ?? null,
69
+ };
70
+
46
71
  const CURVE_SURFACE = withPluginStateNamespace(COMMODITIES_VIEW_STATE.curve, FuturesCurvePane);
47
72
  const COT_SURFACE = withPluginStateNamespace(COMMODITIES_VIEW_STATE.cot, CotPane);
48
73
  const DOE_SURFACE = withPluginStateNamespace(COMMODITIES_VIEW_STATE.doe, DoePane);
@@ -141,7 +166,7 @@ function activeSettings(context: PaneSettingsContext) {
141
166
  function CommoditiesEnergyPane(props: PaneProps) {
142
167
  const [tab, setTab] = useCommandTab(
143
168
  COMMODITIES_ENERGY_PANE_ID,
144
- "commodities-energy:tab",
169
+ TAB_STATE_KEY,
145
170
  TABS.map(({ value }) => value),
146
171
  "markets",
147
172
  );
@@ -192,6 +217,8 @@ export const commoditiesEnergyModule: PluginModule = {
192
217
  defaultMode: "floating",
193
218
  defaultFloatingSize: { width: 110, height: 32 },
194
219
  tableExport: true,
220
+ reportOptions: [TAB_REPORT_OPTION],
221
+ reportOptionsOnly: true,
195
222
  // The Markets tab is FUT's fixed board, every row of which a shot shows; the other tabs keep their height.
196
223
  shotFitsRows: (pane) => savedTab(pane) === "markets",
197
224
  settings: activeSettings,
@@ -3,6 +3,8 @@
3
3
  * workspace wraps it with and a function's options write to for `shot`.
4
4
  */
5
5
  export const COMMODITIES_VIEW_STATE = {
6
+ /** The workspace's own state: the tab it shows. */
7
+ workspace: "market-overview",
6
8
  curve: "market-overview:futures-curve",
7
9
  cot: "market-overview:cot",
8
10
  doe: "market-overview:doe",