gloomberb 0.16.5 → 0.16.6

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 (478) hide show
  1. package/package.json +2 -1
  2. package/src/api-client/central-bank-rates.ts +6 -1
  3. package/src/api-client/chat.ts +26 -0
  4. package/src/api-client/credit-boards.ts +2 -0
  5. package/src/api-client/data.ts +49 -1
  6. package/src/api-client/europe-energy.ts +106 -0
  7. package/src/api-client/index.ts +9 -0
  8. package/src/api-client/market-discovery.ts +3 -0
  9. package/src/api-client/normalizers.ts +32 -0
  10. package/src/api-client/perps.ts +8 -0
  11. package/src/api-client/request.ts +9 -2
  12. package/src/api-client/socket.ts +29 -0
  13. package/src/api-client/themes.ts +22 -1
  14. package/src/api-client/types.ts +61 -1
  15. package/src/app/global-shortcuts.ts +35 -1
  16. package/src/app/keybindings/actions.ts +12 -1
  17. package/src/app/pane-runtime/plugin-bindings.ts +2 -2
  18. package/src/app/pane-runtime/ticker-open-runtime.ts +9 -3
  19. package/src/app/runtime/desktop-deeplink.ts +10 -5
  20. package/src/app/runtime/startup.ts +1 -1
  21. package/src/app.tsx +6 -0
  22. package/src/architecture/core-builtin-allowlist.json +4 -13
  23. package/src/ask-gloom/pane-context.ts +114 -0
  24. package/src/ask-gloom/pane-request.ts +70 -0
  25. package/src/ask-gloom/pane-text.ts +201 -0
  26. package/src/capabilities/chart-series.ts +8 -1
  27. package/src/capabilities/factories.ts +1 -0
  28. package/src/cli/central-bank-events.ts +23 -0
  29. package/src/cli/command-options.ts +17 -5
  30. package/src/cli/commands/crypto-hints.ts +28 -2
  31. package/src/cli/commands/fred-series.ts +89 -4
  32. package/src/cli/commands/market.ts +101 -18
  33. package/src/cli/commands/overview.ts +47 -14
  34. package/src/cli/commands/search.ts +254 -23
  35. package/src/cli/commands/ticker.ts +73 -13
  36. package/src/cli/desktop-pane-shot.ts +23 -6
  37. package/src/cli/errors.ts +7 -5
  38. package/src/cli/exit-codes.ts +8 -0
  39. package/src/cli/export-source.ts +58 -0
  40. package/src/cli/glossary.ts +62 -8
  41. package/src/cli/help.ts +10 -0
  42. package/src/cli/helpers.ts +2 -5
  43. package/src/cli/history-rows.ts +70 -0
  44. package/src/cli/index.ts +9 -3
  45. package/src/cli/known-gaps.ts +65 -8
  46. package/src/cli/listing-arg.ts +182 -89
  47. package/src/cli/not-a-ticker.ts +12 -4
  48. package/src/cli/pane-functions/access-gate.ts +8 -2
  49. package/src/cli/pane-functions/capabilities.ts +1 -1
  50. package/src/cli/pane-functions/catalog.ts +183 -39
  51. package/src/cli/pane-functions/data.ts +30 -0
  52. package/src/cli/pane-functions/dom.ts +17 -2
  53. package/src/cli/pane-functions/freshness.ts +48 -24
  54. package/src/cli/pane-functions/function-help.ts +19 -10
  55. package/src/cli/pane-functions/headless.ts +55 -15
  56. package/src/cli/pane-functions/index.ts +45 -16
  57. package/src/cli/pane-functions/options.ts +8 -0
  58. package/src/cli/pane-functions/resolver.ts +25 -7
  59. package/src/cli/pane-functions/screenshot.ts +145 -9
  60. package/src/cli/perpetual-contract.ts +60 -0
  61. package/src/cli/registry.ts +3 -1
  62. package/src/cli/report-tables.ts +23 -7
  63. package/src/cli/result.ts +41 -10
  64. package/src/cli/series-search.ts +111 -0
  65. package/src/cli/staged-tickers.ts +1 -1
  66. package/src/cli/symbol-args.ts +18 -0
  67. package/src/cli/symbol-list.ts +1 -19
  68. package/src/cli/symbol-rows.ts +154 -0
  69. package/src/cli/ticker-resolution.ts +99 -8
  70. package/src/components/chart/composite/axis-overlays.tsx +8 -1
  71. package/src/components/chart/composite/composite-chart.tsx +41 -15
  72. package/src/components/chart/composite/crosshair-readout.tsx +150 -0
  73. package/src/components/chart/composite/downsample.ts +1 -1
  74. package/src/components/chart/composite/format.ts +29 -0
  75. package/src/components/chart/composite/interactions.ts +9 -2
  76. package/src/components/chart/composite/legend.tsx +52 -32
  77. package/src/components/chart/composite/panel-bitmap.ts +70 -35
  78. package/src/components/chart/composite/panel-labels.ts +18 -17
  79. package/src/components/chart/composite/panel-series.ts +1 -0
  80. package/src/components/chart/composite/panel-surface.tsx +6 -8
  81. package/src/components/chart/composite/rasterizer.ts +50 -8
  82. package/src/components/chart/composite/scene.ts +2 -1
  83. package/src/components/chart/composite/time-scale.ts +26 -9
  84. package/src/components/chart/composite/types.ts +18 -0
  85. package/src/components/chart/composite/use-composite-viewport.ts +30 -2
  86. package/src/components/chart/native/raster/crosshair.ts +8 -3
  87. package/src/components/chart/native/raster/primitives.ts +85 -21
  88. package/src/components/chart/native/surface/manager.ts +33 -8
  89. package/src/components/chart/surface3d/chart.tsx +1 -1
  90. package/src/components/command-bar/action-runtime.ts +1 -1
  91. package/src/components/command-bar/commands/collection-list.ts +210 -0
  92. package/src/components/command-bar/commands/collection.ts +40 -1
  93. package/src/components/command-bar/commands/direct/index.ts +4 -0
  94. package/src/components/command-bar/commands/registry.ts +8 -0
  95. package/src/components/command-bar/routes/root/plugin-install.ts +4 -4
  96. package/src/components/command-bar/routing/actions.ts +1 -1
  97. package/src/components/command-bar/workflow/tickers.ts +35 -29
  98. package/src/components/layout/detached-pane-shell.tsx +59 -39
  99. package/src/components/layout/floating-pane.tsx +7 -1
  100. package/src/components/layout/header.tsx +5 -0
  101. package/src/components/layout/missing-pane.tsx +3 -3
  102. package/src/components/layout/pane/capture-stamp.ts +41 -0
  103. package/src/components/layout/pane/capture-status.ts +12 -0
  104. package/src/components/layout/pane/footer/keyboard.ts +3 -0
  105. package/src/components/layout/pane/footer/model.ts +7 -1
  106. package/src/components/layout/pane/header.tsx +26 -0
  107. package/src/components/layout/pane/index.tsx +9 -1
  108. package/src/components/layout/pane/sidebar.tsx +10 -11
  109. package/src/components/layout/shell/cursor-occlusion.ts +2 -1
  110. package/src/components/layout/shell/index.tsx +61 -60
  111. package/src/components/layout/shell/menu.ts +9 -1
  112. package/src/components/layout/shell/pane/actions.ts +32 -10
  113. package/src/components/layout/shell/pane/ask.ts +131 -0
  114. package/src/components/layout/shell/pane/capture.ts +162 -0
  115. package/src/components/layout/shell/pane/layers.tsx +26 -5
  116. package/src/components/layout/shell/pane/management-shortcuts.ts +46 -1
  117. package/src/components/layout/shell/shortcuts.ts +21 -4
  118. package/src/components/metric-treemap/heat-surface.tsx +1 -3
  119. package/src/components/reader/article-reader.tsx +642 -0
  120. package/src/components/reader/article-text.ts +527 -0
  121. package/src/components/ticker/list-table-view.tsx +19 -1
  122. package/src/components/ui/data-table/index.tsx +1 -0
  123. package/src/components/ui/icon.tsx +4 -1
  124. package/src/components/ui/query-bar.tsx +10 -1
  125. package/src/data/config/store/migrations.ts +7 -0
  126. package/src/data/config/store/portfolio-as-of-column.ts +57 -0
  127. package/src/docs/snapshot.json +162 -23
  128. package/src/i18n/es.ts +4 -1
  129. package/src/i18n/ja.ts +4 -1
  130. package/src/i18n/ko.ts +4 -1
  131. package/src/i18n/zh-cn.ts +4 -1
  132. package/src/i18n/zh-tw.ts +4 -1
  133. package/src/layout-marketplace/gallery.tsx +1 -1
  134. package/src/market-data/market/freshness.ts +3 -2
  135. package/src/market-data/market/session-close-note.ts +3 -2
  136. package/src/market-data/quotes/contributions.ts +2 -0
  137. package/src/market-data/quotes/metadata.ts +12 -0
  138. package/src/market-data/quotes/resolution.ts +3 -0
  139. package/src/notifications/app-notifier.ts +17 -1
  140. package/src/notifications/notification-log.ts +180 -0
  141. package/src/plugins/auto-update-node.ts +2 -2
  142. package/src/plugins/auto-update.ts +2 -2
  143. package/src/plugins/builtin/account-management/index.tsx +1 -0
  144. package/src/plugins/builtin/alerts/catalysts.ts +1 -1
  145. package/src/plugins/builtin/alerts/focus.ts +27 -0
  146. package/src/plugins/builtin/alerts/index.tsx +6 -2
  147. package/src/plugins/builtin/alerts/pane.tsx +19 -1
  148. package/src/plugins/builtin/analytics/index.tsx +4 -1
  149. package/src/plugins/builtin/analytics/risk-headless.ts +30 -15
  150. package/src/plugins/builtin/attention/headless.ts +1 -1
  151. package/src/plugins/builtin/awards/headless.ts +88 -18
  152. package/src/plugins/builtin/awards/model.ts +41 -1
  153. package/src/plugins/builtin/awards/pane.tsx +19 -12
  154. package/src/plugins/builtin/backtest/headless.ts +2 -2
  155. package/src/plugins/builtin/broker-manager/index.tsx +1 -0
  156. package/src/plugins/builtin/catalysts/headless.ts +1 -1
  157. package/src/plugins/builtin/cds/client.ts +11 -31
  158. package/src/plugins/builtin/cds/headless.ts +5 -2
  159. package/src/plugins/builtin/cds/model.ts +21 -1
  160. package/src/plugins/builtin/cds/pane.tsx +6 -4
  161. package/src/plugins/builtin/central-bank-rates/client.ts +4 -0
  162. package/src/plugins/builtin/central-bank-rates/headless.ts +46 -16
  163. package/src/plugins/builtin/central-bank-rates/index.tsx +1 -1
  164. package/src/plugins/builtin/central-bank-rates/model.ts +99 -0
  165. package/src/plugins/builtin/central-bank-rates/pane.tsx +1 -1
  166. package/src/plugins/builtin/central-bank-rates/series.ts +19 -25
  167. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
  168. package/src/plugins/builtin/chart-composer/headless-schema.ts +1 -1
  169. package/src/plugins/builtin/chart-composer/headless.ts +65 -5
  170. package/src/plugins/builtin/chart-composer/index.tsx +6 -1
  171. package/src/plugins/builtin/chart-composer/pane.tsx +81 -38
  172. package/src/plugins/builtin/chat/content/composer-runtime.ts +6 -1
  173. package/src/plugins/builtin/chat/content/composer.tsx +5 -1
  174. package/src/plugins/builtin/chat/content/footer.tsx +12 -0
  175. package/src/plugins/builtin/chat/content/index.tsx +89 -5
  176. package/src/plugins/builtin/chat/content/new-messages.tsx +89 -0
  177. package/src/plugins/builtin/chat/content/row-activity.ts +132 -0
  178. package/src/plugins/builtin/chat/content/scroll.ts +127 -27
  179. package/src/plugins/builtin/chat/content/shortcuts.ts +2 -2
  180. package/src/plugins/builtin/chat/content/transcript.tsx +145 -78
  181. package/src/plugins/builtin/chat/content/types.ts +1 -0
  182. package/src/plugins/builtin/chat/controller/fetch.ts +8 -2
  183. package/src/plugins/builtin/chat/controller/index.ts +121 -1
  184. package/src/plugins/builtin/chat/controller/message-loading.ts +3 -0
  185. package/src/plugins/builtin/chat/controller/messages.ts +7 -2
  186. package/src/plugins/builtin/chat/controller/realtime.ts +10 -1
  187. package/src/plugins/builtin/chat/controller/send.ts +61 -1
  188. package/src/plugins/builtin/chat/controller/state.ts +8 -0
  189. package/src/plugins/builtin/chat/ghost-user.ts +20 -0
  190. package/src/plugins/builtin/chat/index.tsx +23 -5
  191. package/src/plugins/builtin/chat/layout.ts +78 -5
  192. package/src/plugins/builtin/chat/message/ai-badge.tsx +18 -0
  193. package/src/plugins/builtin/chat/message/desktop.tsx +55 -6
  194. package/src/plugins/builtin/chat/message/header.tsx +16 -4
  195. package/src/plugins/builtin/chat/message/profile-popover.tsx +5 -1
  196. package/src/plugins/builtin/chat/message/reactions.tsx +210 -0
  197. package/src/plugins/builtin/chat/message/render-state.ts +18 -2
  198. package/src/plugins/builtin/chat/message/terminal.tsx +43 -4
  199. package/src/plugins/builtin/chat/message/types.ts +12 -0
  200. package/src/plugins/builtin/chat/reactions.ts +197 -0
  201. package/src/plugins/builtin/chat/share/flow.tsx +87 -0
  202. package/src/plugins/builtin/chat/share/targets.ts +27 -0
  203. package/src/plugins/builtin/chat/status-widget.tsx +6 -3
  204. package/src/plugins/builtin/chat/unread-inbox-pane.tsx +148 -27
  205. package/src/plugins/builtin/chat/unread-inbox.ts +22 -0
  206. package/src/plugins/builtin/cloud/askg/attached-pane.tsx +69 -0
  207. package/src/plugins/builtin/cloud/askg/pane-attachment.ts +94 -0
  208. package/src/plugins/builtin/cloud/askg/pane.tsx +141 -12
  209. package/src/plugins/builtin/cloud/askg/pending-question.ts +11 -0
  210. package/src/plugins/builtin/cloud/plugin.tsx +19 -2
  211. package/src/plugins/builtin/cloud/team/model.ts +5 -0
  212. package/src/plugins/builtin/cloud/team/module.tsx +1 -0
  213. package/src/plugins/builtin/cloud/team/store.ts +8 -3
  214. package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
  215. package/src/plugins/builtin/company-attention/headless.ts +2 -2
  216. package/src/plugins/builtin/company-kpis/headless.ts +97 -10
  217. package/src/plugins/builtin/company-kpis/model.ts +24 -2
  218. package/src/plugins/builtin/company-kpis/pane.tsx +13 -14
  219. package/src/plugins/builtin/connections/index.ts +1 -0
  220. package/src/plugins/builtin/cot/headless.ts +1 -1
  221. package/src/plugins/builtin/cpi/headless.ts +3 -3
  222. package/src/plugins/builtin/credit-boards/cdx-pane.tsx +10 -1
  223. package/src/plugins/builtin/credit-boards/client.ts +6 -2
  224. package/src/plugins/builtin/credit-boards/headless.ts +108 -31
  225. package/src/plugins/builtin/credit-boards/model.ts +11 -1
  226. package/src/plugins/builtin/credit-conditions/client.ts +12 -9
  227. package/src/plugins/builtin/credit-conditions/headless.ts +13 -2
  228. package/src/plugins/builtin/credit-conditions/index.tsx +16 -9
  229. package/src/plugins/builtin/credit-conditions/model.ts +19 -11
  230. package/src/plugins/builtin/credit-conditions/series.ts +8 -18
  231. package/src/plugins/builtin/credit-documents/headless.ts +2 -2
  232. package/src/plugins/builtin/debt-maturities/headless.ts +17 -11
  233. package/src/plugins/builtin/dividend-yield/client.ts +3 -0
  234. package/src/plugins/builtin/dividend-yield/headless.ts +5 -2
  235. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  236. package/src/plugins/builtin/dividend-yield/pane.tsx +3 -1
  237. package/src/plugins/builtin/dividend-yield/types.ts +2 -0
  238. package/src/plugins/builtin/doe/headless.ts +12 -8
  239. package/src/plugins/builtin/earnings/index.tsx +9 -0
  240. package/src/plugins/builtin/earnings-calls/headless.ts +28 -2
  241. package/src/plugins/builtin/earnings-calls/index.tsx +1 -1
  242. package/src/plugins/builtin/earnings-ripple/index.tsx +2 -0
  243. package/src/plugins/builtin/econ/fred-catalog.ts +9 -0
  244. package/src/plugins/builtin/equity-screener/headless.ts +3 -3
  245. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -3
  246. package/src/plugins/builtin/exposure/drivers.ts +13 -0
  247. package/src/plugins/builtin/exposure/headless.ts +205 -13
  248. package/src/plugins/builtin/exposure/index.tsx +1 -0
  249. package/src/plugins/builtin/exposure/model.ts +23 -3
  250. package/src/plugins/builtin/exposure/pane.tsx +11 -11
  251. package/src/plugins/builtin/fear-greed/index.tsx +14 -10
  252. package/src/plugins/builtin/futures-curve/headless.ts +1 -1
  253. package/src/plugins/builtin/futures-curve/index.tsx +1 -1
  254. package/src/plugins/builtin/fx-matrix/client.ts +63 -0
  255. package/src/plugins/builtin/fx-matrix/export.ts +2 -1
  256. package/src/plugins/builtin/fx-matrix/headless.ts +154 -0
  257. package/src/plugins/builtin/fx-matrix/index.tsx +3 -3
  258. package/src/plugins/builtin/gpu/headless.ts +4 -4
  259. package/src/plugins/builtin/help/function-index.ts +2 -0
  260. package/src/plugins/builtin/help/index.tsx +14 -1
  261. package/src/plugins/builtin/ipo-calendar/headless.ts +1 -1
  262. package/src/plugins/builtin/iv-history/client.ts +6 -2
  263. package/src/plugins/builtin/iv-history/format.ts +9 -0
  264. package/src/plugins/builtin/iv-history/headless.ts +50 -18
  265. package/src/plugins/builtin/iv-history/model.ts +35 -4
  266. package/src/plugins/builtin/jobs/headless.ts +6 -8
  267. package/src/plugins/builtin/kelly-sizer/index.tsx +2 -0
  268. package/src/plugins/builtin/market-heatmap/headless.ts +20 -5
  269. package/src/plugins/builtin/market-heatmap/index.tsx +6 -0
  270. package/src/plugins/builtin/members/headless.ts +1 -1
  271. package/src/plugins/builtin/members/pane.tsx +3 -2
  272. package/src/plugins/builtin/mna/distress/headless.ts +4 -4
  273. package/src/plugins/builtin/mna/headless.ts +3 -3
  274. package/src/plugins/builtin/money-markets/headless.ts +5 -4
  275. package/src/plugins/builtin/news/index.tsx +0 -2
  276. package/src/plugins/builtin/news/wire/news/detail-view.tsx +53 -104
  277. package/src/plugins/builtin/news/wire/news/footer.ts +2 -25
  278. package/src/plugins/builtin/news/wire/news/preset-pane.tsx +0 -2
  279. package/src/plugins/builtin/notes/index.tsx +1 -0
  280. package/src/plugins/builtin/options/index.tsx +3 -0
  281. package/src/plugins/builtin/options-positioning/headless.ts +3 -3
  282. package/src/plugins/builtin/perps/client.ts +50 -10
  283. package/src/plugins/builtin/perps/equity-row.tsx +29 -16
  284. package/src/plugins/builtin/perps/headless.ts +2 -2
  285. package/src/plugins/builtin/perps/index.tsx +5 -3
  286. package/src/plugins/builtin/perps/list-perpetuals.ts +118 -0
  287. package/src/plugins/builtin/perps/open-market.ts +15 -0
  288. package/src/plugins/builtin/plugin-marketplace/index.tsx +1 -1
  289. package/src/plugins/builtin/plugin-marketplace/pane.tsx +6 -6
  290. package/src/plugins/builtin/portfolio-list/allocation.ts +5 -4
  291. package/src/plugins/builtin/portfolio-list/cell-version.ts +8 -1
  292. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +23 -135
  293. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +59 -15
  294. package/src/plugins/builtin/portfolio-list/cli/render.ts +248 -51
  295. package/src/plugins/builtin/portfolio-list/cli/shared.ts +5 -12
  296. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +3 -2
  297. package/src/plugins/builtin/portfolio-list/column-values.ts +103 -25
  298. package/src/plugins/builtin/portfolio-list/headless.ts +51 -15
  299. package/src/plugins/builtin/portfolio-list/index.tsx +5 -1
  300. package/src/plugins/builtin/portfolio-list/mutations.ts +2 -9
  301. package/src/plugins/builtin/portfolio-list/pane/data.ts +5 -1
  302. package/src/plugins/builtin/portfolio-list/pane/index.tsx +46 -8
  303. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +16 -10
  304. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +21 -1
  305. package/src/plugins/builtin/portfolio-list/settings.ts +17 -0
  306. package/src/plugins/builtin/portfolio-list/summary/index.tsx +12 -0
  307. package/src/plugins/builtin/portfolio-list/summary/totals.ts +8 -3
  308. package/src/plugins/builtin/portfolio-list/table.tsx +30 -6
  309. package/src/plugins/builtin/power/evidence.ts +57 -8
  310. package/src/plugins/builtin/power/headless.ts +6 -2
  311. package/src/plugins/builtin/power/index.tsx +24 -2
  312. package/src/plugins/builtin/power/model.ts +2 -2
  313. package/src/plugins/builtin/power/pane.tsx +5 -0
  314. package/src/plugins/builtin/power/prices-client.ts +139 -0
  315. package/src/plugins/builtin/power/prices-headless.ts +137 -0
  316. package/src/plugins/builtin/power/prices-model.ts +103 -0
  317. package/src/plugins/builtin/power/prices.tsx +179 -0
  318. package/src/plugins/builtin/rate-path/headless.ts +38 -18
  319. package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
  320. package/src/plugins/builtin/research/index.tsx +2 -0
  321. package/src/plugins/builtin/research-search/article.ts +65 -0
  322. package/src/plugins/builtin/research-search/document-view.tsx +33 -215
  323. package/src/plugins/builtin/research-search/model.ts +0 -9
  324. package/src/plugins/builtin/research-search/pane.tsx +41 -30
  325. package/src/plugins/builtin/research-search/snippet.ts +0 -29
  326. package/src/plugins/builtin/revenue-breakdown/headless.ts +18 -6
  327. package/src/plugins/builtin/sec/headless.ts +25 -3
  328. package/src/plugins/builtin/sec/index.tsx +2 -1
  329. package/src/plugins/builtin/series-inventory.ts +2 -0
  330. package/src/plugins/builtin/shared/cloud-denied.ts +15 -0
  331. package/src/plugins/builtin/shared/free-preview.ts +47 -0
  332. package/src/plugins/builtin/shared/report-freshness.ts +3 -1
  333. package/src/plugins/builtin/shared/volatility/options.ts +4 -1
  334. package/src/plugins/builtin/short-interest/watch-headless.ts +2 -2
  335. package/src/plugins/builtin/short-volume/headless.ts +1 -1
  336. package/src/plugins/builtin/social-mentions/headless.ts +1 -1
  337. package/src/plugins/builtin/supply-chain/headless.ts +43 -11
  338. package/src/plugins/builtin/supply-chain/model.ts +13 -0
  339. package/src/plugins/builtin/supply-chain/pane.tsx +5 -5
  340. package/src/plugins/builtin/themes/headless.ts +74 -10
  341. package/src/plugins/builtin/themes/model.ts +71 -4
  342. package/src/plugins/builtin/themes/pane.tsx +22 -5
  343. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +114 -0
  344. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +57 -2
  345. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +19 -55
  346. package/src/plugins/builtin/ticker-detail/headless-schema.ts +30 -0
  347. package/src/plugins/builtin/ticker-detail/headless.ts +86 -0
  348. package/src/plugins/builtin/ticker-detail/index.tsx +23 -11
  349. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +1 -1
  350. package/src/plugins/builtin/time-sales/headless.ts +1 -1
  351. package/src/plugins/builtin/time-sales/index.tsx +2 -1
  352. package/src/plugins/builtin/vol-surface/evidence.ts +7 -1
  353. package/src/plugins/builtin/vol-surface/headless.ts +50 -17
  354. package/src/plugins/builtin/vol-surface/heat-grid.tsx +113 -0
  355. package/src/plugins/builtin/vol-surface/model.ts +39 -6
  356. package/src/plugins/builtin/vol-surface/pane.tsx +14 -13
  357. package/src/plugins/builtin/vol-surface/stored.ts +63 -3
  358. package/src/plugins/builtin/vol-surface/surface.tsx +30 -2
  359. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +6 -5
  360. package/src/plugins/builtin/world-venue-map/basemap.ts +6 -3
  361. package/src/plugins/builtin/world-venue-map/geo-draw.tsx +2 -1
  362. package/src/plugins/builtin/world-venue-map/geo-svg.tsx +6 -6
  363. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +16 -9
  364. package/src/plugins/builtin/world-venue-map/map.tsx +144 -13
  365. package/src/plugins/builtin/world-venue-map/model.ts +56 -19
  366. package/src/plugins/builtin/world-venue-map/pane.tsx +5 -2
  367. package/src/plugins/builtin/yield-curve/index.tsx +1 -1
  368. package/src/plugins/installer.ts +2 -2
  369. package/src/plugins/loader.ts +15 -0
  370. package/src/plugins/manager-node.ts +1 -1
  371. package/src/plugins/{builtin/plugin-marketplace → marketplace}/feed.ts +2 -2
  372. package/src/plugins/{builtin/plugin-marketplace → marketplace}/model.ts +6 -6
  373. package/src/plugins/{builtin/plugin-marketplace → marketplace}/store.ts +1 -1
  374. package/src/plugins/registry/host-actions.ts +11 -0
  375. package/src/portfolio/collection-name.ts +31 -0
  376. package/src/portfolio/valuation-basis.ts +79 -0
  377. package/src/public/time-series.ts +1 -1
  378. package/src/react/input.ts +33 -1
  379. package/src/react/key-repeat.ts +86 -0
  380. package/src/remote/controller.ts +21 -1
  381. package/src/remote/schema.ts +3 -2
  382. package/src/renderers/browser/main.tsx +1 -1
  383. package/src/renderers/browser/research-entry.ts +4 -2
  384. package/src/renderers/dom/data-table/row.tsx +3 -0
  385. package/src/renderers/dom/desktop/icons.tsx +9 -0
  386. package/src/renderers/dom/host/block-glyph-canvas.tsx +6 -3
  387. package/src/renderers/dom/host/box.tsx +7 -2
  388. package/src/renderers/dom/host/chart-surface.tsx +27 -0
  389. package/src/renderers/dom/host/scroll-box.tsx +32 -0
  390. package/src/renderers/dom/host/size-observer.ts +24 -9
  391. package/src/renderers/dom/host/sticky-scroll.ts +128 -0
  392. package/src/renderers/dom/host/style.ts +1 -1
  393. package/src/renderers/dom/host/surface-3d.tsx +13 -6
  394. package/src/renderers/dom/host/surface-fit.ts +406 -0
  395. package/src/renderers/dom/input-host.tsx +1 -0
  396. package/src/renderers/dom/styles.css +48 -12
  397. package/src/renderers/electrobun/bun/application-menu/click.ts +18 -0
  398. package/src/renderers/electrobun/bun/index.ts +3 -2
  399. package/src/renderers/electrobun/shared/protocol.ts +1 -1
  400. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +12 -0
  401. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +59 -24
  402. package/src/renderers/electrobun/view/main.tsx +3 -3
  403. package/src/renderers/electrobun/view/remote/asset-data-client.ts +2 -0
  404. package/src/renderers/opentui/chart-surface.tsx +1 -0
  405. package/src/renderers/opentui/frame-capture.ts +33 -0
  406. package/src/renderers/opentui/host.tsx +10 -13
  407. package/src/renderers/opentui/pane-image/glyphs-license.txt +107 -0
  408. package/src/renderers/opentui/pane-image/glyphs.json +1 -0
  409. package/src/renderers/opentui/pane-image/index.ts +107 -0
  410. package/src/renderers/opentui/pane-image/raster.ts +428 -0
  411. package/src/renderers/opentui/start.tsx +3 -3
  412. package/src/renderers/opentui/test-utils.tsx +3 -0
  413. package/src/renderers/opentui/ui-host.tsx +29 -1
  414. package/src/series/resolve.ts +3 -2
  415. package/src/series/types.ts +8 -0
  416. package/src/series/validate.ts +1 -1
  417. package/src/shares/chat.ts +34 -0
  418. package/src/shares/dialog.tsx +295 -0
  419. package/src/shares/flow.tsx +56 -0
  420. package/src/shares/live.ts +14 -22
  421. package/src/shares/pane-image.ts +152 -0
  422. package/src/shares/personal-pane.ts +64 -0
  423. package/src/shares/portable-layout.ts +4 -2
  424. package/src/shares/prepare.ts +20 -0
  425. package/src/sources/gloomberb-cloud/index.ts +102 -3
  426. package/src/sources/gloomberb-cloud/normalizers.ts +2 -0
  427. package/src/sources/gloomberb-cloud/perpetuals.ts +249 -0
  428. package/src/sources/history-retention.ts +11 -0
  429. package/src/sources/listing-target.ts +4 -0
  430. package/src/sources/provider-router/index.ts +14 -0
  431. package/src/state/hooks/inline-tickers.ts +49 -11
  432. package/src/test-support/shell-pane-keys.tsx +1 -0
  433. package/src/theme/theme-context.tsx +15 -1
  434. package/src/tickers/instrument-kind.ts +9 -1
  435. package/src/tickers/listing-name.ts +34 -0
  436. package/src/tickers/listing-venues.ts +132 -0
  437. package/src/tickers/open-target.ts +11 -3
  438. package/src/tickers/perpetual-listing.ts +151 -0
  439. package/src/tickers/prediction-listing.ts +26 -0
  440. package/src/tickers/search/index.ts +27 -4
  441. package/src/tickers/search/ranking.ts +66 -4
  442. package/src/tickers/ticker-changes.ts +213 -0
  443. package/src/time-series/economic.ts +2 -6
  444. package/src/time-series/ice-credit.ts +39 -0
  445. package/src/time-series/resolve.ts +116 -13
  446. package/src/time-series/studies.ts +1 -0
  447. package/src/time-series/types.ts +8 -0
  448. package/src/types/config.ts +4 -2
  449. package/src/types/data-provider.ts +6 -0
  450. package/src/types/financials.ts +10 -0
  451. package/src/types/headless.ts +52 -0
  452. package/src/types/instrument.ts +4 -0
  453. package/src/types/plugin.ts +33 -2
  454. package/src/types/ticker-changes.ts +26 -0
  455. package/src/ui/context-menu.tsx +13 -1
  456. package/src/ui/host.tsx +43 -7
  457. package/src/ui/live-resize.ts +10 -0
  458. package/src/ui/live-stretch.ts +51 -19
  459. package/src/ui/sticky-scroll.ts +7 -0
  460. package/src/utils/central-banks.ts +76 -0
  461. package/src/utils/cli-output.ts +126 -16
  462. package/src/utils/currency-units.ts +11 -0
  463. package/src/utils/datetime-format.ts +27 -6
  464. package/src/utils/dom-screenshot.ts +3 -1
  465. package/src/utils/double-escape-close.ts +15 -1
  466. package/src/utils/exchanges.ts +36 -0
  467. package/src/utils/format.ts +19 -2
  468. package/src/utils/forward-dividend.ts +14 -0
  469. package/src/utils/fx-status.ts +6 -1
  470. package/src/utils/inline-content-tokenizer.ts +22 -3
  471. package/src/utils/market-capitalization.ts +8 -0
  472. package/src/utils/one-shot.ts +73 -0
  473. package/src/utils/options.ts +37 -8
  474. package/src/utils/utc-time.ts +12 -0
  475. package/src/ui/pane-fill.ts +0 -11
  476. /package/src/plugins/{builtin/plugin-marketplace → marketplace}/activation.ts +0 -0
  477. /package/src/plugins/{builtin/plugin-marketplace → marketplace}/ids.ts +0 -0
  478. /package/src/plugins/{builtin/plugin-marketplace → marketplace}/packs.ts +0 -0
@@ -1,4 +1,4 @@
1
- import { useEffect, useRef, type Dispatch } from "react";
1
+ import { useEffect, useRef, useState, type Dispatch } from "react";
2
2
  import { useShortcut } from "../react/input";
3
3
  import { useNativeRenderer, useRendererHost, useUiHost } from "../ui";
4
4
  import { useDialogState } from "../ui/dialog";
@@ -13,6 +13,7 @@ import { getVisiblePaneCycleOrder } from "../components/layout/pane/cycle-order"
13
13
  import { requestFunctionHelp, useFunctionHelpHost } from "../plugins/builtin/help/function-card";
14
14
  import { buildRegistryHelpIndex, helpFunctionForPane } from "../plugins/builtin/help/function-index";
15
15
  import { recordFunctionOpen } from "../telemetry/usage-counts";
16
+ import { createOneShots } from "../utils/one-shot";
16
17
  import { DOCS_PANE_TEMPLATE_ID } from "../docs/content";
17
18
  import { registerPaneDocsHandler } from "../docs/requests";
18
19
  import { isMoveDownShortcut, isMoveUpShortcut } from "../components/command-bar/keyboard-handlers";
@@ -117,6 +118,10 @@ export function useAppGlobalShortcuts({
117
118
  const uiKind = useUiHost().kind;
118
119
  const toastHost = useToastHost();
119
120
  useKeybindingIssueNotice(keybindings, pluginRegistry, state.initialized);
121
+ // Every action here runs once per press: a held key, or a terminal that does
122
+ // not say it is a repeat, must not run it again. Only moving focus between
123
+ // panes (Tab) and switching layouts by number (idempotent) are left to repeat.
124
+ const [shots] = useState(createOneShots);
120
125
  useFunctionHelpHost({
121
126
  closeCommandBar: () => {
122
127
  if (state.commandBarOpen) dispatch({ type: "SET_COMMAND_BAR", open: false });
@@ -149,6 +154,23 @@ export function useAppGlobalShortcuts({
149
154
 
150
155
  const match = matchKeybinding(keybindings, event);
151
156
  const action = match?.kind === "action" ? match.id : null;
157
+ /**
158
+ * Whether the action already ran for this press or hold. An action that
159
+ * takes the key (`claims`) swallows the refused ones as well; one that
160
+ * leaves it to the pane (R) does not, so a pane's own key keeps working.
161
+ */
162
+ const ranAlready = (id: string, claims = true): boolean => {
163
+ const shot = shots.get(id);
164
+ if (shot.refuses(event)) {
165
+ if (claims) {
166
+ event.preventDefault();
167
+ event.stopPropagation();
168
+ }
169
+ return true;
170
+ }
171
+ shot.end();
172
+ return false;
173
+ };
152
174
 
153
175
  // Terminals send Ctrl; the browser and the desktop webview send Cmd on
154
176
  // macOS, which the OpenTUI host also reports as `super` under the kitty
@@ -172,6 +194,7 @@ export function useAppGlobalShortcuts({
172
194
  // The status bar's star line answers the same keys once no toast does,
173
195
  // but only over the workspace itself.
174
196
  if (action === "notification-action" || action === "notification-dismiss") {
197
+ if (ranAlready(action)) return;
175
198
  const toastHandled = action === "notification-action"
176
199
  ? toastHost.activateNewest?.() === true
177
200
  : toastHost.dismissNewest?.() === true;
@@ -195,12 +218,14 @@ export function useAppGlobalShortcuts({
195
218
  // Ctrl+P and Ctrl+N move the open bar's selection, so a bar chord that
196
219
  // is one of them only opens it; Esc and the bar's other chords close it.
197
220
  if (state.commandBarOpen && (isMoveUpShortcut(event) || isMoveDownShortcut(event))) return;
221
+ if (ranAlready(action)) return;
198
222
  event.preventDefault();
199
223
  event.stopPropagation();
200
224
  dispatch({ type: "TOGGLE_COMMAND_BAR" });
201
225
  return;
202
226
  }
203
227
  if (!isDetachedWindow && action === "ticker-search" && !state.commandBarOpen) {
228
+ if (ranAlready(action)) return;
204
229
  event.preventDefault();
205
230
  event.stopPropagation();
206
231
  dispatch({
@@ -233,6 +258,7 @@ export function useAppGlobalShortcuts({
233
258
  // Command and function keys are never text, so they still fire.
234
259
  const editing = state.inputCaptured || event.targetEditable === true;
235
260
  if (editing && event.ctrl && !(event.meta || event.super)) return;
261
+ if (ranAlready(`command:${match.command.query}`)) return;
236
262
  event.preventDefault();
237
263
  event.stopPropagation();
238
264
  dispatch({
@@ -246,6 +272,7 @@ export function useAppGlobalShortcuts({
246
272
 
247
273
  // A function key is never text, so the card opens from a focused field too.
248
274
  if (action === "function-help") {
275
+ if (ranAlready(action)) return;
249
276
  event.preventDefault();
250
277
  event.stopPropagation();
251
278
  recordFunctionOpen({ shortcut: "HELP", externalPluginId: null });
@@ -259,6 +286,7 @@ export function useAppGlobalShortcuts({
259
286
  if (state.inputCaptured) return;
260
287
 
261
288
  if (!isDetachedWindow && action === "help") {
289
+ if (ranAlready(action)) return;
262
290
  event.preventDefault();
263
291
  event.stopPropagation();
264
292
  pluginRegistry.showPane("help");
@@ -266,13 +294,16 @@ export function useAppGlobalShortcuts({
266
294
  }
267
295
 
268
296
  if (!isDetachedWindow && action === "quit") {
297
+ if (ranAlready(action, false)) return;
269
298
  if (uiKind === "opentui") rendererHost.requestExit();
270
299
  } else if (action === "refresh-ticker") {
300
+ if (ranAlready(action, false)) return;
271
301
  if (focusedTickerSymbol) {
272
302
  const ticker = state.tickers.get(focusedTickerSymbol);
273
303
  if (ticker) refreshTicker(ticker.metadata.ticker, ticker.metadata.exchange, ticker, 0);
274
304
  }
275
305
  } else if (action === "refresh-all") {
306
+ if (ranAlready(action, false)) return;
276
307
  for (const ticker of state.tickers.values()) {
277
308
  refreshTicker(ticker.metadata.ticker, ticker.metadata.exchange, ticker, 1);
278
309
  }
@@ -280,10 +311,12 @@ export function useAppGlobalShortcuts({
280
311
  // A release that can install itself downloads on its own, so the key is
281
312
  // for the one that waits for a restart and for the one that failed.
282
313
  if (!isDetachedWindow && canRestartToApply(state.updateProgress)) {
314
+ if (ranAlready(action)) return;
283
315
  event.preventDefault();
284
316
  event.stopPropagation();
285
317
  restartToApplyUpdate();
286
318
  } else if (canRetryUpdate(state)) {
319
+ if (ranAlready(action)) return;
287
320
  event.preventDefault();
288
321
  event.stopPropagation();
289
322
  startUpdate(state.updateAvailable!);
@@ -296,6 +329,7 @@ export function useAppGlobalShortcuts({
296
329
  if (ownerId && disabledPlugins.has(ownerId)) continue;
297
330
  const chords = resolvePluginShortcutChords(keybindingsConfig, shortcut);
298
331
  if (chords.some((chord) => matchesKeyChord(chord, event))) {
332
+ if (ranAlready(`plugin:${shortcut.id}`, false)) return;
299
333
  shortcut.execute();
300
334
  break;
301
335
  }
@@ -28,6 +28,7 @@ export type CoreKeybindingActionId =
28
28
  | "pane-screenshot"
29
29
  | "pane-export-csv"
30
30
  | "pane-share"
31
+ | "pane-ask"
31
32
  | "layout-gallery"
32
33
  | "tidy-windows"
33
34
  | "window-move-mode"
@@ -59,6 +60,7 @@ export const PANE_ACTION_IDS = new Set<CoreKeybindingActionId>([
59
60
  "pane-screenshot",
60
61
  "pane-export-csv",
61
62
  "pane-share",
63
+ "pane-ask",
62
64
  "layout-gallery",
63
65
  "tidy-windows",
64
66
  "window-move-mode",
@@ -225,9 +227,18 @@ export const KEYBINDING_ACTIONS: readonly KeybindingActionDef[] = [
225
227
  {
226
228
  id: "pane-share",
227
229
  category: "Pane Management",
228
- description: "Share the focused pane.",
230
+ description: "Share the focused pane: post a picture to chat or copy its link.",
229
231
  defaults: ["CmdOrCtrl+Shift+S"],
230
232
  },
233
+ {
234
+ id: "pane-ask",
235
+ category: "Pane Management",
236
+ description: "Ask Gloom about the focused pane, in a new conversation with the pane attached.",
237
+ // A for ask. Alt+A first, because it reaches most terminals, where
238
+ // Ctrl+Shift+A is often the terminal's own select all; the desktop app
239
+ // advertises the chord on its platform modifier.
240
+ defaults: ["Alt+A", "CmdOrCtrl+Shift+A"],
241
+ },
231
242
  {
232
243
  id: "layout-gallery",
233
244
  category: "Pane Management",
@@ -16,8 +16,8 @@ import {
16
16
  } from "../../components/layout/shell/visible-layout";
17
17
  import { applyPluginToggles } from "../../plugins/ownership";
18
18
  import { setLayoutManagerDispatch } from "../../plugins/builtin/layout-manager";
19
- import { setMarketplaceHost } from "../../plugins/builtin/plugin-marketplace/store";
20
- import type { InstalledPlugin } from "../../plugins/builtin/plugin-marketplace/model";
19
+ import { setMarketplaceHost } from "../../plugins/marketplace/store";
20
+ import type { InstalledPlugin } from "../../plugins/marketplace/model";
21
21
  import {
22
22
  listExternalPlugins,
23
23
  removeExternalPlugin,
@@ -111,11 +111,11 @@ export function useAppTickerOpenRuntime({
111
111
  return true;
112
112
  }, [pluginRegistry, stateRef]);
113
113
 
114
- const placePinnedTickerTarget = useCallback((target: TickerOpenTarget, options?: PinTickerOptions) => {
114
+ const placePinnedTickerTarget = useCallback((target: TickerOpenTarget, options?: PinTickerOptions, typed?: string) => {
115
115
  const paneType = normalizePaneId(options?.paneType ?? TICKER_RESEARCH_PANE_ID);
116
116
  const paneDef = pluginRegistry.panes.get(paneType);
117
117
  if (!paneDef) return;
118
- if (refuseWhileOwnerOff(target.symbol, options, () => placePinnedTickerTarget(target, options))) return;
118
+ if (refuseWhileOwnerOff(target.symbol, options, () => placePinnedTickerTarget(target, options, typed))) return;
119
119
 
120
120
  publishTickerOpenTarget(target);
121
121
  const symbol = target.symbol;
@@ -128,6 +128,12 @@ export function useAppTickerOpenRuntime({
128
128
  let existing = options?.forceNewPane
129
129
  ? null
130
130
  : findFixedTickerPaneForSymbol(currentLayout, paneType, symbol, instrument);
131
+ // A pane bound to the key as typed (the web terminal's first pane for ?ticker=7203:TSE) is the one the
132
+ // resolved listing (7203:JPX) settles.
133
+ const typedKey = typed?.trim().toUpperCase();
134
+ if (!options?.forceNewPane && !existing && typedKey && typedKey !== symbol) {
135
+ existing = findFixedTickerPaneForSymbol(currentLayout, paneType, typedKey, instrument);
136
+ }
131
137
  // Without a broker route, the public listing and an unnamed route are the same security: a link that names
132
138
  // neither still finds the DES the command bar opened on the public listing, and leaves its binding as it is.
133
139
  let keepBinding = false;
@@ -213,7 +219,7 @@ export function useAppTickerOpenRuntime({
213
219
  ? { symbol: selectedTicker.metadata.ticker, ticker: selectedTicker, created: false, instrument: options?.instrument, listing: options?.listing }
214
220
  : await resolveOpenTickerTarget(rawSymbol, options?.instrument === null);
215
221
  if (!target) return;
216
- placePinnedTickerTarget(target, options);
222
+ placePinnedTickerTarget(target, options, rawSymbol);
217
223
  const action = attentionActionForPane(options?.paneType ?? TICKER_RESEARCH_PANE_ID);
218
224
  if (action && pluginRegistry.panes.has(options?.paneType ?? TICKER_RESEARCH_PANE_ID)) {
219
225
  recordAttention(publicTickerKey(target.symbol, target.listing?.exchange ?? target.ticker.metadata.exchange), action);
@@ -17,6 +17,7 @@ import { getShare } from "../../shares/api";
17
17
  import { openPaneShare } from "../../shares/pane";
18
18
  import { PluginOffError, notifyPluginOff } from "../../plugins/plugin-off";
19
19
  import { materializeMarketplaceLayout } from "../../shares/portable-layout";
20
+ import { settleTypedListingKey } from "../../tickers/listing-venues";
20
21
 
21
22
  type CloudDeepLinkRoute = {
22
23
  kind: "cloud-alerts" | "cloud-emails" | "cloud-roundup" | "cloud-success" | "cloud-teams";
@@ -475,11 +476,15 @@ function handleOpenNews(
475
476
  notifyError(pluginRegistry, "Ticker news is unavailable.");
476
477
  return;
477
478
  }
478
- void pluginRegistry.createPaneFromTemplateAsync("ticker-news-pane", { symbol: action.symbol }).then(() => {
479
- notifySuccess(pluginRegistry, action.message);
480
- }).catch((error) => {
481
- notifyError(pluginRegistry, error instanceof Error ? error.message : "Failed to open ticker news.");
482
- });
479
+ // A link's 7203:TSE is the venue its symbol trades on; ticker and alert links settle it where they open.
480
+ void settleTypedListingKey(action.symbol, { store: pluginRegistry.tickerRepository, dataProvider: pluginRegistry.marketData })
481
+ .then((symbol) => pluginRegistry.createPaneFromTemplateAsync("ticker-news-pane", { symbol: symbol.toUpperCase() }))
482
+ .then(() => {
483
+ notifySuccess(pluginRegistry, action.message);
484
+ })
485
+ .catch((error) => {
486
+ notifyError(pluginRegistry, error instanceof Error ? error.message : "Failed to open ticker news.");
487
+ });
483
488
  return;
484
489
  }
485
490
 
@@ -6,7 +6,7 @@ import type { MarketDataCoordinator } from "../../market-data/coordinator";
6
6
  import { instrumentFromTicker, type InstrumentRef } from "../../market-data/request-types";
7
7
  import { useSavedLayoutWarmup } from "./layout-warmup";
8
8
  import { chatController } from "../../plugins/builtin/chat/controller";
9
- import { PLUGIN_MARKETPLACE_PANE_ID } from "../../plugins/builtin/plugin-marketplace/ids";
9
+ import { PLUGIN_MARKETPLACE_PANE_ID } from "../../plugins/marketplace/ids";
10
10
  import type { LoadedExternalPlugin } from "../../plugins/loader";
11
11
  import type { PluginRegistry } from "../../plugins/registry";
12
12
  import type {
package/src/app.tsx CHANGED
@@ -38,6 +38,7 @@ import type { LayoutBounds } from "./layout/pane-manager";
38
38
  import type { AppSessionSnapshot } from "./core/state/session-persistence";
39
39
  import type { MarketDataCoordinator } from "./market-data/coordinator";
40
40
  import { createAppNotifier } from "./notifications/app-notifier";
41
+ import { attachNotificationLog } from "./notifications/notification-log";
41
42
  import { useBrokerImportRuntime } from "./app/runtime/broker-import";
42
43
  import { useDesktopDeepLinkRuntime } from "./app/runtime/desktop-deeplink";
43
44
  import { useDesktopApplicationMenuRuntime } from "./app/runtime/desktop-menu";
@@ -374,6 +375,11 @@ function AppInner({
374
375
 
375
376
  // Wire up app-level notifications.
376
377
  pluginRegistry.bindHost({ notify: appNotifier.notify });
378
+ // Missed alerts live in this device's state store. A detached window keeps
379
+ // its own in memory rather than overwrite the main window's.
380
+ useEffect(() => (
381
+ isDetachedWindow ? undefined : attachNotificationLog(pluginRegistry.persistence.pluginState)
382
+ ), [isDetachedWindow, pluginRegistry]);
377
383
 
378
384
  // Persist layout changes (switching, saving, deleting, renaming layouts).
379
385
  // The saved layouts also mirror live pane state and focus, so they change on
@@ -2,10 +2,10 @@
2
2
  "src/api-client/askg.ts": ["cloud"],
3
3
  "src/app.tsx": ["cloud"],
4
4
  "src/app/global-shortcuts.ts": ["help"],
5
- "src/app/pane-runtime/plugin-bindings.ts": ["broker-manager","layout-manager","plugin-marketplace"],
5
+ "src/app/pane-runtime/plugin-bindings.ts": ["broker-manager","layout-manager"],
6
6
  "src/app/runtime/broker-import.ts": ["portfolio-list"],
7
7
  "src/app/runtime/desktop-deeplink.ts": ["account-management","chat","cloud"],
8
- "src/app/runtime/startup.ts": ["chat","plugin-marketplace"],
8
+ "src/app/runtime/startup.ts": ["chat"],
9
9
  "src/cli/commands/market.ts": ["holders","insider","research","sec"],
10
10
  "src/cli/commands/options-chain.ts": ["options","options-calculator"],
11
11
  "src/cli/commands/options-leaps.ts": ["options","vol-surface"],
@@ -23,7 +23,6 @@
23
23
  "src/components/command-bar/commands/direct/index.ts": ["broker-manager","portfolio-list"],
24
24
  "src/components/command-bar/routes/root/command-items.ts": ["portfolio-list"],
25
25
  "src/components/command-bar/routes/root/help-items.ts": ["help"],
26
- "src/components/command-bar/routes/root/plugin-install.ts": ["plugin-marketplace"],
27
26
  "src/components/command-bar/routes/root/shortcut-items.ts": ["portfolio-list"],
28
27
  "src/components/command-bar/workflow/builtin.ts": ["cloud","portfolio-list"],
29
28
  "src/components/command-bar/workflow/collection-actions.ts": ["cloud","portfolio-list"],
@@ -32,30 +31,22 @@
32
31
  "src/components/feedback-dialog.tsx": ["cloud"],
33
32
  "src/components/form-modal/routes.ts": ["portfolio-list"],
34
33
  "src/components/index.ts": ["portfolio-list"],
35
- "src/components/layout/missing-pane.tsx": ["plugin-marketplace"],
36
34
  "src/components/layout/shell/index.tsx": ["cloud"],
37
35
  "src/components/layout/status-bar-groups.ts": ["cloud"],
38
36
  "src/components/layout/status-bar.tsx": ["cloud"],
39
37
  "src/components/onboarding/use-onboarding-upgrade.ts": ["chat"],
40
38
  "src/components/onboarding/wizard-model.ts": ["portfolio-list"],
41
39
  "src/components/onboarding/wizard-positions.ts": ["portfolio-list"],
42
- "src/layout-marketplace/gallery.tsx": ["cloud","plugin-marketplace"],
40
+ "src/layout-marketplace/gallery.tsx": ["cloud"],
43
41
  "src/layout-marketplace/linked-sync.ts": ["cloud"],
44
42
  "src/layout/desks.ts": ["chart-composer"],
45
- "src/plugins/auto-update-node.ts": ["plugin-marketplace"],
46
- "src/plugins/auto-update.ts": ["plugin-marketplace"],
47
43
  "src/plugins/catalog-browser.ts": ["alerts","analytics","attention","awards","backtest","bond-calculator","catalysts","cds","central-bank-rates","changelog","chart-composer","clinical-trials","cloud","comment-letters","company-attention","company-kpis","connections","correlation","cot","cpi","credit-boards","credit-conditions","credit-documents","crypto-board","debt-maturities","dividend-yield","docs","doe","earnings-calls","earnings-ripple","econ","econ-statistics","equity-screener","estimate-revisions","executives","exposure","fear-greed","filing-events","futures","futures-curve","fx-matrix","gpu","help","insider","ipo-calendar","iv-history","jobs","kelly-sizer","layout-manager","macro-day","market-halts","market-heatmap","market-valuation","members","mna","money-markets","news","openfda","options","options-calculator","options-positioning","options-scenario","pe-band","perps","portfolio-list","power","rate-path","realized-vol","relative-rotation","research","research-search","revenue-breakdown","reverse-dcf","risk-factors","scanner","seasonality","sec","sectors","short-interest","short-volume","social-mentions","supply-chain","ticker-detail","time-sales","treasury-auctions","vol-surface","volatility","world-indices","world-venue-map","yield-curve"],
48
44
  "src/plugins/catalog-ui.ts": ["alerts","clinical-trials","cloud","comment-letters","custom-view","fear-greed","ipo-calendar","market-halts","market-heatmap","members","news","notes","openfda","research-search"],
49
45
  "src/plugins/catalog.ts": ["debug"],
50
- "src/plugins/installer.ts": ["plugin-marketplace"],
51
- "src/plugins/manager-node.ts": ["plugin-marketplace"],
52
46
  "src/remote/controller.ts": ["custom-view"],
53
- "src/renderers/browser/main.tsx": ["plugin-marketplace"],
54
47
  "src/renderers/electrobun/bun/core-capabilities.ts": ["notes"],
55
- "src/renderers/electrobun/shared/protocol.ts": ["plugin-marketplace"],
56
48
  "src/renderers/electrobun/view/cli-pane-shot-entry.tsx": ["econ-statistics","market-valuation","time-sales"],
57
- "src/renderers/electrobun/view/main.tsx": ["notes","plugin-marketplace"],
49
+ "src/renderers/electrobun/view/main.tsx": ["notes"],
58
50
  "src/renderers/electrobun/view/remote/connection-health.ts": ["connections"],
59
- "src/renderers/opentui/start.tsx": ["plugin-marketplace"],
60
51
  "src/sync/core-contributors.ts": ["analytics","portfolio-list"]
61
52
  }
@@ -0,0 +1,114 @@
1
+ import type { PluginRegistry } from "../plugins/registry";
2
+ import { paneShowsPersonalData } from "../shares/personal-pane";
3
+ import type { AppConfig, PaneInstanceConfig } from "../types/config";
4
+ import type { PaneSharePrivateFields } from "../types/plugin";
5
+ import type { TickerRecord } from "../types/ticker";
6
+ import type { AskGloomPaneAttachment } from "./pane-request";
7
+
8
+ /** A handful of the pane's own settings is enough to say how it is set up. */
9
+ const MAX_ARGS = 8;
10
+ const MAX_ARG_KEY_LENGTH = 32;
11
+ const MAX_ARG_VALUE_LENGTH = 48;
12
+ /** Layout and view bookkeeping, not what the pane shows. */
13
+ const BOOKKEEPING_KEYS = [
14
+ /scroll|width|height|offset|index|expanded|collapsed|focus|hover|sidebar|column|sort|order|version|draft/i,
15
+ // The cursor's position, but not the symbol it is on.
16
+ /^cursor(?!Symbol)/,
17
+ // Timestamps such as `updatedAt`.
18
+ /[a-z]At$/,
19
+ ];
20
+
21
+ type ArgSource = Readonly<Record<string, unknown>> | undefined;
22
+
23
+ function isPrivate(fields: PaneSharePrivateFields | undefined, key: string): boolean {
24
+ return fields === true || (Array.isArray(fields) && fields.includes(key));
25
+ }
26
+
27
+ function scalarArgs(source: ArgSource, privateFields: PaneSharePrivateFields | undefined): Array<[string, string]> {
28
+ if (!source || privateFields === true) return [];
29
+ return Object.entries(source).flatMap(([key, value]): Array<[string, string]> => {
30
+ if (key.length > MAX_ARG_KEY_LENGTH || BOOKKEEPING_KEYS.some((pattern) => pattern.test(key)) || isPrivate(privateFields, key)) return [];
31
+ if (typeof value === "number" && Number.isFinite(value)) return [[key, String(value)]];
32
+ if (typeof value !== "string") return [];
33
+ const trimmed = value.trim();
34
+ return trimmed && trimmed.length <= MAX_ARG_VALUE_LENGTH ? [[key, trimmed]] : [];
35
+ });
36
+ }
37
+
38
+ /**
39
+ * The function code a pane is opened by: the one its title starts with when
40
+ * that opens this pane (a chart opened with `GP` stays `GP`), else the first
41
+ * template that opens it.
42
+ */
43
+ function functionCode(registry: Pick<PluginRegistry, "paneTemplates">, paneType: string, title: string): string | null {
44
+ const prefixes = [...registry.paneTemplates.values()]
45
+ .filter((template) => template.paneId === paneType && template.shortcut?.prefix)
46
+ .map((template) => template.shortcut!.prefix.toUpperCase());
47
+ const token = title.trim().split(/\s+/)[0]?.toUpperCase() ?? "";
48
+ if (token && prefixes.includes(token)) return token;
49
+ return prefixes[0] ?? null;
50
+ }
51
+
52
+ export interface PaneAttachmentSource {
53
+ registry: Pick<PluginRegistry, "panes" | "paneTemplates" | "brokers" | "getPanePluginId" | "getBrokerPluginId">;
54
+ instance: PaneInstanceConfig;
55
+ /** What the header calls it. */
56
+ title: string;
57
+ symbol: string | null;
58
+ paneState?: Readonly<Record<string, unknown>>;
59
+ config: Pick<AppConfig, "portfolios" | "brokerInstances">;
60
+ tickers?: ReadonlyMap<string, TickerRecord>;
61
+ /** The tab each of its tab strips has open, outermost first. */
62
+ activeTabs?: readonly string[];
63
+ visibleText: string | null;
64
+ }
65
+
66
+ /**
67
+ * What Ask Gloom is told about a pane: its function and arguments as the
68
+ * user set them, and its text as drawn. Fields the pane keeps to itself when
69
+ * shared (`portableShare.private`) stay out of its arguments.
70
+ */
71
+ export function buildAskGloomPaneAttachment({
72
+ registry,
73
+ instance,
74
+ title,
75
+ symbol,
76
+ paneState,
77
+ config,
78
+ tickers,
79
+ activeTabs = [],
80
+ visibleText,
81
+ }: PaneAttachmentSource): AskGloomPaneAttachment {
82
+ const privateFields = registry.panes.get(instance.paneId)?.portableShare?.private;
83
+ const args: Record<string, string> = {};
84
+ const tabs = activeTabs.map((tab) => tab.trim()).filter(Boolean);
85
+ if (tabs.length > 0) args.tab = tabs.join(" > ").slice(0, MAX_ARG_VALUE_LENGTH);
86
+ for (const [key, value] of [
87
+ ...scalarArgs(instance.params, privateFields?.params),
88
+ ...scalarArgs(instance.settings, privateFields?.settings),
89
+ ...scalarArgs(paneState, privateFields?.state),
90
+ ]) {
91
+ if (Object.keys(args).length >= MAX_ARGS) break;
92
+ if (key in args || value === symbol) continue;
93
+ args[key] = value;
94
+ }
95
+ return {
96
+ paneId: instance.instanceId,
97
+ paneType: instance.paneId,
98
+ title,
99
+ code: functionCode(registry, instance.paneId, title),
100
+ symbol,
101
+ args,
102
+ visibleText,
103
+ personal: showsPersonalData({ registry, instance, paneState, symbol, config, tickers }),
104
+ };
105
+ }
106
+
107
+ /** A pane that cannot be read for it counts as personal: its contents then wait for a yes. */
108
+ function showsPersonalData(source: Parameters<typeof paneShowsPersonalData>[0]): boolean {
109
+ try {
110
+ return paneShowsPersonalData(source);
111
+ } catch {
112
+ return true;
113
+ }
114
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Asking Ask Gloom about a pane. Every pane offers it the same way, with no
3
+ * code of its own: the button beside the `?` in a desktop pane header, Ask
4
+ * Gloom in the pane menu, and the pane-ask key. The shell describes the pane
5
+ * here, and Ask Gloom, while its plugin is on, opens a new conversation with
6
+ * the pane attached.
7
+ */
8
+
9
+ /** A pane as Ask Gloom receives it: what it is and what it showed when asked. */
10
+ export interface AskGloomPaneAttachment {
11
+ /** The pane instance. */
12
+ paneId: string;
13
+ /** Its pane type. */
14
+ paneType: string;
15
+ /** What its header calls it, such as `DES AAPL`. */
16
+ title: string;
17
+ /** The function code that opens it, such as `DES`, when one does. */
18
+ code: string | null;
19
+ /** The ticker it shows, when it shows one. */
20
+ symbol: string | null;
21
+ /** How it is set up as the user sees it: its tab, range or view. Short values only. */
22
+ args: Readonly<Record<string, string>>;
23
+ /** Its text as drawn when asked, bounded; null when none could be read. */
24
+ visibleText: string | null;
25
+ /**
26
+ * It shows holdings, balances or account data, so Ask Gloom asks before
27
+ * anything it shows leaves the device.
28
+ */
29
+ personal: boolean;
30
+ }
31
+
32
+ type AskGloomPaneHandler = (attachment: AskGloomPaneAttachment) => void;
33
+
34
+ const handlers = new Set<AskGloomPaneHandler>();
35
+ const listeners = new Set<() => void>();
36
+
37
+ function changed(): void {
38
+ for (const listener of [...listeners]) listener();
39
+ }
40
+
41
+ /**
42
+ * Ask Gloom takes pane questions while it is registered. The shell offers the
43
+ * button, the menu entry and the key only then, so a profile with the cloud
44
+ * plugin off shows none of them.
45
+ */
46
+ export function registerAskGloomPaneHandler(handler: AskGloomPaneHandler): () => void {
47
+ handlers.add(handler);
48
+ changed();
49
+ return () => {
50
+ if (handlers.delete(handler)) changed();
51
+ };
52
+ }
53
+
54
+ export function canAskGloomAboutPanes(): boolean {
55
+ return handlers.size > 0;
56
+ }
57
+
58
+ export function subscribeAskGloomAboutPanes(listener: () => void): () => void {
59
+ listeners.add(listener);
60
+ return () => {
61
+ listeners.delete(listener);
62
+ };
63
+ }
64
+
65
+ /** Hands the pane to Ask Gloom. False when nothing takes it. */
66
+ export function askGloomAboutPane(attachment: AskGloomPaneAttachment): boolean {
67
+ if (handlers.size === 0) return false;
68
+ for (const handler of [...handlers]) handler(attachment);
69
+ return true;
70
+ }