gloomberb 0.11.3 → 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 +6 -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 +103 -1
- package/src/api-client/index.test.ts +127 -0
- package/src/api-client/index.ts +129 -1
- package/src/api-client/normalizers.ts +39 -0
- package/src/api-client/paths.ts +85 -1
- package/src/api-client/types.ts +196 -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/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 +58 -28
- 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/restore-plugins.ts +34 -0
- 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/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 +3 -2
- 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/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/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/pane.tsx +22 -8
- 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 +14 -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-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 +2 -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/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/kelly-sizer/pane.tsx +1 -1
- package/src/plugins/builtin/kelly-sizer/sections.tsx +2 -3
- 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/index.tsx +1 -0
- package/src/plugins/builtin/options/view.test.tsx +29 -1
- package/src/plugins/builtin/options/view.tsx +1 -22
- 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.ts +9 -1
- 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/sec/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/index.tsx +0 -14
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +1 -1
- package/src/plugins/builtin/volatility/index.tsx +1 -1
- package/src/plugins/builtin/world-venue-map/map.desktop.test.tsx +106 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +213 -69
- package/src/plugins/builtin/world-venue-map/model.test.ts +32 -0
- package/src/plugins/builtin/world-venue-map/model.ts +134 -13
- 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-browser.test.ts +1 -0
- package/src/plugins/catalog-browser.ts +10 -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.ts +6 -13
- 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/cloudflare/worker.test.ts +19 -0
- package/src/renderers/cloudflare/worker.ts +1 -1
- package/src/renderers/electrobun/bun/external-plugins.ts +140 -0
- package/src/renderers/electrobun/bun/index.ts +5 -2
- package/src/renderers/electrobun/shared/protocol.ts +21 -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/opentui/chart-surface.tsx +5 -1
- package/src/renderers/opentui/host.tsx +16 -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 +19 -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/resolution.test.ts +25 -26
- package/src/time-series/resolution.ts +41 -10
- package/src/time-series/resolve.ts +7 -0
- 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 +102 -0
- package/src/ui/host.tsx +12 -1
- package/src/ui/index.tsx +1 -0
- package/src/ui/toast.tsx +8 -4
- 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/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,7 +1,6 @@
|
|
|
1
1
|
import { mkdir, mkdtemp, rm, writeFile } from "fs/promises";
|
|
2
2
|
import { tmpdir } from "os";
|
|
3
|
-
import { join } from "path";
|
|
4
|
-
import { pathToFileURL } from "url";
|
|
3
|
+
import { join, resolve, sep } from "path";
|
|
5
4
|
import type { AppConfig } from "../types/config";
|
|
6
5
|
import type { ResolvedSeries } from "../time-series/types";
|
|
7
6
|
import type { OptionsChain, TickerFinancials } from "../types/financials";
|
|
@@ -9,6 +8,7 @@ import type { TickerRecord } from "../types/ticker";
|
|
|
9
8
|
import type { PaneRuntimeState } from "../core/state/app/state";
|
|
10
9
|
import type { RemoteUiNodeSnapshot } from "../remote/types";
|
|
11
10
|
import type { FredSeriesCacheEntry } from "../data/fred-series";
|
|
11
|
+
import type { DatedObservation } from "../plugins/builtin/market-valuation/series";
|
|
12
12
|
import {
|
|
13
13
|
electrobunViewPath,
|
|
14
14
|
writeElectrobunViewPage,
|
|
@@ -21,16 +21,46 @@ export interface DesktopPaneShotPayload {
|
|
|
21
21
|
heightCells: number;
|
|
22
22
|
widthPx: number;
|
|
23
23
|
heightPx: number;
|
|
24
|
+
/** Chrome device scale factor; 2 keeps text crisp, higher values zoom the layout. */
|
|
25
|
+
deviceScaleFactor?: number;
|
|
26
|
+
/** Label drawn at the right edge of the pane title bar; null draws nothing. */
|
|
27
|
+
watermark?: string | null;
|
|
24
28
|
tickers: TickerRecord[];
|
|
25
29
|
financials: Array<[string, TickerFinancials]>;
|
|
26
30
|
optionsChains: Array<[string, OptionsChain]>;
|
|
27
31
|
fredSeries: Array<[string, FredSeriesCacheEntry]>;
|
|
32
|
+
valuationSeries: Array<[string, DatedObservation[]]>;
|
|
33
|
+
statSeries: Array<[string, DatedObservation[]]>;
|
|
28
34
|
capabilitySeries: Array<[string, ResolvedSeries]>;
|
|
29
35
|
paneState: Record<string, PaneRuntimeState>;
|
|
30
36
|
}
|
|
31
37
|
|
|
38
|
+
/** Kept in Bun memory and never serialized into the browser page or CLI result. */
|
|
39
|
+
export interface DesktopPaneShotApiProxy {
|
|
40
|
+
baseUrl: string;
|
|
41
|
+
sessionToken: string | null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface DesktopPaneShotRenderedCell {
|
|
45
|
+
columnId?: string;
|
|
46
|
+
columnLabel: string;
|
|
47
|
+
text: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface DesktopPaneShotRenderedRow {
|
|
51
|
+
tableIndex: number;
|
|
52
|
+
rowIndex: number;
|
|
53
|
+
key?: string;
|
|
54
|
+
selected: boolean;
|
|
55
|
+
cells: DesktopPaneShotRenderedCell[];
|
|
56
|
+
}
|
|
57
|
+
|
|
32
58
|
export interface DesktopPaneShotRenderResult {
|
|
33
59
|
visibleText: string;
|
|
60
|
+
rows: DesktopPaneShotRenderedRow[];
|
|
61
|
+
loadingStateDetected: boolean;
|
|
62
|
+
errorStateDetected: boolean;
|
|
63
|
+
errorStateMarkers: string[];
|
|
34
64
|
emptyStateDetected: boolean;
|
|
35
65
|
emptyStateMarkers: string[];
|
|
36
66
|
semanticUi: RemoteUiNodeSnapshot[];
|
|
@@ -47,30 +77,47 @@ type PendingCdpCall = {
|
|
|
47
77
|
reject: (error: Error) => void;
|
|
48
78
|
};
|
|
49
79
|
|
|
80
|
+
const SHOT_MODE_CSS = [
|
|
81
|
+
"[data-gloom-role='composite-chart-toolbar']",
|
|
82
|
+
"[data-gloom-role='chart-series-quick-add']",
|
|
83
|
+
"[data-gloom-role='pane-close']",
|
|
84
|
+
].join(", ") + " { display: none !important; }\n"
|
|
85
|
+
// Sits where the hidden close button was: one cell high, right-aligned in the title bar.
|
|
86
|
+
+ "[data-gloom-role='shot-watermark'] { position: fixed; top: 1px; right: 10px; height: var(--cell-h);"
|
|
87
|
+
+ " line-height: var(--cell-h); font-size: 12px; letter-spacing: 0.02em; color: var(--gloom-text-dim, #888);"
|
|
88
|
+
+ " pointer-events: none; z-index: 1000; }";
|
|
89
|
+
|
|
50
90
|
const CHROME_POLL_ATTEMPTS = 80;
|
|
51
|
-
const SHOT_READY_TIMEOUT_MS =
|
|
91
|
+
const SHOT_READY_TIMEOUT_MS = 45_000;
|
|
52
92
|
const CDP_CALL_TIMEOUT_MS = 10_000;
|
|
53
|
-
const
|
|
93
|
+
const DEFAULT_DEVICE_SCALE_FACTOR = 2;
|
|
94
|
+
const SHOT_API_PROXY_PREFIX = "/__gloom_cli_api__";
|
|
95
|
+
const SESSION_COOKIE_NAMES = ["__Secure-gloomberb.session_token", "gloomberb.session_token"] as const;
|
|
54
96
|
|
|
55
97
|
export async function renderDesktopPaneScreenshot(
|
|
56
98
|
payload: DesktopPaneShotPayload,
|
|
57
99
|
outputPath: string,
|
|
100
|
+
apiProxy: DesktopPaneShotApiProxy,
|
|
58
101
|
): Promise<DesktopPaneShotRenderResult> {
|
|
59
102
|
const tempDir = await mkdtemp(join(tmpdir(), "gloom-pane-shot-"));
|
|
103
|
+
let server: ReturnType<typeof Bun.serve> | null = null;
|
|
60
104
|
try {
|
|
61
105
|
const outdir = join(tempDir, "assets");
|
|
62
106
|
await mkdir(outdir, { recursive: true });
|
|
63
|
-
|
|
107
|
+
await buildShotPage(outdir, payload);
|
|
108
|
+
server = serveShotPage(outdir, apiProxy);
|
|
64
109
|
const chrome = await findChromeExecutable();
|
|
65
110
|
return await capturePageScreenshot({
|
|
66
111
|
chrome,
|
|
67
|
-
url:
|
|
112
|
+
url: new URL("/", server.url).href,
|
|
68
113
|
outputPath,
|
|
69
114
|
widthPx: payload.widthPx,
|
|
70
115
|
heightPx: payload.heightPx,
|
|
116
|
+
deviceScaleFactor: payload.deviceScaleFactor ?? DEFAULT_DEVICE_SCALE_FACTOR,
|
|
71
117
|
userDataDir: join(tempDir, "chrome-profile"),
|
|
72
118
|
});
|
|
73
119
|
} finally {
|
|
120
|
+
server?.stop(true);
|
|
74
121
|
await rm(tempDir, { recursive: true, force: true });
|
|
75
122
|
}
|
|
76
123
|
}
|
|
@@ -90,6 +137,20 @@ async function buildShotPage(outdir: string, payload: DesktopPaneShotPayload): P
|
|
|
90
137
|
loadingText: "Rendering pane...",
|
|
91
138
|
bootstrapScript: `
|
|
92
139
|
window.__GLOOM_CLI_SHOT_PAYLOAD__ = ${payloadJson};
|
|
140
|
+
(() => {
|
|
141
|
+
// A screenshot cannot be interacted with, so drawing tools, the
|
|
142
|
+
// quick-add input and the close button only add noise to the image.
|
|
143
|
+
const style = document.createElement("style");
|
|
144
|
+
style.textContent = ${JSON.stringify(SHOT_MODE_CSS)};
|
|
145
|
+
document.head.appendChild(style);
|
|
146
|
+
const watermark = ${JSON.stringify(payload.watermark ?? null)};
|
|
147
|
+
if (watermark) {
|
|
148
|
+
const mark = document.createElement("div");
|
|
149
|
+
mark.setAttribute("data-gloom-role", "shot-watermark");
|
|
150
|
+
mark.textContent = watermark;
|
|
151
|
+
document.addEventListener("DOMContentLoaded", () => document.body.appendChild(mark));
|
|
152
|
+
}
|
|
153
|
+
})();
|
|
93
154
|
window.addEventListener("error", (event) => {
|
|
94
155
|
window.__GLOOM_CLI_SHOT_ERROR__ = event.error && event.error.stack ? event.error.stack : String(event.error || event.message);
|
|
95
156
|
});
|
|
@@ -100,6 +161,116 @@ async function buildShotPage(outdir: string, payload: DesktopPaneShotPayload): P
|
|
|
100
161
|
});
|
|
101
162
|
}
|
|
102
163
|
|
|
164
|
+
function serveShotPage(
|
|
165
|
+
outdir: string,
|
|
166
|
+
apiProxy: DesktopPaneShotApiProxy,
|
|
167
|
+
): ReturnType<typeof Bun.serve> {
|
|
168
|
+
const staticRoot = resolve(outdir);
|
|
169
|
+
return Bun.serve({
|
|
170
|
+
hostname: "127.0.0.1",
|
|
171
|
+
port: 0,
|
|
172
|
+
idleTimeout: 60,
|
|
173
|
+
fetch(request) {
|
|
174
|
+
const url = new URL(request.url);
|
|
175
|
+
if (url.pathname.startsWith(`${SHOT_API_PROXY_PREFIX}/`)) {
|
|
176
|
+
return proxyShotApiRequest(request, url, apiProxy);
|
|
177
|
+
}
|
|
178
|
+
return serveShotAsset(url, staticRoot);
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async function serveShotAsset(url: URL, staticRoot: string): Promise<Response> {
|
|
184
|
+
let pathname: string;
|
|
185
|
+
try {
|
|
186
|
+
pathname = decodeURIComponent(url.pathname);
|
|
187
|
+
} catch {
|
|
188
|
+
return new Response("Bad request", { status: 400 });
|
|
189
|
+
}
|
|
190
|
+
const relativePath = pathname === "/" ? "index.html" : pathname.replace(/^\/+/, "");
|
|
191
|
+
const filePath = resolve(staticRoot, relativePath);
|
|
192
|
+
if (filePath !== staticRoot && !filePath.startsWith(`${staticRoot}${sep}`)) {
|
|
193
|
+
return new Response("Not found", { status: 404 });
|
|
194
|
+
}
|
|
195
|
+
const file = Bun.file(filePath);
|
|
196
|
+
if (!(await file.exists())) return new Response("Not found", { status: 404 });
|
|
197
|
+
return new Response(file);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async function proxyShotApiRequest(
|
|
201
|
+
request: Request,
|
|
202
|
+
requestUrl: URL,
|
|
203
|
+
apiProxy: DesktopPaneShotApiProxy,
|
|
204
|
+
): Promise<Response> {
|
|
205
|
+
const baseUrl = new URL(apiProxy.baseUrl);
|
|
206
|
+
const proxiedPath = requestUrl.pathname.slice(SHOT_API_PROXY_PREFIX.length) || "/";
|
|
207
|
+
const target = new URL(baseUrl);
|
|
208
|
+
const basePath = baseUrl.pathname.replace(/\/+$/, "");
|
|
209
|
+
target.pathname = `${basePath}${proxiedPath.startsWith("/") ? proxiedPath : `/${proxiedPath}`}`;
|
|
210
|
+
target.search = requestUrl.search;
|
|
211
|
+
target.hash = "";
|
|
212
|
+
const headers = new Headers(request.headers);
|
|
213
|
+
for (const name of [
|
|
214
|
+
"authorization",
|
|
215
|
+
"connection",
|
|
216
|
+
"content-length",
|
|
217
|
+
"cookie",
|
|
218
|
+
"host",
|
|
219
|
+
"origin",
|
|
220
|
+
"proxy-authorization",
|
|
221
|
+
"referer",
|
|
222
|
+
"te",
|
|
223
|
+
"trailer",
|
|
224
|
+
"transfer-encoding",
|
|
225
|
+
"upgrade",
|
|
226
|
+
"x-forwarded-for",
|
|
227
|
+
"x-forwarded-host",
|
|
228
|
+
"x-forwarded-proto",
|
|
229
|
+
]) {
|
|
230
|
+
headers.delete(name);
|
|
231
|
+
}
|
|
232
|
+
const browserOwnedHeaders: string[] = [];
|
|
233
|
+
headers.forEach((_value, name) => {
|
|
234
|
+
if (name.startsWith("sec-") || name === "accept-encoding") browserOwnedHeaders.push(name);
|
|
235
|
+
});
|
|
236
|
+
for (const name of browserOwnedHeaders) headers.delete(name);
|
|
237
|
+
headers.set("Origin", baseUrl.origin);
|
|
238
|
+
if (apiProxy.sessionToken) {
|
|
239
|
+
headers.set(
|
|
240
|
+
"Cookie",
|
|
241
|
+
SESSION_COOKIE_NAMES.map((name) => `${name}=${apiProxy.sessionToken}`).join("; "),
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
try {
|
|
246
|
+
const response = await fetch(target, {
|
|
247
|
+
method: request.method,
|
|
248
|
+
headers,
|
|
249
|
+
body: request.method === "GET" || request.method === "HEAD" ? undefined : request.body,
|
|
250
|
+
redirect: "follow",
|
|
251
|
+
});
|
|
252
|
+
const responseHeaders = new Headers(response.headers);
|
|
253
|
+
for (const name of [
|
|
254
|
+
"access-control-allow-credentials",
|
|
255
|
+
"access-control-allow-origin",
|
|
256
|
+
"content-encoding",
|
|
257
|
+
"content-length",
|
|
258
|
+
"set-cookie",
|
|
259
|
+
"transfer-encoding",
|
|
260
|
+
]) {
|
|
261
|
+
responseHeaders.delete(name);
|
|
262
|
+
}
|
|
263
|
+
responseHeaders.set("Cache-Control", "no-store");
|
|
264
|
+
return new Response(response.body, {
|
|
265
|
+
status: response.status,
|
|
266
|
+
statusText: response.statusText,
|
|
267
|
+
headers: responseHeaders,
|
|
268
|
+
});
|
|
269
|
+
} catch {
|
|
270
|
+
return Response.json({ error: "Cloud API request failed." }, { status: 502 });
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
103
274
|
async function findChromeExecutable(): Promise<string> {
|
|
104
275
|
const candidates = [
|
|
105
276
|
process.env.CHROME_PATH,
|
|
@@ -123,6 +294,7 @@ async function capturePageScreenshot({
|
|
|
123
294
|
outputPath,
|
|
124
295
|
widthPx,
|
|
125
296
|
heightPx,
|
|
297
|
+
deviceScaleFactor,
|
|
126
298
|
userDataDir,
|
|
127
299
|
}: {
|
|
128
300
|
chrome: string;
|
|
@@ -130,6 +302,7 @@ async function capturePageScreenshot({
|
|
|
130
302
|
outputPath: string;
|
|
131
303
|
widthPx: number;
|
|
132
304
|
heightPx: number;
|
|
305
|
+
deviceScaleFactor: number;
|
|
133
306
|
userDataDir: string;
|
|
134
307
|
}): Promise<DesktopPaneShotRenderResult> {
|
|
135
308
|
await mkdir(userDataDir, { recursive: true });
|
|
@@ -166,7 +339,7 @@ async function capturePageScreenshot({
|
|
|
166
339
|
await session.send("Emulation.setDeviceMetricsOverride", {
|
|
167
340
|
width: widthPx,
|
|
168
341
|
height: heightPx,
|
|
169
|
-
deviceScaleFactor
|
|
342
|
+
deviceScaleFactor,
|
|
170
343
|
mobile: false,
|
|
171
344
|
});
|
|
172
345
|
await waitForShotReady(session);
|
|
@@ -189,6 +362,21 @@ async function capturePageScreenshot({
|
|
|
189
362
|
}
|
|
190
363
|
}
|
|
191
364
|
|
|
365
|
+
const LOADING_STATE_PATTERNS = [
|
|
366
|
+
/\bLoading(?: [^.]{0,80})?\.{3}/gi,
|
|
367
|
+
/\bRendering pane\.{3}/gi,
|
|
368
|
+
];
|
|
369
|
+
|
|
370
|
+
const ERROR_STATE_PATTERNS = [
|
|
371
|
+
/\b[^.]{1,100} unavailable\./gi,
|
|
372
|
+
/\bFailed to fetch\b/gi,
|
|
373
|
+
/\bCould not load\b/gi,
|
|
374
|
+
/\bSign in to\b/gi,
|
|
375
|
+
/\bVerify your email\b/gi,
|
|
376
|
+
/\bpart of Gloom Cloud Pro\b/gi,
|
|
377
|
+
/\bCloud API request failed\b/gi,
|
|
378
|
+
];
|
|
379
|
+
|
|
192
380
|
const EMPTY_STATE_PATTERNS = [
|
|
193
381
|
/\bNo chart data\b/gi,
|
|
194
382
|
/\bNo graph data\b/gi,
|
|
@@ -197,21 +385,94 @@ const EMPTY_STATE_PATTERNS = [
|
|
|
197
385
|
/\bNo comparison tickers configured\b/gi,
|
|
198
386
|
/\bNo relationship tickers configured\b/gi,
|
|
199
387
|
/\bNo overlapping price history\b/gi,
|
|
200
|
-
/\
|
|
201
|
-
/\bRendering pane\.{0,3}\b/gi,
|
|
202
|
-
/\bNo tickers selected\b/gi,
|
|
203
|
-
/\bMarket data unavailable\b/gi,
|
|
388
|
+
/\bNo tickers? selected\b/gi,
|
|
204
389
|
/\bNo data(?: available)?\b/gi,
|
|
390
|
+
/\bNothing to show yet\b/gi,
|
|
391
|
+
/\bNo transcribed calls(?: for [^.]+)? yet\b/gi,
|
|
392
|
+
/\bNo short interest (?:data|found)\b/gi,
|
|
393
|
+
/\bNo (?:House PTR |insider )?(?:trades|members|transactions|filings)\b/gi,
|
|
205
394
|
];
|
|
206
395
|
|
|
396
|
+
function stateMarkers(text: string, patterns: RegExp[]): string[] {
|
|
397
|
+
return [...new Set(patterns.flatMap((pattern) => (
|
|
398
|
+
[...text.matchAll(pattern)].map((match) => match[0])
|
|
399
|
+
)))];
|
|
400
|
+
}
|
|
401
|
+
|
|
207
402
|
async function readRenderedPaneState(session: CdpSession): Promise<DesktopPaneShotRenderResult> {
|
|
208
403
|
const result = await session.send("Runtime.evaluate", {
|
|
209
404
|
expression: `(() => {
|
|
210
405
|
const root = document.getElementById("root") || document.body;
|
|
406
|
+
const semanticUi = window.__GLOOM_CLI_SHOT_SEMANTIC_UI__ || [];
|
|
407
|
+
const normalize = (value) => String(value || "").replace(/\\s+/g, " ").trim();
|
|
408
|
+
const isVisible = (element) => {
|
|
409
|
+
if (!(element instanceof HTMLElement)) return false;
|
|
410
|
+
const style = getComputedStyle(element);
|
|
411
|
+
if (style.display === "none" || style.visibility === "hidden" || style.opacity === "0") return false;
|
|
412
|
+
const rect = element.getBoundingClientRect();
|
|
413
|
+
return rect.width > 0 && rect.height > 0
|
|
414
|
+
&& rect.right > 0 && rect.bottom > 0
|
|
415
|
+
&& rect.left < window.innerWidth && rect.top < window.innerHeight;
|
|
416
|
+
};
|
|
417
|
+
const semanticTables = semanticUi.filter((node) => node && node.role === "table");
|
|
418
|
+
const rows = [];
|
|
419
|
+
[...root.querySelectorAll('[data-gloom-role="data-table"]')]
|
|
420
|
+
.filter(isVisible)
|
|
421
|
+
.forEach((table, tableIndex) => {
|
|
422
|
+
const tableMetadata = semanticTables[tableIndex] && semanticTables[tableIndex].metadata || {};
|
|
423
|
+
const semanticColumns = Array.isArray(tableMetadata.columns) ? tableMetadata.columns : [];
|
|
424
|
+
const semanticRows = Array.isArray(tableMetadata.rows) ? tableMetadata.rows : [];
|
|
425
|
+
const headers = [...table.querySelectorAll('[data-gloom-role="data-table-header-cell"]')]
|
|
426
|
+
.map((cell) => normalize(cell.innerText || cell.textContent));
|
|
427
|
+
const rowElements = [...table.querySelectorAll(
|
|
428
|
+
'[data-gloom-role="data-table-row"], [data-gloom-role="data-table-section-header"]',
|
|
429
|
+
)].filter(isVisible);
|
|
430
|
+
rowElements.forEach((row, rowIndex) => {
|
|
431
|
+
const cellElements = [...row.querySelectorAll('[data-gloom-role="data-table-cell"]')];
|
|
432
|
+
const values = cellElements.length > 0 ? cellElements : [row];
|
|
433
|
+
const semanticRow = semanticRows[rowIndex] || {};
|
|
434
|
+
const cells = values.map((cell, cellIndex) => {
|
|
435
|
+
const semanticColumn = semanticColumns[cellIndex] || {};
|
|
436
|
+
return {
|
|
437
|
+
...(typeof semanticColumn.id === "string" ? { columnId: semanticColumn.id } : {}),
|
|
438
|
+
columnLabel: typeof semanticColumn.label === "string"
|
|
439
|
+
? semanticColumn.label
|
|
440
|
+
: headers[cellIndex] || (values.length === 1 ? "Row" : String(cellIndex + 1)),
|
|
441
|
+
text: normalize(cell.innerText || cell.textContent),
|
|
442
|
+
};
|
|
443
|
+
}).filter((cell) => cell.text.length > 0);
|
|
444
|
+
if (cells.length === 0) return;
|
|
445
|
+
rows.push({
|
|
446
|
+
tableIndex,
|
|
447
|
+
rowIndex,
|
|
448
|
+
...(typeof semanticRow.key === "string" ? { key: semanticRow.key } : {}),
|
|
449
|
+
selected: row.getAttribute("data-selected") === "true" || semanticRow.selected === true,
|
|
450
|
+
cells,
|
|
451
|
+
});
|
|
452
|
+
});
|
|
453
|
+
});
|
|
454
|
+
if (rows.length === 0) {
|
|
455
|
+
[...root.querySelectorAll('[data-gloom-role="desktop-list-row"]')]
|
|
456
|
+
.filter(isVisible)
|
|
457
|
+
.forEach((row, rowIndex) => {
|
|
458
|
+
const text = normalize(row.innerText || row.textContent);
|
|
459
|
+
if (!text) return;
|
|
460
|
+
rows.push({
|
|
461
|
+
tableIndex: 0,
|
|
462
|
+
rowIndex,
|
|
463
|
+
selected: row.getAttribute("data-selected") === "true",
|
|
464
|
+
cells: [{ columnLabel: "Row", text }],
|
|
465
|
+
});
|
|
466
|
+
});
|
|
467
|
+
}
|
|
211
468
|
return {
|
|
212
469
|
visibleText: root.innerText || root.textContent || "",
|
|
213
470
|
error: window.__GLOOM_CLI_SHOT_ERROR__ || "",
|
|
214
|
-
|
|
471
|
+
loadingStateDetected: root.querySelector('[data-gloom-status="loading"]') !== null,
|
|
472
|
+
errorStateDetected: root.querySelector('[data-gloom-status="error"]') !== null,
|
|
473
|
+
emptyStateDetected: root.querySelector('[data-gloom-status="empty"]') !== null,
|
|
474
|
+
rows,
|
|
475
|
+
semanticUi,
|
|
215
476
|
};
|
|
216
477
|
})()`,
|
|
217
478
|
returnByValue: true,
|
|
@@ -220,6 +481,10 @@ async function readRenderedPaneState(session: CdpSession): Promise<DesktopPaneSh
|
|
|
220
481
|
value?: {
|
|
221
482
|
visibleText?: string;
|
|
222
483
|
error?: string;
|
|
484
|
+
loadingStateDetected?: boolean;
|
|
485
|
+
errorStateDetected?: boolean;
|
|
486
|
+
emptyStateDetected?: boolean;
|
|
487
|
+
rows?: DesktopPaneShotRenderedRow[];
|
|
223
488
|
semanticUi?: RemoteUiNodeSnapshot[];
|
|
224
489
|
};
|
|
225
490
|
};
|
|
@@ -227,12 +492,16 @@ async function readRenderedPaneState(session: CdpSession): Promise<DesktopPaneSh
|
|
|
227
492
|
const value = result.result?.value;
|
|
228
493
|
if (value?.error) throw new Error(value.error);
|
|
229
494
|
const visibleText = (value?.visibleText ?? "").replace(/\s+/g, " ").trim();
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
)
|
|
495
|
+
const loadingStateMarkers = stateMarkers(visibleText, LOADING_STATE_PATTERNS);
|
|
496
|
+
const errorStateMarkers = stateMarkers(visibleText, ERROR_STATE_PATTERNS);
|
|
497
|
+
const emptyStateMarkers = stateMarkers(visibleText, EMPTY_STATE_PATTERNS);
|
|
233
498
|
return {
|
|
234
499
|
visibleText,
|
|
235
|
-
|
|
500
|
+
rows: Array.isArray(value?.rows) ? value.rows : [],
|
|
501
|
+
loadingStateDetected: value?.loadingStateDetected === true || loadingStateMarkers.length > 0,
|
|
502
|
+
errorStateDetected: value?.errorStateDetected === true || errorStateMarkers.length > 0,
|
|
503
|
+
errorStateMarkers,
|
|
504
|
+
emptyStateDetected: value?.emptyStateDetected === true || emptyStateMarkers.length > 0,
|
|
236
505
|
emptyStateMarkers,
|
|
237
506
|
semanticUi: Array.isArray(value?.semanticUi) ? value.semanticUi : [],
|
|
238
507
|
};
|
package/src/cli/index.ts
CHANGED
|
@@ -121,7 +121,7 @@ function createCoreCliCommands(
|
|
|
121
121
|
aliases: ["screenshot"],
|
|
122
122
|
description: "Render a desktop-style screenshot for a pane-backed market function",
|
|
123
123
|
help: {
|
|
124
|
-
usage: ["shot <function-or-pane> [argument] [--output path] [--width px] [--height px] [--key value]"],
|
|
124
|
+
usage: ["shot <function-or-pane> [argument] [--output path] [--width px] [--height px] [--theme id] [--scale n] [--watermark text] [--key value]"],
|
|
125
125
|
},
|
|
126
126
|
execute: async (args, ctx) => {
|
|
127
127
|
await runPaneScreenshot(args, ctx);
|
|
@@ -1,32 +1,22 @@
|
|
|
1
1
|
import { CHART_RESOLUTIONS } from "../../time-series/range";
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
HeadlessPaneArgumentDef,
|
|
4
|
+
HeadlessPaneDefinition,
|
|
5
|
+
HeadlessPaneOptionDef,
|
|
6
|
+
HeadlessPaneOptionType,
|
|
7
|
+
HeadlessPaneOptionValue,
|
|
8
|
+
PaneDef,
|
|
9
|
+
PaneTemplateDef,
|
|
10
|
+
} from "../../types/plugin";
|
|
3
11
|
|
|
4
12
|
export type PaneFunctionReadiness = "ready" | "partial" | "unsupported";
|
|
13
|
+
export type PaneFunctionScreenshotReadiness = PaneFunctionReadiness | "live-dom";
|
|
5
14
|
export type PaneFunctionTickerCardinality = "none" | "one" | "one-or-more" | "two-or-more" | "one-or-two";
|
|
6
|
-
export type PaneFunctionOptionType =
|
|
15
|
+
export type PaneFunctionOptionType = HeadlessPaneOptionType;
|
|
16
|
+
export type PaneFunctionOptionValue = HeadlessPaneOptionValue;
|
|
17
|
+
export type PaneFunctionOptionDef = HeadlessPaneOptionDef;
|
|
7
18
|
export type NormalizedPaneFunctionOptions = Record<string, string | number | boolean>;
|
|
8
19
|
|
|
9
|
-
export interface PaneFunctionOptionValue {
|
|
10
|
-
value: string;
|
|
11
|
-
aliases?: string[];
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface PaneFunctionOptionDef {
|
|
15
|
-
key: string;
|
|
16
|
-
description: string;
|
|
17
|
-
type: PaneFunctionOptionType;
|
|
18
|
-
aliases?: string[];
|
|
19
|
-
values?: PaneFunctionOptionValue[];
|
|
20
|
-
defaultValue?: string | number | boolean;
|
|
21
|
-
minimum?: number;
|
|
22
|
-
maximum?: number;
|
|
23
|
-
settingKey?: string;
|
|
24
|
-
pluginState?: {
|
|
25
|
-
pluginId: string;
|
|
26
|
-
key?: string;
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
20
|
export interface PaneFunctionCapability {
|
|
31
21
|
id: string;
|
|
32
22
|
botSafe: boolean;
|
|
@@ -35,7 +25,7 @@ export interface PaneFunctionCapability {
|
|
|
35
25
|
intents: string[];
|
|
36
26
|
outputKind: string;
|
|
37
27
|
reportReadiness: PaneFunctionReadiness;
|
|
38
|
-
screenshotReadiness:
|
|
28
|
+
screenshotReadiness: PaneFunctionScreenshotReadiness;
|
|
39
29
|
dataRequirements: string[];
|
|
40
30
|
limitations: string[];
|
|
41
31
|
options: PaneFunctionOptionDef[];
|
|
@@ -401,9 +391,11 @@ const UNSUPPORTED_CAPABILITY: PaneFunctionCapability = {
|
|
|
401
391
|
intents: [],
|
|
402
392
|
outputKind: "pane",
|
|
403
393
|
reportReadiness: "unsupported",
|
|
404
|
-
screenshotReadiness: "
|
|
394
|
+
screenshotReadiness: "live-dom",
|
|
405
395
|
dataRequirements: [],
|
|
406
|
-
limitations: [
|
|
396
|
+
limitations: [
|
|
397
|
+
"Reports are not verified for automation. Screenshots render live and derive evidence from visible DOM rows.",
|
|
398
|
+
],
|
|
407
399
|
options: [],
|
|
408
400
|
};
|
|
409
401
|
|
|
@@ -411,11 +403,49 @@ function optionToken(value: string): string {
|
|
|
411
403
|
return value.trim().toLowerCase().replace(/[\s_.-]+/g, "");
|
|
412
404
|
}
|
|
413
405
|
|
|
406
|
+
function headlessTickerCardinality(argument: HeadlessPaneArgumentDef): PaneFunctionTickerCardinality {
|
|
407
|
+
switch (argument.kind) {
|
|
408
|
+
case "ticker":
|
|
409
|
+
return "one";
|
|
410
|
+
case "tickers":
|
|
411
|
+
case "symbol-list":
|
|
412
|
+
return (argument.minimum ?? 1) >= 2 ? "two-or-more" : "one-or-more";
|
|
413
|
+
case "none":
|
|
414
|
+
case "free-text":
|
|
415
|
+
return "none";
|
|
416
|
+
default: {
|
|
417
|
+
const _exhaustive: never = argument.kind;
|
|
418
|
+
return _exhaustive;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
export function getHeadlessPaneDefinition(
|
|
424
|
+
template: PaneTemplateDef | undefined,
|
|
425
|
+
pane: PaneDef,
|
|
426
|
+
): HeadlessPaneDefinition | undefined {
|
|
427
|
+
return template?.headless ?? pane.headless;
|
|
428
|
+
}
|
|
429
|
+
|
|
414
430
|
export function getPaneFunctionCapability(
|
|
415
431
|
template: PaneTemplateDef | undefined,
|
|
416
|
-
|
|
432
|
+
pane: PaneDef,
|
|
417
433
|
): PaneFunctionCapability {
|
|
418
|
-
|
|
434
|
+
const existing = template ? CAPABILITIES[template.id] ?? UNSUPPORTED_CAPABILITY : UNSUPPORTED_CAPABILITY;
|
|
435
|
+
const headless = getHeadlessPaneDefinition(template, pane);
|
|
436
|
+
if (!headless) return existing;
|
|
437
|
+
|
|
438
|
+
const hasExistingCapability = existing !== UNSUPPORTED_CAPABILITY;
|
|
439
|
+
return {
|
|
440
|
+
...(hasExistingCapability ? existing : UNSUPPORTED_CAPABILITY),
|
|
441
|
+
id: hasExistingCapability ? existing.id : template?.id ?? pane.id,
|
|
442
|
+
botSafe: true,
|
|
443
|
+
tickerCardinality: headlessTickerCardinality(headless.argument),
|
|
444
|
+
outputKind: headless.shape,
|
|
445
|
+
reportReadiness: "ready",
|
|
446
|
+
options: [...headless.options],
|
|
447
|
+
...(hasExistingCapability ? {} : { limitations: [] }),
|
|
448
|
+
};
|
|
419
449
|
}
|
|
420
450
|
|
|
421
451
|
function resolveOptionDef(
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from "./options";
|
|
8
8
|
import {
|
|
9
9
|
capabilityOptionSummary,
|
|
10
|
+
getHeadlessPaneDefinition,
|
|
10
11
|
getPaneFunctionCapability,
|
|
11
12
|
type PaneFunctionCapability,
|
|
12
13
|
} from "./capabilities";
|
|
@@ -120,6 +121,7 @@ async function buildTemplateCatalogEntry(
|
|
|
120
121
|
}
|
|
121
122
|
}
|
|
122
123
|
|
|
124
|
+
const headless = getHeadlessPaneDefinition(template, pane);
|
|
123
125
|
return {
|
|
124
126
|
token: template.shortcut?.prefix ?? template.id,
|
|
125
127
|
label: template.label,
|
|
@@ -128,8 +130,8 @@ async function buildTemplateCatalogEntry(
|
|
|
128
130
|
paneName: pane.name,
|
|
129
131
|
templateId: template.id,
|
|
130
132
|
shortcut: template.shortcut?.prefix,
|
|
131
|
-
argKind: template.shortcut?.argKind,
|
|
132
|
-
argPlaceholder: template.shortcut?.argPlaceholder,
|
|
133
|
+
argKind: headless?.argument.kind ?? template.shortcut?.argKind,
|
|
134
|
+
argPlaceholder: headless?.argument.placeholder ?? template.shortcut?.argPlaceholder,
|
|
133
135
|
keywords: template.keywords ?? [],
|
|
134
136
|
defaultSettings,
|
|
135
137
|
capability: getPaneFunctionCapability(template, pane),
|
|
@@ -158,6 +160,8 @@ export async function buildPaneCatalogEntries(
|
|
|
158
160
|
description: `Open the ${pane.name} pane.`,
|
|
159
161
|
paneId: pane.id,
|
|
160
162
|
paneName: pane.name,
|
|
163
|
+
argKind: pane.headless?.argument.kind,
|
|
164
|
+
argPlaceholder: pane.headless?.argument.placeholder,
|
|
161
165
|
keywords: [],
|
|
162
166
|
defaultSettings: {},
|
|
163
167
|
capability: getPaneFunctionCapability(undefined, pane),
|
|
@@ -251,7 +255,13 @@ export function renderPaneCatalogReport(entries: PaneCatalogEntry[], args: Parse
|
|
|
251
255
|
}
|
|
252
256
|
|
|
253
257
|
for (const entry of shown) {
|
|
254
|
-
const arg = entry.
|
|
258
|
+
const arg = entry.argKind === "none"
|
|
259
|
+
? ""
|
|
260
|
+
: entry.argPlaceholder
|
|
261
|
+
? `<${entry.argPlaceholder}>`
|
|
262
|
+
: entry.argKind
|
|
263
|
+
? `<${entry.argKind}>`
|
|
264
|
+
: "[argument]";
|
|
255
265
|
lines.push(`${entry.token} | ${entry.label}`);
|
|
256
266
|
lines.push(` Description: ${entry.description}`);
|
|
257
267
|
lines.push(` Pane: ${entry.paneId} (${entry.paneName})`);
|
|
@@ -273,7 +283,9 @@ export function renderPaneCatalogReport(entries: PaneCatalogEntry[], args: Parse
|
|
|
273
283
|
lines.push(` Limitations: ${entry.capability.limitations.join(" ")}`);
|
|
274
284
|
}
|
|
275
285
|
lines.push(` Defaults: ${formatCatalogSettings(entry.defaultSettings)}`);
|
|
276
|
-
|
|
286
|
+
const fnExample = `gloomberb fn ${entry.token}${arg ? ` ${arg}` : ""}`;
|
|
287
|
+
const shotExample = `gloomberb shot ${entry.token}${arg ? ` ${arg}` : ""} --output /tmp/${entry.token.toLowerCase()}.png`;
|
|
288
|
+
lines.push(` Examples: ${fnExample} | ${shotExample}`);
|
|
277
289
|
lines.push("");
|
|
278
290
|
}
|
|
279
291
|
|
|
@@ -76,6 +76,7 @@ function buildDiscoveryContext({
|
|
|
76
76
|
registerPane: (pane: PaneDef) => panes.set(pane.id, pane),
|
|
77
77
|
registerPaneTemplate: (template: PaneTemplateDef) => paneTemplates.set(template.id, template),
|
|
78
78
|
registerCommand: () => {},
|
|
79
|
+
registerCommandBarSearchProvider: () => () => {},
|
|
79
80
|
registerColumn: () => {},
|
|
80
81
|
registerBroker: () => {},
|
|
81
82
|
registerCapability: () => {},
|