gloomberb 0.11.2 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -4
- package/README.zh-CN.md +4 -2
- package/package.json +28 -1
- package/src/api-client/auth.ts +10 -0
- package/src/api-client/data.ts +108 -1
- package/src/api-client/index.test.ts +127 -0
- package/src/api-client/index.ts +134 -1
- package/src/api-client/normalizers.ts +39 -0
- package/src/api-client/paths.ts +85 -1
- package/src/api-client/types.ts +220 -0
- package/src/app/pane-runtime/index.tsx +15 -12
- package/src/app/pane-runtime/layout-placement.test.ts +27 -0
- package/src/app/pane-runtime/layout-placement.ts +13 -0
- package/src/app/pane-runtime/plugin-bindings.ts +62 -0
- package/src/app.tsx +60 -18
- package/src/architecture/browser-entry-graph.test.ts +96 -0
- package/src/brokers/profile-form.test.ts +25 -27
- package/src/brokers/test-broker.ts +68 -0
- package/src/capabilities/chart-series.ts +3 -2
- package/src/cli/commands/market.ts +2 -2
- package/src/cli/commands/plugins.ts +39 -11
- package/src/cli/desktop-pane-shot.ts +285 -16
- package/src/cli/index.ts +1 -1
- package/src/cli/pane-functions/capabilities.ts +61 -31
- package/src/cli/pane-functions/catalog.ts +16 -4
- package/src/cli/pane-functions/discovery.ts +1 -0
- package/src/cli/pane-functions/headless.test.ts +247 -0
- package/src/cli/pane-functions/headless.ts +423 -0
- package/src/cli/pane-functions/index.test.ts +9 -0
- package/src/cli/pane-functions/index.ts +6 -2
- package/src/cli/pane-functions/options.ts +27 -2
- package/src/cli/pane-functions/report.ts +4 -0
- package/src/cli/pane-functions/resolver.ts +26 -8
- package/src/cli/pane-functions/screenshot.test.ts +76 -0
- package/src/cli/pane-functions/screenshot.ts +236 -20
- package/src/cli/registry.ts +0 -22
- package/src/cli/restore-plugins.ts +34 -0
- package/src/cli/result.ts +7 -10
- package/src/components/chart/{static/chart → composite}/axis-overlays.test.tsx +3 -3
- package/src/components/chart/{static/chart → composite}/axis-overlays.tsx +6 -11
- package/src/components/chart/{static/chart → composite}/bitmap.ts +17 -3
- package/src/components/chart/composite/composite-chart.test.tsx +68 -20
- package/src/components/chart/composite/composite-chart.tsx +301 -204
- package/src/components/chart/composite/format.ts +8 -2
- package/src/components/chart/composite/interactions.test.ts +68 -102
- package/src/components/chart/composite/interactions.ts +214 -264
- package/src/components/chart/composite/price-axis-labels.test.ts +21 -0
- package/src/components/chart/{price-axis-labels.tsx → composite/price-axis-labels.tsx} +9 -4
- package/src/components/chart/composite/scene.ts +57 -3
- package/src/components/chart/composite/text-renderer.ts +3 -2
- package/src/components/chart/composite/time-scale.ts +138 -57
- package/src/components/chart/composite/types.ts +25 -1
- package/src/components/chart/core/data.ts +9 -13
- package/src/components/chart/core/date-window.ts +7 -1
- package/src/components/chart/core/pointer.ts +3 -0
- package/src/components/chart/core/types.ts +0 -45
- package/src/components/chart/native/chart-rasterizer.ts +0 -1
- package/src/components/chart/native/kitty/index.test.ts +0 -188
- package/src/components/chart/native/raster/crosshair.ts +6 -5
- package/src/components/chart/native/raster/primitives.ts +0 -23
- package/src/components/chart/native/renderer-selection.ts +81 -31
- package/src/components/chart/static/{chart/surface.test.tsx → chart-surface.test.tsx} +28 -80
- package/src/components/chart/static/chart-surface.tsx +150 -0
- package/src/components/chart/static/index.ts +8 -0
- package/src/components/chart/static/multi-line-chart-surface.tsx +51 -166
- package/src/components/chart/static/scatter-chart-surface.test.ts +30 -0
- package/src/components/chart/static/scatter-chart-surface.tsx +135 -34
- package/src/components/chart/static/series.ts +49 -0
- package/src/components/command-bar/action-runtime.ts +1 -3
- package/src/components/command-bar/assist/model.test.ts +17 -2
- package/src/components/command-bar/assist/model.ts +40 -9
- package/src/components/command-bar/commands/direct/index.ts +1 -1
- package/src/components/command-bar/commands/direct/runtime.ts +1 -1
- package/src/components/command-bar/commands/registry.ts +0 -11
- package/src/components/command-bar/helpers.test.ts +2 -2
- package/src/components/command-bar/helpers.ts +2 -6
- package/src/components/command-bar/keyboard-shortcuts.ts +0 -11
- package/src/components/command-bar/list/badge.test.ts +54 -0
- package/src/components/command-bar/list/badge.ts +62 -0
- package/src/components/command-bar/list/model.test.ts +103 -0
- package/src/components/command-bar/list/model.ts +61 -4
- package/src/components/command-bar/list/view.test.tsx +113 -0
- package/src/components/command-bar/list/view.tsx +147 -131
- package/src/components/command-bar/pane-templates/workflow.ts +1 -1
- package/src/components/command-bar/panel/body.tsx +51 -65
- package/src/components/command-bar/panel/index.tsx +48 -13
- package/src/components/command-bar/panel/layout.test.ts +139 -0
- package/src/components/command-bar/panel/layout.ts +65 -28
- package/src/components/command-bar/panel/native-surface.ts +24 -0
- package/src/components/command-bar/panel/prompt-binding.ts +54 -0
- package/src/components/command-bar/panel/runtime.ts +6 -3
- package/src/components/command-bar/panel/state.ts +41 -7
- package/src/components/command-bar/panel/types.ts +7 -1
- package/src/components/command-bar/routes/root/provider-search.ts +34 -15
- package/src/components/command-bar/routes/root/results.test.ts +161 -0
- package/src/components/command-bar/routes/root/results.ts +30 -28
- package/src/components/command-bar/routes/root/runtime.ts +37 -20
- package/src/components/command-bar/routes/root/search-providers.test.tsx +224 -0
- package/src/components/command-bar/routes/root/search-providers.ts +205 -0
- package/src/components/command-bar/routes/root/selection.ts +1 -12
- package/src/components/command-bar/routes/root/shortcuts.test.ts +8 -8
- package/src/components/command-bar/routes/ticker-search/actions.ts +10 -9
- package/src/components/command-bar/routes/ticker-search/results.test.ts +54 -1
- package/src/components/command-bar/routes/ticker-search/results.ts +60 -19
- package/src/components/command-bar/routes/ticker-search/route.ts +1 -0
- package/src/components/command-bar/routing/actions.ts +1 -81
- package/src/components/command-bar/routing/launch-request.ts +1 -1
- package/src/components/command-bar/routing/list-state.ts +6 -21
- package/src/components/command-bar/selection-runtime.ts +1 -1
- package/src/components/command-bar/surface/assist.test.tsx +14 -10
- package/src/components/command-bar/surface/environment.ts +8 -1
- package/src/components/command-bar/surface/index.test.tsx +84 -68
- package/src/components/command-bar/surface/index.tsx +33 -36
- package/src/components/command-bar/surface/test-harness.tsx +15 -3
- package/src/components/command-bar/theme-picker.tsx +43 -15
- package/src/components/command-bar/view-model.test.ts +53 -8
- package/src/components/command-bar/view-model.ts +43 -14
- package/src/components/command-bar/workflow/tickers.ts +1 -0
- package/src/components/command-bar/workflow/types.ts +1 -1
- package/src/components/data-table/export.test.ts +21 -0
- package/src/components/data-table/export.ts +21 -0
- package/src/components/data-table/view.test.tsx +45 -6
- package/src/components/data-table/view.tsx +55 -9
- package/src/components/index.ts +10 -2
- package/src/components/input-search-bar.test.tsx +36 -2
- package/src/components/input-search-bar.tsx +18 -1
- package/src/components/layout/header.test.tsx +57 -10
- package/src/components/layout/header.tsx +292 -149
- package/src/components/layout/market-summary.test.ts +81 -0
- package/src/components/layout/market-summary.ts +109 -0
- package/src/components/layout/shell/chrome.ts +96 -1
- package/src/components/layout/shell/index.tsx +11 -3
- package/src/components/layout/shell/menu.ts +9 -0
- package/src/components/layout/shell/pane/actions.ts +29 -0
- package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
- package/src/components/layout/shell/shortcuts.ts +3 -0
- package/src/components/layout/status-bar.test.tsx +9 -8
- package/src/components/layout/status-bar.tsx +85 -54
- package/src/components/onboarding/onboarding-frame.tsx +2 -26
- package/src/components/price-sparkline/index.ts +61 -34
- package/src/components/price-sparkline/view.tsx +1 -1
- package/src/components/sign-in-gate.test.tsx +128 -0
- package/src/components/sign-in-gate.tsx +149 -0
- package/src/components/speedometer-gauge/desktop.tsx +2 -12
- package/src/components/ticker/badge/list.tsx +17 -3
- package/src/components/ticker/list-table-view.tsx +6 -3
- package/src/components/ui/data-table/index.tsx +22 -4
- package/src/components/ui/data-table/opentui/index.tsx +165 -120
- package/src/components/ui/frame.tsx +28 -0
- package/src/components/ui/index.ts +3 -0
- package/src/components/ui/native-select.tsx +20 -10
- package/src/components/ui/select-button.tsx +138 -0
- package/src/components/ui/status.tsx +2 -2
- package/src/components/ui/table-layout.ts +1 -1
- package/src/components/use-double-click-activation.ts +7 -3
- package/src/core/app-services.ts +3 -3
- package/src/data/config/chart-settings.ts +4 -4
- package/src/data/config/layout.ts +12 -6
- package/src/data/config/store/index.test.ts +97 -0
- package/src/data/config/store/migrations.ts +41 -0
- package/src/data/config/store/normalize.ts +5 -3
- package/src/i18n/es.ts +6 -2
- package/src/i18n/ja.ts +6 -2
- package/src/i18n/ko.ts +6 -2
- package/src/i18n/zh-cn.ts +6 -2
- package/src/i18n/zh-tw.ts +6 -2
- package/src/layout-marketplace/gallery-terminal.tsx +126 -96
- package/src/layout-marketplace/gallery.test.tsx +65 -1
- package/src/layout-marketplace/pane-imagery.ts +1 -0
- package/src/layout-marketplace/payload.test.ts +17 -0
- package/src/layout-marketplace/payload.ts +40 -5
- package/src/market-data/coordinator/index.ts +3 -2
- package/src/market-data/coordinator/quotes.ts +173 -66
- package/src/market-data/coordinator/subscriptions.test.ts +215 -37
- package/src/pane-settings.ts +1 -1
- package/src/plugins/builtin/analytics/pane-model.ts +1 -1
- package/src/plugins/builtin/analytics/view.tsx +1 -1
- package/src/plugins/builtin/broker-manager/index.test.tsx +3 -2
- package/src/plugins/builtin/broker-manager/model.test.ts +2 -2
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +16 -2
- package/src/plugins/builtin/chart-composer/cli-options.ts +12 -9
- package/src/plugins/builtin/chart-composer/pane.tsx +22 -8
- package/src/plugins/builtin/chart-composer/settings.ts +2 -13
- package/src/plugins/builtin/chat/content/composer.tsx +8 -4
- package/src/plugins/builtin/cloud/auth-dialog.tsx +14 -228
- package/src/plugins/builtin/cloud/auth-form.tsx +277 -0
- package/src/plugins/builtin/cloud/plugin.tsx +1 -0
- package/src/plugins/builtin/composite-plugins.ts +16 -1
- package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
- package/src/plugins/builtin/correlation/relationship/pane.tsx +2 -6
- package/src/plugins/builtin/correlation/relationship/view-model.ts +2 -2
- package/src/plugins/builtin/credit-conditions/index.test.tsx +12 -6
- package/src/plugins/builtin/credit-conditions/index.tsx +2 -21
- package/src/plugins/builtin/dividend-yield/index.tsx +1 -0
- package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
- package/src/plugins/builtin/earnings/index.tsx +1 -0
- package/src/plugins/builtin/earnings-calls/data.ts +223 -0
- package/src/plugins/builtin/earnings-calls/format.ts +49 -0
- package/src/plugins/builtin/earnings-calls/index.tsx +69 -0
- package/src/plugins/builtin/earnings-calls/pane.tsx +756 -0
- package/src/plugins/builtin/earnings-calls/prose.test.ts +36 -0
- package/src/plugins/builtin/earnings-calls/prose.ts +59 -0
- package/src/plugins/builtin/earnings-calls/transcript-view.tsx +334 -0
- package/src/plugins/builtin/econ/detail-view.tsx +1 -2
- package/src/plugins/builtin/econ/fred-series-map.ts +16 -1
- package/src/plugins/builtin/econ/index.tsx +3 -1
- package/src/plugins/builtin/econ-statistics/cache.ts +4 -0
- package/src/plugins/builtin/econ-statistics/client.ts +92 -0
- package/src/plugins/builtin/econ-statistics/defs.ts +66 -0
- package/src/plugins/builtin/econ-statistics/detail.tsx +154 -0
- package/src/plugins/builtin/econ-statistics/headless.test.ts +54 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +171 -0
- package/src/plugins/builtin/econ-statistics/index.tsx +54 -0
- package/src/plugins/builtin/econ-statistics/pane.tsx +356 -0
- package/src/plugins/builtin/econ-statistics/stats.ts +522 -0
- package/src/plugins/builtin/econ-statistics/transform.test.ts +86 -0
- package/src/plugins/builtin/econ-statistics/transform.ts +85 -0
- package/src/plugins/builtin/econ-statistics/trend.ts +57 -0
- package/src/plugins/builtin/econ-statistics/view.ts +90 -0
- package/src/plugins/builtin/fear-greed/charts.tsx +7 -18
- package/src/plugins/builtin/fear-greed/data.ts +6 -1
- package/src/plugins/builtin/futures/index.tsx +1 -0
- package/src/plugins/builtin/fx-matrix/index.tsx +1 -0
- package/src/plugins/builtin/help/index.tsx +4 -0
- package/src/plugins/builtin/holders/index.tsx +1 -0
- package/src/plugins/builtin/insider/index.tsx +1 -0
- package/src/plugins/builtin/ipo-calendar/index.tsx +1 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +1 -1
- package/src/plugins/builtin/kelly-sizer/sections.tsx +2 -3
- package/src/plugins/builtin/market-halts/index.tsx +1 -0
- package/src/plugins/builtin/market-movers/index.tsx +1 -0
- package/src/plugins/builtin/market-valuation/align.ts +122 -0
- package/src/plugins/builtin/market-valuation/cache.ts +32 -0
- package/src/plugins/builtin/market-valuation/chart-projection.ts +217 -0
- package/src/plugins/builtin/market-valuation/chart-series.ts +89 -0
- package/src/plugins/builtin/market-valuation/client.test.ts +141 -0
- package/src/plugins/builtin/market-valuation/client.ts +116 -0
- package/src/plugins/builtin/market-valuation/defs.ts +251 -0
- package/src/plugins/builtin/market-valuation/detail.tsx +159 -0
- package/src/plugins/builtin/market-valuation/headless.test.ts +58 -0
- package/src/plugins/builtin/market-valuation/headless.ts +170 -0
- package/src/plugins/builtin/market-valuation/index.tsx +64 -0
- package/src/plugins/builtin/market-valuation/indicators.ts +422 -0
- package/src/plugins/builtin/market-valuation/model.test.ts +350 -0
- package/src/plugins/builtin/market-valuation/model.ts +8 -0
- package/src/plugins/builtin/market-valuation/pane.test.tsx +247 -0
- package/src/plugins/builtin/market-valuation/pane.tsx +344 -0
- package/src/plugins/builtin/market-valuation/series.ts +12 -0
- package/src/plugins/builtin/market-valuation/settings.ts +38 -0
- package/src/plugins/builtin/market-valuation/sources.ts +130 -0
- package/src/plugins/builtin/market-valuation/trend.ts +89 -0
- package/src/plugins/builtin/market-valuation/view.ts +137 -0
- package/src/plugins/builtin/market-valuation/zone-scale/desktop.tsx +123 -0
- package/src/plugins/builtin/market-valuation/zone-scale/index.tsx +12 -0
- package/src/plugins/builtin/market-valuation/zone-scale/model.ts +60 -0
- package/src/plugins/builtin/market-valuation/zone-scale/terminal.tsx +94 -0
- package/src/plugins/builtin/news/wire/breaking/filters.test.ts +99 -0
- package/src/plugins/builtin/news/wire/breaking/filters.ts +110 -0
- package/src/plugins/builtin/news/wire/breaking/notifications.test.ts +157 -53
- package/src/plugins/builtin/news/wire/breaking/notifications.ts +91 -25
- package/src/plugins/builtin/news/wire/index.tsx +31 -44
- package/src/plugins/builtin/options/analytics.test.ts +83 -0
- package/src/plugins/builtin/options/analytics.ts +110 -0
- package/src/plugins/builtin/options/index.tsx +18 -2
- package/src/plugins/builtin/options/table.ts +121 -51
- package/src/plugins/builtin/options/types.ts +22 -15
- package/src/plugins/builtin/options/view.test.tsx +53 -1
- package/src/plugins/builtin/options/view.tsx +92 -41
- package/src/plugins/builtin/plugin-marketplace/feed.ts +80 -0
- package/src/plugins/builtin/plugin-marketplace/index.tsx +31 -0
- package/src/plugins/builtin/plugin-marketplace/model.test.ts +200 -0
- package/src/plugins/builtin/plugin-marketplace/model.ts +204 -0
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +385 -0
- package/src/plugins/builtin/plugin-marketplace/store.ts +46 -0
- package/src/plugins/builtin/plugin-module.test.ts +2 -4
- package/src/plugins/builtin/plugin-module.ts +9 -8
- package/src/plugins/builtin/portfolio-list/index.tsx +1 -0
- package/src/plugins/builtin/research/index.tsx +4 -0
- package/src/plugins/builtin/research-search/command-bar-search.test.ts +81 -0
- package/src/plugins/builtin/research-search/command-bar-search.ts +175 -0
- package/src/plugins/builtin/research-search/data.ts +109 -0
- package/src/plugins/builtin/research-search/document-view.test.tsx +75 -0
- package/src/plugins/builtin/research-search/document-view.tsx +254 -0
- package/src/plugins/builtin/research-search/filter-bar.tsx +62 -0
- package/src/plugins/builtin/research-search/focus-handoff.ts +47 -0
- package/src/plugins/builtin/research-search/index.tsx +85 -0
- package/src/plugins/builtin/research-search/model.test.ts +40 -0
- package/src/plugins/builtin/research-search/model.ts +291 -0
- package/src/plugins/builtin/research-search/pane.test.tsx +241 -0
- package/src/plugins/builtin/research-search/pane.tsx +678 -0
- package/src/plugins/builtin/research-search/saved-view.tsx +171 -0
- package/src/plugins/builtin/research-search/snippet-text.tsx +35 -0
- package/src/plugins/builtin/research-search/snippet.test.ts +78 -0
- package/src/plugins/builtin/research-search/snippet.ts +134 -0
- package/src/plugins/builtin/scanner/flow-model.test.ts +11 -1
- package/src/plugins/builtin/scanner/flow-model.ts +29 -1
- package/src/plugins/builtin/scanner/flow-pane.tsx +78 -22
- package/src/plugins/builtin/scanner/index.ts +2 -0
- package/src/plugins/builtin/sec/index.tsx +1 -0
- package/src/plugins/builtin/sectors/index.tsx +1 -0
- package/src/plugins/builtin/shared/series-cache.ts +93 -0
- package/src/plugins/builtin/short-interest/index.tsx +1 -0
- package/src/plugins/builtin/short-interest/pane.tsx +1 -1
- package/src/plugins/builtin/thirteenf/index.tsx +1 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +3 -5
- package/src/plugins/builtin/ticker-detail/index.tsx +2 -14
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +1 -1
- package/src/plugins/builtin/treasury-auctions/index.tsx +1 -0
- package/src/plugins/builtin/volatility/index.tsx +1 -1
- package/src/plugins/builtin/world-indices/index.tsx +1 -0
- package/src/plugins/builtin/world-venue-map/index.ts +27 -0
- package/src/plugins/builtin/world-venue-map/map.desktop.test.tsx +106 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +481 -0
- package/src/plugins/builtin/world-venue-map/model.test.ts +85 -0
- package/src/plugins/builtin/world-venue-map/model.ts +268 -0
- package/src/plugins/builtin/world-venue-map/pane.tsx +300 -0
- package/src/plugins/builtin/world-venue-map/world-outlines.ts +2 -0
- package/src/plugins/builtin/yield-curve/index.tsx +1 -1
- package/src/plugins/bundle.test.ts +109 -0
- package/src/plugins/bundle.ts +139 -0
- package/src/plugins/catalog-backend.ts +6 -44
- package/src/plugins/catalog-browser.test.ts +1 -0
- package/src/plugins/catalog-browser.ts +12 -0
- package/src/plugins/catalog-manifest.test.ts +43 -0
- package/src/plugins/catalog-manifest.ts +92 -0
- package/src/plugins/catalog-ui.ts +20 -4
- package/src/plugins/catalog.ts +9 -2
- package/src/plugins/current-target.ts +28 -0
- package/src/plugins/host-contract.ts +37 -0
- package/src/plugins/host-link.ts +158 -0
- package/src/plugins/host-modules.ts +61 -0
- package/src/plugins/loader.ts +41 -22
- package/src/plugins/ownership.ts +1 -0
- package/src/plugins/prediction-markets/index.tsx +1 -0
- package/src/plugins/registry/context.ts +3 -0
- package/src/plugins/registry/contributions.ts +27 -0
- package/src/plugins/registry/index.test.ts +25 -0
- package/src/plugins/registry/index.ts +8 -0
- package/src/plugins/registry/pane-settings.test.ts +53 -0
- package/src/plugins/registry/pane-settings.ts +29 -3
- package/src/plugins/seed.test.ts +83 -0
- package/src/plugins/seed.ts +80 -0
- package/src/public/broker.ts +31 -0
- package/src/public/market-data.ts +9 -0
- package/src/public/pane-hooks.ts +57 -0
- package/src/public/public-api.test.ts +285 -0
- package/src/public/react.ts +62 -0
- package/src/public/test-support.ts +23 -0
- package/src/public/time-series.ts +8 -0
- package/src/public/utils.ts +77 -0
- package/src/remote/layout-helpers.ts +6 -8
- package/src/remote/resources.ts +2 -0
- package/src/remote/schema.ts +1 -0
- package/src/remote/semantic-tree.test.tsx +105 -0
- package/src/remote/semantic-tree.tsx +53 -35
- package/src/renderers/browser/main.tsx +6 -0
- package/src/renderers/browser/ui-host.tsx +11 -0
- package/src/renderers/cloudflare/worker.test.ts +19 -0
- package/src/renderers/cloudflare/worker.ts +1 -1
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -2
- package/src/renderers/electrobun/bun/external-plugins.ts +140 -0
- package/src/renderers/electrobun/bun/index.ts +6 -2
- package/src/renderers/electrobun/shared/protocol.ts +25 -0
- package/src/renderers/electrobun/view/build-assets.ts +0 -1
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +51 -1
- package/src/renderers/electrobun/view/external-plugins.test.ts +45 -0
- package/src/renderers/electrobun/view/external-plugins.ts +63 -0
- package/src/renderers/electrobun/view/host/ascii-text.test.ts +48 -0
- package/src/renderers/electrobun/view/host/ascii-text.ts +11 -1
- package/src/renderers/electrobun/view/host/chart-surface.tsx +38 -32
- package/src/renderers/electrobun/view/host/mouse.ts +16 -2
- package/src/renderers/electrobun/view/main.tsx +27 -2
- package/src/renderers/electrobun/view/styles.css +5 -0
- package/src/renderers/electrobun/view/toast-host.tsx +18 -0
- package/src/renderers/electrobun/view/ui-host.tsx +3 -0
- package/src/renderers/opentui/chart-surface.tsx +5 -1
- package/src/renderers/opentui/host.tsx +20 -2
- package/src/renderers/opentui/interaction-performance.test.ts +79 -0
- package/src/renderers/opentui/interaction-performance.ts +188 -0
- package/src/renderers/opentui/start.tsx +26 -1
- package/src/renderers/opentui/test-utils.tsx +13 -0
- package/src/renderers/opentui/toast-host.tsx +26 -2
- package/src/renderers/opentui/ui-host.tsx +1 -0
- package/src/sources/provider-router/search.test.ts +191 -0
- package/src/sources/provider-router/search.ts +92 -39
- package/src/state/app/context/index.tsx +2 -0
- package/src/state/app/context/selector.test.tsx +33 -1
- package/src/state/hooks/quote-streaming.test.tsx +93 -0
- package/src/state/hooks/quote-streaming.ts +106 -30
- package/src/state/pane-table-export-registry.ts +50 -0
- package/src/theme/color-utils.ts +1 -1
- package/src/theme/colors.ts +50 -0
- package/src/theme/themes.test.ts +15 -2
- package/src/theme/themes.ts +19 -1
- package/src/tickers/search/index.test.ts +26 -0
- package/src/tickers/search/index.ts +42 -17
- package/src/tickers/search/ranking.ts +14 -0
- package/src/time-series/chart-data.test.ts +216 -0
- package/src/time-series/range.ts +12 -0
- package/src/time-series/resolution.test.ts +25 -26
- package/src/time-series/resolution.ts +44 -25
- package/src/time-series/resolve.ts +7 -0
- package/src/time-series/spec.ts +5 -5
- package/src/time-series/types.ts +3 -1
- package/src/time-series/use-chart-resolution.ts +5 -0
- package/src/types/config.ts +123 -3
- package/src/types/data-provider.ts +11 -0
- package/src/types/headless.ts +161 -0
- package/src/types/plugin.ts +104 -20
- package/src/ui/host.tsx +19 -1
- package/src/ui/index.tsx +1 -0
- package/src/ui/toast.tsx +8 -4
- package/src/utils/csv.test.ts +13 -0
- package/src/utils/csv.ts +37 -0
- package/src/utils/format.ts +35 -0
- package/src/utils/fuzzy-search.test.ts +94 -0
- package/src/utils/fuzzy-search.ts +81 -22
- package/src/utils/save-text-file.test.ts +24 -0
- package/src/utils/save-text-file.ts +36 -0
- package/src/utils/shortcut-labels.ts +14 -0
- package/src/components/chart/core/axis-format.ts +0 -157
- package/src/components/chart/core/index.test.ts +0 -1075
- package/src/components/chart/core/projection.ts +0 -357
- package/src/components/chart/core/render-utils.ts +0 -4
- package/src/components/chart/core/renderer.ts +0 -244
- package/src/components/chart/core/scene.ts +0 -180
- package/src/components/chart/core/time-axis.ts +0 -330
- package/src/components/chart/cursor-motion.ts +0 -47
- package/src/components/chart/indicators/types.ts +0 -26
- package/src/components/chart/market-session.ts +0 -176
- package/src/components/chart/multi-line/renderer.test.ts +0 -83
- package/src/components/chart/multi-line/renderer.ts +0 -161
- package/src/components/chart/multi-line/scene.ts +0 -188
- package/src/components/chart/native/raster/layout.ts +0 -129
- package/src/components/chart/native/raster/price-chart.ts +0 -244
- package/src/components/chart/rendering/chart-draw.ts +0 -270
- package/src/components/chart/rendering/geometry.ts +0 -95
- package/src/components/chart/rendering/pixel-buffer.ts +0 -267
- package/src/components/chart/scatter-chart-renderer.test.ts +0 -31
- package/src/components/chart/scatter-chart-renderer.ts +0 -223
- package/src/components/chart/static/chart/surface.tsx +0 -358
- package/src/components/command-bar/routes/root/article-results.test.ts +0 -83
- package/src/components/command-bar/routes/root/article-results.ts +0 -55
- package/src/plugins/builtin/news/wire/article-search.test.ts +0 -72
- package/src/plugins/builtin/news/wire/article-search.ts +0 -140
- package/src/plugins/builtin/substack/api/auth.ts +0 -185
- package/src/plugins/builtin/substack/api/cache.ts +0 -82
- package/src/plugins/builtin/substack/api/loaders.ts +0 -170
- package/src/plugins/builtin/substack/api/store.ts +0 -186
- package/src/plugins/builtin/substack/api/types.ts +0 -42
- package/src/plugins/builtin/substack/api.test.ts +0 -298
- package/src/plugins/builtin/substack/article-detail.tsx +0 -397
- package/src/plugins/builtin/substack/article-stack.tsx +0 -133
- package/src/plugins/builtin/substack/content.ts +0 -478
- package/src/plugins/builtin/substack/feed-tabs.tsx +0 -44
- package/src/plugins/builtin/substack/index.tsx +0 -49
- package/src/plugins/builtin/substack/login-view.tsx +0 -126
- package/src/plugins/builtin/substack/model.test.ts +0 -155
- package/src/plugins/builtin/substack/normalize.ts +0 -343
- package/src/plugins/builtin/substack/pane-footer.ts +0 -52
- package/src/plugins/builtin/substack/pane-state.ts +0 -170
- package/src/plugins/builtin/substack/pane.tsx +0 -547
- package/src/plugins/builtin/substack/read-state.ts +0 -30
- package/src/plugins/builtin/substack/table.ts +0 -111
- package/src/plugins/builtin/substack/types.ts +0 -71
- package/src/plugins/builtin/substack/utils.ts +0 -131
- package/src/plugins/builtin/ticker-detail/data-panes/provider-search.tsx +0 -229
- package/src/plugins/ibkr/account-cache.test.ts +0 -102
- package/src/plugins/ibkr/account-cache.ts +0 -24
- package/src/plugins/ibkr/broker-adapter.ts +0 -286
- package/src/plugins/ibkr/config.test.ts +0 -79
- package/src/plugins/ibkr/config.ts +0 -250
- package/src/plugins/ibkr/dialogs.tsx +0 -40
- package/src/plugins/ibkr/flex/index.test.ts +0 -264
- package/src/plugins/ibkr/flex/index.ts +0 -367
- package/src/plugins/ibkr/flex/statement-client.ts +0 -235
- package/src/plugins/ibkr/fundamental-parser.ts +0 -149
- package/src/plugins/ibkr/gateway/account-loaders.ts +0 -266
- package/src/plugins/ibkr/gateway/account-summary.ts +0 -164
- package/src/plugins/ibkr/gateway/client-lock.ts +0 -154
- package/src/plugins/ibkr/gateway/connection-events.ts +0 -114
- package/src/plugins/ibkr/gateway/connection.ts +0 -152
- package/src/plugins/ibkr/gateway/contracts.ts +0 -132
- package/src/plugins/ibkr/gateway/fundamentals.ts +0 -83
- package/src/plugins/ibkr/gateway/helpers.ts +0 -33
- package/src/plugins/ibkr/gateway/history-requests.ts +0 -158
- package/src/plugins/ibkr/gateway/history.ts +0 -120
- package/src/plugins/ibkr/gateway/instrument-lookup.ts +0 -117
- package/src/plugins/ibkr/gateway/market-data.ts +0 -345
- package/src/plugins/ibkr/gateway/order-execution.ts +0 -218
- package/src/plugins/ibkr/gateway/orders.ts +0 -63
- package/src/plugins/ibkr/gateway/price-normalization.test.ts +0 -44
- package/src/plugins/ibkr/gateway/price-normalization.ts +0 -50
- package/src/plugins/ibkr/gateway/quote-stream-controller.ts +0 -203
- package/src/plugins/ibkr/gateway/quote-stream.ts +0 -171
- package/src/plugins/ibkr/gateway/selection.ts +0 -51
- package/src/plugins/ibkr/gateway/service/index.test.ts +0 -675
- package/src/plugins/ibkr/gateway/service/index.ts +0 -429
- package/src/plugins/ibkr/gateway/service/lifecycle.ts +0 -191
- package/src/plugins/ibkr/gateway/service/manager.ts +0 -52
- package/src/plugins/ibkr/gateway/service/market-data.ts +0 -48
- package/src/plugins/ibkr/gateway/service/native-loader.ts +0 -12
- package/src/plugins/ibkr/gateway/service/native.ts +0 -543
- package/src/plugins/ibkr/gateway/timeouts.ts +0 -13
- package/src/plugins/ibkr/gateway/types.ts +0 -27
- package/src/plugins/ibkr/index.test.tsx +0 -162
- package/src/plugins/ibkr/index.tsx +0 -159
- package/src/plugins/ibkr/instance-selection.test.ts +0 -120
- package/src/plugins/ibkr/instance-selection.ts +0 -36
- package/src/plugins/ibkr/portfolio-performance.test.ts +0 -32
- package/src/plugins/ibkr/portfolio-performance.ts +0 -129
- package/src/plugins/ibkr/trade/badge.tsx +0 -28
- package/src/plugins/ibkr/trade/dialogs.tsx +0 -44
- package/src/plugins/ibkr/trade/preview-panel.tsx +0 -130
- package/src/plugins/ibkr/trade/tab/actions.tsx +0 -443
- package/src/plugins/ibkr/trade/tab/field-editors.tsx +0 -79
- package/src/plugins/ibkr/trade/tab/footer.ts +0 -53
- package/src/plugins/ibkr/trade/tab/header.tsx +0 -167
- package/src/plugins/ibkr/trade/tab/index.test.tsx +0 -178
- package/src/plugins/ibkr/trade/tab/index.tsx +0 -298
- package/src/plugins/ibkr/trade/tab/model.ts +0 -159
- package/src/plugins/ibkr/trade/tab/order-request.ts +0 -64
- package/src/plugins/ibkr/trade/tab/shortcuts.ts +0 -89
- package/src/plugins/ibkr/trade/tab/state-sync.ts +0 -86
- package/src/plugins/ibkr/trade/ticket-panel.tsx +0 -301
- package/src/plugins/ibkr/trade/utils.test.ts +0 -175
- package/src/plugins/ibkr/trade/utils.ts +0 -144
- package/src/plugins/ibkr/trading/pane-view.tsx +0 -237
- package/src/plugins/ibkr/trading/pane.tsx +0 -332
- package/src/plugins/ibkr/trading/state.test.ts +0 -109
- package/src/plugins/ibkr/trading/state.ts +0 -335
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import type { GloomPlugin } from "../types/plugin";
|
|
2
|
+
import type { LoadedExternalPlugin } from "./loader";
|
|
2
3
|
import { newsPlugin } from "./builtin/news";
|
|
3
4
|
import { notesPlugin } from "./builtin/notes";
|
|
4
|
-
import { substackPlugin } from "./builtin/substack";
|
|
5
5
|
import { aiPlugin } from "./builtin/ai";
|
|
6
6
|
import { gloomberbCloudPlugin } from "./builtin/cloud";
|
|
7
|
-
import { ibkrPlugin } from "./ibkr";
|
|
8
7
|
import { publicPlugin } from "./broker-sync/public";
|
|
9
8
|
import { robinhoodPlugin } from "./broker-sync/robinhood";
|
|
10
9
|
import { simpleFinPlugin } from "./broker-sync/simplefin";
|
|
11
10
|
import { predictionMarketsPlugin } from "./prediction-markets";
|
|
12
11
|
import { pollsPlugin } from "./builtin/polls";
|
|
13
12
|
import { alertsPlugin } from "./builtin/alerts";
|
|
13
|
+
import { researchSearchPlugin } from "./builtin/research-search";
|
|
14
14
|
import {
|
|
15
15
|
applicationPlugin,
|
|
16
16
|
brokerPlugin,
|
|
@@ -25,13 +25,11 @@ export const uiBuiltinPlugins: GloomPlugin[] = [
|
|
|
25
25
|
portfolioPlugin,
|
|
26
26
|
tickerResearchPlugin,
|
|
27
27
|
brokerPlugin,
|
|
28
|
-
ibkrPlugin,
|
|
29
28
|
publicPlugin,
|
|
30
29
|
robinhoodPlugin,
|
|
31
30
|
simpleFinPlugin,
|
|
32
31
|
applicationPlugin,
|
|
33
32
|
newsPlugin,
|
|
34
|
-
substackPlugin,
|
|
35
33
|
notesPlugin,
|
|
36
34
|
aiPlugin,
|
|
37
35
|
predictionMarketsPlugin,
|
|
@@ -39,8 +37,26 @@ export const uiBuiltinPlugins: GloomPlugin[] = [
|
|
|
39
37
|
marketOverviewPlugin,
|
|
40
38
|
macroPlugin,
|
|
41
39
|
alertsPlugin,
|
|
40
|
+
researchSearchPlugin,
|
|
42
41
|
];
|
|
43
42
|
|
|
44
43
|
export function getRendererBuiltinPlugins(): GloomPlugin[] {
|
|
45
44
|
return uiBuiltinPlugins;
|
|
46
45
|
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The plugin list for a UI renderer: the built-ins it ships with, plus any
|
|
49
|
+
* external plugins that loaded and support this renderer.
|
|
50
|
+
*
|
|
51
|
+
* Deliberately not `getLoadablePlugins`, which is the CLI catalog and also
|
|
52
|
+
* carries the Yahoo fallback provider and the debug plugin. Routing the desktop
|
|
53
|
+
* through it would quietly change which plugins the app runs.
|
|
54
|
+
*/
|
|
55
|
+
export function getRendererPlugins(externalPlugins: readonly LoadedExternalPlugin[] = []): GloomPlugin[] {
|
|
56
|
+
return [
|
|
57
|
+
...uiBuiltinPlugins,
|
|
58
|
+
...externalPlugins
|
|
59
|
+
.filter((entry) => !entry.error && !entry.unsupportedTarget)
|
|
60
|
+
.map((entry) => entry.plugin),
|
|
61
|
+
];
|
|
62
|
+
}
|
package/src/plugins/catalog.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GloomPlugin } from "../types/plugin";
|
|
1
|
+
import type { GloomPlugin, PluginTarget } from "../types/plugin";
|
|
2
2
|
import type { LoadedExternalPlugin } from "./loader";
|
|
3
3
|
import { debugPlugin } from "./builtin/debug";
|
|
4
4
|
import { yahooPlugin } from "./builtin/yahoo";
|
|
@@ -9,6 +9,12 @@ export interface PluginCatalogEntry {
|
|
|
9
9
|
source: "builtin" | "external";
|
|
10
10
|
path?: string;
|
|
11
11
|
error?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Set when the plugin installed cleanly but cannot run here — IBKR Gateway on
|
|
14
|
+
* the web build, for example. The catalog still lists it so the marketplace
|
|
15
|
+
* can explain why it is inert instead of leaving the user wondering.
|
|
16
|
+
*/
|
|
17
|
+
unsupportedTarget?: PluginTarget;
|
|
12
18
|
}
|
|
13
19
|
|
|
14
20
|
const builtinPlugins: GloomPlugin[] = [
|
|
@@ -28,12 +34,13 @@ export function getPluginCatalog(externalPlugins: LoadedExternalPlugin[] = []):
|
|
|
28
34
|
source: "external" as const,
|
|
29
35
|
path: entry.path,
|
|
30
36
|
error: entry.error,
|
|
37
|
+
unsupportedTarget: entry.unsupportedTarget,
|
|
31
38
|
})),
|
|
32
39
|
];
|
|
33
40
|
}
|
|
34
41
|
|
|
35
42
|
export function getLoadablePlugins(externalPlugins: LoadedExternalPlugin[] = []): GloomPlugin[] {
|
|
36
43
|
return getPluginCatalog(externalPlugins)
|
|
37
|
-
.filter((entry) => !entry.error)
|
|
44
|
+
.filter((entry) => !entry.error && !entry.unsupportedTarget)
|
|
38
45
|
.map((entry) => entry.plugin);
|
|
39
46
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { PluginTarget } from "../types/plugin";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Which renderer is running.
|
|
5
|
+
*
|
|
6
|
+
* Renderers declare this at startup rather than having it sniffed from globals:
|
|
7
|
+
* the Electrobun view and the hosted browser app are both browser contexts and
|
|
8
|
+
* are otherwise hard to tell apart, yet they differ in what a plugin can do
|
|
9
|
+
* (the desktop app can shell out to git; term.gloom.sh cannot).
|
|
10
|
+
*/
|
|
11
|
+
let currentTarget: PluginTarget = "cli";
|
|
12
|
+
|
|
13
|
+
export function setCurrentPluginTarget(target: PluginTarget): void {
|
|
14
|
+
currentTarget = target;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function getCurrentPluginTarget(): PluginTarget {
|
|
18
|
+
return currentTarget;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Whether this renderer can install plugins itself. Installing means cloning a
|
|
23
|
+
* repository and running `bun install`, so only the Bun-hosted renderers can;
|
|
24
|
+
* elsewhere the marketplace shows the command to run instead.
|
|
25
|
+
*/
|
|
26
|
+
export function canInstallPlugins(): boolean {
|
|
27
|
+
return currentTarget === "cli" || currentTarget === "tui";
|
|
28
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The contract shared between the plugin bundler and the renderers that load
|
|
3
|
+
* its output.
|
|
4
|
+
*
|
|
5
|
+
* Kept in its own module with no imports on purpose. The bundler runs in Bun
|
|
6
|
+
* and reaches the filesystem; the renderers that consume it are browser
|
|
7
|
+
* contexts. Pulling these two constants from `bundle.ts` dragged the whole
|
|
8
|
+
* bundler — and through it `plugins/loader.ts`, which reads `process.env.HOME`
|
|
9
|
+
* at module scope — into the desktop view, where it threw on load.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export const PLUGIN_HOST_GLOBAL = "__GLOOM_PLUGIN_HOST__";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Specifiers a plugin may import that must resolve to the host's copy. Anything
|
|
16
|
+
* else is a plugin's own dependency and gets bundled normally.
|
|
17
|
+
*
|
|
18
|
+
* Deliberately no `react-dom`: it is a renderer package, and plugins are
|
|
19
|
+
* required to be renderer-neutral so the same code runs in the terminal. A
|
|
20
|
+
* plugin reaching for it should fail to bundle rather than quietly work on the
|
|
21
|
+
* desktop and break in the TUI.
|
|
22
|
+
*/
|
|
23
|
+
export const SHARED_SPECIFIERS = [
|
|
24
|
+
"react",
|
|
25
|
+
"react/jsx-runtime",
|
|
26
|
+
"react/jsx-dev-runtime",
|
|
27
|
+
"gloomberb/types/plugin",
|
|
28
|
+
"gloomberb/types/persistence",
|
|
29
|
+
"gloomberb/ui",
|
|
30
|
+
"gloomberb/components",
|
|
31
|
+
"gloomberb/theme",
|
|
32
|
+
"gloomberb/capabilities",
|
|
33
|
+
"gloomberb/utils",
|
|
34
|
+
"gloomberb/react",
|
|
35
|
+
] as const;
|
|
36
|
+
|
|
37
|
+
export type SharedSpecifier = (typeof SHARED_SPECIFIERS)[number];
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { existsSync, lstatSync, mkdirSync, readlinkSync, rmSync, symlinkSync } from "fs";
|
|
2
|
+
import { dirname, join, resolve } from "path";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* External plugins live in `~/.gloomberb/plugins/<name>/`, outside any
|
|
6
|
+
* `node_modules` chain that could reach the running Gloomberb install. Left
|
|
7
|
+
* alone, `import { Box } from "gloomberb/ui"` does not resolve, and a plugin
|
|
8
|
+
* that lists `react` as a real dependency gets its *own* copy — two React
|
|
9
|
+
* instances in one process, which throws on the first hook.
|
|
10
|
+
*
|
|
11
|
+
* So the host links itself and its React into each plugin's `node_modules`.
|
|
12
|
+
* Plugins declare both as peer dependencies and never install them. This keeps
|
|
13
|
+
* one module instance per process and makes plugin imports resolve exactly the
|
|
14
|
+
* way they do for first-party code.
|
|
15
|
+
*
|
|
16
|
+
* Links are rebuilt after every install and update, because `bun install`
|
|
17
|
+
* prunes entries it does not know about, and repaired at load time so a plugin
|
|
18
|
+
* copied in by hand still works.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const LINKED_PACKAGES = ["gloomberb", "react", "react-dom"] as const;
|
|
22
|
+
|
|
23
|
+
let cachedHostRoot: string | null | undefined;
|
|
24
|
+
|
|
25
|
+
/** Walks up from this module to the directory holding the `gloomberb` package.json. */
|
|
26
|
+
export function findHostPackageRoot(startDir: string = import.meta.dir): string | null {
|
|
27
|
+
if (cachedHostRoot !== undefined && startDir === import.meta.dir) return cachedHostRoot;
|
|
28
|
+
let dir = resolve(startDir);
|
|
29
|
+
for (let depth = 0; depth < 12; depth += 1) {
|
|
30
|
+
const pkgPath = join(dir, "package.json");
|
|
31
|
+
if (existsSync(pkgPath)) {
|
|
32
|
+
try {
|
|
33
|
+
const pkg = JSON.parse(require("fs").readFileSync(pkgPath, "utf-8")) as { name?: string };
|
|
34
|
+
if (pkg.name === "gloomberb") {
|
|
35
|
+
if (startDir === import.meta.dir) cachedHostRoot = dir;
|
|
36
|
+
return dir;
|
|
37
|
+
}
|
|
38
|
+
} catch {
|
|
39
|
+
// Unreadable package.json — keep walking rather than giving up.
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const parent = dirname(dir);
|
|
43
|
+
if (parent === dir) break;
|
|
44
|
+
dir = parent;
|
|
45
|
+
}
|
|
46
|
+
if (startDir === import.meta.dir) cachedHostRoot = null;
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function linkTarget(hostRoot: string, pkg: string): string | null {
|
|
51
|
+
if (pkg === "gloomberb") return hostRoot;
|
|
52
|
+
const candidate = join(hostRoot, "node_modules", pkg);
|
|
53
|
+
return existsSync(candidate) ? candidate : null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** True when `path` is already a symlink pointing at `target`. */
|
|
57
|
+
function alreadyLinked(path: string, target: string): boolean {
|
|
58
|
+
try {
|
|
59
|
+
return lstatSync(path).isSymbolicLink() && resolve(dirname(path), readlinkSync(path)) === resolve(target);
|
|
60
|
+
} catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Links sibling plugins a plugin declares as peer dependencies.
|
|
67
|
+
*
|
|
68
|
+
* A plugin can legitimately extend another — IBKR Gateway builds on the Flex
|
|
69
|
+
* plugin, which owns the broker id and the shared bridge. Those live in separate
|
|
70
|
+
* install directories with no path between them, so the peer is linked the same
|
|
71
|
+
* way the host is. A missing sibling is not an error here: the plugin reports it
|
|
72
|
+
* at load, which is more useful than failing the install.
|
|
73
|
+
*/
|
|
74
|
+
function linkPeerPlugins(pluginDir: string, pluginsDir: string): string[] {
|
|
75
|
+
const linked: string[] = [];
|
|
76
|
+
let peers: string[] = [];
|
|
77
|
+
try {
|
|
78
|
+
const pkg = JSON.parse(require("fs").readFileSync(join(pluginDir, "package.json"), "utf-8"));
|
|
79
|
+
peers = Object.keys(pkg.peerDependencies ?? {}).filter((name) => name.startsWith("gloomberb-"));
|
|
80
|
+
} catch {
|
|
81
|
+
return linked;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
for (const peer of peers) {
|
|
85
|
+
// Installed directories are named after the repository, which is the package
|
|
86
|
+
// name for every plugin in the registry.
|
|
87
|
+
const target = join(pluginsDir, peer);
|
|
88
|
+
if (!existsSync(target)) continue;
|
|
89
|
+
const linkPath = join(pluginDir, "node_modules", peer);
|
|
90
|
+
if (alreadyLinked(linkPath, target)) {
|
|
91
|
+
linked.push(peer);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
mkdirSync(join(pluginDir, "node_modules"), { recursive: true });
|
|
96
|
+
if (existsSync(linkPath) || lstatSync(linkPath, { throwIfNoEntry: false })) {
|
|
97
|
+
rmSync(linkPath, { recursive: true, force: true });
|
|
98
|
+
}
|
|
99
|
+
symlinkSync(target, linkPath, "dir");
|
|
100
|
+
linked.push(peer);
|
|
101
|
+
} catch {
|
|
102
|
+
// Reported by the plugin's own load failure if it actually needed it.
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return linked;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface HostLinkResult {
|
|
109
|
+
linked: string[];
|
|
110
|
+
skipped: string[];
|
|
111
|
+
error?: string;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Points `<pluginDir>/node_modules/{gloomberb,react,react-dom}` at the running
|
|
116
|
+
* install. Safe to call repeatedly.
|
|
117
|
+
*/
|
|
118
|
+
export function linkHostPackages(
|
|
119
|
+
pluginDir: string,
|
|
120
|
+
hostRoot = findHostPackageRoot(),
|
|
121
|
+
pluginsDir = dirname(pluginDir),
|
|
122
|
+
): HostLinkResult {
|
|
123
|
+
if (!hostRoot) return { linked: [], skipped: [...LINKED_PACKAGES], error: "Could not locate the Gloomberb install." };
|
|
124
|
+
|
|
125
|
+
const modulesDir = join(pluginDir, "node_modules");
|
|
126
|
+
const linked: string[] = [];
|
|
127
|
+
const skipped: string[] = [];
|
|
128
|
+
|
|
129
|
+
for (const pkg of LINKED_PACKAGES) {
|
|
130
|
+
const target = linkTarget(hostRoot, pkg);
|
|
131
|
+
if (!target) {
|
|
132
|
+
skipped.push(pkg);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const linkPath = join(modulesDir, pkg);
|
|
136
|
+
if (alreadyLinked(linkPath, target)) {
|
|
137
|
+
linked.push(pkg);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
mkdirSync(modulesDir, { recursive: true });
|
|
142
|
+
// A real directory here means `bun install` fetched a second copy; replacing
|
|
143
|
+
// it is the whole point, otherwise the plugin runs against a duplicate React.
|
|
144
|
+
if (existsSync(linkPath) || lstatSync(linkPath, { throwIfNoEntry: false })) {
|
|
145
|
+
rmSync(linkPath, { recursive: true, force: true });
|
|
146
|
+
}
|
|
147
|
+
symlinkSync(target, linkPath, "dir");
|
|
148
|
+
linked.push(pkg);
|
|
149
|
+
} catch (err) {
|
|
150
|
+
skipped.push(pkg);
|
|
151
|
+
if (pkg === "gloomberb") return { linked, skipped, error: String(err) };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
linked.push(...linkPeerPlugins(pluginDir, pluginsDir));
|
|
156
|
+
|
|
157
|
+
return { linked, skipped };
|
|
158
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { PLUGIN_HOST_GLOBAL, SHARED_SPECIFIERS } from "./host-contract";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Publishes the host's shared modules for compiled plugin bundles to read.
|
|
5
|
+
*
|
|
6
|
+
* Browser-context renderers load plugins as separate ES modules, so the bundler
|
|
7
|
+
* rewrites their `react` and `gloomberb/*` imports to read from this registry
|
|
8
|
+
* (see `bundle.ts`). This must run before any plugin bundle is imported, and
|
|
9
|
+
* the modules here must be the same instances the app itself uses — importing
|
|
10
|
+
* them normally is what guarantees that.
|
|
11
|
+
*/
|
|
12
|
+
export async function installPluginHostModules(): Promise<void> {
|
|
13
|
+
const globals = globalThis as Record<string, unknown>;
|
|
14
|
+
if (globals[PLUGIN_HOST_GLOBAL]) return;
|
|
15
|
+
|
|
16
|
+
const [
|
|
17
|
+
react,
|
|
18
|
+
jsxRuntime,
|
|
19
|
+
typesPlugin,
|
|
20
|
+
typesPersistence,
|
|
21
|
+
ui,
|
|
22
|
+
components,
|
|
23
|
+
theme,
|
|
24
|
+
capabilities,
|
|
25
|
+
utils,
|
|
26
|
+
pluginReact,
|
|
27
|
+
] = await Promise.all([
|
|
28
|
+
import("react"),
|
|
29
|
+
import("react/jsx-runtime"),
|
|
30
|
+
// Type-only modules still need an entry: a plugin may import a runtime
|
|
31
|
+
// value from them, and a missing key throws a clearer error than undefined.
|
|
32
|
+
import("../types/plugin"),
|
|
33
|
+
import("../types/persistence"),
|
|
34
|
+
import("../ui"),
|
|
35
|
+
import("../components"),
|
|
36
|
+
import("../theme/colors"),
|
|
37
|
+
import("../capabilities"),
|
|
38
|
+
import("../public/utils"),
|
|
39
|
+
import("../public/react"),
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
const registry: Record<string, unknown> = {
|
|
43
|
+
"react": react,
|
|
44
|
+
"react/jsx-runtime": jsxRuntime,
|
|
45
|
+
"react/jsx-dev-runtime": jsxRuntime,
|
|
46
|
+
"gloomberb/types/plugin": typesPlugin,
|
|
47
|
+
"gloomberb/types/persistence": typesPersistence,
|
|
48
|
+
"gloomberb/ui": ui,
|
|
49
|
+
"gloomberb/components": components,
|
|
50
|
+
"gloomberb/theme": theme,
|
|
51
|
+
"gloomberb/capabilities": capabilities,
|
|
52
|
+
"gloomberb/utils": utils,
|
|
53
|
+
"gloomberb/react": pluginReact,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
for (const specifier of SHARED_SPECIFIERS) {
|
|
57
|
+
if (!registry[specifier]) throw new Error(`Plugin host registry is missing "${specifier}"`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
globals[PLUGIN_HOST_GLOBAL] = registry;
|
|
61
|
+
}
|
package/src/plugins/loader.ts
CHANGED
|
@@ -2,8 +2,9 @@ import { readdir } from "fs/promises";
|
|
|
2
2
|
import { join } from "path";
|
|
3
3
|
import { existsSync } from "fs";
|
|
4
4
|
import { homedir } from "os";
|
|
5
|
-
import type { GloomPlugin } from "../types/plugin";
|
|
5
|
+
import type { GloomPlugin, PluginTarget } from "../types/plugin";
|
|
6
6
|
import { debugLog } from "../utils/debug-log";
|
|
7
|
+
import { linkHostPackages } from "./host-link";
|
|
7
8
|
|
|
8
9
|
const loaderLog = debugLog.createLogger("plugin-loader");
|
|
9
10
|
|
|
@@ -13,13 +14,41 @@ export interface LoadedExternalPlugin {
|
|
|
13
14
|
plugin: GloomPlugin;
|
|
14
15
|
path: string;
|
|
15
16
|
error?: string;
|
|
17
|
+
/** Set when the plugin loaded but does not support the running renderer. */
|
|
18
|
+
unsupportedTarget?: PluginTarget;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
export function getPluginsDir(): string {
|
|
19
22
|
return PLUGINS_DIR;
|
|
20
23
|
}
|
|
21
24
|
|
|
22
|
-
|
|
25
|
+
/** Resolves a plugin directory's entry file the way `bun install` would. */
|
|
26
|
+
export async function resolvePluginEntry(pluginDir: string): Promise<string | null> {
|
|
27
|
+
const pkgPath = join(pluginDir, "package.json");
|
|
28
|
+
if (existsSync(pkgPath)) {
|
|
29
|
+
try {
|
|
30
|
+
const pkg = JSON.parse(await Bun.file(pkgPath).text());
|
|
31
|
+
if (pkg.main) {
|
|
32
|
+
const main = join(pluginDir, pkg.main);
|
|
33
|
+
if (existsSync(main)) return main;
|
|
34
|
+
}
|
|
35
|
+
} catch {
|
|
36
|
+
// Malformed package.json falls through to the index candidates.
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
for (const candidate of ["index.ts", "index.tsx", "index.js"]) {
|
|
40
|
+
const path = join(pluginDir, candidate);
|
|
41
|
+
if (existsSync(path)) return path;
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function pluginSupportsTarget(plugin: GloomPlugin, target: PluginTarget): boolean {
|
|
47
|
+
// No declaration means "everywhere"; the registry fills this in for listed plugins.
|
|
48
|
+
return !plugin.targets || plugin.targets.length === 0 || plugin.targets.includes(target);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function loadExternalPlugins(target: PluginTarget = "cli"): Promise<LoadedExternalPlugin[]> {
|
|
23
52
|
if (!existsSync(PLUGINS_DIR)) return [];
|
|
24
53
|
|
|
25
54
|
const results: LoadedExternalPlugin[] = [];
|
|
@@ -29,32 +58,22 @@ export async function loadExternalPlugins(): Promise<LoadedExternalPlugin[]> {
|
|
|
29
58
|
if (!entry.isDirectory()) continue;
|
|
30
59
|
const pluginDir = join(PLUGINS_DIR, entry.name);
|
|
31
60
|
|
|
32
|
-
|
|
33
|
-
let entryFile: string | null = null;
|
|
34
|
-
|
|
35
|
-
// Check package.json first
|
|
36
|
-
const pkgPath = join(pluginDir, "package.json");
|
|
37
|
-
if (existsSync(pkgPath)) {
|
|
38
|
-
try {
|
|
39
|
-
const pkg = JSON.parse(await Bun.file(pkgPath).text());
|
|
40
|
-
if (pkg.main) entryFile = join(pluginDir, pkg.main);
|
|
41
|
-
} catch { /* ignore malformed package.json */ }
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Fall back to index files
|
|
45
|
-
if (!entryFile) {
|
|
46
|
-
for (const candidate of ["index.ts", "index.tsx", "index.js"]) {
|
|
47
|
-
const p = join(pluginDir, candidate);
|
|
48
|
-
if (existsSync(p)) { entryFile = p; break; }
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
61
|
+
const entryFile = await resolvePluginEntry(pluginDir);
|
|
52
62
|
if (!entryFile) continue;
|
|
53
63
|
|
|
64
|
+
// Repairs `gloomberb`/`react` links for plugins copied in by hand or left
|
|
65
|
+
// behind by a `bun install` that pruned them.
|
|
66
|
+
linkHostPackages(pluginDir);
|
|
67
|
+
|
|
54
68
|
try {
|
|
55
69
|
const mod = await import(entryFile);
|
|
56
70
|
const plugin: GloomPlugin = mod.default ?? mod.plugin;
|
|
57
71
|
if (plugin && plugin.id && plugin.name) {
|
|
72
|
+
if (!pluginSupportsTarget(plugin, target)) {
|
|
73
|
+
loaderLog.info(`Skipped ${plugin.id}: does not support "${target}"`);
|
|
74
|
+
results.push({ plugin, path: pluginDir, unsupportedTarget: target });
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
58
77
|
loaderLog.info(`Loaded external plugin: ${plugin.id} v${plugin.version ?? "0.0.0"}`);
|
|
59
78
|
results.push({ plugin, path: pluginDir });
|
|
60
79
|
}
|
package/src/plugins/ownership.ts
CHANGED
|
@@ -7,6 +7,7 @@ const BUILTIN_PLUGIN_OWNER_ALIASES: Record<string, string> = {
|
|
|
7
7
|
"comparison-chart": "ticker-research",
|
|
8
8
|
correlation: "market-overview",
|
|
9
9
|
"earnings-calendar": "macro",
|
|
10
|
+
"earnings-calls": "macro",
|
|
10
11
|
"ipo-calendar": "macro",
|
|
11
12
|
"fear-greed": "market-overview",
|
|
12
13
|
"fx-matrix": "market-overview",
|
|
@@ -43,6 +43,7 @@ export const predictionMarketsPlugin: GloomPlugin = {
|
|
|
43
43
|
defaultPosition: "left",
|
|
44
44
|
defaultMode: "floating",
|
|
45
45
|
defaultFloatingSize: { width: 132, height: 36 },
|
|
46
|
+
tableExport: true,
|
|
46
47
|
settings: (context) =>
|
|
47
48
|
buildPredictionMarketsPaneSettingsDef(
|
|
48
49
|
context.config,
|
|
@@ -142,6 +142,9 @@ export function createRegistryPluginContext({
|
|
|
142
142
|
registerPane: (pane) => contributions.registerPane(pluginId, pane, items),
|
|
143
143
|
registerPaneTemplate: (template) => contributions.registerPaneTemplate(pluginId, template, items),
|
|
144
144
|
registerCommand: (command) => contributions.registerCommand(pluginId, command, items),
|
|
145
|
+
registerCommandBarSearchProvider: (provider) => (
|
|
146
|
+
contributions.registerCommandBarSearchProvider(pluginId, provider, items)
|
|
147
|
+
),
|
|
145
148
|
registerColumn: (column) => contributions.registerColumn(pluginId, column, items),
|
|
146
149
|
registerBroker: (broker) => contributions.registerBroker(pluginId, broker, items),
|
|
147
150
|
registerCapability: (capability) => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { BrokerAdapter } from "../../types/broker";
|
|
2
2
|
import type {
|
|
3
|
+
CommandBarSearchProvider,
|
|
3
4
|
CommandDef,
|
|
4
5
|
ContextMenuProviderDef,
|
|
5
6
|
CustomColumnDef,
|
|
@@ -19,6 +20,7 @@ export interface PluginItems {
|
|
|
19
20
|
panes: string[];
|
|
20
21
|
paneTemplates: string[];
|
|
21
22
|
commands: string[];
|
|
23
|
+
commandBarSearchProviders: string[];
|
|
22
24
|
columns: string[];
|
|
23
25
|
brokers: string[];
|
|
24
26
|
capabilities: string[];
|
|
@@ -45,6 +47,7 @@ function setUnique<T>(map: Map<string, T>, id: string, value: T): void {
|
|
|
45
47
|
export class RegistryContributions {
|
|
46
48
|
readonly pluginItems = new Map<string, PluginItems>();
|
|
47
49
|
readonly commandOwners = new Map<string, string>();
|
|
50
|
+
readonly commandBarSearchProviderOwners = new Map<string, string>();
|
|
48
51
|
readonly paneOwners = new Map<string, string>();
|
|
49
52
|
readonly paneTemplateOwners = new Map<string, string>();
|
|
50
53
|
readonly shortcutOwners = new Map<string, string>();
|
|
@@ -54,6 +57,7 @@ export class RegistryContributions {
|
|
|
54
57
|
readonly panesMap = new Map<string, PaneDef>();
|
|
55
58
|
readonly paneTemplatesMap = new Map<string, PaneTemplateDef>();
|
|
56
59
|
readonly commandsMap = new Map<string, CommandDef>();
|
|
60
|
+
readonly commandBarSearchProvidersMap = new Map<string, CommandBarSearchProvider>();
|
|
57
61
|
readonly columnsMap = new Map<string, CustomColumnDef>();
|
|
58
62
|
readonly brokersMap = new Map<string, BrokerAdapter>();
|
|
59
63
|
readonly tickerResearchTabsMap = new Map<string, TickerResearchTabDef>();
|
|
@@ -71,6 +75,7 @@ export class RegistryContributions {
|
|
|
71
75
|
panes: [],
|
|
72
76
|
paneTemplates: [],
|
|
73
77
|
commands: [],
|
|
78
|
+
commandBarSearchProviders: [],
|
|
74
79
|
columns: [],
|
|
75
80
|
brokers: [],
|
|
76
81
|
capabilities: [],
|
|
@@ -104,6 +109,24 @@ export class RegistryContributions {
|
|
|
104
109
|
items.commands.push(command.id);
|
|
105
110
|
}
|
|
106
111
|
|
|
112
|
+
registerCommandBarSearchProvider(
|
|
113
|
+
pluginId: string,
|
|
114
|
+
provider: CommandBarSearchProvider,
|
|
115
|
+
items = this.getOrCreatePluginItems(pluginId),
|
|
116
|
+
): () => void {
|
|
117
|
+
setUnique(this.commandBarSearchProvidersMap, provider.id, provider);
|
|
118
|
+
this.commandBarSearchProviderOwners.set(provider.id, pluginId);
|
|
119
|
+
items.commandBarSearchProviders.push(provider.id);
|
|
120
|
+
return () => {
|
|
121
|
+
// Only the registration still in place may be withdrawn: a re-registered
|
|
122
|
+
// provider under the same id belongs to whoever registered it last.
|
|
123
|
+
if (this.commandBarSearchProvidersMap.get(provider.id) !== provider) return;
|
|
124
|
+
this.commandBarSearchProvidersMap.delete(provider.id);
|
|
125
|
+
this.commandBarSearchProviderOwners.delete(provider.id);
|
|
126
|
+
items.commandBarSearchProviders = items.commandBarSearchProviders.filter((id) => id !== provider.id);
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
107
130
|
registerColumn(_pluginId: string, column: CustomColumnDef, items: PluginItems): void {
|
|
108
131
|
setUnique(this.columnsMap, column.id, column);
|
|
109
132
|
items.columns.push(column.id);
|
|
@@ -158,6 +181,10 @@ export class RegistryContributions {
|
|
|
158
181
|
this.commandsMap.delete(commandId);
|
|
159
182
|
this.commandOwners.delete(commandId);
|
|
160
183
|
}
|
|
184
|
+
for (const providerId of items.commandBarSearchProviders) {
|
|
185
|
+
this.commandBarSearchProvidersMap.delete(providerId);
|
|
186
|
+
this.commandBarSearchProviderOwners.delete(providerId);
|
|
187
|
+
}
|
|
161
188
|
for (const columnId of items.columns) this.columnsMap.delete(columnId);
|
|
162
189
|
for (const brokerId of items.brokers) this.brokersMap.delete(brokerId);
|
|
163
190
|
for (const capabilityId of items.capabilities) this.capabilityOwners.delete(capabilityId);
|
|
@@ -317,6 +317,31 @@ describe("PluginRegistry ticker research tabs", () => {
|
|
|
317
317
|
});
|
|
318
318
|
});
|
|
319
319
|
|
|
320
|
+
describe("PluginRegistry command bar search providers", () => {
|
|
321
|
+
test("withdraws providers on dispose and on plugin unregister", async () => {
|
|
322
|
+
const registry = createRegistry();
|
|
323
|
+
const provider = (id: string) => ({
|
|
324
|
+
id,
|
|
325
|
+
category: "Documents",
|
|
326
|
+
provide: async () => [],
|
|
327
|
+
});
|
|
328
|
+
let disposeSelfRegistered: (() => void) | null = null;
|
|
329
|
+
|
|
330
|
+
await registry.register(plugin("research-search", (ctx) => {
|
|
331
|
+
ctx.registerCommandBarSearchProvider(provider("documents"));
|
|
332
|
+
disposeSelfRegistered = ctx.registerCommandBarSearchProvider(provider("self-withdrawn"));
|
|
333
|
+
}));
|
|
334
|
+
|
|
335
|
+
expect(registry.getCommandBarSearchProviderPluginId("documents")).toBe("research-search");
|
|
336
|
+
disposeSelfRegistered!();
|
|
337
|
+
expect(registry.commandBarSearchProviders.has("self-withdrawn")).toBe(false);
|
|
338
|
+
|
|
339
|
+
registry.unregister("research-search");
|
|
340
|
+
expect(registry.commandBarSearchProviders.size).toBe(0);
|
|
341
|
+
expect(registry.getCommandBarSearchProviderPluginId("documents")).toBeUndefined();
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
|
|
320
345
|
describe("PluginRegistry pane settings", () => {
|
|
321
346
|
test("resolves effective pane setting values from settings definitions", async () => {
|
|
322
347
|
const registry = createRegistry();
|
|
@@ -19,6 +19,7 @@ import type {
|
|
|
19
19
|
AppNotificationDelivery,
|
|
20
20
|
AppNotificationRequest,
|
|
21
21
|
BrokerInstanceUpdateOptions,
|
|
22
|
+
CommandBarSearchProvider,
|
|
22
23
|
CommandDef,
|
|
23
24
|
CustomColumnDef,
|
|
24
25
|
GloomPlugin,
|
|
@@ -258,6 +259,9 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
258
259
|
get panes(): ReadonlyMap<string, PaneDef> { return this.contributions.panesMap; }
|
|
259
260
|
get paneTemplates(): ReadonlyMap<string, PaneTemplateDef> { return this.contributions.paneTemplatesMap; }
|
|
260
261
|
get commands(): ReadonlyMap<string, CommandDef> { return this.contributions.commandsMap; }
|
|
262
|
+
get commandBarSearchProviders(): ReadonlyMap<string, CommandBarSearchProvider> {
|
|
263
|
+
return this.contributions.commandBarSearchProvidersMap;
|
|
264
|
+
}
|
|
261
265
|
get columns(): ReadonlyMap<string, CustomColumnDef> { return this.contributions.columnsMap; }
|
|
262
266
|
get brokers(): ReadonlyMap<string, BrokerAdapter> { return this.contributions.brokersMap; }
|
|
263
267
|
get tickerResearchTabs(): ReadonlyMap<string, TickerResearchTabDef> { return this.contributions.tickerResearchTabsMap; }
|
|
@@ -430,6 +434,10 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
430
434
|
return this.contributions.commandOwners.get(commandId);
|
|
431
435
|
}
|
|
432
436
|
|
|
437
|
+
getCommandBarSearchProviderPluginId(providerId: string): string | undefined {
|
|
438
|
+
return this.contributions.commandBarSearchProviderOwners.get(providerId);
|
|
439
|
+
}
|
|
440
|
+
|
|
433
441
|
getPanePluginId(paneId: string): string | undefined {
|
|
434
442
|
return this.contributions.paneOwners.get(paneId);
|
|
435
443
|
}
|