gloomberb 0.18.3 → 0.18.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (886) 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/src/account/checkout-handoff.tsx +225 -0
  6. package/src/account/device-signin-dialog.tsx +2 -2
  7. package/src/account/device-signin.ts +2 -2
  8. package/src/account/upgrade-dialog.tsx +1 -1
  9. package/src/api-client/askg.ts +2 -2
  10. package/src/api-client/auth.ts +2 -2
  11. package/src/api-client/central-bank-rates.ts +6 -0
  12. package/src/api-client/collections.ts +5 -1
  13. package/src/api-client/cot.ts +2 -0
  14. package/src/api-client/crypto-etf-flows.ts +37 -0
  15. package/src/api-client/crypto-markets.ts +60 -0
  16. package/src/api-client/data.ts +84 -5
  17. package/src/api-client/doe.ts +15 -0
  18. package/src/api-client/equity-screener.ts +28 -0
  19. package/src/api-client/exchange-announcements.ts +38 -0
  20. package/src/api-client/fund-facts.ts +39 -0
  21. package/src/api-client/futures-curve.ts +9 -1
  22. package/src/api-client/hiring.ts +301 -0
  23. package/src/api-client/index.ts +22 -5
  24. package/src/api-client/market-discovery.ts +14 -0
  25. package/src/api-client/members.ts +6 -0
  26. package/src/api-client/mna.ts +6 -0
  27. package/src/api-client/paths.ts +18 -1
  28. package/src/api-client/request.ts +21 -4
  29. package/src/api-client/short-side-publications.ts +37 -0
  30. package/src/api-client/socket.ts +64 -4
  31. package/src/api-client/swap-curve.ts +35 -0
  32. package/src/api-client/themes.ts +7 -1
  33. package/src/api-client/types.ts +90 -2
  34. package/src/app/pane-runtime/plugin-bindings.ts +9 -2
  35. package/src/app/runtime/desktop-deeplink.ts +5 -5
  36. package/src/app/runtime/plugin-bindings.ts +2 -2
  37. package/src/app/runtime/startup.ts +13 -0
  38. package/src/app/star-prompt/status-line.tsx +2 -2
  39. package/src/architecture/core-builtin-allowlist.json +5 -2
  40. package/src/architecture/ui-literals-allowlist.json +3 -3
  41. package/src/architecture/ui-tokens-allowlist.json +1 -1
  42. package/src/brokers/broker-portfolio-sync.ts +37 -0
  43. package/src/brokers/directory.ts +11 -0
  44. package/src/brokers/logos.ts +3 -1
  45. package/src/brokers/signed-in/adapter.ts +304 -26
  46. package/src/brokers/signed-in/client.ts +14 -2
  47. package/src/brokers/signed-in/connect.ts +10 -2
  48. package/src/brokers/sync-broker-instance.ts +9 -1
  49. package/src/capabilities/chart-series.ts +22 -6
  50. package/src/cli/bank-section.ts +1 -1
  51. package/src/cli/base-converter.ts +23 -14
  52. package/src/cli/central-bank-events.ts +1 -1
  53. package/src/cli/command-options.ts +59 -4
  54. package/src/cli/commands/api.ts +9 -6
  55. package/src/cli/commands/broker.ts +2 -2
  56. package/src/cli/commands/command-utils.ts +2 -2
  57. package/src/cli/commands/crypto-hints.ts +7 -20
  58. package/src/cli/commands/fred-series.ts +4 -2
  59. package/src/cli/commands/keybindings.ts +2 -2
  60. package/src/cli/commands/market.ts +1117 -264
  61. package/src/cli/commands/news-hints.ts +2 -2
  62. package/src/cli/commands/news-search.ts +59 -6
  63. package/src/cli/commands/options-leaps.ts +41 -26
  64. package/src/cli/commands/overview.ts +121 -48
  65. package/src/cli/commands/plugins.ts +9 -9
  66. package/src/cli/commands/remote.ts +13 -10
  67. package/src/cli/commands/search.ts +64 -44
  68. package/src/cli/commands/system.ts +27 -19
  69. package/src/cli/commands/themes.ts +1 -1
  70. package/src/cli/commands/ticker.ts +192 -47
  71. package/src/cli/context.ts +3 -2
  72. package/src/cli/desktop-pane-shot-view.ts +2 -2
  73. package/src/cli/desktop-pane-shot.ts +1 -1
  74. package/src/cli/earnings-calendar.ts +4 -4
  75. package/src/cli/entry.ts +18 -1
  76. package/src/cli/errors.ts +20 -2
  77. package/src/cli/exit-codes.ts +1 -1
  78. package/src/cli/export-source.ts +10 -4
  79. package/src/cli/freshness.ts +2 -8
  80. package/src/cli/fx-forward.ts +130 -0
  81. package/src/cli/fx-pair.ts +10 -9
  82. package/src/cli/glossary.ts +64 -20
  83. package/src/cli/help.ts +19 -13
  84. package/src/cli/history-export.ts +126 -0
  85. package/src/cli/history-rows.ts +196 -43
  86. package/src/cli/index-roots.ts +5 -45
  87. package/src/cli/index.ts +24 -18
  88. package/src/cli/known-gaps.ts +118 -25
  89. package/src/cli/listing-arg.ts +300 -41
  90. package/src/cli/name-entries.ts +30 -18
  91. package/src/cli/native-smoke.ts +2 -0
  92. package/src/cli/not-a-ticker.ts +19 -9
  93. package/src/cli/opentui-libc.ts +5 -0
  94. package/src/cli/options.ts +12 -0
  95. package/src/cli/pane-functions/capabilities.ts +75 -20
  96. package/src/cli/pane-functions/catalog.ts +24 -23
  97. package/src/cli/pane-functions/discovery.ts +1 -1
  98. package/src/cli/pane-functions/dom.ts +10 -7
  99. package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
  100. package/src/cli/pane-functions/freshness.ts +174 -23
  101. package/src/cli/pane-functions/function-help.ts +66 -27
  102. package/src/cli/pane-functions/headless.ts +24 -11
  103. package/src/cli/pane-functions/index.ts +18 -16
  104. package/src/cli/pane-functions/options.ts +22 -2
  105. package/src/cli/pane-functions/report-notices.ts +12 -4
  106. package/src/cli/pane-functions/report.ts +5 -5
  107. package/src/cli/pane-functions/resolver.ts +47 -10
  108. package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
  109. package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
  110. package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
  111. package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
  112. package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
  113. package/src/cli/pane-functions/screenshot-payload.ts +453 -0
  114. package/src/cli/pane-functions/screenshot-render.ts +316 -0
  115. package/src/cli/pane-functions/screenshot-types.ts +162 -0
  116. package/src/cli/pane-functions/shot-options.ts +8 -3
  117. package/src/cli/peso-dollar-rates.ts +79 -0
  118. package/src/cli/quote-answer.ts +38 -3
  119. package/src/cli/report-tables.ts +61 -16
  120. package/src/cli/restore-plugins.ts +29 -14
  121. package/src/cli/result.ts +111 -22
  122. package/src/cli/series-search.ts +5 -5
  123. package/src/cli/statement-filings.ts +19 -0
  124. package/src/cli/suffixed-listing-rows.ts +49 -0
  125. package/src/cli/symbol-args.ts +50 -15
  126. package/src/cli/symbol-cells.ts +120 -0
  127. package/src/cli/symbol-list.ts +198 -68
  128. package/src/cli/symbol-rows.ts +131 -25
  129. package/src/cli/ticker-resolution.ts +108 -11
  130. package/src/cli/treasury-yields.ts +5 -5
  131. package/src/cli/types.ts +2 -0
  132. package/src/cli/uncovered-instrument.ts +3 -3
  133. package/src/cli/unknown-command.ts +6 -6
  134. package/src/components/chart/composite/chart-layout.ts +131 -0
  135. package/src/components/chart/composite/composite-chart.tsx +373 -16
  136. package/src/components/chart/composite/interactions.ts +7 -2
  137. package/src/components/chart/composite/legend.tsx +75 -3
  138. package/src/components/chart/composite/levels.ts +5 -0
  139. package/src/components/chart/composite/panel-gestures.ts +41 -0
  140. package/src/components/chart/composite/panel-labels.ts +2 -1
  141. package/src/components/chart/composite/panel-surface.tsx +305 -11
  142. package/src/components/chart/composite/price-axis-labels.tsx +27 -3
  143. package/src/components/chart/composite/rasterizer.ts +44 -19
  144. package/src/components/chart/composite/scene.ts +16 -4
  145. package/src/components/chart/composite/text-renderer.ts +48 -21
  146. package/src/components/chart/composite/toolbar.tsx +52 -5
  147. package/src/components/chart/composite/types.ts +13 -0
  148. package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
  149. package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
  150. package/src/components/chart/composite/use-composite-viewport.ts +12 -3
  151. package/src/components/chart/composite/value-scale.ts +149 -0
  152. package/src/components/chart/composite/volume-profile-paint.ts +6 -3
  153. package/src/components/chart/core/pointer.ts +2 -0
  154. package/src/components/chart-table/index.ts +2 -0
  155. package/src/components/chart-table/read.tsx +74 -0
  156. package/src/components/command-bar/commands/collection-list.ts +41 -19
  157. package/src/components/command-bar/commands/collection.ts +9 -3
  158. package/src/components/command-bar/commands/direct/index.ts +1 -1
  159. package/src/components/command-bar/commands/direct/runtime.ts +3 -2
  160. package/src/components/command-bar/pane-templates/items.ts +59 -6
  161. package/src/components/command-bar/pane-templates/workflow.ts +10 -1
  162. package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
  163. package/src/components/command-bar/routes/root/provider-search.ts +42 -11
  164. package/src/components/command-bar/routes/root/results.ts +18 -4
  165. package/src/components/command-bar/routes/root/runtime.ts +15 -3
  166. package/src/components/command-bar/routes/root/search-providers.ts +25 -2
  167. package/src/components/command-bar/routes/root/selection.ts +6 -1
  168. package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
  169. package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
  170. package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
  171. package/src/components/command-bar/selection-runtime.ts +50 -10
  172. package/src/components/command-bar/surface/index.tsx +24 -2
  173. package/src/components/command-bar/view-model.ts +7 -0
  174. package/src/components/command-bar/workflow/broker.ts +2 -2
  175. package/src/components/command-bar/workflow/collection-actions.ts +46 -7
  176. package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
  177. package/src/components/command-bar/workflow/fields.ts +8 -2
  178. package/src/components/command-bar/workflow/ops.ts +18 -4
  179. package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
  180. package/src/components/command-bar/workflow/submit.ts +3 -2
  181. package/src/components/command-bar/workflow/tickers.ts +5 -1
  182. package/src/components/company-logo.tsx +39 -0
  183. package/src/components/data-table/sections.ts +4 -2
  184. package/src/components/form-modal/confirm.tsx +2 -1
  185. package/src/components/form-modal/request.ts +5 -0
  186. package/src/components/form-modal/routes.ts +4 -1
  187. package/src/components/index.ts +12 -6
  188. package/src/components/layout/header.tsx +7 -6
  189. package/src/components/layout/market-summary.ts +9 -6
  190. package/src/components/layout/pane/capture-status.ts +1 -1
  191. package/src/components/layout/pane/footer/model.ts +11 -5
  192. package/src/components/layout/shell/chrome.ts +19 -6
  193. package/src/components/layout/shell/index.tsx +2 -1
  194. package/src/components/layout/shell/pane/layers.tsx +19 -1
  195. package/src/components/layout/status-bar.tsx +2 -2
  196. package/src/components/market-board/index.tsx +11 -3
  197. package/src/components/onboarding/onboarding-wizard.tsx +1 -0
  198. package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
  199. package/src/components/onboarding/wizard-broker-sync.ts +4 -1
  200. package/src/components/pane-settings-dialog/desktop.tsx +20 -7
  201. package/src/components/pane-settings-dialog/tui.tsx +17 -9
  202. package/src/components/pane-settings-dialog/value.ts +8 -1
  203. package/src/components/pane-settings-dialog.tsx +44 -13
  204. package/src/components/sign-in-code-panel.tsx +27 -19
  205. package/src/components/ui/column-grid.tsx +48 -4
  206. package/src/components/ui/country-flag-art.tsx +180 -0
  207. package/src/components/ui/country-flag.tsx +118 -12
  208. package/src/components/ui/data-table/opentui/index.tsx +61 -2
  209. package/src/components/ui/data-table/opentui/model.ts +109 -2
  210. package/src/components/ui/data-table/types.ts +1 -1
  211. package/src/components/ui/display.tsx +5 -1
  212. package/src/components/ui/index.ts +3 -1
  213. package/src/components/ui/logo-mark.tsx +11 -2
  214. package/src/components/ui/query-bar.tsx +1 -1
  215. package/src/components/ui/row-notes.ts +79 -0
  216. package/src/core/state/app/layout.ts +4 -4
  217. package/src/data/cached-query.ts +8 -1
  218. package/src/data/config/chart-settings.ts +3 -3
  219. package/src/data/config/home.ts +10 -2
  220. package/src/data/config/layout.ts +4 -1
  221. package/src/data/config/store/node.ts +4 -0
  222. package/src/data/config/store/normalize.ts +13 -3
  223. package/src/data/config/store/portfolio-as-of-column.ts +2 -2
  224. package/src/data/json-storage.ts +2 -0
  225. package/src/data/saved-copies.ts +84 -0
  226. package/src/docs/snapshot.json +65 -32
  227. package/src/i18n/es.ts +29 -12
  228. package/src/i18n/ja.ts +29 -12
  229. package/src/i18n/ko.ts +29 -12
  230. package/src/i18n/zh-cn.ts +29 -12
  231. package/src/i18n/zh-tw.ts +29 -12
  232. package/src/layout/desks.ts +1 -1
  233. package/src/layout/launch-layout.ts +1 -1
  234. package/src/layout/pane-manager/floating-actions.ts +5 -3
  235. package/src/layout/pane-manager/floating.ts +43 -1
  236. package/src/layout/pane-manager/index.ts +2 -0
  237. package/src/layout/selected-ticker.ts +74 -0
  238. package/src/market-data/depositary-pair.ts +251 -0
  239. package/src/market-data/futures-board.ts +1 -1
  240. package/src/market-data/futures-contract.ts +124 -40
  241. package/src/market-data/fx-closes.ts +17 -2
  242. package/src/market-data/hooks.tsx +19 -11
  243. package/src/market-data/market/change-basis.ts +49 -7
  244. package/src/market-data/market/freshness.ts +34 -5
  245. package/src/market-data/market/period-return.ts +163 -0
  246. package/src/market-data/market/trading-sessions.ts +13 -0
  247. package/src/market-data/market/year-to-date.ts +8 -13
  248. package/src/market-data/performance.ts +20 -14
  249. package/src/market-data/perpetual-premium.ts +32 -0
  250. package/src/market-data/published-apac-sessions.ts +2 -1
  251. package/src/market-data/published-futures-sessions.ts +69 -0
  252. package/src/market-data/quotes/contributions.ts +5 -1
  253. package/src/market-data/quotes/freshness.ts +42 -0
  254. package/src/market-data/quotes/intraday-bar.ts +37 -0
  255. package/src/market-data/quotes/regular-session-valuation.ts +13 -8
  256. package/src/market-data/quotes/resolution.ts +4 -2
  257. package/src/market-data/tax-equivalent.ts +1 -1
  258. package/src/market-data/ticker-price-returns.ts +3 -1
  259. package/src/news/aggregator.ts +5 -1
  260. package/src/news/news-model.ts +4 -0
  261. package/src/news/types.ts +11 -0
  262. package/src/notifications/app-notifier.ts +1 -1
  263. package/src/plugins/auto-update.ts +2 -2
  264. package/src/plugins/builtin/account-management/index.tsx +1 -0
  265. package/src/plugins/builtin/account-management/pane.tsx +9 -8
  266. package/src/plugins/builtin/alerts/alert-engine.ts +29 -19
  267. package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
  268. package/src/plugins/builtin/alerts/cli.ts +485 -76
  269. package/src/plugins/builtin/alerts/command.ts +5 -10
  270. package/src/plugins/builtin/alerts/event-rows.ts +9 -5
  271. package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
  272. package/src/plugins/builtin/alerts/events.ts +107 -5
  273. package/src/plugins/builtin/alerts/fired-log.ts +78 -0
  274. package/src/plugins/builtin/alerts/format.ts +2 -1
  275. package/src/plugins/builtin/alerts/headless.ts +100 -39
  276. package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
  277. package/src/plugins/builtin/alerts/history-rows.ts +89 -0
  278. package/src/plugins/builtin/alerts/index.tsx +45 -18
  279. package/src/plugins/builtin/alerts/iv-level.ts +365 -0
  280. package/src/plugins/builtin/alerts/levels.ts +3 -3
  281. package/src/plugins/builtin/alerts/pane.tsx +97 -29
  282. package/src/plugins/builtin/alerts/price.ts +35 -0
  283. package/src/plugins/builtin/alerts/quotes.ts +24 -0
  284. package/src/plugins/builtin/alerts/research-builder.ts +84 -11
  285. package/src/plugins/builtin/alerts/research-rules.ts +76 -3
  286. package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
  287. package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
  288. package/src/plugins/builtin/alerts/scheduled.ts +188 -29
  289. package/src/plugins/builtin/alerts/storage.ts +13 -10
  290. package/src/plugins/builtin/alerts/targets.ts +12 -3
  291. package/src/plugins/builtin/analytics/index.tsx +8 -2
  292. package/src/plugins/builtin/analytics/metrics.ts +1 -1
  293. package/src/plugins/builtin/analytics/risk-book.ts +215 -0
  294. package/src/plugins/builtin/analytics/risk-client.ts +13 -6
  295. package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
  296. package/src/plugins/builtin/analytics/risk-math.ts +6 -3
  297. package/src/plugins/builtin/analytics/risk-model.ts +297 -104
  298. package/src/plugins/builtin/analytics/risk-options.ts +17 -2
  299. package/src/plugins/builtin/analytics/risk-pane.tsx +97 -36
  300. package/src/plugins/builtin/attention/pane.tsx +6 -2
  301. package/src/plugins/builtin/awards/headless.ts +7 -3
  302. package/src/plugins/builtin/awards/model.ts +18 -0
  303. package/src/plugins/builtin/awards/pane.tsx +6 -3
  304. package/src/plugins/builtin/backtest/headless.ts +3 -3
  305. package/src/plugins/builtin/backtest/rules.ts +41 -5
  306. package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
  307. package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
  308. package/src/plugins/builtin/broker-manager/footer.ts +27 -11
  309. package/src/plugins/builtin/broker-manager/index.tsx +21 -12
  310. package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
  311. package/src/plugins/builtin/broker-manager/model.ts +12 -2
  312. package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
  313. package/src/plugins/builtin/broker-manager/table.ts +28 -12
  314. package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
  315. package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
  316. package/src/plugins/builtin/broker-trading/controller.ts +45 -13
  317. package/src/plugins/builtin/broker-trading/dock.tsx +22 -4
  318. package/src/plugins/builtin/broker-trading/headless.ts +2 -1
  319. package/src/plugins/builtin/broker-trading/index.tsx +7 -1
  320. package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
  321. package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
  322. package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
  323. package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
  324. package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
  325. package/src/plugins/builtin/broker-trading/pane.tsx +110 -23
  326. package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
  327. package/src/plugins/builtin/broker-trading/ticket.tsx +112 -31
  328. package/src/plugins/builtin/buildout/cells.tsx +4 -0
  329. package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
  330. package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
  331. package/src/plugins/builtin/buildout/pane/index.tsx +25 -12
  332. package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
  333. package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
  334. package/src/plugins/builtin/catalysts/detail.tsx +3 -2
  335. package/src/plugins/builtin/catalysts/index.tsx +1 -1
  336. package/src/plugins/builtin/catalysts/model.ts +49 -4
  337. package/src/plugins/builtin/catalysts/pane.tsx +6 -8
  338. package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
  339. package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
  340. package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
  341. package/src/plugins/builtin/changelog/index.tsx +1 -0
  342. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
  343. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
  344. package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
  345. package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
  346. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
  347. package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
  348. package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
  349. package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
  350. package/src/plugins/builtin/chart-composer/headless.ts +253 -35
  351. package/src/plugins/builtin/chart-composer/index.tsx +12 -2
  352. package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
  353. package/src/plugins/builtin/chart-composer/pane.tsx +127 -28
  354. package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
  355. package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
  356. package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
  357. package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
  358. package/src/plugins/builtin/chart-composer/settings.ts +31 -19
  359. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
  360. package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
  361. package/src/plugins/builtin/chat/attachments/model.ts +3 -1
  362. package/src/plugins/builtin/chat/content/index.tsx +1 -1
  363. package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
  364. package/src/plugins/builtin/chat/people.ts +1 -1
  365. package/src/plugins/builtin/clinical-trials/client.ts +5 -2
  366. package/src/plugins/builtin/clinical-trials/model.ts +13 -4
  367. package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
  368. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
  369. package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
  370. package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
  371. package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
  372. package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
  373. package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
  374. package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
  375. package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
  376. package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
  377. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  378. package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
  379. package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
  380. package/src/plugins/builtin/commodity-balances/pane.tsx +11 -4
  381. package/src/plugins/builtin/company-attention/app-rank.tsx +7 -5
  382. package/src/plugins/builtin/company-attention/building-model.ts +222 -0
  383. package/src/plugins/builtin/company-attention/building.tsx +172 -0
  384. package/src/plugins/builtin/company-attention/client.ts +117 -1
  385. package/src/plugins/builtin/company-attention/evidence.ts +16 -3
  386. package/src/plugins/builtin/company-attention/headless.ts +101 -5
  387. package/src/plugins/builtin/company-attention/index.tsx +6 -3
  388. package/src/plugins/builtin/company-attention/model.ts +33 -7
  389. package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
  390. package/src/plugins/builtin/company-attention/moves.tsx +159 -0
  391. package/src/plugins/builtin/company-attention/pane.tsx +79 -23
  392. package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
  393. package/src/plugins/builtin/company-attention/signals.tsx +160 -0
  394. package/src/plugins/builtin/company-kpis/headless.ts +3 -2
  395. package/src/plugins/builtin/company-kpis/model.ts +2 -2
  396. package/src/plugins/builtin/company-kpis/pane.tsx +1 -1
  397. package/src/plugins/builtin/composite-plugins.ts +2 -1
  398. package/src/plugins/builtin/congress-trades/headless.ts +1 -1
  399. package/src/plugins/builtin/connections/index.ts +1 -0
  400. package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
  401. package/src/plugins/builtin/correlation/headless.ts +5 -3
  402. package/src/plugins/builtin/cot/headless.ts +28 -6
  403. package/src/plugins/builtin/cot/model.ts +12 -0
  404. package/src/plugins/builtin/cot/pane.tsx +3 -2
  405. package/src/plugins/builtin/cpi/headless.ts +5 -1
  406. package/src/plugins/builtin/cpi/pane.tsx +11 -9
  407. package/src/plugins/builtin/credit-boards/model.ts +2 -0
  408. package/src/plugins/builtin/credit-documents/headless.ts +1 -1
  409. package/src/plugins/builtin/crypto-board/client.ts +86 -0
  410. package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
  411. package/src/plugins/builtin/crypto-board/defi.ts +239 -0
  412. package/src/plugins/builtin/crypto-board/headless.ts +117 -6
  413. package/src/plugins/builtin/crypto-board/index.tsx +8 -3
  414. package/src/plugins/builtin/crypto-board/model.ts +40 -8
  415. package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
  416. package/src/plugins/builtin/crypto-board/series.ts +19 -1
  417. package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
  418. package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
  419. package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
  420. package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
  421. package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
  422. package/src/plugins/builtin/debug/index.tsx +1 -0
  423. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  424. package/src/plugins/builtin/docs/index.tsx +1 -1
  425. package/src/plugins/builtin/docs/pane.tsx +2 -2
  426. package/src/plugins/builtin/docs/targets.ts +1 -1
  427. package/src/plugins/builtin/doe/client.ts +5 -1
  428. package/src/plugins/builtin/doe/headless.ts +12 -6
  429. package/src/plugins/builtin/doe/model.ts +43 -6
  430. package/src/plugins/builtin/doe/pane.tsx +18 -11
  431. package/src/plugins/builtin/earnings/board-model.ts +13 -6
  432. package/src/plugins/builtin/earnings/board-table.ts +4 -1
  433. package/src/plugins/builtin/earnings/board.tsx +253 -50
  434. package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
  435. package/src/plugins/builtin/earnings/calendar.tsx +338 -0
  436. package/src/plugins/builtin/earnings/client.ts +4 -3
  437. package/src/plugins/builtin/earnings/headless.ts +53 -15
  438. package/src/plugins/builtin/earnings/history-model.ts +53 -36
  439. package/src/plugins/builtin/earnings/index.tsx +15 -22
  440. package/src/plugins/builtin/earnings/model.ts +17 -12
  441. package/src/plugins/builtin/earnings/scope.ts +89 -0
  442. package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
  443. package/src/plugins/builtin/earnings-calls/data.ts +146 -2
  444. package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
  445. package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
  446. package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
  447. package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
  448. package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
  449. package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
  450. package/src/plugins/builtin/econ/calendar-model.ts +132 -20
  451. package/src/plugins/builtin/econ/detail-view.tsx +48 -10
  452. package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
  453. package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
  454. package/src/plugins/builtin/econ/index.tsx +112 -25
  455. package/src/plugins/builtin/econ/print-watch.ts +2 -1
  456. package/src/plugins/builtin/econ/types.ts +32 -1
  457. package/src/plugins/builtin/econ-statistics/client.ts +16 -3
  458. package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
  459. package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
  460. package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
  461. package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
  462. package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
  463. package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
  464. package/src/plugins/builtin/econ-statistics/view.ts +16 -1
  465. package/src/plugins/builtin/equity-screener/client.ts +21 -3
  466. package/src/plugins/builtin/equity-screener/headless.ts +68 -6
  467. package/src/plugins/builtin/equity-screener/live.ts +1 -1
  468. package/src/plugins/builtin/equity-screener/model.ts +6 -0
  469. package/src/plugins/builtin/equity-screener/pane.tsx +45 -10
  470. package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
  471. package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
  472. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
  473. package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
  474. package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
  475. package/src/plugins/builtin/exposure/headless.ts +51 -6
  476. package/src/plugins/builtin/exposure/index.tsx +28 -2
  477. package/src/plugins/builtin/exposure/model.ts +7 -0
  478. package/src/plugins/builtin/exposure/pane.tsx +6 -1
  479. package/src/plugins/builtin/fear-greed/index.tsx +1 -1
  480. package/src/plugins/builtin/filing-events/index.tsx +1 -1
  481. package/src/plugins/builtin/futures/model.ts +10 -9
  482. package/src/plugins/builtin/futures/returns.ts +8 -36
  483. package/src/plugins/builtin/futures/table.tsx +1 -1
  484. package/src/plugins/builtin/futures-curve/client.ts +40 -9
  485. package/src/plugins/builtin/futures-curve/headless.ts +39 -17
  486. package/src/plugins/builtin/futures-curve/model.ts +258 -69
  487. package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
  488. package/src/plugins/builtin/fx-matrix/client.ts +15 -8
  489. package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
  490. package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
  491. package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
  492. package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
  493. package/src/plugins/builtin/gpu/headless.ts +9 -4
  494. package/src/plugins/builtin/help/index.tsx +13 -3
  495. package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
  496. package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
  497. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  498. package/src/plugins/builtin/holders/client.ts +13 -1
  499. package/src/plugins/builtin/holders/format.ts +28 -17
  500. package/src/plugins/builtin/holders/headless.ts +46 -7
  501. package/src/plugins/builtin/holders/index-holders.ts +264 -0
  502. package/src/plugins/builtin/holders/pane.tsx +79 -15
  503. package/src/plugins/builtin/holders/report-rows.ts +35 -7
  504. package/src/plugins/builtin/holders/table-model.ts +2 -1
  505. package/src/plugins/builtin/holders/treemap.tsx +2 -2
  506. package/src/plugins/builtin/insider/headless.ts +1 -1
  507. package/src/plugins/builtin/insider/signals-client.ts +1 -1
  508. package/src/plugins/builtin/insider/signals.tsx +1 -1
  509. package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
  510. package/src/plugins/builtin/iv-history/client.ts +20 -0
  511. package/src/plugins/builtin/iv-history/headless.ts +4 -4
  512. package/src/plugins/builtin/iv-history/index.tsx +1 -1
  513. package/src/plugins/builtin/iv-history/model.ts +13 -4
  514. package/src/plugins/builtin/iv-history/series.ts +3 -1
  515. package/src/plugins/builtin/jobs/lock-note.ts +1 -1
  516. package/src/plugins/builtin/jobs/model.ts +4 -15
  517. package/src/plugins/builtin/jobs/pane.tsx +7 -5
  518. package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
  519. package/src/plugins/builtin/jodi/pane.tsx +10 -4
  520. package/src/plugins/builtin/layout-manager/index.tsx +1 -0
  521. package/src/plugins/builtin/macro-day/headless.ts +20 -7
  522. package/src/plugins/builtin/macro-day/index.tsx +3 -2
  523. package/src/plugins/builtin/macro-day/model.ts +29 -8
  524. package/src/plugins/builtin/macro-day/pane.tsx +46 -10
  525. package/src/plugins/builtin/macro-day/releases.ts +55 -13
  526. package/src/plugins/builtin/market-heatmap/data.ts +9 -2
  527. package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
  528. package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
  529. package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
  530. package/src/plugins/builtin/market-heatmap/model.ts +10 -7
  531. package/src/plugins/builtin/market-movers/client.ts +33 -19
  532. package/src/plugins/builtin/market-movers/headless.ts +8 -2
  533. package/src/plugins/builtin/market-movers/index.tsx +16 -10
  534. package/src/plugins/builtin/market-movers/screener.ts +29 -8
  535. package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
  536. package/src/plugins/builtin/market-movers/session-table.ts +4 -2
  537. package/src/plugins/builtin/market-movers/table.ts +4 -1
  538. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  539. package/src/plugins/builtin/market-valuation/view.ts +5 -0
  540. package/src/plugins/builtin/members/headless.ts +6 -5
  541. package/src/plugins/builtin/members/pane.tsx +11 -4
  542. package/src/plugins/builtin/mna/client.ts +1 -0
  543. package/src/plugins/builtin/mna/detail.tsx +20 -32
  544. package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
  545. package/src/plugins/builtin/mna/distress/model.ts +3 -2
  546. package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
  547. package/src/plugins/builtin/mna/headless.ts +6 -13
  548. package/src/plugins/builtin/mna/model.ts +93 -15
  549. package/src/plugins/builtin/mna/pane.tsx +5 -4
  550. package/src/plugins/builtin/news/headless.ts +12 -6
  551. package/src/plugins/builtin/news/index.tsx +10 -1
  552. package/src/plugins/builtin/news/wire/index.tsx +3 -2
  553. package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
  554. package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
  555. package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
  556. package/src/plugins/builtin/notes/cli.ts +49 -14
  557. package/src/plugins/builtin/openfda/pane.tsx +1 -1
  558. package/src/plugins/builtin/options/carry.ts +2 -2
  559. package/src/plugins/builtin/options/index.tsx +1 -1
  560. package/src/plugins/builtin/options/view.tsx +10 -10
  561. package/src/plugins/builtin/options-calculator/headless.ts +46 -7
  562. package/src/plugins/builtin/options-scenario/client.ts +123 -28
  563. package/src/plugins/builtin/options-scenario/collar.ts +8 -6
  564. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
  565. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
  566. package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
  567. package/src/plugins/builtin/options-scenario/csp.ts +101 -21
  568. package/src/plugins/builtin/options-scenario/headless.ts +36 -15
  569. package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
  570. package/src/plugins/builtin/options-scenario/index.tsx +28 -3
  571. package/src/plugins/builtin/options-scenario/model.ts +13 -0
  572. package/src/plugins/builtin/options-scenario/pane.tsx +9 -5
  573. package/src/plugins/builtin/perps/equity-row.tsx +11 -3
  574. package/src/plugins/builtin/perps/freshness.ts +8 -5
  575. package/src/plugins/builtin/perps/headless.ts +3 -1
  576. package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
  577. package/src/plugins/builtin/perps/live-rows.ts +161 -0
  578. package/src/plugins/builtin/perps/markets-section.tsx +154 -0
  579. package/src/plugins/builtin/perps/pane.tsx +36 -17
  580. package/src/plugins/builtin/perps/venue-markets.ts +96 -0
  581. package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
  582. package/src/plugins/builtin/plugin-marketplace/pane.tsx +143 -59
  583. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +72 -24
  584. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
  585. package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
  586. package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
  587. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
  588. package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
  589. package/src/plugins/builtin/portfolio-list/income.ts +13 -2
  590. package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
  591. package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
  592. package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
  593. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
  594. package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
  595. package/src/plugins/builtin/power/client.ts +4 -1
  596. package/src/plugins/builtin/power/evidence.ts +22 -7
  597. package/src/plugins/builtin/power/gas.tsx +5 -1
  598. package/src/plugins/builtin/power/pane.tsx +8 -1
  599. package/src/plugins/builtin/power/prices.tsx +10 -3
  600. package/src/plugins/builtin/research/analyst-headless.ts +25 -8
  601. package/src/plugins/builtin/research/analyst-model.ts +68 -3
  602. package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
  603. package/src/plugins/builtin/research/event-model.ts +3 -1
  604. package/src/plugins/builtin/research/event-sources.ts +12 -4
  605. package/src/plugins/builtin/research/index.tsx +2 -1
  606. package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
  607. package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
  608. package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
  609. package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
  610. package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
  611. package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
  612. package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
  613. package/src/plugins/builtin/reverse-dcf/model.ts +6 -2
  614. package/src/plugins/builtin/risk-factors/index.tsx +2 -2
  615. package/src/plugins/builtin/scanner/lock-note.ts +1 -1
  616. package/src/plugins/builtin/sec/forms.ts +13 -0
  617. package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
  618. package/src/plugins/builtin/sec/fund-facts.ts +68 -8
  619. package/src/plugins/builtin/sec/headless.ts +85 -8
  620. package/src/plugins/builtin/sec/index.tsx +58 -12
  621. package/src/plugins/builtin/sectors/client.ts +2 -1
  622. package/src/plugins/builtin/sectors/sector-model.ts +11 -15
  623. package/src/plugins/builtin/series-inventory.ts +2 -0
  624. package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
  625. package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
  626. package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
  627. package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
  628. package/src/plugins/builtin/shared/earnings-report.ts +3 -3
  629. package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
  630. package/src/plugins/builtin/shared/job-posting.ts +129 -0
  631. package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
  632. package/src/plugins/builtin/shared/report-freshness.ts +3 -0
  633. package/src/plugins/builtin/shared/research-trading.tsx +21 -0
  634. package/src/plugins/builtin/shared/series-cache.ts +2 -0
  635. package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
  636. package/src/plugins/builtin/short-interest/client.ts +2 -0
  637. package/src/plugins/builtin/short-interest/headless.ts +41 -12
  638. package/src/plugins/builtin/short-interest/index.tsx +23 -1
  639. package/src/plugins/builtin/short-interest/model.ts +70 -19
  640. package/src/plugins/builtin/short-interest/pane.tsx +19 -2
  641. package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
  642. package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
  643. package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
  644. package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
  645. package/src/plugins/builtin/short-interest/schedule.ts +35 -2
  646. package/src/plugins/builtin/short-interest/surface.tsx +11 -4
  647. package/src/plugins/builtin/short-interest/types.ts +9 -0
  648. package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
  649. package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
  650. package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
  651. package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
  652. package/src/plugins/builtin/supply-chain/model.ts +51 -3
  653. package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
  654. package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
  655. package/src/plugins/builtin/themes/headless.ts +8 -5
  656. package/src/plugins/builtin/themes/model.ts +14 -4
  657. package/src/plugins/builtin/themes/pane.tsx +24 -5
  658. package/src/plugins/builtin/thirteenf/headless.ts +5 -5
  659. package/src/plugins/builtin/thirteenf/signals.ts +3 -1
  660. package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
  661. package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
  662. package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
  663. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
  664. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
  665. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
  666. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
  667. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
  668. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
  669. package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
  670. package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
  671. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
  672. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
  673. package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
  674. package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
  675. package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
  676. package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
  677. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
  678. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
  679. package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
  680. package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
  681. package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
  682. package/src/plugins/builtin/vol-surface/client.ts +5 -4
  683. package/src/plugins/builtin/vol-surface/headless.ts +12 -3
  684. package/src/plugins/builtin/vol-surface/model.ts +4 -2
  685. package/src/plugins/builtin/volatility/model.ts +5 -10
  686. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
  687. package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
  688. package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
  689. package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
  690. package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
  691. package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
  692. package/src/plugins/builtin/world-venue-map/index.ts +3 -26
  693. package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
  694. package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
  695. package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
  696. package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
  697. package/src/plugins/builtin/yield-curve/client.ts +25 -0
  698. package/src/plugins/builtin/yield-curve/curves.ts +7 -4
  699. package/src/plugins/builtin/yield-curve/headless.ts +38 -4
  700. package/src/plugins/builtin/yield-curve/history.ts +4 -3
  701. package/src/plugins/builtin/yield-curve/index.tsx +12 -6
  702. package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
  703. package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
  704. package/src/plugins/bundle.ts +1 -1
  705. package/src/plugins/catalog-browser.ts +2 -1
  706. package/src/plugins/compat.ts +3 -3
  707. package/src/plugins/dependencies.ts +75 -14
  708. package/src/plugins/extracted-plugins.ts +132 -34
  709. package/src/plugins/host-link.ts +149 -34
  710. package/src/plugins/installer.ts +35 -10
  711. package/src/plugins/loader.ts +206 -38
  712. package/src/plugins/manager-node.ts +2 -2
  713. package/src/plugins/marketplace/deactivation.ts +22 -0
  714. package/src/plugins/marketplace/model.ts +2 -2
  715. package/src/plugins/marketplace/packs.ts +1 -1
  716. package/src/plugins/ownership.ts +1 -1
  717. package/src/plugins/peer-retry.ts +155 -0
  718. package/src/plugins/registry/contributions.ts +3 -1
  719. package/src/plugins/registry/index.ts +4 -3
  720. package/src/plugins/registry/plugin-state.ts +3 -0
  721. package/src/plugins/seed-notice.ts +20 -0
  722. package/src/plugins/shortcut-argument.ts +39 -0
  723. package/src/portfolio/allocation.ts +1 -1
  724. package/src/portfolio/collection-name.ts +31 -0
  725. package/src/portfolio/column-values.ts +10 -8
  726. package/src/portfolio/cost-fx.ts +296 -19
  727. package/src/portfolio/manual-lots.ts +75 -0
  728. package/src/portfolio/mutations.ts +60 -22
  729. package/src/portfolio/suffixed-listings.ts +209 -0
  730. package/src/portfolio/totals-currency.ts +24 -0
  731. package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
  732. package/src/public/time-series.ts +11 -8
  733. package/src/remote/schema.ts +1 -1
  734. package/src/renderers/browser/config-host.ts +3 -0
  735. package/src/renderers/browser/main.tsx +23 -3
  736. package/src/renderers/dom/boot-frame-page.ts +187 -0
  737. package/src/renderers/dom/boot-frame.ts +237 -0
  738. package/src/renderers/dom/build-assets.ts +46 -8
  739. package/src/renderers/dom/dom-ui-host.tsx +4 -29
  740. package/src/renderers/dom/host/ascii-text.ts +16 -2
  741. package/src/renderers/dom/host/box.tsx +43 -2
  742. package/src/renderers/dom/host/chart-surface.tsx +2 -0
  743. package/src/renderers/dom/host/hls.chunk.ts +3 -0
  744. package/src/renderers/dom/host/image-surface.tsx +49 -0
  745. package/src/renderers/dom/host/media-surface.tsx +24 -18
  746. package/src/renderers/dom/host/mouse.ts +30 -0
  747. package/src/renderers/dom/host/size-observer.ts +1 -1
  748. package/src/renderers/dom/host/style.ts +1 -1
  749. package/src/renderers/dom/styles.css +76 -0
  750. package/src/renderers/dom/test-utils.tsx +2 -1
  751. package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
  752. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
  753. package/src/renderers/electrobun/bun/desktop/backend.ts +46 -3
  754. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
  755. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
  756. package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
  757. package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
  758. package/src/renderers/electrobun/bun/index.ts +11 -1
  759. package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
  760. package/src/renderers/electrobun/bun/window/create.ts +4 -1
  761. package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
  762. package/src/renderers/electrobun/shared/protocol.ts +6 -1
  763. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
  764. package/src/renderers/electrobun/view/config-host.ts +3 -0
  765. package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
  766. package/src/renderers/electrobun/view/main.tsx +30 -4
  767. package/src/renderers/electrobun/view/news-source.ts +5 -5
  768. package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -1
  769. package/src/renderers/electrobun/view/ui-host.tsx +1 -1
  770. package/src/renderers/opentui/browser-open.ts +88 -0
  771. package/src/renderers/opentui/host.tsx +5 -14
  772. package/src/renderers/opentui/image/loader.ts +3 -2
  773. package/src/renderers/opentui/native-smoke.ts +10 -1
  774. package/src/renderers/opentui/pane-image/index.ts +2 -1
  775. package/src/renderers/opentui/render-lib.ts +253 -0
  776. package/src/renderers/opentui/render-timing-smoke.ts +1 -1
  777. package/src/renderers/opentui/start.tsx +1 -1
  778. package/src/renderers/share/layout-view.tsx +2 -2
  779. package/src/renderers/share/main.tsx +4 -4
  780. package/src/renderers/share/view.tsx +1 -1
  781. package/src/series/resolve.ts +22 -6
  782. package/src/series/standalone.ts +30 -2
  783. package/src/series/types.ts +8 -1
  784. package/src/shares/api.ts +4 -1
  785. package/src/shares/pane.ts +1 -1
  786. package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
  787. package/src/sources/gloomberb-cloud/index.ts +32 -16
  788. package/src/sources/gloomberb-cloud/news.ts +39 -0
  789. package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
  790. package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
  791. package/src/sources/listing-symbols.ts +37 -0
  792. package/src/sources/provider-errors.ts +16 -2
  793. package/src/sources/provider-router/financial-routes.ts +21 -3
  794. package/src/sources/provider-router/financials.ts +15 -2
  795. package/src/sources/provider-router/history.ts +30 -8
  796. package/src/sources/provider-router/primary.ts +1 -1
  797. package/src/state/app/bootstrap.ts +23 -0
  798. package/src/state/hooks/inline-tickers.ts +30 -5
  799. package/src/sync/controller.ts +1 -1
  800. package/src/sync/core-contributors.ts +46 -14
  801. package/src/team/collections-sync.ts +2 -1
  802. package/src/team/collections.ts +178 -17
  803. package/src/telemetry/crash-reports.ts +17 -4
  804. package/src/test-support/builtin-panes.ts +1 -1
  805. package/src/theme/colors.ts +3 -30
  806. package/src/theme/ui-tokens.ts +37 -1
  807. package/src/tickers/company-name-listing.ts +210 -33
  808. package/src/tickers/index-roots.ts +47 -0
  809. package/src/tickers/instrument-label.ts +5 -1
  810. package/src/tickers/metadata.ts +10 -0
  811. package/src/tickers/perpetual-listing.ts +5 -2
  812. package/src/tickers/search/home-listing.ts +75 -0
  813. package/src/tickers/search/index.ts +76 -27
  814. package/src/tickers/search/ranking.ts +54 -4
  815. package/src/tickers/search/upsert.ts +29 -0
  816. package/src/tickers/terminal-codes.ts +416 -40
  817. package/src/time-series/bar-aggregation.ts +243 -0
  818. package/src/time-series/base-series.ts +307 -0
  819. package/src/time-series/chart-bounds.ts +349 -0
  820. package/src/time-series/chart-seed.ts +142 -0
  821. package/src/time-series/economic.ts +5 -0
  822. package/src/time-series/fundamentals.ts +18 -3
  823. package/src/time-series/history-acquisition.ts +499 -0
  824. package/src/time-series/leverage.ts +100 -0
  825. package/src/time-series/market-resolution.ts +4 -2
  826. package/src/time-series/market.ts +2 -1
  827. package/src/time-series/price-comparison.ts +175 -30
  828. package/src/time-series/range.ts +9 -1
  829. package/src/time-series/resolution.ts +174 -16
  830. package/src/time-series/resolve-context.ts +157 -0
  831. package/src/time-series/resolve.ts +126 -1577
  832. package/src/time-series/series-name.ts +38 -0
  833. package/src/time-series/series-presentation.ts +208 -0
  834. package/src/time-series/spec.ts +11 -6
  835. package/src/time-series/studies.ts +109 -12
  836. package/src/time-series/tail-reconcile.ts +121 -0
  837. package/src/time-series/types.ts +29 -2
  838. package/src/time-series/use-chart-resolution.ts +4 -5
  839. package/src/types/broker.ts +10 -0
  840. package/src/types/config.ts +14 -0
  841. package/src/types/data-provider.ts +14 -0
  842. package/src/types/exchange-rate.ts +6 -0
  843. package/src/types/financials.ts +104 -7
  844. package/src/types/headless.ts +76 -6
  845. package/src/types/instrument.ts +3 -0
  846. package/src/types/plugin.ts +65 -8
  847. package/src/types/price-history.ts +2 -0
  848. package/src/types/ticker.ts +13 -0
  849. package/src/types/trading.ts +59 -1
  850. package/src/ui/ascii-font.ts +13 -1
  851. package/src/ui/host.tsx +6 -1
  852. package/src/updater/command-names.ts +175 -0
  853. package/src/updater/index.ts +10 -5
  854. package/src/utils/calendar-date.ts +32 -15
  855. package/src/utils/cash-runway.ts +241 -0
  856. package/src/utils/central-banks.ts +42 -0
  857. package/src/utils/cli-output.ts +259 -80
  858. package/src/utils/contract-month.ts +16 -0
  859. package/src/utils/crypto-pair.ts +61 -3
  860. package/src/utils/currency-units.ts +29 -0
  861. package/src/utils/datetime-format.ts +10 -0
  862. package/src/utils/debug-log.ts +1 -1
  863. package/src/utils/decimal-comma.ts +39 -6
  864. package/src/utils/exchange-announcements.ts +71 -0
  865. package/src/utils/exchange-rate-snapshot.ts +10 -0
  866. package/src/utils/financial-statements.ts +83 -4
  867. package/src/utils/format.ts +34 -16
  868. package/src/utils/fundamentals.ts +150 -34
  869. package/src/utils/fx-market-hours.ts +10 -1
  870. package/src/utils/latest-financial-period.ts +8 -0
  871. package/src/utils/linux-libc.ts +54 -0
  872. package/src/utils/market-capitalization.ts +111 -15
  873. package/src/utils/max-drawdown.ts +64 -0
  874. package/src/utils/network-failure.ts +83 -0
  875. package/src/utils/option-expiry.ts +139 -7
  876. package/src/utils/price-earnings.ts +11 -5
  877. package/src/utils/price-history.ts +18 -8
  878. package/src/utils/price-window.ts +131 -0
  879. package/src/utils/release-date.ts +47 -0
  880. package/src/utils/sec.ts +3 -0
  881. package/src/utils/throttled-fetch.ts +11 -4
  882. package/src/utils/trailing-eps.ts +67 -0
  883. package/src/utils/typed-text.ts +21 -0
  884. package/src/utils/utc-time.ts +24 -1
  885. package/src/version.ts +6 -0
  886. package/src/cli/pane-functions/screenshot.ts +0 -2122
@@ -22,6 +22,7 @@ import {
22
22
  type PaneHint,
23
23
  } from "../../../components";
24
24
  import { loadingErrorFooterInfo } from "../../../components/data-table/table-pane";
25
+ import { useRowNotes } from "../../../components/ui/row-notes";
25
26
  import { colors } from "../../../theme/colors";
26
27
  import { t, tf } from "../../../i18n";
27
28
  import type { PaneProps } from "../../../types/plugin";
@@ -68,6 +69,7 @@ import {
68
69
  versionLabel,
69
70
  type MarketplaceEntry,
70
71
  type MarketplaceRow,
72
+ type MarketplaceStatus,
71
73
  type MarketplaceStatusKind,
72
74
  type RegistryPlugin,
73
75
  } from "../../marketplace/model";
@@ -165,7 +167,7 @@ function renderCell(
165
167
  row: MarketplaceRow,
166
168
  column: Column,
167
169
  rowState: { selected: boolean },
168
- busyId: string | null,
170
+ rowStatus: (entry: MarketplaceEntry) => MarketplaceStatus,
169
171
  facts: (entry: MarketplaceEntry) => EntryFacts,
170
172
  ): DataTableCell {
171
173
  if (row.type === "header") return { text: "" };
@@ -192,8 +194,7 @@ function renderCell(
192
194
  case "tagline":
193
195
  return { text: entry.tagline, color: selected ?? colors.textDim };
194
196
  case "status": {
195
- if (busyId === entry.id) return { text: "working", color: selected ?? colors.textDim };
196
- const status = statusOf(entry);
197
+ const status = rowStatus(entry);
197
198
  return { text: status.text, color: selected ?? STATUS_COLORS[status.kind] };
198
199
  }
199
200
  }
@@ -212,14 +213,21 @@ function describeContributions(entry: MarketplaceEntry, host: MarketplaceHost |
212
213
  return parts;
213
214
  }
214
215
 
215
- function EntryDetail({ entry, width, host }: { entry: MarketplaceEntry; width: number; host: MarketplaceHost | null }) {
216
+ function EntryDetail({ entry, width, host, status, failure }: {
217
+ entry: MarketplaceEntry;
218
+ width: number;
219
+ host: MarketplaceHost | null;
220
+ /** The row's STATUS. */
221
+ status: MarketplaceStatus;
222
+ /** What the last action on this plugin ran into, said in full. */
223
+ failure: ActionFailure | null;
224
+ }) {
216
225
  const contributes = describeContributions(entry, host);
217
226
  const live = entry.installed && host ? host.contributions(entry.id) : null;
218
227
  const opensWith = live
219
228
  ? live.templates.map((template) => template.prefix ?? template.label).filter(Boolean)
220
229
  : [];
221
230
  const rowWidth = Math.max(1, width - 2);
222
- const status = statusOf(entry);
223
231
 
224
232
  return (
225
233
  <ScrollBox flexDirection="column" width={width} flexGrow={1} flexBasis={0} minHeight={0} paddingLeft={1} paddingRight={1} scrollY focusable={false}>
@@ -236,6 +244,12 @@ function EntryDetail({ entry, width, host }: { entry: MarketplaceEntry; width: n
236
244
  </Box>
237
245
  ) : null}
238
246
 
247
+ {failure ? (
248
+ <Box paddingTop={1} flexDirection="column">
249
+ <Text fg={STATUS_COLORS[failure.kind ?? "failed"]} wrapText>{failure.text}</Text>
250
+ </Box>
251
+ ) : null}
252
+
239
253
  <Box paddingTop={1} flexDirection="column">
240
254
  {contributes.length > 0 ? <KeyValueRow labelWidth={10} width={rowWidth} emphasis={false} label="Adds" value={contributes.join(", ")} /> : null}
241
255
  {opensWith.length > 0 ? <KeyValueRow labelWidth={10} width={rowWidth} emphasis={false} label="Opens with" value={opensWith.join(", ")} /> : null}
@@ -246,7 +260,7 @@ function EntryDetail({ entry, width, host }: { entry: MarketplaceEntry; width: n
246
260
  */}
247
261
  {entry.hosts.length > 0 ? <KeyValueRow labelWidth={10} width={rowWidth} emphasis={false} label="Declares" value={entry.hosts.join(", ")} /> : null}
248
262
  {entry.repo ? <KeyValueRow labelWidth={10} width={rowWidth} emphasis={false} label="Source" value={`github.com/${entry.repo}`} /> : null}
249
- {entry.minGloomberb ? <KeyValueRow labelWidth={10} width={rowWidth} emphasis={false} label="Requires" value={requiredGloomberb(entry.minGloomberb) ? `Gloomberb ${entry.minGloomberb}, this is ${VERSION}` : `Gloomberb ${entry.minGloomberb}`} /> : null}
263
+ {entry.minGloomberb ? <KeyValueRow labelWidth={10} width={rowWidth} emphasis={false} label="Requires" value={requiredGloomberb(entry.minGloomberb) ? `Gloom ${entry.minGloomberb}, this is ${VERSION}` : `Gloom ${entry.minGloomberb}`} /> : null}
250
264
  {entry.linked ? <KeyValueRow labelWidth={10} width={rowWidth} emphasis={false} label="Linked" value={entry.directory ?? "local checkout"} /> : null}
251
265
  {entry.installedCommit ? <KeyValueRow labelWidth={10} width={rowWidth} emphasis={false} label="Commit" value={entry.installedCommit.slice(0, 7)} /> : null}
252
266
  {!entry.installed && entry.availableCommit ? <KeyValueRow labelWidth={10} width={rowWidth} emphasis={false} label="Pinned" value={`${entry.availableVersion ?? ""} ${entry.availableCommit.slice(0, 7)}`.trim()} /> : null}
@@ -259,7 +273,7 @@ function EntryDetail({ entry, width, host }: { entry: MarketplaceEntry; width: n
259
273
  runsExternalPlugins() ? (
260
274
  <Box paddingTop={1} flexDirection="column">
261
275
  <Text fg={colors.textDim}>Runs with your full permissions. Read the source first.</Text>
262
- <Text fg={colors.textBright}>{`gloomberb install ${entry.repo}`}</Text>
276
+ <Text fg={colors.textBright}>{`gloom install ${entry.repo}`}</Text>
263
277
  </Box>
264
278
  ) : (
265
279
  // No shell here, so the install command would be a dead end. Say
@@ -321,7 +335,7 @@ function BuiltinDetail({ entry, width, facts, scrollRef }: {
321
335
  <RemoteImage
322
336
  key={code}
323
337
  src={functionShotUrl(code)}
324
- alt={`${code} in Gloomberb`}
338
+ alt={`${code} in Gloom`}
325
339
  label={code}
326
340
  width={shotWidth}
327
341
  height={Math.max(8, Math.floor(shotWidth * 0.3))}
@@ -400,6 +414,25 @@ function PackChangeBody({ change, name }: { change: PackChange; name: (id: strin
400
414
 
401
415
  type Busy = { id: string; verb: "installing" | "updating" | "removing" } | null;
402
416
 
417
+ /**
418
+ * What the last action on one plugin ran into, said on its row: `status` in
419
+ * STATUS, `text` in its detail. It stands while the row's own status is what
420
+ * it was when the failure first showed, and goes when that moves: a toggle,
421
+ * a restart, a later install.
422
+ */
423
+ interface ActionFailure {
424
+ status: string;
425
+ text: string;
426
+ /** STATUS's tone; a failure by default. */
427
+ kind?: MarketplaceStatusKind;
428
+ }
429
+
430
+ function statusKey(entry: MarketplaceEntry): string {
431
+ const status = statusOf(entry);
432
+ return `${status.kind}:${status.text}`;
433
+ }
434
+ const entryId = (entry: MarketplaceEntry) => entry.id;
435
+
403
436
  export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
404
437
  const dialog = useDialog();
405
438
  const { createPaneFromTemplate, showPane, openPluginCommandWorkflow, notify } = usePluginAppActions();
@@ -419,14 +452,15 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
419
452
  // Bumped after any local change so the list is re-read from the host.
420
453
  const [localRevision, setLocalRevision] = useState(0);
421
454
  const [busy, setBusy] = useState<Busy>(null);
422
- const [lastError, setLastError] = useState<string | null>(null);
423
455
  // Remote heads for plugins the registry does not pin, so a private or
424
456
  // side-loaded install can report an update like every other row.
425
457
  const [remoteHeads, setRemoteHeads] = useState<Record<string, string>>({});
426
458
  const [checkingRemotes, setCheckingRemotes] = useState(false);
427
- const busyId = busy?.id ?? null;
459
+ const [remoteCheckError, setRemoteCheckError] = useState<string | null>(null);
460
+ const [remoteRevision, setRemoteRevision] = useState(0);
428
461
 
429
462
  const refresh = useCallback((force: boolean) => {
463
+ if (force) setRemoteRevision((value) => value + 1);
430
464
  setStatus((current) => (current === "ready" ? current : "loading"));
431
465
  void loadRegistry({ force }).then((result) => {
432
466
  setRegistry(result.plugins);
@@ -461,12 +495,22 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
461
495
  return facts;
462
496
  };
463
497
  }, [entries, host]);
498
+ // By plugin id, until the next action on the plugin. A failure takes the
499
+ // row's status as the list shows it after the action, and goes once that
500
+ // status moves on.
501
+ const { noteFor: failureFor, setNote: setFailure } = useRowNotes<MarketplaceEntry, ActionFailure>(entries, { key: entryId, signature: statusKey });
502
+ // What an action on one plugin is doing, or ran into, is said on its row.
503
+ const rowStatus = useCallback((entry: MarketplaceEntry): MarketplaceStatus => {
504
+ if (busy?.id === entry.id) return { kind: "none", text: busy.verb };
505
+ const failure = failureFor(entry);
506
+ return failure ? { kind: failure.kind ?? "failed", text: failure.status } : statusOf(entry);
507
+ }, [busy, failureFor]);
464
508
  const renderRow = useCallback((
465
509
  row: MarketplaceRow,
466
510
  column: Column,
467
511
  _index: number,
468
512
  rowState: { selected: boolean },
469
- ) => renderCell(row, column, rowState, busyId, factsFor), [busyId, factsFor]);
513
+ ) => renderCell(row, column, rowState, rowStatus, factsFor), [factsFor, rowStatus]);
470
514
 
471
515
  // Keyed by the folders themselves: the entries array is rebuilt whenever an
472
516
  // answer lands, and re-running the check on its own result would never stop.
@@ -477,24 +521,42 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
477
521
  const unlistedKey = unlistedDirectories.join(",");
478
522
 
479
523
  useEffect(() => {
524
+ const directories = unlistedKey ? unlistedKey.split(",") : [];
525
+ const eligible = new Set(directories);
526
+ // Forget removed or newly pinned/linked installs, including the last one.
527
+ setRemoteHeads((previous) => {
528
+ const retained = Object.entries(previous).filter(([directory]) => eligible.has(directory));
529
+ return retained.length === Object.keys(previous).length ? previous : Object.fromEntries(retained);
530
+ });
531
+ setRemoteCheckError(null);
480
532
  const check = manager?.remoteHeads;
481
- if (!check || unlistedKey.length === 0) return;
533
+ if (!check || directories.length === 0) {
534
+ setCheckingRemotes(false);
535
+ return;
536
+ }
482
537
  let cancelled = false;
483
538
  setCheckingRemotes(true);
484
- void check(unlistedKey.split(","))
485
- // Offline, or a private repository this machine has no credentials for:
486
- // the row keeps whatever it knew, without an error in the way.
487
- .catch(logFailure("plugin-marketplace.pane", "Check installed plugin remote heads failed", {}))
488
- .then((heads) => {
539
+ void (async () => {
540
+ try {
541
+ const heads = await check(directories);
489
542
  if (cancelled) return;
490
- setRemoteHeads(heads);
491
- setCheckingRemotes(false);
492
- });
493
- return () => {
494
- cancelled = true;
495
- setCheckingRemotes(false);
496
- };
497
- }, [manager, unlistedKey, localRevision]);
543
+ // An omitted folder is unanswered, not proof that it is up to date.
544
+ const answers = directories.filter((directory) => !!heads[directory]);
545
+ setRemoteHeads((previous) => ({
546
+ ...previous,
547
+ ...Object.fromEntries(answers.map((directory) => [directory, heads[directory]!])),
548
+ }));
549
+ setRemoteCheckError(answers.length < directories.length ? "Update check incomplete" : null);
550
+ } catch (error) {
551
+ if (cancelled) return;
552
+ logFailure("plugin-marketplace.pane", "Check installed plugin remote heads failed")(error);
553
+ setRemoteCheckError("Plugin update check failed");
554
+ } finally {
555
+ if (!cancelled) setCheckingRemotes(false);
556
+ }
557
+ })();
558
+ return () => { cancelled = true; };
559
+ }, [manager, unlistedKey, localRevision, remoteRevision]);
498
560
 
499
561
  const visible = useMemo(
500
562
  () => filterEntries(entries, { query, category, showBuiltin }),
@@ -546,16 +608,23 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
546
608
  /**
547
609
  * The registry's code for this plugin needs a newer Gloomberb. Installing or
548
610
  * updating would land it anyway and it would then fail to compile, so say
549
- * what to do instead. Also leaves a working older checkout alone, and does
550
- * not update one that already needs a newer Gloomberb: updates only move
551
- * forward, so that would not help either.
611
+ * what to do instead, on the row: its STATUS already says `needs …` unless
612
+ * something outranks it there (`failed`, `needs restart`). Also leaves a
613
+ * working older checkout alone, and does not update one that already needs
614
+ * a newer Gloomberb: updates only move forward, so that would not help either.
552
615
  */
553
616
  const refuseTooNew = useCallback((entry: MarketplaceEntry): boolean => {
554
617
  const required = requiredGloomberb(entry.minGloomberb) ?? entry.needsGloomberb;
555
618
  if (!required) return false;
556
- notify({ body: `${entry.name} needs Gloomberb ${required}. Update Gloomberb first.`, type: "error" });
619
+ if (statusOf(entry).kind !== "needs-gloomberb") {
620
+ setFailure(entry.id, {
621
+ kind: "needs-gloomberb",
622
+ status: `needs ${required}`,
623
+ text: `${entry.name} needs Gloom ${required}. Update Gloom first.`,
624
+ });
625
+ }
557
626
  return true;
558
- }, [notify]);
627
+ }, [setFailure]);
559
628
 
560
629
  const installSelected = useCallback(async () => {
561
630
  if (!selected || !isInstallable(selected) || !manager || !host || busy) return;
@@ -577,12 +646,11 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
577
646
 
578
647
  const entry = selected;
579
648
  setBusy({ id: entry.id, verb: "installing" });
580
- setLastError(null);
649
+ setFailure(entry.id, null);
581
650
  const result = await manager.install(repo, pin);
582
651
  if (!result.ok) {
583
652
  setBusy(null);
584
- setLastError(result.error);
585
- notify({ body: `Could not install ${entry.name}: ${result.error}`, type: "error" });
653
+ setFailure(entry.id, { status: "install failed", text: `Could not install ${entry.name}: ${result.error}` });
586
654
  return;
587
655
  }
588
656
  const activated = await activateInstall(result, host, manager);
@@ -590,8 +658,8 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
590
658
  bump();
591
659
  if (activated.ok && activated.restart) notify({ body: `Restart to finish installing ${entry.name}.`, type: "info" });
592
660
  else if (activated.ok) announceAdded(activated.pluginId, activated.name, "Installed", host);
593
- else notify({ body: `${entry.name} installed but did not load: ${activated.error}`, type: "error" });
594
- }, [announceAdded, bump, busy, confirmWidth, dialog, host, manager, notify, refuseTooNew, selected]);
661
+ else setFailure(entry.id, { status: "load failed", text: `${entry.name} installed but did not load: ${activated.error}` });
662
+ }, [announceAdded, bump, busy, confirmWidth, dialog, host, manager, notify, refuseTooNew, selected, setFailure]);
595
663
 
596
664
  const updateSelected = useCallback(async () => {
597
665
  if (!selected || !isManaged(selected) || !manager || !host || busy || selected.linked) return;
@@ -600,12 +668,11 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
600
668
  const entry = selected;
601
669
  const reinstall = !!entry.loadError;
602
670
  setBusy({ id: entry.id, verb: "updating" });
603
- setLastError(null);
671
+ setFailure(entry.id, null);
604
672
  const result = await manager.update(directory, registryPin(entry));
605
673
  if (!result.ok) {
606
674
  setBusy(null);
607
- setLastError(result.error);
608
- notify({ body: `Could not update ${entry.name}: ${result.error}`, type: "error" });
675
+ setFailure(entry.id, { status: "update failed", text: `Could not update ${entry.name}: ${result.error}` });
609
676
  return;
610
677
  }
611
678
  if (result.kept) {
@@ -621,9 +688,21 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
621
688
  } else if (activated.ok) {
622
689
  announceAdded(activated.pluginId, activated.name, reinstall ? "Reloaded" : "Updated", host);
623
690
  } else {
624
- notify({ body: `${entry.name} updated but did not load: ${activated.error}`, type: "error" });
691
+ setFailure(entry.id, { status: "load failed", text: `${entry.name} updated but did not load: ${activated.error}` });
625
692
  }
626
- }, [announceAdded, bump, busy, host, manager, notify, refuseTooNew, selected]);
693
+ }, [announceAdded, bump, busy, host, manager, notify, refuseTooNew, selected, setFailure]);
694
+
695
+ /**
696
+ * A removal that failed is said on the plugin's row while the list still
697
+ * has one. A stopped plugin can leave the list, files and all; then only a
698
+ * toast is left to say it.
699
+ */
700
+ const failRemoval = useCallback((entry: MarketplaceEntry, failure: ActionFailure) => {
701
+ const installed = host?.listInstalled() ?? [];
702
+ const listed = mergeCatalog({ registry, installed, target, remoteHeads }).some((candidate) => candidate.id === entry.id);
703
+ if (listed) setFailure(entry.id, failure);
704
+ else notify({ body: failure.text, type: "error" });
705
+ }, [host, notify, registry, remoteHeads, setFailure, target]);
627
706
 
628
707
  const removeSelected = useCallback(async () => {
629
708
  if (!selected || !isManaged(selected) || !manager || !host || busy) return;
@@ -638,18 +717,27 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
638
717
  });
639
718
  if (!confirmed) return;
640
719
  setBusy({ id: entry.id, verb: "removing" });
641
- setLastError(null);
642
- await host.deactivate(entry.id, entry.directory).catch(logFailure("plugin-marketplace.pane", "Deactivate plugin view before removal failed"));
643
- await manager.deactivate?.(entry.id).catch(logFailure("plugin-marketplace.pane", "Deactivate plugin host before removal failed"));
644
- const result = await manager.remove(entry.directory!);
645
- setBusy(null);
646
- bump();
647
- if (result.ok) notify({ body: `Removed ${entry.name}.`, type: "success" });
648
- else {
649
- setLastError(result.error);
650
- notify({ body: `Could not remove ${entry.name}: ${result.error}`, type: "error" });
720
+ setFailure(entry.id, null);
721
+ let removalStarted = false;
722
+ try {
723
+ // Stop the native side first: a successful view stop drops its catalog
724
+ // entry, so it must remain available if the native stop fails.
725
+ await manager.deactivate?.(entry.id);
726
+ await host.deactivate(entry.id, entry.directory);
727
+ removalStarted = true;
728
+ const result = await manager.remove(entry.directory!);
729
+ if (result.ok) notify({ body: `Removed ${entry.name}.`, type: "success" });
730
+ else failRemoval(entry, { status: "remove failed", text: `Could not remove ${entry.name}: ${result.error}` });
731
+ } catch (error) {
732
+ logFailure("plugin-marketplace.pane", "Remove plugin failed")(error);
733
+ failRemoval(entry, removalStarted
734
+ ? { status: "remove failed", text: `Could not remove ${entry.name}. Removal failed. Restart and try again.` }
735
+ : { status: "stop failed", text: `Could not remove ${entry.name}. Plugin could not be stopped. Files kept. Restart before removing it.` });
736
+ } finally {
737
+ setBusy(null);
738
+ bump();
651
739
  }
652
- }, [bump, busy, confirmWidth, dialog, host, manager, notify, selected]);
740
+ }, [bump, busy, confirmWidth, dialog, failRemoval, host, manager, notify, selected]);
653
741
 
654
742
  const toggleSelected = useCallback(async () => {
655
743
  if (!host || !selected || !selected.installed || !selected.toggleable || selected.loadError) return;
@@ -828,11 +916,7 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
828
916
  const info = loadingErrorFooterInfo(status === "loading", status === "error" ? "catalog unavailable" : null);
829
917
  if (stale) info.push({ id: "stale", parts: [{ text: "stale catalog", tone: "warning" }] });
830
918
  if (checkingRemotes) info.push({ id: "remote-check", parts: [{ text: "checking unlisted plugins", tone: "muted" }] });
831
- if (busy) {
832
- const name = entries.find((entry) => entry.id === busy.id)?.name ?? busy.id;
833
- info.push({ id: "busy", parts: [{ text: `${busy.verb} ${name}`, tone: "muted" }] });
834
- }
835
- if (lastError && !busy) info.push({ id: "op-error", parts: [{ text: lastError, tone: "warning" }] });
919
+ if (remoteCheckError) info.push({ id: "remote-error", parts: [{ text: remoteCheckError, tone: "warning" }] });
836
920
  const restartCount = entries.filter((entry) => entry.needsRestart).length;
837
921
  if (restartCount > 0 && !busy) {
838
922
  info.push({ id: "restart", parts: [{ text: "restart to finish loading", tone: "warning" }] });
@@ -869,8 +953,8 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
869
953
 
870
954
  const fit = useMemo(() => ({
871
955
  functions: Math.min(16, Math.max(9, ...visible.map((entry) => factsFor(entry).codes.join(" ").length))),
872
- status: Math.min(14, Math.max(7, ...visible.map((entry) => statusOf(entry).text.length))),
873
- }), [factsFor, visible]);
956
+ status: Math.min(14, Math.max(7, ...visible.map((entry) => rowStatus(entry).text.length))),
957
+ }), [factsFor, rowStatus, visible]);
874
958
  const columns = useMemo(() => buildColumns(width, fit), [fit, width]);
875
959
  // The pick is saved with the pane, so keep it listed (and resettable) even
876
960
  // when the catalog no longer has plugins in it.
@@ -918,7 +1002,7 @@ export function PluginMarketplacePane({ focused, width, height }: PaneProps) {
918
1002
  detailContent={selected
919
1003
  ? selected.bundled
920
1004
  ? <BuiltinDetail entry={selected} width={width} facts={factsFor(selected)} scrollRef={detailScrollRef} />
921
- : <EntryDetail entry={selected} width={width} host={host} />
1005
+ : <EntryDetail entry={selected} width={width} host={host} status={rowStatus(selected)} failure={failureFor(selected)} />
922
1006
  : null}
923
1007
  detailTitle={selected?.name}
924
1008
  rootBefore={(
@@ -1,10 +1,11 @@
1
1
  import type { CliCommandContext } from "../../../../types/plugin";
2
2
  import type { TickerRecord } from "../../../../types/ticker";
3
3
  import type { MarketContext } from "../../../../cli/types";
4
- import { listingFields, loadSavedListing, parseListingArg, savedListingName } from "../../../../cli/listing-arg";
4
+ import { listingFields, loadSavedListingOf, savedListingCandidates, savedListingName } from "../../../../cli/listing-arg";
5
5
  import { withSuggestion } from "../../../../cli/listing-suggestion";
6
6
  import { StagedTickerRepository } from "../../../../cli/staged-tickers";
7
- import { splitSymbolWords, symbolInputKey } from "../../../../cli/symbol-args";
7
+ import { splitSymbolArgs, splitSymbolWords, symbolInputKey } from "../../../../cli/symbol-args";
8
+ import { notASymbolError } from "../../../../cli/symbol-cells";
8
9
  import { readSymbolList, SymbolListError } from "../../../../cli/symbol-list";
9
10
  import { cliStyles } from "../../../../utils/cli-output";
10
11
  import { dryRunNote } from "../../../../cli/helpers";
@@ -37,23 +38,35 @@ export const FILE_OPTION = {
37
38
  export const SYMBOL_LIST_HELP = {
38
39
  title: "Several symbols",
39
40
  lines: [
40
- "add and remove take any number of symbols split by spaces, commas or newlines, a --file, or piped input (or -). An entry of a list with commas, semicolons or newlines that has spaces in it is a company's name when search finds one (philip morris intl is PM), read as its US listing first with a line under it saying which, else the symbols it holds when each is written as a symbol or has a quote (AAPL MSFT), and otherwise a name not found. A file or piped list reads each line as such an entry. A CSV is read from its Symbol, Ticker or Code column, else its Name or Company column as names. Without that header every cell is a symbol, unless names, prices or weights sit beside them: then the first column is read and the cells left out are named. Quote a list name with spaces.",
41
- "Each symbol gets a line, then a summary. Exit status 0 when at least one symbol was added (or removed) or already was, 1 when none resolved or the usage is wrong.",
42
- "A bare US-style symbol is not added when the listing it matched stopped trading, is abroad (DFS as DFS:LSE) or was taken by another company in the last two years (BRKL), or when nothing lists under it now and its company trades as another. Those are listed under Needs a choice, with the add for what their company trades as now and the listing that matched, which naming keeps; one symbol alone fails with the same. A symbol another company took longer ago says so under its line.",
41
+ "add and remove take any number of symbols split by spaces, commas or newlines, a --file, or piped input (or -). An entry of a list with commas, semicolons or newlines that has spaces in it is a company's name when search finds one (philip morris intl is PM), read as its US listing first with a line under it saying which, else the symbols it holds when each is written as a symbol or has a quote (AAPL MSFT), and otherwise a name not found. A file or piped list reads each line as such an entry. A CSV is read from its Symbol, Ticker or Code column, else its Name or Company column as names. Without that header every cell is a symbol, unless names, prices or weights sit beside them: then the first column is read and the cells left out are named. Each line is split by its own tab, semicolon, comma or spaces, and a price is never a symbol, written either way (2.582,52 or 1,899.21). A comma between plain digits (0700,25) splits them unless the line also has a tab, a semicolon or spaces between cells. Quote a list name with spaces.",
42
+ "Each symbol gets a line, then a summary. An entry that cannot be a symbol (N/A, $$$, --, a price alone) is named as not a symbol without a lookup. Symbols Gloom Cloud did not answer for are listed together with one command that adds them again. Exit status 0 when at least one symbol was added (or removed) or already was, 1 when none resolved or the usage is wrong.",
43
+ "A bare US-style symbol is not added when the listing it matched stopped trading, is abroad while the symbol also names a US listing (DFS as DFS:LSE, Discover's old symbol) or was taken by another company in the last two years (BRKL), or when nothing lists under it now and its company trades as another. Those are listed under Needs a choice, with the add for what their company trades as now and the listing that matched, which naming keeps; one symbol alone fails with the same. A symbol another company took longer ago says so under its line, and one listed only abroad (GARAN) is added with a line naming its venue and currency.",
44
+ "A vendor's suffix is the venue it names: GARAN.IS is stored as GARAN:BIST, the same row GARAN:BIST and GARAN add to.",
43
45
  "add --dry-run looks every symbol up and prints the same lines without saving.",
44
46
  ],
45
47
  };
46
48
 
49
+ /**
50
+ * One word of a command line as a shell reads it back: as written when it
51
+ * holds nothing a shell treats specially (`NVDA`, `SAN:EPA`, `BRK.B`), else
52
+ * in single quotes (`'Altria Group'`, `'$nvda'`, `'AT&T'`).
53
+ */
54
+ export function shellWord(word: string): string {
55
+ return /^[\p{L}\p{N}._:@%+,/][\p{L}\p{N}._:@%+,/=-]*$/u.test(word) ? word : `'${word.replaceAll("'", "'\\''")}'`;
56
+ }
57
+
47
58
  /**
48
59
  * A row's line, and under it the listing a company's name was read as, the
49
- * company that had the symbol before the listing added, and the coin hint
50
- * when a bare coin ticker was read as something else.
60
+ * company that had the symbol before the listing added, the venue and
61
+ * currency of a bare symbol added on its only listing, abroad, and the coin
62
+ * hint when a bare coin ticker was read as something else.
51
63
  */
52
64
  function rowLines(row: SymbolRow, verb: Verb): string {
53
65
  return [
54
66
  rowLine(row, verb),
55
67
  ...row.readAs ? [` ${cliStyles.muted(row.readAs)}`] : [],
56
68
  ...row.changeNote ? [` ${cliStyles.warning(row.changeNote)}`] : [],
69
+ ...row.abroad ? [` ${cliStyles.warning(row.abroad)}`] : [],
57
70
  ...row.hint ? [` ${cliStyles.warning(row.hint)}`] : [],
58
71
  ].join("\n");
59
72
  }
@@ -71,9 +84,28 @@ function rowLine(row: SymbolRow, verb: Verb): string {
71
84
  case "not_found": return cliStyles.danger(`Not found: ${typed}${row.message && !NO_MATCH.test(row.message) ? ` (${reason(row.message, typed)})` : ""}${row.suggestion ? `; did you mean ${row.suggestion}?` : ""}`);
72
85
  case "needs_choice": return cliStyles.warning(` ${row.message ?? typed}`);
73
86
  case "failed": return cliStyles.danger(`Not ${verb === "add" ? "added" : "removed"}: ${typed} (${failedReason(row, typed)})`);
87
+ // Named as written (`$$$`), and a figure says it is one.
88
+ case "not_a_symbol": return cliStyles.warning(`Not a symbol: ${row.input.trim()}${row.message?.includes("a number") ? " (a number)" : ""}`);
89
+ case "not_looked_up": return cliStyles.danger(`Not looked up: ${typed}`);
74
90
  }
75
91
  }
76
92
 
93
+ /**
94
+ * The symbols of an add Gloom Cloud did not answer for, after the other
95
+ * lines: one line naming them as they were written, and one command that adds
96
+ * them all again, each entry one shell word (`'philip morris intl'`).
97
+ */
98
+ function unansweredLines(rows: readonly SymbolRow[], retry: ((keys: string) => string) | undefined): string[] {
99
+ const unanswered = rows.filter((row) => row.status === "not_looked_up").map((row) => row.input.trim());
100
+ if (unanswered.length === 0) return [];
101
+ const count = unanswered.length === 1 ? "1 symbol" : `${unanswered.length} symbols`;
102
+ return [
103
+ "",
104
+ cliStyles.danger(`Gloom Cloud did not answer for ${count}, so ${unanswered.length === 1 ? "it was" : "they were"} not looked up: ${unanswered.join(", ")}`),
105
+ ...retry ? [`Try again in a minute: ${retry(unanswered.map(shellWord).join(" "))}`] : [],
106
+ ];
107
+ }
108
+
77
109
  /**
78
110
  * What symbols that need a choice offer: the add that takes the companies
79
111
  * they trade as now, and the add that keeps each match as it is by naming its
@@ -82,7 +114,7 @@ function rowLine(row: SymbolRow, verb: Verb): string {
82
114
  function choiceOffers(choices: readonly SymbolRow[], retry: ((keys: string) => string) | undefined): { successors: string | null; matches: string | null } {
83
115
  const successors = [...new Set(choices.flatMap((row) => row.tradesAs ? [row.tradesAs] : []))];
84
116
  const matches = [...new Set(choices.flatMap((row) => row.listing ? [row.listing] : []))];
85
- const command = (keys: string[]) => retry ? retry(keys.join(" ")) : keys.join(" ");
117
+ const command = (keys: string[]) => retry ? retry(keys.map(shellWord).join(" ")) : keys.join(" ");
86
118
  const one = choices.length === 1;
87
119
  return {
88
120
  successors: successors.length > 0 ? `Add what ${one ? "it trades" : "they trade"} as now: ${command(successors)}` : null,
@@ -131,18 +163,21 @@ export function printSymbolRows(
131
163
  ): void {
132
164
  const summary = `${collection.kind === "watchlist" ? "Watchlist" : "Portfolio"} "${collection.name}": ${summarizeSymbolRows(rows, verb, repeated)}`;
133
165
  const count = (status: SymbolStatus) => rows.filter((row) => row.status === status).length;
166
+ const extra = (key: string, status: SymbolStatus) => count(status) > 0 ? { [key]: count(status) } : {};
134
167
  const counts = verb === "add"
135
168
  ? { added: count("added"), alreadyListed: count("already_listed"), notFound: count("not_found"), notAdded: count("failed"),
136
- ...count("needs_choice") > 0 ? { needsChoice: count("needs_choice") } : {} }
137
- : { removed: count("removed"), notListed: count("not_listed"), notFound: count("not_found"), notRemoved: count("failed") };
169
+ ...extra("needsChoice", "needs_choice"), ...extra("notLookedUp", "not_looked_up"), ...extra("notASymbol", "not_a_symbol") }
170
+ : { removed: count("removed"), notListed: count("not_listed"), notFound: count("not_found"), notRemoved: count("failed"),
171
+ ...extra("notASymbol", "not_a_symbol") };
138
172
  ctx.printResult({
139
173
  data: rows,
140
174
  metadata: { [collection.kind]: collection.name, ...counts, repeated, summary, ...dryRun ? { dryRun } : {} },
141
175
  ...notes.length > 0 ? { warnings: [...notes] } : {},
142
176
  }, {
143
177
  text: () => [
144
- ...rows.filter((row) => row.status !== "needs_choice").map((row) => rowLines(row, verb)),
178
+ ...rows.filter((row) => row.status !== "needs_choice" && row.status !== "not_looked_up").map((row) => rowLines(row, verb)),
145
179
  ...choiceLines(rows, retry),
180
+ ...unansweredLines(rows, retry),
146
181
  "",
147
182
  `${summary}${dryRunNote(dryRun)}`,
148
183
  ].join("\n"),
@@ -155,16 +190,18 @@ export function printSymbolRows(
155
190
  /**
156
191
  * `watchlist add` and `portfolio add` given one symbol: added as a symbol of a
157
192
  * list is (`addSymbol`), and said as one listing, added or already there with
158
- * its notes as warnings. A symbol a list would leave for a choice fails the
193
+ * its notes as warnings, after `notes` on what was left out of the input (the
194
+ * price of `ED 2.582,52`). A symbol a list would leave for a choice fails the
159
195
  * command, saying why, with what a list offers under the error; any other
160
196
  * failure fails it as the lookup's error, a busy service's to retry.
161
197
  */
162
198
  export async function addOneSymbol(
163
199
  ctx: CliCommandContext,
164
200
  market: MarketContext,
165
- { symbol, exchange, collection, retry, reject, add }: {
201
+ { symbol, exchange, collection, notes: inputNotes = [], retry, reject, add }: {
166
202
  symbol: string;
167
203
  exchange: string | undefined;
204
+ notes?: readonly string[];
168
205
  collection: CollectionRef;
169
206
  /** The add of one listing, for the choices a failure names. */
170
207
  retry: (key: string) => string;
@@ -189,7 +226,8 @@ export async function addOneSymbol(
189
226
  const { change, formerIssuer, notes } = lookup;
190
227
  const data = { changed, ...listingFields(saved), [collection.kind]: collection.name,
191
228
  ...change ? { tickerChange: change } : {}, ...formerIssuer ? { formerIssuer } : {}, ...dryRun ? { dryRun } : {} };
192
- const warnings = notes.length > 0 ? notes : undefined;
229
+ const said = [...inputNotes, ...notes, ...row.abroad ? [row.abroad] : []];
230
+ const warnings = said.length > 0 ? said : undefined;
193
231
  ctx.printResult({ data, warnings }, {
194
232
  text: () => changed
195
233
  ? `${cliStyles.success(`Added ${saved.label} to "${collection.name}".`)}${dryRunNote(dryRun)}`
@@ -208,7 +246,9 @@ export function retryNotice(ctx: CliCommandContext): (count: number, waitMs: num
208
246
  /**
209
247
  * The symbols an add or remove was given, failing the command when there are
210
248
  * none or the file cannot be read. An add reads a typed company's name with
211
- * `readNameEntries`; without it (a remove) every entry is its words.
249
+ * `readNameEntries`; without it (a remove) every entry is its words. `single`
250
+ * is the one symbol typed alone, and `notes` what the single command says
251
+ * beside it: none when it goes as typed, else what was left out of it.
212
252
  */
213
253
  export async function requireSymbolList(
214
254
  ctx: CliCommandContext,
@@ -225,12 +265,16 @@ export async function requireSymbolList(
225
265
  typed ??= read;
226
266
  return read;
227
267
  } });
228
- if (list.symbols.length === 0) ctx.fail(usage);
268
+ // Only numbers or strays says what it left out, not only how to call the command.
269
+ if (list.symbols.length === 0) ctx.fail(list.notes.length > 0 ? ["No symbols.", ...list.notes].join(" ") : usage, list.notes.length > 0 ? usage : undefined);
229
270
  // One symbol typed alone keeps the single-symbol output and errors. It goes as typed, so a separator
230
- // left on it (`UPST;`) is named by the listing it resolves to.
271
+ // left on it (`UPST;`) is named by the listing it resolves to; without the figure typed beside it
272
+ // (`ED 2.582,52`), which the notes name.
231
273
  const entries: string[] = typed ?? [];
232
- const single = file == null && !args.includes("-") && entries.length === 1 ? (args.length === 1 ? args[0]!.trim() : entries[0]!) : null;
233
- return { ...list, single };
274
+ const split = splitSymbolArgs(args);
275
+ const asTyped = args.length === 1 && split.length === 1 && split[0] === entries[0];
276
+ const single = file == null && !args.includes("-") && entries.length === 1 ? (asTyped ? args[0]!.trim() : entries[0]!) : null;
277
+ return { ...list, single, notes: single && asTyped ? [] : list.notes };
234
278
  } catch (error) {
235
279
  if (error instanceof SymbolListError) ctx.fail(error.message, usage);
236
280
  throw error;
@@ -248,29 +292,33 @@ export async function removeSymbols({
248
292
  exchange,
249
293
  store,
250
294
  reject,
295
+ holds,
251
296
  remove,
252
297
  }: BulkSymbolsOptions & {
253
298
  reject?: (input: string) => Error | null;
299
+ /** Whether the list being changed holds the row: of two a symbol may be saved as (GARAN:BIST and GARAN.IS), the one it holds. */
300
+ holds?: (ticker: TickerRecord) => boolean;
254
301
  remove: (ticker: TickerRecord) => { changed: boolean; ticker: TickerRecord; extra?: Record<string, unknown> };
255
302
  }): Promise<SymbolRow[]> {
256
303
  const staged = new StagedTickerRepository(store);
257
304
  const rows: SymbolRow[] = [];
258
305
  for (const input of symbols) {
259
- const refusal = reject?.(input);
306
+ const refusal = notASymbolError(input) ?? reject?.(input);
260
307
  if (refusal) {
261
308
  rows.push(failedRow(input, refusal));
262
309
  continue;
263
310
  }
264
- let listing;
311
+ let listings;
265
312
  try {
266
- listing = parseListingArg(input, exchange, { ownExchangeWins: true });
313
+ // GARAN.IS is the row of GARAN:BIST, else a row still saved under that key (a broker's).
314
+ listings = savedListingCandidates(input, exchange, { ownExchangeWins: true });
267
315
  } catch (error) {
268
316
  rows.push(failedRow(input, error instanceof Error ? error : new Error(String(error))));
269
317
  continue;
270
318
  }
271
- const ticker = listing.symbol ? await loadSavedListing(staged, listing) : null;
319
+ const ticker = listings[0]!.symbol ? (await loadSavedListingOf(staged, listings, holds))?.ticker : null;
272
320
  if (!ticker) {
273
- rows.push(failedRow(input, new Error(`Ticker "${listing.key}" was not found in your local data.`), "not_found"));
321
+ rows.push(failedRow(input, new Error(`Ticker "${listings[0]!.key}" was not found in your local data.`), "not_found"));
274
322
  continue;
275
323
  }
276
324
  const result = remove(ticker);