gloomberb 0.19.2 → 0.19.3
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 -1
- package/package.json +1 -1
- package/patches/electrobun@1.18.1.patch +108 -1
- package/src/account/upgrade-dialog.tsx +4 -23
- package/src/api-client/coalesce.ts +118 -0
- package/src/api-client/credit-boards.ts +13 -0
- package/src/api-client/crypto-etf-flows.ts +6 -0
- package/src/api-client/crypto-markets.ts +40 -0
- package/src/api-client/data.ts +201 -14
- package/src/api-client/equity-screener.ts +10 -0
- package/src/api-client/errors.ts +20 -0
- package/src/api-client/gpu.ts +29 -0
- package/src/api-client/index.ts +5 -2
- package/src/api-client/plan-access.ts +10 -1
- package/src/api-client/plan-rules.ts +35 -0
- package/src/api-client/research-activity.ts +1 -32
- package/src/api-client/types.ts +21 -1
- package/src/app/attention-notice.tsx +94 -0
- package/src/app.tsx +23 -1
- package/src/architecture/core-builtin-allowlist.json +2 -1
- package/src/capabilities/factories.ts +1 -0
- package/src/cli/ascii-output.ts +42 -0
- package/src/cli/base-converter.ts +10 -2
- package/src/cli/command-options.ts +16 -1
- package/src/cli/commands/crypto-hints.ts +23 -4
- package/src/cli/commands/market.ts +92 -23
- package/src/cli/commands/news-search.ts +24 -5
- package/src/cli/commands/overview.ts +9 -4
- package/src/cli/commands/search.ts +71 -12
- package/src/cli/commands/system.ts +22 -30
- package/src/cli/commands/ticker.ts +49 -9
- package/src/cli/commands/version.ts +33 -0
- package/src/cli/context.ts +5 -9
- package/src/cli/data-dir.ts +7 -0
- package/src/cli/desktop-pane-shot-api-policy.ts +85 -0
- package/src/cli/desktop-pane-shot-browser.ts +320 -0
- package/src/cli/desktop-pane-shot-routes.ts +26 -1
- package/src/cli/desktop-pane-shot.ts +196 -256
- package/src/cli/early-command.ts +42 -0
- package/src/cli/earnings-calendar.ts +9 -0
- package/src/cli/entry.ts +19 -13
- package/src/cli/errors.ts +12 -2
- package/src/cli/help.ts +1 -1
- package/src/cli/history-export.ts +22 -2
- package/src/cli/history-rows.ts +154 -4
- package/src/cli/index.ts +18 -1
- package/src/cli/known-gaps.ts +40 -5
- package/src/cli/listing-arg.ts +46 -9
- package/src/cli/options.ts +1 -1
- package/src/cli/output-file.ts +60 -13
- package/src/cli/pane-functions/catalog.ts +14 -3
- package/src/cli/pane-functions/data.ts +1 -1
- package/src/cli/pane-functions/dom.ts +45 -0
- package/src/cli/pane-functions/freshness.ts +46 -9
- package/src/cli/pane-functions/function-help.ts +17 -9
- package/src/cli/pane-functions/headless.ts +22 -14
- package/src/cli/pane-functions/index.ts +6 -2
- package/src/cli/pane-functions/options.ts +6 -2
- package/src/cli/pane-functions/resolver.ts +27 -5
- package/src/cli/pane-functions/screenshot-assessment.ts +33 -0
- package/src/cli/pane-functions/screenshot-bridge.ts +94 -13
- package/src/cli/pane-functions/screenshot-http.ts +70 -0
- package/src/cli/pane-functions/screenshot-render.ts +19 -5
- package/src/cli/quote-answer.ts +20 -0
- package/src/cli/registry.ts +41 -13
- package/src/cli/result.ts +12 -6
- package/src/cli/ticker-resolution.ts +2 -1
- package/src/cli/types.ts +2 -0
- package/src/components/chart/composite/format.ts +3 -0
- package/src/components/chart-table/header.tsx +1 -1
- package/src/components/chart-table/layout.ts +28 -11
- package/src/components/command-bar/action-runtime.ts +4 -0
- package/src/components/command-bar/commands/direct/index.ts +18 -33
- package/src/components/command-bar/commands/direct/runtime.ts +5 -0
- package/src/components/command-bar/commands/registry.ts +10 -1
- package/src/components/command-bar/routes/root/command-items.ts +9 -4
- package/src/components/command-bar/routes/root/runtime.ts +24 -1
- package/src/components/command-bar/surface/index.tsx +9 -3
- package/src/components/company-logo.tsx +2 -1
- package/src/components/layout/header.tsx +8 -3
- package/src/components/layout/market-summary.ts +25 -7
- package/src/components/layout/pane/footer/index.tsx +7 -2
- package/src/components/layout/pane/footer/model.ts +40 -5
- package/src/components/market-board/index.tsx +3 -2
- package/src/components/onboarding/desks-step.tsx +12 -4
- package/src/components/onboarding/first-run-workspace.ts +81 -4
- package/src/components/onboarding/onboarding-frame.tsx +2 -1
- package/src/components/onboarding/onboarding-keyboard.ts +8 -5
- package/src/components/onboarding/onboarding-wizard.tsx +54 -23
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +7 -2
- package/src/components/onboarding/run-setup-again.ts +24 -0
- package/src/components/onboarding/use-onboarding-progress.ts +33 -15
- package/src/components/onboarding/use-onboarding-upgrade.ts +2 -6
- package/src/components/onboarding/wizard-model.ts +57 -3
- package/src/components/onboarding/wizard-positions.ts +1 -1
- package/src/components/ui/delayed-mark.tsx +56 -0
- package/src/components/ui/external-link.tsx +3 -6
- package/src/components/ui/icon.tsx +8 -1
- package/src/components/ui/logo-mark.tsx +8 -5
- package/src/components/ui/stat-grid.tsx +263 -19
- package/src/data/config/store/node.ts +11 -5
- package/src/data/config/store/normalize.ts +16 -3
- package/src/data/profile-permissions.ts +47 -0
- package/src/data/resource-store.ts +34 -31
- package/src/data/sqlite/access.ts +19 -8
- package/src/data/sqlite/checkpointer.ts +95 -8
- package/src/data/sqlite/database.ts +40 -7
- package/src/docs/snapshot.json +191 -78
- package/src/i18n/es.ts +18 -2
- package/src/i18n/ja.ts +18 -2
- package/src/i18n/ko.ts +18 -2
- package/src/i18n/zh-cn.ts +18 -2
- package/src/i18n/zh-tw.ts +18 -2
- package/src/layout/desk-keys.ts +4 -1
- package/src/layout/desks.ts +38 -5
- package/src/layout-marketplace/gallery-desktop.tsx +45 -16
- package/src/market-data/batched-reads.ts +16 -0
- package/src/market-data/coordinator/auxiliary.ts +4 -2
- package/src/market-data/coordinator/index.ts +11 -2
- package/src/market-data/futures-board.ts +1 -1
- package/src/market-data/futures-contract.ts +3 -1
- package/src/market-data/market/index-level.ts +6 -4
- package/src/market-data/published-apac-sessions.ts +6 -0
- package/src/news/aggregator.ts +7 -4
- package/src/news/news-model.ts +11 -0
- package/src/news/story-id.ts +22 -0
- package/src/news/ticker-symbols.ts +17 -1
- package/src/notifications/app-notifier.ts +35 -14
- package/src/plugins/builtin/account-management/form-components.tsx +1 -1
- package/src/plugins/builtin/account-management/index.tsx +2 -3
- package/src/plugins/builtin/account-management/model.ts +1 -1
- package/src/plugins/builtin/alerts/cli-forms.ts +15 -1
- package/src/plugins/builtin/alerts/events-pane.tsx +7 -5
- package/src/plugins/builtin/alerts/events.ts +10 -2
- package/src/plugins/builtin/alerts/index.tsx +5 -5
- package/src/plugins/builtin/alerts/research-builder.ts +5 -1
- package/src/plugins/builtin/alerts/research-rules.ts +18 -0
- package/src/plugins/builtin/alerts/targets.ts +4 -1
- package/src/plugins/builtin/attention/headless.ts +1 -1
- package/src/plugins/builtin/attention/index.tsx +2 -4
- package/src/plugins/builtin/attention/listing.ts +1 -1
- package/src/plugins/builtin/attention/series.ts +1 -1
- package/src/plugins/builtin/awards/index.tsx +1 -2
- package/src/plugins/builtin/backtest/client.ts +1 -0
- package/src/plugins/builtin/backtest/index.tsx +1 -2
- package/src/plugins/builtin/backtest/rules.ts +3 -1
- package/src/plugins/builtin/backtest/window.ts +8 -7
- package/src/plugins/builtin/broker-manager/detail.tsx +16 -3
- package/src/plugins/builtin/broker-manager/index.tsx +1 -1
- package/src/plugins/builtin/buildout/cells.tsx +5 -0
- package/src/plugins/builtin/buildout/company/flow.tsx +367 -0
- package/src/plugins/builtin/buildout/company/id.ts +2 -0
- package/src/plugins/builtin/buildout/company/model.ts +247 -0
- package/src/plugins/builtin/buildout/company/pane.tsx +317 -0
- package/src/plugins/builtin/buildout/data-runtime.ts +31 -10
- package/src/plugins/builtin/buildout/facilities.ts +309 -0
- package/src/plugins/builtin/buildout/format.ts +9 -0
- package/src/plugins/builtin/buildout/index.tsx +51 -5
- package/src/plugins/builtin/buildout/model/index.ts +62 -10
- package/src/plugins/builtin/buildout/model/normalizers.ts +5 -0
- package/src/plugins/builtin/buildout/model/types.ts +11 -2
- package/src/plugins/builtin/buildout/pane/index.tsx +91 -20
- package/src/plugins/builtin/buildout/pane/status.tsx +1 -1
- package/src/plugins/builtin/buildout/pane/themes.tsx +110 -0
- package/src/plugins/builtin/buildout/table-model.ts +26 -2
- package/src/plugins/builtin/builtin-plugin-meta.ts +16 -0
- package/src/plugins/builtin/cds/headless.ts +10 -2
- package/src/plugins/builtin/cds/model.ts +7 -3
- package/src/plugins/builtin/central-bank-rates/index.tsx +1 -2
- package/src/plugins/builtin/central-bank-rates/pane.tsx +2 -1
- package/src/plugins/builtin/changelog/index.tsx +3 -2
- package/src/plugins/builtin/chart-composer/headless-schema.ts +7 -2
- package/src/plugins/builtin/chart-composer/headless.ts +88 -21
- package/src/plugins/builtin/chart-composer/index.tsx +2 -3
- package/src/plugins/builtin/chart-composer/pane.tsx +26 -2
- package/src/plugins/builtin/chart-composer/series-expression.ts +3 -2
- package/src/plugins/builtin/chart-composer/studies.ts +1 -1
- package/src/plugins/builtin/chat/controller/index.ts +1 -1
- package/src/plugins/builtin/chat/controller/messages.ts +15 -4
- package/src/plugins/builtin/chat/ghost-user.ts +8 -0
- package/src/plugins/builtin/chat/index.tsx +5 -5
- package/src/plugins/builtin/clinical-trials/index.tsx +1 -2
- package/src/plugins/builtin/cloud/company-picker.tsx +1 -1
- package/src/plugins/builtin/cloud/index.tsx +1 -2
- package/src/plugins/builtin/cloud/plugin.tsx +6 -4
- package/src/plugins/builtin/cloud/team/module.tsx +1 -1
- package/src/plugins/builtin/cloud/thesis/module.tsx +1 -1
- package/src/plugins/builtin/cloud/trial-offer-status-widget.tsx +24 -1
- package/src/plugins/builtin/cloud/upgrade-status-widget.tsx +39 -15
- package/src/plugins/builtin/comment-letters/index.tsx +1 -2
- package/src/plugins/builtin/commodity-balances/index.tsx +3 -3
- package/src/plugins/builtin/commodity-balances/pane.tsx +2 -2
- package/src/plugins/builtin/congress-trades/aggregates.ts +13 -2
- package/src/plugins/builtin/congress-trades/detail.tsx +20 -4
- package/src/plugins/builtin/congress-trades/headless.ts +2 -0
- package/src/plugins/builtin/congress-trades/model.ts +92 -64
- package/src/plugins/builtin/congress-trades/table.tsx +14 -2
- package/src/plugins/builtin/connections/index.ts +2 -3
- package/src/plugins/builtin/cot/index.tsx +1 -2
- package/src/plugins/builtin/cpi/index.tsx +1 -2
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +2 -1
- package/src/plugins/builtin/credit-boards/client.ts +7 -2
- package/src/plugins/builtin/credit-boards/headless.ts +25 -12
- package/src/plugins/builtin/credit-boards/model.ts +29 -0
- package/src/plugins/builtin/credit-boards/sovr-pane.tsx +9 -4
- package/src/plugins/builtin/crypto-board/bitcoin-network.ts +143 -0
- package/src/plugins/builtin/crypto-board/headless.ts +4 -3
- package/src/plugins/builtin/crypto-board/index.tsx +4 -2
- package/src/plugins/builtin/crypto-board/series.ts +2 -0
- package/src/plugins/builtin/crypto-etf-flows/client.ts +9 -2
- package/src/plugins/builtin/crypto-etf-flows/headless.ts +61 -6
- package/src/plugins/builtin/crypto-etf-flows/index.tsx +1 -2
- package/src/plugins/builtin/crypto-etf-flows/model.ts +14 -1
- package/src/plugins/builtin/crypto-etf-flows/pane.tsx +8 -5
- package/src/plugins/builtin/debt-maturities/headless.ts +4 -3
- package/src/plugins/builtin/debt-maturities/model.ts +17 -1
- package/src/plugins/builtin/debt-maturities/pane.tsx +18 -4
- package/src/plugins/builtin/debug/index.tsx +1 -1
- package/src/plugins/builtin/dividend-yield/client.ts +32 -2
- package/src/plugins/builtin/dividend-yield/headless.ts +58 -33
- package/src/plugins/builtin/dividend-yield/index.tsx +37 -2
- package/src/plugins/builtin/dividend-yield/pane.tsx +32 -13
- package/src/plugins/builtin/dividend-yield/ranking-reads.ts +73 -0
- package/src/plugins/builtin/dividend-yield/ranking-view.tsx +163 -0
- package/src/plugins/builtin/dividend-yield/ranking.ts +1 -1
- package/src/plugins/builtin/dividend-yield/view.ts +21 -0
- package/src/plugins/builtin/docs/index.tsx +2 -3
- package/src/plugins/builtin/doe/headless.ts +16 -3
- package/src/plugins/builtin/doe/index.tsx +5 -4
- package/src/plugins/builtin/earnings/board.tsx +2 -1
- package/src/plugins/builtin/earnings/history.tsx +2 -1
- package/src/plugins/builtin/earnings-ripple/client.ts +32 -7
- package/src/plugins/builtin/earnings-ripple/index.tsx +1 -2
- package/src/plugins/builtin/econ/calendar-model.ts +29 -6
- package/src/plugins/builtin/econ-statistics/index.tsx +1 -2
- package/src/plugins/builtin/equity-screener/client.ts +1 -1
- package/src/plugins/builtin/equity-screener/headless.ts +1 -0
- package/src/plugins/builtin/equity-screener/ideas.ts +30 -1
- package/src/plugins/builtin/equity-screener/index.tsx +1 -2
- package/src/plugins/builtin/equity-screener/model.ts +28 -4
- package/src/plugins/builtin/equity-screener/pane.tsx +5 -0
- package/src/plugins/builtin/equity-screener/screen-check.ts +23 -1
- package/src/plugins/builtin/estimate-revisions/index.tsx +1 -2
- package/src/plugins/builtin/exposure/holdings.ts +35 -13
- package/src/plugins/builtin/exposure/index.tsx +1 -2
- package/src/plugins/builtin/fear-greed/cli.ts +44 -0
- package/src/plugins/builtin/fear-greed/index.tsx +5 -53
- package/src/plugins/builtin/fear-greed/pane.tsx +2 -1
- package/src/plugins/builtin/fixed-income/index.tsx +1 -2
- package/src/plugins/builtin/futures/board-reads.ts +25 -0
- package/src/plugins/builtin/futures/coalesced-bump.ts +44 -0
- package/src/plugins/builtin/futures/index.tsx +15 -0
- package/src/plugins/builtin/futures/model.ts +14 -0
- package/src/plugins/builtin/futures/use-board-terms.ts +22 -15
- package/src/plugins/builtin/futures/use-front-returns.ts +20 -14
- package/src/plugins/builtin/futures-curve/headless.ts +6 -1
- package/src/plugins/builtin/futures-curve/index.tsx +1 -2
- package/src/plugins/builtin/fx-matrix/index.tsx +2 -2
- package/src/plugins/builtin/gpu/board.tsx +51 -12
- package/src/plugins/builtin/gpu/client.ts +15 -2
- package/src/plugins/builtin/gpu/equities.tsx +5 -2
- package/src/plugins/builtin/gpu/headless.ts +14 -2
- package/src/plugins/builtin/gpu/index.tsx +1 -2
- package/src/plugins/builtin/gpu/model.ts +20 -2
- package/src/plugins/builtin/gpu/pane.tsx +1 -1
- package/src/plugins/builtin/help/index.tsx +1 -1
- package/src/plugins/builtin/holders/index-holders.ts +24 -12
- package/src/plugins/builtin/holders/index.tsx +2 -3
- package/src/plugins/builtin/ipo-calendar/index.tsx +1 -2
- package/src/plugins/builtin/iv-history/index.tsx +1 -2
- package/src/plugins/builtin/jodi/index.tsx +1 -2
- package/src/plugins/builtin/kelly-sizer/index.tsx +1 -2
- package/src/plugins/builtin/layout-manager/index.tsx +9 -8
- package/src/plugins/builtin/macro-day/pane.tsx +4 -2
- package/src/plugins/builtin/market-halts/index.tsx +1 -2
- package/src/plugins/builtin/market-heatmap/index.tsx +11 -2
- package/src/plugins/builtin/market-movers/index.tsx +7 -1
- package/src/plugins/builtin/market-movers/session-body.tsx +4 -1
- package/src/plugins/builtin/market-valuation/index.tsx +1 -2
- package/src/plugins/builtin/members/index.tsx +1 -2
- package/src/plugins/builtin/money-markets/index.tsx +1 -2
- package/src/plugins/builtin/money-markets/pane.tsx +2 -1
- package/src/plugins/builtin/news/headless.ts +7 -0
- package/src/plugins/builtin/news/wire/index.tsx +1 -1
- package/src/plugins/builtin/news/wire/news/pop-out.tsx +9 -3
- package/src/plugins/builtin/notes/index.tsx +3 -6
- package/src/plugins/builtin/openfda/index.tsx +1 -2
- package/src/plugins/builtin/options/view.tsx +6 -5
- package/src/plugins/builtin/options-calculator/index.tsx +1 -2
- package/src/plugins/builtin/options-positioning/index.tsx +1 -2
- package/src/plugins/builtin/options-scenario/index.tsx +2 -4
- package/src/plugins/builtin/perps/index.tsx +1 -2
- package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -3
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +2 -1
- package/src/plugins/builtin/plugin-module.ts +16 -2
- package/src/plugins/builtin/portfolio-list/cli/render.ts +53 -3
- package/src/plugins/builtin/portfolio-list/index.tsx +1 -2
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +11 -0
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +2 -2
- package/src/plugins/builtin/power/index.tsx +1 -2
- package/src/plugins/builtin/rate-path/index.tsx +1 -2
- package/src/plugins/builtin/realized-vol/headless.ts +2 -0
- package/src/plugins/builtin/realized-vol/index.tsx +1 -2
- package/src/plugins/builtin/realized-vol/model.ts +16 -2
- package/src/plugins/builtin/realized-vol/pane.tsx +3 -3
- package/src/plugins/builtin/relative-rotation/index.tsx +1 -2
- package/src/plugins/builtin/research/analyst-headless.ts +33 -6
- package/src/plugins/builtin/research/analyst-model.ts +37 -2
- package/src/plugins/builtin/research/analyst-pane.tsx +25 -5
- package/src/plugins/builtin/research/index.tsx +5 -8
- package/src/plugins/builtin/research-search/index.tsx +1 -2
- package/src/plugins/builtin/revenue-breakdown/headless.ts +22 -8
- package/src/plugins/builtin/revenue-breakdown/model.ts +23 -0
- package/src/plugins/builtin/reverse-dcf/pane.tsx +4 -2
- package/src/plugins/builtin/roadmap/index.tsx +2 -3
- package/src/plugins/builtin/roadmap/pane.tsx +49 -2
- package/src/plugins/builtin/scanner/hilo-model.ts +18 -1
- package/src/plugins/builtin/scanner/hilo-pane.tsx +12 -2
- package/src/plugins/builtin/scanner/live-pane.tsx +7 -4
- package/src/plugins/builtin/sec/filing-content.ts +38 -6
- package/src/plugins/builtin/sec/headless.ts +5 -1
- package/src/plugins/builtin/sec/index.tsx +4 -2
- package/src/plugins/builtin/sec/model.ts +2 -0
- package/src/plugins/builtin/sectors/index.tsx +11 -5
- package/src/plugins/builtin/series-inventory.ts +2 -0
- package/src/plugins/builtin/shared/cloud-resource.ts +60 -0
- package/src/plugins/builtin/shared/cloud-upgrade.ts +24 -1
- package/src/plugins/builtin/shared/forming-bars.ts +29 -0
- package/src/plugins/builtin/shared/fx-rate-freshness.ts +17 -0
- package/src/plugins/builtin/shared/series-detail-chart.tsx +4 -2
- package/src/plugins/builtin/shared/use-quote-board.ts +5 -0
- package/src/plugins/builtin/short-interest/publications-pane.tsx +2 -1
- package/src/plugins/builtin/short-volume/pane.tsx +2 -1
- package/src/plugins/builtin/social-mentions/index.tsx +1 -2
- package/src/plugins/builtin/social-mentions/pane.tsx +2 -1
- package/src/plugins/builtin/supply-chain/client.ts +22 -1
- package/src/plugins/builtin/supply-chain/graph-client.ts +22 -1
- package/src/plugins/builtin/supply-chain/index.tsx +1 -2
- package/src/plugins/builtin/thirteenf/api.ts +116 -13
- package/src/plugins/builtin/thirteenf/data.ts +132 -30
- package/src/plugins/builtin/thirteenf/index.tsx +2 -4
- package/src/plugins/builtin/thirteenf/model.ts +2 -0
- package/src/plugins/builtin/thirteenf/pane.tsx +20 -11
- package/src/plugins/builtin/thirteenf/types.ts +12 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +17 -4
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +81 -11
- package/src/plugins/builtin/ticker-detail/headless.ts +11 -3
- package/src/plugins/builtin/ticker-detail/index.tsx +5 -10
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +16 -6
- package/src/plugins/builtin/time-sales/index.tsx +1 -2
- package/src/plugins/builtin/time-sales/pane.tsx +3 -1
- package/src/plugins/builtin/trace-bonds/headless.ts +11 -2
- package/src/plugins/builtin/trace-bonds/model.ts +44 -10
- package/src/plugins/builtin/trace-bonds/pane.tsx +12 -7
- package/src/plugins/builtin/treasury-auctions/pane.tsx +2 -2
- package/src/plugins/builtin/vol-surface/client.ts +18 -3
- package/src/plugins/builtin/vol-surface/index.tsx +1 -2
- package/src/plugins/builtin/volatility/index.tsx +1 -2
- package/src/plugins/builtin/world-indices/footer.ts +6 -1
- package/src/plugins/builtin/world-venue-map/client.ts +10 -1
- package/src/plugins/builtin/world-venue-map/index.ts +6 -2
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +48 -7
- package/src/plugins/builtin/world-venue-map/layers.ts +17 -0
- package/src/plugins/builtin/world-venue-map/local-layers.ts +141 -0
- package/src/plugins/builtin/world-venue-map/map-symbols.ts +18 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +4 -2
- package/src/plugins/builtin/world-venue-map/scope.ts +63 -0
- package/src/plugins/builtin/yield-curve/curves.ts +16 -2
- package/src/plugins/builtin/yield-curve/headless.ts +3 -3
- package/src/plugins/bundle.ts +52 -2
- package/src/plugins/catalog-browser.ts +2 -2
- package/src/plugins/catalog-cli.ts +20 -0
- package/src/plugins/host-link.ts +13 -1
- package/src/plugins/installer.ts +15 -4
- package/src/plugins/loader.ts +43 -11
- package/src/plugins/peer-imports.ts +201 -0
- package/src/plugins/peer-retry.ts +26 -29
- package/src/plugins/plugin-process.ts +128 -0
- package/src/plugins/redirection-guard.ts +45 -0
- package/src/remote/endpoint.ts +16 -3
- package/src/renderers/browser/main.tsx +3 -2
- package/src/renderers/cloudflare/http-proxy.ts +7 -123
- package/src/renderers/dom/desktop/icons.tsx +2 -0
- package/src/renderers/dom/host/image-surface.tsx +46 -21
- package/src/renderers/dom/styles.css +7 -0
- package/src/renderers/dom/toast-host.tsx +2 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +7 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +3 -2
- package/src/renderers/electrobun/bun/desktop/rpc-timing.ts +88 -0
- package/src/renderers/electrobun/bun/desktop/update.ts +20 -4
- package/src/renderers/electrobun/bun/desktop/view-ids.ts +8 -4
- package/src/renderers/electrobun/bun/external-plugins.ts +4 -0
- package/src/renderers/electrobun/bun/window/create.ts +4 -2
- package/src/renderers/electrobun/bun/window/native-timing.ts +48 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +82 -4
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +13 -5
- package/src/renderers/electrobun/view/desktop/window/snapshot.ts +3 -0
- package/src/renderers/electrobun/view/main.tsx +7 -2
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -0
- package/src/renderers/opentui/browser-open.ts +10 -4
- package/src/renderers/opentui/image/surface.tsx +1 -1
- package/src/renderers/opentui/start.tsx +12 -6
- package/src/renderers/opentui/toast-host.tsx +2 -1
- package/src/series/registry.ts +18 -0
- package/src/series/standalone.ts +10 -1
- package/src/series/types.ts +7 -0
- package/src/series/validate.ts +11 -2
- package/src/sources/gloomberb-cloud/index.ts +28 -5
- package/src/sources/gloomberb-cloud/news.ts +24 -3
- package/src/sources/gloomberb-cloud/normalizers.ts +17 -2
- package/src/sources/provider-errors.ts +26 -3
- package/src/sources/provider-router/history.ts +5 -0
- package/src/sources/provider-router/index.ts +13 -0
- package/src/sync/core-contributors.ts +32 -0
- package/src/telemetry/attention-counts.ts +64 -6
- package/src/telemetry/attention-setting.ts +33 -0
- package/src/telemetry/crash-reports-node.ts +3 -1
- package/src/telemetry/stall-clocks.ts +93 -0
- package/src/telemetry/stall-reports-node.ts +12 -7
- package/src/telemetry/stall-reports.ts +34 -5
- package/src/test-support/preload.ts +9 -0
- package/src/tickers/company-name.ts +19 -0
- package/src/tickers/listing-fate.ts +14 -3
- package/src/tickers/saved-instrument.ts +17 -0
- package/src/tickers/search/home-listing.ts +13 -2
- package/src/tickers/search/index.ts +4 -1
- package/src/tickers/search/types.ts +6 -1
- package/src/time-series/bar-aggregation.ts +7 -1
- package/src/time-series/base-series.ts +3 -3
- package/src/time-series/chart-bounds.ts +1 -1
- package/src/time-series/chart-data.ts +5 -2
- package/src/time-series/chart-seed.ts +1 -1
- package/src/time-series/coin-session-close.ts +211 -0
- package/src/time-series/live-bars.ts +13 -2
- package/src/time-series/live-quotes.ts +1 -1
- package/src/time-series/official-close.ts +159 -0
- package/src/time-series/price-comparison.ts +55 -6
- package/src/time-series/resolve.ts +12 -3
- package/src/time-series/series-presentation.ts +1 -1
- package/src/time-series/studies/formula.ts +205 -0
- package/src/time-series/studies/indicators.ts +299 -0
- package/src/time-series/studies/leverage.ts +75 -0
- package/src/time-series/studies/pair.ts +138 -0
- package/src/time-series/studies/resolve.ts +333 -0
- package/src/time-series/studies/shared.ts +141 -0
- package/src/time-series/studies/units.ts +243 -0
- package/src/time-series/studies/vwap.ts +274 -0
- package/src/types/config.ts +18 -2
- package/src/types/data-provider.ts +23 -0
- package/src/types/financials.ts +22 -0
- package/src/types/headless.ts +42 -3
- package/src/types/plugin.ts +32 -3
- package/src/ui/host.tsx +11 -0
- package/src/ui/toast.tsx +26 -1
- package/src/utils/ascii-text.ts +140 -0
- package/src/utils/cli-output.ts +91 -18
- package/src/utils/concurrency.ts +24 -0
- package/src/utils/exchanges.ts +6 -0
- package/src/utils/external-url.ts +20 -7
- package/src/utils/futures-generic.ts +4 -4
- package/src/utils/http-proxy-upstream.ts +124 -0
- package/src/utils/main-thread-stall.ts +75 -3
- package/src/utils/perf-marks.ts +36 -2
- package/src/utils/private-files.ts +141 -0
- package/src/utils/public-address.ts +99 -0
- package/src/account/upgrade-personalization.ts +0 -57
- package/src/account/upgrade-tickers.ts +0 -124
- package/src/api-client/upgrade-experiment.ts +0 -91
- package/src/plugins/builtin/cloud/browser.tsx +0 -3
- package/src/renderers/electrobun/launcher/preload.ts +0 -13
- package/src/renderers/electrobun/launcher/windows-emulation.ts +0 -50
- package/src/time-series/studies.ts +0 -1628
package/src/cli/options.ts
CHANGED
|
@@ -14,7 +14,7 @@ export interface CliGlobalOptions {
|
|
|
14
14
|
limit?: number;
|
|
15
15
|
/** `--tail <n>`: the newest n rows of a dated series, in their printed order. Never set with `limit`. */
|
|
16
16
|
tail?: number;
|
|
17
|
-
/** `--width <n>`: fit tables to n columns. Unset, a terminal's own width fits them and piped output is not fitted. */
|
|
17
|
+
/** `--width <n>`: fit tables to n columns. Unset, a terminal's own width fits them, and piped output fits `COLUMNS` when set, else is not fitted. */
|
|
18
18
|
width?: number;
|
|
19
19
|
refresh: boolean;
|
|
20
20
|
dryRun: boolean;
|
package/src/cli/output-file.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { lstat, mkdir } from "fs/promises";
|
|
2
2
|
import { homedir } from "os";
|
|
3
3
|
import { posix, win32 } from "path";
|
|
4
|
+
import { NOT_A_PLAIN_FILE, writePrivateFile } from "../utils/private-files";
|
|
4
5
|
|
|
5
6
|
interface OutputPathContext {
|
|
6
7
|
cwd?: string;
|
|
@@ -40,29 +41,75 @@ function isFolder(path: string, paths: typeof posix): Error {
|
|
|
40
41
|
return new Error(`Cannot write ${path}: it is a folder. Name a file in it, such as ${paths.join(path, "report.csv")}.`);
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
function isLink(path: string): Error {
|
|
45
|
+
return new Error(`Cannot write ${path}: it is a link. Name the file it points to, or a new file.`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function isNotAFile(path: string): Error {
|
|
49
|
+
return new Error(`Cannot write ${path}: it is not a plain file. Name a new file, or a file to replace.`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Fails when `path` names a folder, a link or anything else that is not a
|
|
54
|
+
* plain file (a device, a pipe): checked before a report loads, so it stops
|
|
55
|
+
* at once, and again as the file is opened.
|
|
56
|
+
*/
|
|
44
57
|
export async function checkOutputPath(path: string, platform: NodeJS.Platform = process.platform): Promise<void> {
|
|
45
|
-
const existing = await
|
|
58
|
+
const existing = await lstat(path).catch(() => {
|
|
46
59
|
// Intentional ignore: a path that does not exist yet is the usual case, and writing reports any real failure.
|
|
47
60
|
return null;
|
|
48
61
|
});
|
|
49
|
-
if (existing
|
|
62
|
+
if (!existing) return;
|
|
63
|
+
if (existing.isDirectory()) throw isFolder(path, platform === "win32" ? win32 : posix);
|
|
64
|
+
if (existing.isSymbolicLink()) throw isLink(path);
|
|
65
|
+
if (!existing.isFile()) throw isNotAFile(path);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Creates the folder `path` goes in and the folders above it, failing with
|
|
70
|
+
* that folder named when it cannot: `--output /nonexistent/x.png` cannot
|
|
71
|
+
* create /nonexistent, which says more than the `mkdir` error behind it.
|
|
72
|
+
*/
|
|
73
|
+
export async function createOutputFolder(path: string, platform: NodeJS.Platform = process.platform): Promise<void> {
|
|
74
|
+
const folder = (platform === "win32" ? win32 : posix).dirname(path);
|
|
75
|
+
try {
|
|
76
|
+
await mkdir(folder, { recursive: true });
|
|
77
|
+
} catch (error) {
|
|
78
|
+
const code = errorCode(error);
|
|
79
|
+
const lead = `Cannot create the folder ${folder}`;
|
|
80
|
+
if (code === "EACCES" || code === "EPERM") throw new Error(`${lead}: permission denied.`);
|
|
81
|
+
if (code === "EROFS") throw new Error(`${lead}: the disk is read-only.`);
|
|
82
|
+
if (code === "ENOTDIR" || code === "EEXIST") throw new Error(`${lead}: a file stands where one of its folders would be.`);
|
|
83
|
+
throw new Error(`${lead}: ${error instanceof Error ? error.message : String(error)}`);
|
|
84
|
+
}
|
|
50
85
|
}
|
|
51
86
|
|
|
52
87
|
/**
|
|
53
88
|
* Writes a command's output to `path`, creating the folders it names as
|
|
54
|
-
* `shot --output` does, and failing with what to do when it cannot.
|
|
89
|
+
* `shot --output` does, and failing with what to do when it cannot. The file
|
|
90
|
+
* is readable by the user alone, as one it replaces is made, and only a plain
|
|
91
|
+
* file is written: a link or a device in its place is refused, checked first
|
|
92
|
+
* and again as the file is opened.
|
|
55
93
|
*/
|
|
56
|
-
export async function writeOutputFile(path: string, contents: string, platform: NodeJS.Platform = process.platform): Promise<void> {
|
|
94
|
+
export async function writeOutputFile(path: string, contents: string | Uint8Array, platform: NodeJS.Platform = process.platform): Promise<void> {
|
|
57
95
|
const paths = platform === "win32" ? win32 : posix;
|
|
96
|
+
await createOutputFolder(path, platform);
|
|
97
|
+
await checkOutputPath(path, platform);
|
|
58
98
|
try {
|
|
59
|
-
await
|
|
60
|
-
await writeFile(path, contents);
|
|
99
|
+
await writePrivateFile(path, contents);
|
|
61
100
|
} catch (error) {
|
|
62
|
-
|
|
63
|
-
if (code === "EISDIR") throw isFolder(path, paths);
|
|
64
|
-
if (code === "EACCES" || code === "EPERM") throw new Error(`Cannot write ${path}: permission denied.`);
|
|
65
|
-
if (code === "ENOTDIR" || code === "EEXIST") throw new Error(`Cannot write ${path}: a file stands where one of its folders would be.`);
|
|
66
|
-
throw new Error(`Cannot write ${path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
101
|
+
throw writeFailure(path, paths, error);
|
|
67
102
|
}
|
|
68
103
|
}
|
|
104
|
+
|
|
105
|
+
function writeFailure(path: string, paths: typeof posix, error: unknown): Error {
|
|
106
|
+
const code = errorCode(error);
|
|
107
|
+
if (code === "EISDIR") return isFolder(path, paths);
|
|
108
|
+
// A link opened without following it: ELOOP on Linux and macOS, EMLINK on FreeBSD.
|
|
109
|
+
if (code === "ELOOP" || code === "EMLINK") return isLink(path);
|
|
110
|
+
// A device, or a pipe no one reads.
|
|
111
|
+
if (code === NOT_A_PLAIN_FILE || code === "ENXIO") return isNotAFile(path);
|
|
112
|
+
if (code === "EACCES" || code === "EPERM") return new Error(`Cannot write ${path}: permission denied.`);
|
|
113
|
+
if (code === "ENOTDIR" || code === "EEXIST") return new Error(`Cannot write ${path}: a file stands where one of its folders would be.`);
|
|
114
|
+
return new Error(`Cannot write ${path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
115
|
+
}
|
|
@@ -32,6 +32,17 @@ import {
|
|
|
32
32
|
import { renderGlossaryEntries, type GlossaryLookup } from "../glossary";
|
|
33
33
|
import { renderSeriesMatches, type SeriesMatch } from "../series-search";
|
|
34
34
|
import { typoDistance } from "../../utils/typo-distance";
|
|
35
|
+
import { quotedSearchCommand } from "../commands/news-search";
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The `news` search for words no function matches (`catalog hurricane`):
|
|
39
|
+
* one word quoted so `news` searches the stories rather than a ticker, several
|
|
40
|
+
* as typed in one pair of quotes.
|
|
41
|
+
*/
|
|
42
|
+
function catalogNewsCommand(query: string): string {
|
|
43
|
+
const words = query.trim().replace(/\s+/g, " ").replace(/["']/g, "");
|
|
44
|
+
return /\s/.test(words) ? `gloom news "${words}"` : quotedSearchCommand(words.toLowerCase());
|
|
45
|
+
}
|
|
35
46
|
|
|
36
47
|
export interface PaneFunctionCatalog {
|
|
37
48
|
panes: ReadonlyMap<string, PaneDef>;
|
|
@@ -253,9 +264,9 @@ async function buildTemplateCatalogEntry(
|
|
|
253
264
|
const sampleArg = sampleArgForTemplate(template);
|
|
254
265
|
const createOptions: PaneTemplateCreateOptions | undefined = buildCreateOptions(template, sampleArg);
|
|
255
266
|
const primarySymbol = createOptions?.symbol ?? createOptions?.symbols?.[0] ?? null;
|
|
256
|
-
let defaultSettings: Record<string, unknown> = {};
|
|
267
|
+
let defaultSettings: Record<string, unknown> = template.catalogSettings ?? {};
|
|
257
268
|
|
|
258
|
-
if (template.createInstance) {
|
|
269
|
+
if (template.catalogSettings === undefined && template.createInstance) {
|
|
259
270
|
try {
|
|
260
271
|
const spec = await template.createInstance(buildTemplateContext(context, primarySymbol), createOptions);
|
|
261
272
|
defaultSettings = spec?.settings ?? {};
|
|
@@ -810,7 +821,7 @@ export function renderPaneCatalogReport(
|
|
|
810
821
|
if (charted) return withGap([charted, terms].filter(Boolean).join("\n\n"));
|
|
811
822
|
if (glossary.exact.length > 0 || gap || setting) return withGap(terms);
|
|
812
823
|
return withTerms(note(args.query
|
|
813
|
-
? `No functions match "${args.query}". Run gloom catalog to browse them all.`
|
|
824
|
+
? `No functions match "${args.query}". For stories that mention it: ${catalogNewsCommand(args.query)}. Run gloom catalog to browse them all.`
|
|
814
825
|
: "No functions are available."));
|
|
815
826
|
}
|
|
816
827
|
|
|
@@ -238,7 +238,7 @@ export function collectShotSymbols(resolved: ResolvedPaneFunction, rawArg: strin
|
|
|
238
238
|
}
|
|
239
239
|
}
|
|
240
240
|
// A text argument is a phrase, not a symbol, so it must never be looked up as one.
|
|
241
|
-
const argIsTicker = argumentNamesTicker(resolved.template, resolved.headless);
|
|
241
|
+
const argIsTicker = argumentNamesTicker(resolved.template, resolved.headless, resolved.pane);
|
|
242
242
|
let symbols = resolved.createOptions?.symbols?.length
|
|
243
243
|
? resolved.createOptions.symbols
|
|
244
244
|
: [
|
|
@@ -10,6 +10,7 @@ import { createHeadlessPaneContext } from "./headless";
|
|
|
10
10
|
import type { HeadlessPaneContext } from "../../types/headless";
|
|
11
11
|
import { lockNoteReason } from "../../plugins/builtin/shared/pro-lock-note";
|
|
12
12
|
import { renderDesktopShot } from "./screenshot-render";
|
|
13
|
+
import { resolvePersistedCloudSessionToken } from "./cloud-session";
|
|
13
14
|
import type { PaneScreenshotResult } from "./screenshot-types";
|
|
14
15
|
import { deriveRenderedFreshness, formatFreshnessLine, type ReportFreshness } from "./freshness";
|
|
15
16
|
import { exportTextTable, reportFooterLines, type CliReportTables } from "../report-tables";
|
|
@@ -389,11 +390,55 @@ class RenderedReportFailure extends Error {
|
|
|
389
390
|
}
|
|
390
391
|
}
|
|
391
392
|
|
|
393
|
+
/**
|
|
394
|
+
* The report of a pane the sign-in wall covers whole (`PaneDef.signInWall`)
|
|
395
|
+
* when there is no session: its lock note, as the rendered wall reports it,
|
|
396
|
+
* without waiting for the wall to render. Null with a session, or for any
|
|
397
|
+
* other pane.
|
|
398
|
+
*/
|
|
399
|
+
async function signedOutDomReport(
|
|
400
|
+
resolved: ResolvedPaneFunction,
|
|
401
|
+
context: MarketContext,
|
|
402
|
+
rawArg: string,
|
|
403
|
+
): Promise<PaneFunctionReport | null> {
|
|
404
|
+
if (!resolved.pane.signInWall || !resolved.pane.reportLockNote || resolvePersistedCloudSessionToken(context)) return null;
|
|
405
|
+
const symbols = collectShotSymbols(resolved, rawArg);
|
|
406
|
+
const note = await resolved.pane.reportLockNote({
|
|
407
|
+
gate: "sign-in", symbol: symbols[0] ?? null, token: resolved.token,
|
|
408
|
+
context: createHeadlessPaneContext(resolved, context, new AbortController().signal),
|
|
409
|
+
});
|
|
410
|
+
const reason = lockNoteReason(note);
|
|
411
|
+
return {
|
|
412
|
+
data: {
|
|
413
|
+
kind: "rendered-view",
|
|
414
|
+
target: resolved.token,
|
|
415
|
+
capabilityId: resolved.capability.id,
|
|
416
|
+
symbols,
|
|
417
|
+
options: resolved.options,
|
|
418
|
+
rowCount: 0,
|
|
419
|
+
empty: true,
|
|
420
|
+
complete: false,
|
|
421
|
+
unavailableSymbols: [],
|
|
422
|
+
rows: [],
|
|
423
|
+
visibleText: "",
|
|
424
|
+
truncated: false,
|
|
425
|
+
truncationReasons: [],
|
|
426
|
+
limitation: DOM_LIMITATION,
|
|
427
|
+
reason,
|
|
428
|
+
locked: "sign-in",
|
|
429
|
+
},
|
|
430
|
+
text: [resolved.label, "", ...lockNoteLines(note)].join("\n").trimEnd(),
|
|
431
|
+
tables: domReportTables([], resolved.label, null, reason, []),
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
|
|
392
435
|
export async function buildDomFunctionReport(
|
|
393
436
|
resolved: ResolvedPaneFunction,
|
|
394
437
|
context: MarketContext,
|
|
395
438
|
rawArg: string,
|
|
396
439
|
): Promise<PaneFunctionReport> {
|
|
440
|
+
const signedOut = await signedOutDomReport(resolved, context, rawArg);
|
|
441
|
+
if (signedOut) return signedOut;
|
|
397
442
|
let result: PaneScreenshotResult;
|
|
398
443
|
try {
|
|
399
444
|
result = await renderDesktopShot({
|
|
@@ -123,6 +123,8 @@ export interface ReportFreshness {
|
|
|
123
123
|
ageOnly?: true;
|
|
124
124
|
/** What the newest observation is, said before its time: `newest story Tue 29 Sep 2026 20:17 UTC`. */
|
|
125
125
|
asOfLabel?: string;
|
|
126
|
+
/** The newest observation is a bar of this many minutes opening at `asOf`: the line names its span (`last bar 15:00–16:00 UTC`). */
|
|
127
|
+
barMinutes?: number;
|
|
126
128
|
/** The line says when the report was retrieved after the newest observation's date (`retrieved Wed 28 Oct 2026 19:07 UTC`). */
|
|
127
129
|
retrievedToo?: true;
|
|
128
130
|
/** What the figures are, said after the status: `funding = current estimate, pays 08:00 UTC`. */
|
|
@@ -572,6 +574,7 @@ function resolveFreshness({ declared, signals, observations, now }: FreshnessInp
|
|
|
572
574
|
const note = declared.note?.trim();
|
|
573
575
|
const noteVariants = note ? (declared.noteVariants ?? []).map((variant) => variant.trim()).filter((variant) => variant && variant !== note) : [];
|
|
574
576
|
const asOfLabel = asOf ? declared.asOfLabel?.trim() : undefined;
|
|
577
|
+
const barMinutes = asOf && !asOf.dateOnly && !declaredAsOf && declared.barMinutes != null && declared.barMinutes > 0 ? declared.barMinutes : undefined;
|
|
575
578
|
const schedule = declared.schedule?.trim();
|
|
576
579
|
const scheduleVariants = schedule ? (declared.scheduleVariants ?? []).map((variant) => variant.trim()).filter((variant) => variant && variant !== schedule) : [];
|
|
577
580
|
const publisher = declared.publisher?.trim();
|
|
@@ -612,6 +615,7 @@ function resolveFreshness({ declared, signals, observations, now }: FreshnessInp
|
|
|
612
615
|
...(oldestAgeMinutes != null ? { oldestAgeMinutes } : {}),
|
|
613
616
|
...(status === "unreported" && declared.ageOnly ? { ageOnly: true as const } : {}),
|
|
614
617
|
...(asOfLabel ? { asOfLabel } : {}),
|
|
618
|
+
...(barMinutes ? { barMinutes } : {}),
|
|
615
619
|
...(asOf && declared.retrievedToo ? { retrievedToo: true as const } : {}),
|
|
616
620
|
...(note ? { note } : {}),
|
|
617
621
|
...(noteVariants.length > 0 ? { noteVariants } : {}),
|
|
@@ -619,10 +623,16 @@ function resolveFreshness({ declared, signals, observations, now }: FreshnessInp
|
|
|
619
623
|
...(scheduleVariants.length > 0 ? { scheduleVariants } : {}),
|
|
620
624
|
...(publisher ? { publisher } : {}),
|
|
621
625
|
...(publishedAt ? { publishedAt: isoTime(publishedAt) } : {}),
|
|
622
|
-
retrievedAt: new Date(now).toISOString(),
|
|
626
|
+
retrievedAt: declaredRetrieval(declared.retrievedAt, now) ?? new Date(now).toISOString(),
|
|
623
627
|
};
|
|
624
628
|
}
|
|
625
629
|
|
|
630
|
+
/** A declared retrieval (`retrievedAt`): when the source last read the data, not in the future. */
|
|
631
|
+
function declaredRetrieval(value: string | undefined, now: number): string | null {
|
|
632
|
+
const time = value ? Date.parse(value) : Number.NaN;
|
|
633
|
+
return Number.isFinite(time) && time <= now + FUTURE_TOLERANCE_MS ? new Date(time).toISOString() : null;
|
|
634
|
+
}
|
|
635
|
+
|
|
626
636
|
/**
|
|
627
637
|
* Source, as-of and status for a headless report: what the loader declared
|
|
628
638
|
* (the result's `freshness` over the definition's), the rest read from the
|
|
@@ -914,6 +924,8 @@ function asOfText(freshness: ReportFreshness, short: boolean, local: boolean, un
|
|
|
914
924
|
: period ? `${periodText(freshness.asOf, period)} (${period})`
|
|
915
925
|
: freshness.asOfClose
|
|
916
926
|
? `${tradingDayText(freshness.asOfClose, market)} close`
|
|
927
|
+
: freshness.barMinutes && time && !time.dateOnly
|
|
928
|
+
? barSpanText(time.time, freshness.barMinutes, undated && onRetrievalDay(new Date(time.time).toISOString(), freshness.retrievedAt))
|
|
917
929
|
: time?.dateOnly ? tradingDayText(freshness.asOf, market)
|
|
918
930
|
: undated && time && onRetrievalDay(new Date(time.time).toISOString(), freshness.retrievedAt)
|
|
919
931
|
? `${new Date(time.time).toISOString().slice(11, 16)} UTC` : timeText(freshness.asOf, local);
|
|
@@ -924,6 +936,14 @@ function asOfText(freshness: ReportFreshness, short: boolean, local: boolean, un
|
|
|
924
936
|
return oldest && !short && freshness.oldestAgeMinutes == null ? `${dated} (oldest ${oldest})` : dated;
|
|
925
937
|
}
|
|
926
938
|
|
|
939
|
+
/** `Fri 30 Oct 2026, last bar 15:00–16:00 UTC`: the newest bar's span; `undated` leaves the day off. */
|
|
940
|
+
function barSpanText(open: number, minutes: number, undated: boolean): string {
|
|
941
|
+
const start = new Date(open).toISOString();
|
|
942
|
+
const end = new Date(open + minutes * 60_000).toISOString();
|
|
943
|
+
const span = `last bar ${start.slice(11, 16)}–${end.slice(11, 16)} UTC`;
|
|
944
|
+
return undated ? span : `${dayText(start)}, ${span}`;
|
|
945
|
+
}
|
|
946
|
+
|
|
927
947
|
/**
|
|
928
948
|
* Each source's own as-of, the zone named once at the end:
|
|
929
949
|
* `Sun 11 Oct 2026 · Binance 02:15 · Bybit 02:24 UTC`. The day leads, the newest source's,
|
|
@@ -986,6 +1006,15 @@ function marketText(market: ReportMarket, now: number, short: boolean, local: bo
|
|
|
986
1006
|
}
|
|
987
1007
|
}
|
|
988
1008
|
|
|
1009
|
+
/**
|
|
1010
|
+
* Where one venue's market stands now and the status line's words for it (`markets closed until Mon`), for a pane with
|
|
1011
|
+
* no dated rows to read that from, such as a scanner. Null when no calendar places the venue.
|
|
1012
|
+
*/
|
|
1013
|
+
export function venueMarketLine(exchange: string, now: number): { state: ReportMarket["state"]; text: string } | null {
|
|
1014
|
+
const { market } = reportMarketSession([{ exchange, time: null }], now);
|
|
1015
|
+
return market ? { state: market.state, text: marketText(market, now, false, false) } : null;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
989
1018
|
/** Whether every market of a mixed report reads the same (`markets closed until Mon`): one line then says it for all. */
|
|
990
1019
|
function sameMarketText(markets: readonly VenueMarket[], now: number): boolean {
|
|
991
1020
|
return new Set(markets.map((market) => marketText(market, now, false, false))).size === 1;
|
|
@@ -1092,8 +1121,10 @@ function observedDayText(date: string, retrievedAt: string): string {
|
|
|
1092
1121
|
}
|
|
1093
1122
|
|
|
1094
1123
|
interface DatasetLineDetail {
|
|
1095
|
-
/**
|
|
1096
|
-
source?: "none";
|
|
1124
|
+
/** The source without its `Source:` label, or left out. */
|
|
1125
|
+
source?: "bare" | "none";
|
|
1126
|
+
/** Leave out how many days the data lags, which a narrow line gives up before its source and date. */
|
|
1127
|
+
lag?: "none";
|
|
1097
1128
|
/** Leave out the oldest observation. */
|
|
1098
1129
|
oldest?: "none";
|
|
1099
1130
|
/** Count stale rows without their total. */
|
|
@@ -1113,11 +1144,12 @@ function lagText(days: number): string {
|
|
|
1113
1144
|
* `Source: DTCC · last trade 2026-10-09 · lag 2 days`.
|
|
1114
1145
|
*/
|
|
1115
1146
|
function datasetLineParts(freshness: ReportFreshness, asOf: string, lagDays: number, detail: DatasetLineDetail = {}): string[] {
|
|
1147
|
+
const source = detail.source === "none" ? [] : [detail.source === "bare" ? freshness.source : `Source: ${freshness.source}`];
|
|
1116
1148
|
if (freshness.observation) {
|
|
1117
1149
|
return [
|
|
1118
|
-
...
|
|
1150
|
+
...source,
|
|
1119
1151
|
`${freshness.observation} ${asOf.slice(0, 10)}`,
|
|
1120
|
-
lagText(lagDays),
|
|
1152
|
+
...(detail.lag === "none" ? [] : [lagText(lagDays)]),
|
|
1121
1153
|
...(freshness.savedAt ? [savedCopyText(freshness.savedAt, freshness.retrievedAt, false)]
|
|
1122
1154
|
: freshness.status === "stale" ? ["stale"] : []),
|
|
1123
1155
|
];
|
|
@@ -1127,9 +1159,9 @@ function datasetLineParts(freshness: ReportFreshness, asOf: string, lagDays: num
|
|
|
1127
1159
|
const oldest = freshness.oldest && detail.oldest !== "none" ? ` (oldest ${dated(freshness.oldest)})` : "";
|
|
1128
1160
|
const stale = freshness.status !== "stale" ? null : staleRowsText(freshness, detail.status === "short") ?? "stale";
|
|
1129
1161
|
return [
|
|
1130
|
-
...
|
|
1162
|
+
...source,
|
|
1131
1163
|
`observed ${dated(asOf)}${period ? ` (${period})` : ""}${oldest}`,
|
|
1132
|
-
`lag ${lagDays}d
|
|
1164
|
+
...(detail.lag === "none" ? [] : [`lag ${lagDays}d`]),
|
|
1133
1165
|
...(freshness.savedAt ? [savedCopyText(freshness.savedAt, freshness.retrievedAt, false)] : stale ? [stale] : []),
|
|
1134
1166
|
];
|
|
1135
1167
|
}
|
|
@@ -1190,16 +1222,21 @@ export function paneStatusLineVariants(freshness: ReportFreshness): string[] {
|
|
|
1190
1222
|
* `Source: CFTC · Tue 6 Oct 2026 · not a live feed (weekly report)`, shortens
|
|
1191
1223
|
* the same way and gives up its source last. A dataset reads
|
|
1192
1224
|
* `Source: Gloom Cloud · observed Sun 4 Oct · lag 6d` and gives up its oldest
|
|
1193
|
-
* observation, the stale total, then its source
|
|
1225
|
+
* observation, the stale total, then its lag; its source loses its label
|
|
1226
|
+
* (`Gloom Cloud · observed Sun 4 Oct`), and the narrowest line is the date
|
|
1227
|
+
* alone (`Observed Sun 4 Oct`): the source goes before the date.
|
|
1194
1228
|
*/
|
|
1195
1229
|
export function statusLineVariants(freshness: ReportFreshness, { source = false }: { source?: boolean } = {}): string[] {
|
|
1196
1230
|
if (datesObservation(freshness)) {
|
|
1197
1231
|
const { asOf, lagDays } = freshness;
|
|
1232
|
+
// The lag, relative to the reading, goes before the source and the date; the source before the date.
|
|
1198
1233
|
const datasetDetails: DatasetLineDetail[] = [
|
|
1199
1234
|
{},
|
|
1200
1235
|
{ oldest: "none" },
|
|
1201
1236
|
{ oldest: "none", status: "short" },
|
|
1202
|
-
{
|
|
1237
|
+
{ oldest: "none", status: "short", lag: "none" },
|
|
1238
|
+
{ oldest: "none", status: "short", lag: "none", source: "bare" },
|
|
1239
|
+
{ oldest: "none", status: "short", lag: "none", source: "none" },
|
|
1203
1240
|
];
|
|
1204
1241
|
return [...new Set(datasetDetails.map((detail) => capitalize(datasetLineParts(freshness, asOf, lagDays, detail).join(" · "))))];
|
|
1205
1242
|
}
|
|
@@ -234,10 +234,11 @@ export const FUNCTION_HELP: Readonly<Record<string, FunctionHelp>> = {
|
|
|
234
234
|
bloomberg: ["RV"],
|
|
235
235
|
},
|
|
236
236
|
EQS: {
|
|
237
|
-
summary: "Screen covered stocks on valuation, growth, margins, liquidity, volatility, technicals, float and ownership, short interest, insider activity and 13F holders, then rank the matches by any metric. "
|
|
237
|
+
summary: "Screen covered stocks on valuation, growth, margins, returns on capital, leverage, liquidity, volatility, technicals, float and ownership, short interest, insider activity and 13F holders, then rank the matches by any metric. "
|
|
238
238
|
+ "ATR% is the 14-session average true range as a percent of the last close. IV rank is a rank, not an IV percentile: 0 is the lowest 30-day implied volatility of the past 52 weeks and 100 the highest. IV percentile, IV30 change in vol points, HV20 and HV rank screen premium to sell. "
|
|
239
|
-
+ "Technical fields read the last completed session: RSI 14, price vs SMA 20, 50 and 200, trading days since a MACD or golden cross and since a new 20-day or 52-week high or low, and Bollinger width percentile (0 is a six-month squeeze).
|
|
240
|
-
|
|
239
|
+
+ "Technical fields read the last completed session: RSI 14, price vs SMA 20, 50 and 200, trading days since a MACD or golden cross and since a new 20-day or 52-week high or low, and Bollinger width percentile (0 is a six-month squeeze). "
|
|
240
|
+
+ "ROIC, FCF yield, net debt / EBITDA, debt / equity and the revenue and EPS CAGRs read FA's bases, and forward growth EE's consensus; N/M where FA prints it. Ideas holds ready technical screens and Value, Quality and GARP.",
|
|
241
|
+
usage: ["EQS", "gloom fn EQS --preset golden-cross", "gloom fn EQS --preset quality"],
|
|
241
242
|
keys: [key("a", "dd criterion"), key("m", "etric"), key("t", "check ticker"), key("s", "ave screen"), key("o", "pen research")],
|
|
242
243
|
data: same("Daily snapshot, statements as filed"),
|
|
243
244
|
bloomberg: ["EQS"],
|
|
@@ -533,7 +534,7 @@ export const FUNCTION_HELP: Readonly<Record<string, FunctionHelp>> = {
|
|
|
533
534
|
bloomberg: ["CAST", "DDIS"],
|
|
534
535
|
},
|
|
535
536
|
ATTN: {
|
|
536
|
-
summary: "See which tickers
|
|
537
|
+
summary: "See which tickers Gloom users are researching, with delayed privacy-qualified hourly counts, abnormal attention, sectors, countries and market context. Suppressed activity is unavailable, never zero.",
|
|
537
538
|
usage: ["ATTN", "ATTN 6758:JPX"],
|
|
538
539
|
keys: [OPEN, key("e", "vidence"), key("d", "es"), key("g", "raph"), key("n", "ews")],
|
|
539
540
|
data: { free: "Three published rows per section and the latest history point", pro: "All published rows and hourly history; minimum one-hour publication lag" },
|
|
@@ -1252,10 +1253,17 @@ export const FUNCTION_HELP: Readonly<Record<string, FunctionHelp>> = {
|
|
|
1252
1253
|
bloomberg: [],
|
|
1253
1254
|
},
|
|
1254
1255
|
TBO: {
|
|
1255
|
-
summary: "Data center and semiconductor supply chain intelligence:
|
|
1256
|
+
summary: "Data center and semiconductor supply chain intelligence: a board of AI buildout themes sized by market cap and coloured by median 1Y return, each theme's companies, sites and intel, with limited free data and full access with Buildout.",
|
|
1256
1257
|
usage: ["TBO"],
|
|
1257
|
-
keys: [TABS, OPEN, key("s", "tar")],
|
|
1258
|
-
data: same("Intel 72 hours delayed without
|
|
1258
|
+
keys: [TABS, key("←/→", " theme"), OPEN, key("s", "tar")],
|
|
1259
|
+
data: same("Intel 72 hours delayed without Buildout"),
|
|
1260
|
+
bloomberg: [],
|
|
1261
|
+
},
|
|
1262
|
+
TBOC: {
|
|
1263
|
+
summary: "One company in TheBuildout: its power and hosting deals, suppliers and customers as a flow, its sites, hiring by site and the signals that name it. Linked to TBO, it follows the company under the cursor.",
|
|
1264
|
+
usage: ["TBOC MSFT", "TBOC MSFT --tab signals"],
|
|
1265
|
+
keys: [TABS, OPEN],
|
|
1266
|
+
data: same("Signals 72 hours delayed and no hiring by site without Buildout"),
|
|
1259
1267
|
bloomberg: [],
|
|
1260
1268
|
},
|
|
1261
1269
|
ACM: {
|
|
@@ -1427,9 +1435,9 @@ export const FUNCTION_HELP: Readonly<Record<string, FunctionHelp>> = {
|
|
|
1427
1435
|
bloomberg: [],
|
|
1428
1436
|
},
|
|
1429
1437
|
ROADMAP: {
|
|
1430
|
-
summary: "What is being built, what is planned and what shipped, with each item's votes. Pro members vote on what is building or planned, once per item, and can take the vote back.",
|
|
1438
|
+
summary: "What is being built, what is planned and what shipped, with each item's votes, and the Changelog in a second tab. Pro members vote on what is building or planned, once per item, and can take the vote back.",
|
|
1431
1439
|
usage: ["ROADMAP"],
|
|
1432
|
-
keys: [OPEN, key("v", "ote")],
|
|
1440
|
+
keys: [TABS, OPEN, key("v", "ote")],
|
|
1433
1441
|
data: null,
|
|
1434
1442
|
bloomberg: [],
|
|
1435
1443
|
},
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { getSharedRegistry } from "../../plugins/registry";
|
|
2
|
+
import { seriesExpression, seriesNamedBy } from "../../series/registry";
|
|
2
3
|
import { findCachedPortfolioAccount } from "../../plugins/builtin/portfolio-list/cached-account";
|
|
3
|
-
import { parsePublicTickerKey } from "../../utils/exchanges";
|
|
4
4
|
import { findNamedCollection } from "../../portfolio/collection-name";
|
|
5
5
|
import { readBareListing } from "../listing-arg";
|
|
6
6
|
import { apiClient } from "../../api-client";
|
|
7
|
+
import { resolveSavedInstrument } from "../../tickers/saved-instrument";
|
|
7
8
|
import type { MarketContext } from "../types";
|
|
8
9
|
import type {
|
|
9
10
|
HeadlessArgumentExpansion,
|
|
@@ -190,7 +191,7 @@ async function loadHeadlessPaneModel(
|
|
|
190
191
|
return result;
|
|
191
192
|
}
|
|
192
193
|
|
|
193
|
-
type HeadlessMarketContext = Pick<MarketContext, "config" | "store" | "refresh" | "resolveBroker"> & Partial<Pick<MarketContext, "persistence" | "seriesCapabilities" | "findCatalogSeries">> & {
|
|
194
|
+
type HeadlessMarketContext = Pick<MarketContext, "config" | "store" | "refresh" | "resolveBroker"> & Partial<Pick<MarketContext, "persistence" | "seriesCapabilities" | "findCatalogSeries" | "findCatalogSeriesNamed">> & {
|
|
194
195
|
dataProvider: HeadlessPaneContext["marketData"];
|
|
195
196
|
};
|
|
196
197
|
|
|
@@ -210,6 +211,11 @@ export function createHeadlessPaneContext(
|
|
|
210
211
|
capabilities: getSharedRegistry() ?? context.seriesCapabilities,
|
|
211
212
|
catalogSeriesName: (expression) => (getSharedRegistry()?.series.findByExpression(expression)?.definition
|
|
212
213
|
?? context.findCatalogSeries?.(expression))?.name,
|
|
214
|
+
catalogSeriesNamed: (word) => {
|
|
215
|
+
const registered = getSharedRegistry()?.series?.list().map(({ definition }) => definition) ?? [];
|
|
216
|
+
const definition = seriesNamedBy(registered, word) ?? context.findCatalogSeriesNamed?.(word);
|
|
217
|
+
return definition ? { expression: seriesExpression(definition), name: definition.name } : undefined;
|
|
218
|
+
},
|
|
213
219
|
resolveBroker: context.resolveBroker,
|
|
214
220
|
async resolvePortfolio(id) {
|
|
215
221
|
const portfolio = findNamedCollection(context.config.portfolios, id);
|
|
@@ -222,25 +228,21 @@ export function createHeadlessPaneContext(
|
|
|
222
228
|
if (!watchlist) return null;
|
|
223
229
|
return (await context.store.loadAllTickers()).filter(row => row.metadata.watchlists.includes(watchlist.id));
|
|
224
230
|
},
|
|
225
|
-
|
|
226
|
-
const parsed = parsePublicTickerKey(key);
|
|
227
|
-
const ticker = await context.store.loadTicker(key)
|
|
228
|
-
?? (key !== parsed.symbol ? await context.store.loadTicker(parsed.symbol) : null);
|
|
229
|
-
return { symbol: parsed.symbol, exchange: parsed.exchange ?? ticker?.metadata.exchange };
|
|
230
|
-
},
|
|
231
|
+
resolveInstrument: (key) => resolveSavedInstrument(key, (saved) => context.store.loadTicker(saved)),
|
|
231
232
|
readDeviceState: <T,>(pluginId: string, key: string) =>
|
|
232
233
|
context.persistence?.pluginState.get<T>(pluginId, resumeStateKey(key))?.value ?? null,
|
|
233
234
|
async resolveListing(symbol, argumentWith) {
|
|
234
235
|
const command = `fn ${resolved.token}`;
|
|
235
236
|
const read = await readBareListing(symbol, context, {
|
|
236
237
|
command, noun: "a quote", retry: (key) => `gloom ${command} ${argumentWith(key)}`,
|
|
237
|
-
}, { refresh: !!context.refresh });
|
|
238
|
+
}, { refresh: !!context.refresh, successor: true });
|
|
238
239
|
if (!read) return null;
|
|
239
240
|
return {
|
|
240
241
|
symbol: read.symbol,
|
|
241
242
|
...read.exchange ? { exchange: read.exchange } : {},
|
|
242
243
|
...read.name ? { name: read.name } : {},
|
|
243
244
|
...read.coinNote ? { coinNote: read.coinNote } : {},
|
|
245
|
+
...read.successorNote ? { successorNote: read.successorNote } : {},
|
|
244
246
|
};
|
|
245
247
|
},
|
|
246
248
|
};
|
|
@@ -544,12 +546,17 @@ function renderRows(
|
|
|
544
546
|
stackPriority: column.stackPriority,
|
|
545
547
|
stackRows: column.stackRows,
|
|
546
548
|
minTableWidth: column.minTableWidth,
|
|
549
|
+
optional: column.optional,
|
|
550
|
+
dropPriority: column.dropPriority,
|
|
547
551
|
})),
|
|
548
552
|
rows.map((row) => columns.map((column) => cell(row, column))),
|
|
549
553
|
{
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
554
|
+
// A value the text leaves out (a summary that only repeats the headline) takes no line.
|
|
555
|
+
below: under.length === 0 ? undefined : rows.map((row) => under.flatMap((column) => {
|
|
556
|
+
const text = row[column.key] == null || row[column.key] === "" ? "" : cell(row, column);
|
|
557
|
+
return text === "" ? [] : text.split("\n");
|
|
558
|
+
})),
|
|
559
|
+
...(under.length > 0 && under.every((column) => column.underRow === "line") ? { cutBelow: true } : {}),
|
|
553
560
|
},
|
|
554
561
|
);
|
|
555
562
|
}
|
|
@@ -571,7 +578,7 @@ function renderBundle(
|
|
|
571
578
|
return result.sections.filter((section) => !isLockedSection(section)).flatMap((section, index) => [
|
|
572
579
|
...(index > 0 ? [""] : []),
|
|
573
580
|
// A section with no title is its rows, or its empty message, alone.
|
|
574
|
-
...(section.title ? [renderSection(section.title)] : []),
|
|
581
|
+
...(section.title ? [renderSection(section.textTitle ?? section.title)] : []),
|
|
575
582
|
"rows" in section && section.rows
|
|
576
583
|
? renderRows(section.textRows ?? section.rows, section.textColumns ?? section.columns, definition.columns, section.empty)
|
|
577
584
|
: renderEntries(section.textEntries ?? section.entries),
|
|
@@ -898,7 +905,8 @@ export function renderHeadlessPaneText(
|
|
|
898
905
|
): string {
|
|
899
906
|
// A long title wraps to a narrow --width like the text under a table; each line stays bold.
|
|
900
907
|
const lines = [...wrapToTerminal(reportTitle(definition, args, result, fallbackTitle)).split("\n").map(cliStyles.bold), ""];
|
|
901
|
-
|
|
908
|
+
// A notice wraps to a narrow --width, as the notes and errors under the tables do.
|
|
909
|
+
const notices = textNotices(result).map((notice) => wrapToTerminal(notice));
|
|
902
910
|
if (notices.length) lines.push(...notices, "");
|
|
903
911
|
const gate = reportGate(definition, result);
|
|
904
912
|
const reason = emptyReportReason(definition, result, args, token, gate);
|
|
@@ -46,6 +46,7 @@ import { checkOutputPath, resolveOutputPath, writeOutputFile } from "../output-f
|
|
|
46
46
|
import type { CatalogCommandHit } from "../unknown-command";
|
|
47
47
|
import { CLI_EXIT_CODES } from "../exit-codes";
|
|
48
48
|
import { shotOptionRefusal } from "./shot-options";
|
|
49
|
+
import { listingChangeLine } from "../../tickers/listing-fate";
|
|
49
50
|
import {
|
|
50
51
|
GLOSSARY,
|
|
51
52
|
glossaryRecord,
|
|
@@ -312,7 +313,7 @@ export async function runPaneFunction(args: string[], ctx: CliCommandContext) {
|
|
|
312
313
|
let quoted: ReturnType<typeof loadListingQuoteAnswer> | null = null;
|
|
313
314
|
const quoteAnswer = listing ? () => quoted ??= loadListingQuoteAnswer(context.dataProvider, listing) : null;
|
|
314
315
|
const fate = listing && quoteAnswer && isTickerLinkPeer(resolved.instance, registry.panes)
|
|
315
|
-
? listingFateLoader(listing, context, quoteAnswer().then((answer) => answer.quote))
|
|
316
|
+
? listingFateLoader(listing, context, quoteAnswer().then((answer) => answer.quote), { successor: true })
|
|
316
317
|
: null;
|
|
317
318
|
const moved = { command: "fn", retry: (key: string) => `gloom fn ${resolved.token} ${key}` };
|
|
318
319
|
// A report that fails or comes back empty for an exchange the symbol is not listed on says so.
|
|
@@ -356,7 +357,10 @@ export async function runPaneFunction(args: string[], ctx: CliCommandContext) {
|
|
|
356
357
|
const data = glossary
|
|
357
358
|
? { ...report.data, glossary: glossary.map(({ term, short, definition }) => ({ term, ...(short ? { short } : {}), definition })) }
|
|
358
359
|
: report.data;
|
|
359
|
-
|
|
360
|
+
// What became of the company that had the symbol (GOGL), as `quote` says it, leads.
|
|
361
|
+
const successor = fate ? listingChangeLine(await fate()) : null;
|
|
362
|
+
// A note the listing and the report both make (a coin's code charted as a fund) is said once.
|
|
363
|
+
const warnings = [...new Set([...successor ? [successor] : [], ...parsed.listingNotes ?? [], ...await choice ?? [], ...report.data.warnings ?? []])];
|
|
360
364
|
// A report with no data is printed as it is, and fails: exit 1, and `ok: false` in JSON with the reason.
|
|
361
365
|
const failure = reportFailure(report.data, ["fn", resolved.token, parsed.arg.trim()].filter(Boolean).join(" "), {
|
|
362
366
|
failsWithoutData: resolved.headless?.failsWithoutData, tables: report.tables });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { HeadlessPaneDefinition, PaneTemplateCreateOptions, PaneTemplateDef } from "../../types/plugin";
|
|
1
|
+
import type { HeadlessPaneDefinition, PaneDef, PaneTemplateCreateOptions, PaneTemplateDef } from "../../types/plugin";
|
|
2
2
|
import { parseTickerListInput } from "../../tickers/list";
|
|
3
3
|
import { normalizeTickerInput } from "../../tickers/search";
|
|
4
4
|
import { resolveFinancialPeriodOption } from "../../plugins/builtin/ticker-detail/financials/model";
|
|
@@ -85,12 +85,16 @@ export function cleanTickerInput(value: string): string {
|
|
|
85
85
|
/**
|
|
86
86
|
* Whether a function's argument names the ticker its pane shows. Its report
|
|
87
87
|
* says first: AUCT's `10Y` and IPO's `pending` are free text its own resolver
|
|
88
|
-
* reads, never a symbol to look up. Without a report,
|
|
88
|
+
* reads, never a symbol to look up. Without a report, a rendered pane whose
|
|
89
|
+
* argument is an id it opens (the story pane's story id) says so, then the
|
|
90
|
+
* shortcut.
|
|
89
91
|
*/
|
|
90
92
|
export function argumentNamesTicker(
|
|
91
93
|
template: Pick<PaneTemplateDef, "shortcut"> | undefined,
|
|
92
94
|
headless: Pick<HeadlessPaneDefinition, "argument"> | undefined,
|
|
95
|
+
pane?: Pick<PaneDef, "reportArgument">,
|
|
93
96
|
): boolean {
|
|
97
|
+
if (!headless && pane?.reportArgument?.identifier) return false;
|
|
94
98
|
const kind = headless?.argument.kind;
|
|
95
99
|
if (kind === "free-text" || kind === "none") return false;
|
|
96
100
|
return kind === "tickers" || kind === "symbol-list" || template?.shortcut?.argKind !== "text";
|