@gloom-sh/terminal 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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { join } from "path";
|
|
2
2
|
import { logFailure } from "../../utils/log-failure";
|
|
3
|
-
import {
|
|
3
|
+
import { versionCommand } from "./version";
|
|
4
4
|
import { saveConfig } from "../../data/config/store";
|
|
5
5
|
import { builtinPluginGroupMembers } from "../../plugins/ownership";
|
|
6
6
|
import type { AppConfig, TelemetryConfig } from "../../types/config";
|
|
@@ -9,7 +9,7 @@ import { readBaseCurrency } from "../../utils/base-currency";
|
|
|
9
9
|
import { NIGHTLY_CHANNEL_SUMMARY, parseUpdateChannel, withUpdateChannel } from "../../updater/channel";
|
|
10
10
|
import type { CliCommandDef } from "../../types/plugin";
|
|
11
11
|
import type { BuiltinCliCommandDef } from "../command-options";
|
|
12
|
-
import {
|
|
12
|
+
import { withCliServices, withConfigData } from "../context";
|
|
13
13
|
import { CLI_COMMAND_GROUPS } from "../help";
|
|
14
14
|
import { dryRunNote, formatBytes, formatStatusCell } from "../helpers";
|
|
15
15
|
import { cliStyles, cliTerminalWidth, renderSection, renderTable, wrapText } from "../../utils/cli-output";
|
|
@@ -97,6 +97,21 @@ function describeTimezone(value: unknown): string {
|
|
|
97
97
|
return typeof value === "string" && value ? value : "not set, times print in UTC alone";
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
/** What `config get telemetry.attention` prints while the setting is untouched. */
|
|
101
|
+
const ATTENTION_DEFAULT = "default";
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Attention Counts as set, not as "on": unset is the default, which counts an
|
|
105
|
+
* account only once the app has shown it its notice, so it is not `true`.
|
|
106
|
+
*/
|
|
107
|
+
function attentionSetting(telemetry: TelemetryConfig | undefined): boolean | typeof ATTENTION_DEFAULT {
|
|
108
|
+
return telemetry?.attention ?? ATTENTION_DEFAULT;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function describeAttentionSetting(value: unknown): string {
|
|
112
|
+
return value === ATTENTION_DEFAULT ? "default: on once the app has shown its notice" : describeConfigValue(value);
|
|
113
|
+
}
|
|
114
|
+
|
|
100
115
|
function describeConfigValue(value: unknown): string {
|
|
101
116
|
if (value == null) return "nothing";
|
|
102
117
|
if (Array.isArray(value)) return value.length > 0 ? value.join(", ") : "nothing";
|
|
@@ -174,32 +189,6 @@ function resourceCacheStats(
|
|
|
174
189
|
}
|
|
175
190
|
|
|
176
191
|
export function createSystemCliCommands(): CliCommandDef[] {
|
|
177
|
-
const versionCommand: CliCommandDef = {
|
|
178
|
-
name: "version",
|
|
179
|
-
aliases: ["--version", "-v"],
|
|
180
|
-
description: "Print the version, runtime, and data folder",
|
|
181
|
-
help: { group: CLI_COMMAND_GROUPS.app, usage: ["version"] },
|
|
182
|
-
execute: async (_args, ctx) => {
|
|
183
|
-
// Where the data lives, or will once a command or the app first runs:
|
|
184
|
-
// printing the version never creates the folder.
|
|
185
|
-
let dataDir: string | null = null;
|
|
186
|
-
try {
|
|
187
|
-
dataDir = await resolveCliDataDir();
|
|
188
|
-
} catch (error) {
|
|
189
|
-
logFailure("cli-system", "Resolve data directory failed")(error);
|
|
190
|
-
dataDir = null;
|
|
191
|
-
}
|
|
192
|
-
ctx.printResult({
|
|
193
|
-
data: [{
|
|
194
|
-
version: VERSION,
|
|
195
|
-
bun: typeof Bun === "undefined" ? null : Bun.version,
|
|
196
|
-
platform: process.platform,
|
|
197
|
-
arch: process.arch,
|
|
198
|
-
dataDir,
|
|
199
|
-
}],
|
|
200
|
-
}, { layout: "record" });
|
|
201
|
-
},
|
|
202
|
-
};
|
|
203
192
|
|
|
204
193
|
const doctorCommand: CliCommandDef = {
|
|
205
194
|
name: "doctor",
|
|
@@ -259,6 +248,7 @@ export function createSystemCliCommands(): CliCommandDef[] {
|
|
|
259
248
|
"config set theme <id>",
|
|
260
249
|
"config set telemetry.crashReports false",
|
|
261
250
|
"config set telemetry.usage false",
|
|
251
|
+
"config set telemetry.attention false",
|
|
262
252
|
"config set starPrompt.enabled false",
|
|
263
253
|
"config set timezone <Region/City>|none",
|
|
264
254
|
"config set updates.channel stable|nightly",
|
|
@@ -333,7 +323,7 @@ export function createSystemCliCommands(): CliCommandDef[] {
|
|
|
333
323
|
valueFlashingEnabled: context.config.valueFlashingEnabled,
|
|
334
324
|
"telemetry.crashReports": context.config.telemetry?.crashReports !== false,
|
|
335
325
|
"telemetry.usage": context.config.telemetry?.usage !== false,
|
|
336
|
-
"telemetry.attention": context.config.telemetry
|
|
326
|
+
"telemetry.attention": attentionSetting(context.config.telemetry),
|
|
337
327
|
[STAR_PROMPT_CONFIG_KEY]: context.config.starPrompt?.enabled !== false,
|
|
338
328
|
[TIMEZONE_CONFIG_KEY]: context.config.timezone ?? null,
|
|
339
329
|
[UPDATE_CHANNEL_CONFIG_KEY]: context.config.updates?.channel ?? "stable",
|
|
@@ -348,6 +338,7 @@ export function createSystemCliCommands(): CliCommandDef[] {
|
|
|
348
338
|
...(key === "theme" ? { format: (value: unknown) => describeThemeId(String(value)) } : {}),
|
|
349
339
|
...(key === TIMEZONE_CONFIG_KEY ? { format: describeTimezone } : {}),
|
|
350
340
|
...(key === "baseCurrency" ? { format: describeBaseCurrency } : {}),
|
|
341
|
+
...(key === "telemetry.attention" ? { format: describeAttentionSetting } : {}),
|
|
351
342
|
})),
|
|
352
343
|
});
|
|
353
344
|
return;
|
|
@@ -367,7 +358,8 @@ export function createSystemCliCommands(): CliCommandDef[] {
|
|
|
367
358
|
ctx.printResult({ data: { key, value: safeConfig[key] } }, {
|
|
368
359
|
text: (data) => key === KEYBINDINGS_CONFIG_KEY ? renderKeybindings(data.value)
|
|
369
360
|
: key === TIMEZONE_CONFIG_KEY ? describeTimezone(data.value)
|
|
370
|
-
: key === "baseCurrency" ? describeBaseCurrency(data.value)
|
|
361
|
+
: key === "baseCurrency" ? describeBaseCurrency(data.value)
|
|
362
|
+
: key === "telemetry.attention" ? describeAttentionSetting(data.value) : describeConfigValue(data.value),
|
|
371
363
|
});
|
|
372
364
|
return;
|
|
373
365
|
}
|
|
@@ -72,6 +72,8 @@ import {
|
|
|
72
72
|
quoteChangeText,
|
|
73
73
|
} from "../helpers";
|
|
74
74
|
import { NotesFiles } from "../../plugins/builtin/notes/files";
|
|
75
|
+
import { getFormDescription } from "../../plugins/builtin/sec/model";
|
|
76
|
+
import { rowSummary, rowSummaryTarget } from "../../plugins/builtin/sec/row-summaries";
|
|
75
77
|
import { isKnownNonUsListing, secFilingItemCodes, US_FUND_FACTS_ONLY } from "../../utils/sec";
|
|
76
78
|
import { currentReportItemsLabel, hiddenFilingsNote, loadLatestFilings, type HiddenFilings } from "../../utils/sec-filings";
|
|
77
79
|
import { canonicalExchange, exchangeLabel, isKnownExchangeCode, isUsListingExchange } from "../../utils/exchanges";
|
|
@@ -80,6 +82,7 @@ import {
|
|
|
80
82
|
resolveCliListing, type CliListing, type ListingDataRequest,
|
|
81
83
|
} from "../listing-arg";
|
|
82
84
|
import { movedAwayChange } from "../../tickers/ticker-changes";
|
|
85
|
+
import { listingChangeLine } from "../../tickers/listing-fate";
|
|
83
86
|
import { companyMemberships, loadCompanyMemberships, type CompanyMemberships, type ListMembership } from "../issuer-membership";
|
|
84
87
|
import { isNotATickerMessage } from "../not-a-ticker";
|
|
85
88
|
import { sharesOutstandingInReceipts } from "../../utils/depositary-receipt";
|
|
@@ -305,6 +308,34 @@ function normalizeComparable(value: string): string {
|
|
|
305
308
|
return value.toUpperCase().replace(/\bFORM\b/g, "").replace(/[^A-Z0-9]+/g, "");
|
|
306
309
|
}
|
|
307
310
|
|
|
311
|
+
/** A recent filing with what an insider form's own XML says: who filed it and what it reports (`rowSummary`). */
|
|
312
|
+
type RecentFiling = SecFilingItem & { summary?: string };
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* The recent filings, each insider form (3, 4, 5, 144) with its filer and what it reports, read from the
|
|
316
|
+
* filing as fn SEC's rows read it: "Fred Thiel: sale of 50K shares". A filing that cannot be read keeps its
|
|
317
|
+
* form's meaning alone.
|
|
318
|
+
*/
|
|
319
|
+
async function withFilingSummaries(
|
|
320
|
+
filings: readonly SecFilingItem[],
|
|
321
|
+
dataProvider: { getSecFilingContent?(filing: SecFilingItem): Promise<string | null> },
|
|
322
|
+
): Promise<RecentFiling[]> {
|
|
323
|
+
if (!dataProvider.getSecFilingContent) return [...filings];
|
|
324
|
+
return Promise.all(filings.map(async (filing) => {
|
|
325
|
+
const target = rowSummaryTarget(filing);
|
|
326
|
+
if (!target) return filing;
|
|
327
|
+
const content = await Promise.resolve().then(() => dataProvider.getSecFilingContent!(target))
|
|
328
|
+
.catch(logFailure("cli.commands-ticker", "Read an insider filing failed", null));
|
|
329
|
+
const summary = rowSummary(filing.form, content)?.title;
|
|
330
|
+
return summary ? { ...filing, summary } : filing;
|
|
331
|
+
}));
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/** What the form is: the filing's own description, else the form's meaning ("Insider Transaction"); none beside an 8-K's items. */
|
|
335
|
+
function filingMeaning(filing: SecFilingItem): string {
|
|
336
|
+
return getFilingDescription(filing) ?? (currentReportItemsLabel(filing.items) ? "" : getFormDescription(filing.form));
|
|
337
|
+
}
|
|
338
|
+
|
|
308
339
|
function getFilingDescription(filing: SecFilingItem): string | undefined {
|
|
309
340
|
const description = filing.primaryDocDescription?.trim();
|
|
310
341
|
if (!description) return undefined;
|
|
@@ -1117,7 +1148,7 @@ export async function buildTickerReport({
|
|
|
1117
1148
|
/** "CAR = Avis Budget Group, NASDAQ (different companies on XETRA, ASX)", for a bare symbol several companies list. */
|
|
1118
1149
|
listingNote?: string;
|
|
1119
1150
|
recentNews?: NewsArticle[];
|
|
1120
|
-
recentSecFilings?:
|
|
1151
|
+
recentSecFilings?: RecentFiling[];
|
|
1121
1152
|
/** What `recentSecFilings` left out. */
|
|
1122
1153
|
hiddenSecFilings?: HiddenFilings;
|
|
1123
1154
|
}): Promise<string> {
|
|
@@ -1226,6 +1257,8 @@ export async function buildTickerReport({
|
|
|
1226
1257
|
)
|
|
1227
1258
|
: "—";
|
|
1228
1259
|
const volume = reportedQuoteVolume(quote);
|
|
1260
|
+
// A coin's volume is traded value in its quote currency (BTC-USD: US dollars), not a count of coins.
|
|
1261
|
+
const volumeCurrency = quote.currency && isRoundTheClockCoin(quote.symbol ?? symbol, quote.exchangeName) ? ` ${quote.currency}` : "";
|
|
1229
1262
|
// A futures price is its latest trade; the exchange settlement is its own row, dated by its session.
|
|
1230
1263
|
appendMetricSection(lines, "Quote", [
|
|
1231
1264
|
// A price in cents says what it is per: 314.95¢/lb.
|
|
@@ -1247,7 +1280,7 @@ export async function buildTickerReport({
|
|
|
1247
1280
|
: "—"],
|
|
1248
1281
|
["Bid / Ask", bidAskText(quote, quoteOptions)],
|
|
1249
1282
|
// An index's and a perpetual's 0 means none is counted, not no trades: no Volume row.
|
|
1250
|
-
["Volume", volume != null ? formatNumber(volume, 0) : "—"],
|
|
1283
|
+
["Volume", volume != null ? `${formatNumber(volume, 0)}${volumeCurrency}` : "—"],
|
|
1251
1284
|
["Updated", formatTimestamp(quoteHeadlineTime(quote))],
|
|
1252
1285
|
]);
|
|
1253
1286
|
|
|
@@ -1338,9 +1371,10 @@ export async function buildTickerReport({
|
|
|
1338
1371
|
meta: [
|
|
1339
1372
|
// The items by number and name, so a results 8-K reads apart from another 8-K filed the same day.
|
|
1340
1373
|
filingItemsMeta(filing),
|
|
1341
|
-
|
|
1342
|
-
filing
|
|
1374
|
+
// What the form is, and below it who filed an insider form and what it reports: the file name said neither.
|
|
1375
|
+
filingMeaning(filing),
|
|
1343
1376
|
],
|
|
1377
|
+
body: filing.summary,
|
|
1344
1378
|
link: filing.filingUrl,
|
|
1345
1379
|
})), hiddenFilingsNote(hiddenSecFilings));
|
|
1346
1380
|
|
|
@@ -1384,7 +1418,7 @@ function buildTickerStructuredData({
|
|
|
1384
1418
|
config: AppConfig;
|
|
1385
1419
|
notes: string;
|
|
1386
1420
|
recentNews: NewsArticle[];
|
|
1387
|
-
recentSecFilings:
|
|
1421
|
+
recentSecFilings: RecentFiling[];
|
|
1388
1422
|
hiddenSecFilings: HiddenFilings;
|
|
1389
1423
|
}) {
|
|
1390
1424
|
const quote = financials.quote;
|
|
@@ -1472,6 +1506,8 @@ function buildTickerStructuredData({
|
|
|
1472
1506
|
filingUrl: filing.filingUrl,
|
|
1473
1507
|
primaryDocumentUrl: filing.primaryDocumentUrl ?? "",
|
|
1474
1508
|
description: getFilingDescription(filing) ?? "",
|
|
1509
|
+
// An insider form's filer and what it reports, as the text report shows it.
|
|
1510
|
+
summary: filing.summary ?? "",
|
|
1475
1511
|
items: secFilingItemCodes(filing.items) ?? "",
|
|
1476
1512
|
// The items by number and name, as the text report shows them.
|
|
1477
1513
|
itemsLabel: currentReportItemsLabel(filing.items) ?? "",
|
|
@@ -1524,7 +1560,7 @@ export async function ticker(symbol: string, dependencies: TickerCommandDependen
|
|
|
1524
1560
|
// So does what became of the symbol, read from the research's quote as `history` reads it: a
|
|
1525
1561
|
// company that moved (HFC became DINO), with nothing new listed there, has no profile of its own.
|
|
1526
1562
|
const researchQuote = Promise.withResolvers<Quote | null>();
|
|
1527
|
-
const fate = listingFateLoader(listing, { dataProvider }, researchQuote.promise);
|
|
1563
|
+
const fate = listingFateLoader(listing, { dataProvider }, researchQuote.promise, { successor: true });
|
|
1528
1564
|
const request: ListingDataRequest = { command: "ticker", noun: "research", fate };
|
|
1529
1565
|
/** Nothing to show: a company that moved is under its new symbol. */
|
|
1530
1566
|
const failIfMovedAway = async () => {
|
|
@@ -1568,8 +1604,8 @@ export async function ticker(symbol: string, dependencies: TickerCommandDependen
|
|
|
1568
1604
|
const quote = resolvedFinancials.quote;
|
|
1569
1605
|
// The quote is the old line's (stopped, or named for the company that left): the profile and figures are another security's.
|
|
1570
1606
|
researchQuote.resolve(quote ?? null);
|
|
1571
|
-
const
|
|
1572
|
-
if (moved) failMovedSymbol(moved, request);
|
|
1607
|
+
const researchFate = await fate();
|
|
1608
|
+
if (researchFate.moved) failMovedSymbol(researchFate.moved, request);
|
|
1573
1609
|
|
|
1574
1610
|
const notesFiles = new NotesFiles(dataDir);
|
|
1575
1611
|
const listingName = listingIdentity(listing, quote).name;
|
|
@@ -1630,14 +1666,18 @@ export async function ticker(symbol: string, dependencies: TickerCommandDependen
|
|
|
1630
1666
|
(currency) => dataProvider.getExchangeRate(currency));
|
|
1631
1667
|
const notes = notesResult.status === "fulfilled" ? notesResult.value : "";
|
|
1632
1668
|
const recentNews = newsResult.status === "fulfilled" ? newsResult.value : [];
|
|
1633
|
-
const { filings:
|
|
1669
|
+
const { filings: secFilings, hidden: hiddenSecFilings } = secFilingsResult.status === "fulfilled"
|
|
1634
1670
|
? secFilingsResult.value : { filings: [], hidden: NOTHING_HIDDEN };
|
|
1671
|
+
const recentSecFilings = await withFilingSummaries(secFilings, dataProvider);
|
|
1635
1672
|
|
|
1636
1673
|
// The quote is the feed in this report; without one, the fundamentals date it.
|
|
1637
1674
|
const freshness = quote ? quotesFreshness([quote]) : fundamentalsFreshness(resolvedFinancials);
|
|
1638
1675
|
const quoteNote = quote ? undefined : await quoteUnavailableNote(dataProvider, requestSymbol, exchange);
|
|
1639
1676
|
// A bare coin ticker read as another listing says where the coin is, as `quote` does: from the quote, else from the saved listing.
|
|
1677
|
+
const successor = listingChangeLine(researchFate);
|
|
1640
1678
|
const choiceNotes = [
|
|
1679
|
+
// What became of the company that had the symbol (GOGL), as `quote` says it, then the listing it was read as.
|
|
1680
|
+
...successor ? [successor] : [],
|
|
1641
1681
|
...await listingChoiceNotes(listing, { store, dataProvider }, quote, venues),
|
|
1642
1682
|
...quote || !tickerFile ? [] : coinListingNotes(listing, { name: tickerFile.metadata.name, instrumentType: tickerFile.metadata.assetCategory }),
|
|
1643
1683
|
];
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { VERSION } from "../../version";
|
|
2
|
+
import { logFailure } from "../../utils/log-failure";
|
|
3
|
+
import type { CliCommandContext, CliCommandDef } from "../../types/plugin";
|
|
4
|
+
import { resolveCliDataDir } from "../data-dir";
|
|
5
|
+
import { CLI_COMMAND_GROUPS } from "../help";
|
|
6
|
+
|
|
7
|
+
/** Shared by the early entry point and the command registry. */
|
|
8
|
+
export async function printVersion(printResult: CliCommandContext["printResult"]): Promise<void> {
|
|
9
|
+
// Reading the version never creates the data folder.
|
|
10
|
+
let dataDir: string | null = null;
|
|
11
|
+
try {
|
|
12
|
+
dataDir = await resolveCliDataDir();
|
|
13
|
+
} catch (error) {
|
|
14
|
+
logFailure("cli-system", "Resolve data directory failed")(error);
|
|
15
|
+
}
|
|
16
|
+
printResult({
|
|
17
|
+
data: [{
|
|
18
|
+
version: VERSION,
|
|
19
|
+
bun: typeof Bun === "undefined" ? null : Bun.version,
|
|
20
|
+
platform: process.platform,
|
|
21
|
+
arch: process.arch,
|
|
22
|
+
dataDir,
|
|
23
|
+
}],
|
|
24
|
+
}, { layout: "record" });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const versionCommand: CliCommandDef = {
|
|
28
|
+
name: "version",
|
|
29
|
+
aliases: ["--version", "-v"],
|
|
30
|
+
description: "Print the version, runtime, and data folder",
|
|
31
|
+
help: { group: CLI_COMMAND_GROUPS.app, usage: ["version"] },
|
|
32
|
+
execute: (_args, ctx) => printVersion(ctx.printResult),
|
|
33
|
+
};
|
package/src/cli/context.ts
CHANGED
|
@@ -9,8 +9,7 @@ import { createAppServices } from "../core/app-services";
|
|
|
9
9
|
import type { PluginCapability } from "../capabilities";
|
|
10
10
|
import type { AppConfig } from "../types/config";
|
|
11
11
|
import type { GloomPlugin } from "../types/plugin";
|
|
12
|
-
import {
|
|
13
|
-
import { standaloneSeriesCatalog, standaloneSeriesInvoker } from "../series/standalone";
|
|
12
|
+
import { standaloneSeriesCatalog, standaloneSeriesInvoker, standaloneSeriesNamed } from "../series/standalone";
|
|
14
13
|
import type { PluginRegistry } from "../plugins/registry";
|
|
15
14
|
import type { LoadedExternalPlugin } from "../plugins/loader";
|
|
16
15
|
import { apiClient } from "../api-client";
|
|
@@ -73,11 +72,6 @@ function isUnreadableConfig(configFile: string): boolean {
|
|
|
73
72
|
}
|
|
74
73
|
}
|
|
75
74
|
|
|
76
|
-
/** The data folder this profile uses, whether or not anything has created it yet. Never writes. */
|
|
77
|
-
export async function resolveCliDataDir(): Promise<string> {
|
|
78
|
-
return await getDataDir() ?? getGloomberbDirs().data;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
75
|
/**
|
|
82
76
|
* The data folder and config a command works with. The first command on a new
|
|
83
77
|
* profile creates them with the same `initDataDir` a first launch of the
|
|
@@ -120,7 +114,7 @@ function applyPersistedCloudSession(context: Pick<MarketContext, "persistence">)
|
|
|
120
114
|
export async function initMarketData(options: CliContextOptions = {}): Promise<MarketContext> {
|
|
121
115
|
const context = await initConfigData();
|
|
122
116
|
applyPersistedCloudSession(context);
|
|
123
|
-
const plugins = options.plugins ?? getLoadablePlugins();
|
|
117
|
+
const plugins = options.plugins ?? (require("../plugins/catalog") as typeof import("../plugins/catalog")).getLoadablePlugins();
|
|
124
118
|
const capabilities = resolveCliCapabilities(context.config, plugins);
|
|
125
119
|
const dataProvider = new AssetDataRouter(null, [], context.persistence.resources);
|
|
126
120
|
const registryAdapter: Pick<PluginRegistry, "brokers" | "getEnabledCapabilities"> = {
|
|
@@ -132,10 +126,12 @@ export async function initMarketData(options: CliContextOptions = {}): Promise<M
|
|
|
132
126
|
dataProvider.setBackgroundRevalidation(false);
|
|
133
127
|
const seriesCapabilities = standaloneSeriesInvoker(plugins, context.dataDir, context.config.disabledPlugins);
|
|
134
128
|
const findCatalogSeries = standaloneSeriesCatalog(plugins, context.config.disabledPlugins);
|
|
135
|
-
|
|
129
|
+
const findCatalogSeriesNamed = standaloneSeriesNamed(plugins, context.config.disabledPlugins);
|
|
130
|
+
return { ...context, dataProvider, seriesCapabilities, findCatalogSeries, findCatalogSeriesNamed, statementSources: cloudStatementReportSources };
|
|
136
131
|
}
|
|
137
132
|
|
|
138
133
|
export async function initCliServices(options: CliServicesOptions = {}) {
|
|
134
|
+
const { getLoadablePlugins } = require("../plugins/catalog") as typeof import("../plugins/catalog");
|
|
139
135
|
const { dataDir, config, created } = await openCliDataDir();
|
|
140
136
|
const services = createAppServices({
|
|
141
137
|
config,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { getDataDir } from "../data/config/store";
|
|
2
|
+
import { getGloomberbDirs } from "../data/config/home";
|
|
3
|
+
|
|
4
|
+
/** The data folder this profile uses, whether or not anything has created it yet. Never writes. */
|
|
5
|
+
export async function resolveCliDataDir(): Promise<string> {
|
|
6
|
+
return await getDataDir() ?? getGloomberbDirs().data;
|
|
7
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which Gloom Cloud requests the pane screenshot page may send through its
|
|
3
|
+
* local proxy, which adds the user's session (desktop-pane-shot.ts). The page
|
|
4
|
+
* only draws panes, so it gets the reads panes make and nothing that acts on
|
|
5
|
+
* the account: no sign-in or sign-out, billing, keys, chat, sync or sharing,
|
|
6
|
+
* and no write of any kind.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** The API families panes read their data from. */
|
|
10
|
+
const READ_FAMILIES = /^\/(?:cloud|market|news|public|research)(?:\/|$)/;
|
|
11
|
+
/** Auth routes inside a read family. */
|
|
12
|
+
const AUTH_IN_FAMILY = /^\/cloud\/auth(?:\/|$)/;
|
|
13
|
+
/**
|
|
14
|
+
* Reads outside those families that panes make, none of whose answers holds a
|
|
15
|
+
* credential, token or key: the session and plan an access gate reads (the
|
|
16
|
+
* session cut to its user, see `isShotSessionPath`), plan prices, the service
|
|
17
|
+
* probe, the roadmap, the layout gallery (marketplace and team layouts),
|
|
18
|
+
* theses, and a signed-in broker's catalog, connection status, holdings,
|
|
19
|
+
* orders and fills.
|
|
20
|
+
*/
|
|
21
|
+
const READ_PATHS = [
|
|
22
|
+
/^\/auth\/get-session$/,
|
|
23
|
+
/^\/account\/cloud$/,
|
|
24
|
+
/^\/pricing$/,
|
|
25
|
+
/^\/health$/,
|
|
26
|
+
/^\/roadmap$/,
|
|
27
|
+
/^\/layouts(?:\/[^/]+)?$/,
|
|
28
|
+
/^\/teams\/[^/]+\/layouts$/,
|
|
29
|
+
/^\/theses(?:\/[^/]+)?$/,
|
|
30
|
+
/^\/brokers\/connectors$/,
|
|
31
|
+
/^\/brokers\/[a-z][a-z0-9-]{0,31}(?:\/(?:snapshot|orders|executions))?$/,
|
|
32
|
+
];
|
|
33
|
+
/** Reads sent as a POST because their query is a list: batches, scans and analyses. */
|
|
34
|
+
const READ_POSTS = new Set([
|
|
35
|
+
"/cloud/exposure/analyze",
|
|
36
|
+
"/cloud/perps/equities",
|
|
37
|
+
"/market/financials/batch",
|
|
38
|
+
"/market/history/batch",
|
|
39
|
+
"/market/organization-tickers",
|
|
40
|
+
"/market/quotes/batch",
|
|
41
|
+
"/market/scanner/live",
|
|
42
|
+
"/market/search/batch",
|
|
43
|
+
"/market/ticker-changes/batch",
|
|
44
|
+
"/research/equity-diagnostic",
|
|
45
|
+
]);
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The path as a server could read it: decoded and lower-cased, so an escaped
|
|
49
|
+
* letter or another case cannot step past a check. Null for one that steps up
|
|
50
|
+
* a folder or holds a backslash once decoded, which is refused rather than
|
|
51
|
+
* trusted to reach the server as the path it was checked as. An encoded slash
|
|
52
|
+
* inside a segment (a symbol such as `EUR/USD`) is fine.
|
|
53
|
+
*/
|
|
54
|
+
function readablePath(path: string): string | null {
|
|
55
|
+
if (!path.startsWith("/") || path.includes("//")) return null;
|
|
56
|
+
let decoded: string;
|
|
57
|
+
try {
|
|
58
|
+
decoded = decodeURIComponent(path);
|
|
59
|
+
} catch {
|
|
60
|
+
// Intentional ignore: a path that does not decode is refused outright, never sent on.
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
if (decoded.includes("\\") || decoded.split("/").some((segment) => segment === "." || segment === "..")) return null;
|
|
64
|
+
return decoded.toLowerCase();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Whether the page may send `method` to the API path `path` (the part after
|
|
69
|
+
* the API's base, query excluded). A batch read sent as POST must be named
|
|
70
|
+
* exactly, with nothing escaped.
|
|
71
|
+
*/
|
|
72
|
+
export function isShotApiRequestAllowed(method: string, path: string): boolean {
|
|
73
|
+
const readable = readablePath(path);
|
|
74
|
+
if (readable === null) return false;
|
|
75
|
+
const verb = method.toUpperCase();
|
|
76
|
+
if (verb === "POST") return READ_POSTS.has(path);
|
|
77
|
+
if (verb !== "GET" && verb !== "HEAD") return false;
|
|
78
|
+
if (READ_PATHS.some((pattern) => pattern.test(readable))) return true;
|
|
79
|
+
return READ_FAMILIES.test(readable) && !AUTH_IN_FAMILY.test(readable);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** The session read, whose answer also carries the session's token: the proxy hands the page its user alone. */
|
|
83
|
+
export function isShotSessionPath(path: string): boolean {
|
|
84
|
+
return readablePath(path) === "/auth/get-session";
|
|
85
|
+
}
|