@gloom-sh/terminal 0.19.1 → 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 +2 -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 +58 -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/runtime/startup.ts +3 -1
- package/src/app.tsx +23 -1
- package/src/architecture/core-builtin-allowlist.json +2 -1
- package/src/capabilities/chart-series.ts +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 +101 -27
- package/src/cli/commands/news-search.ts +24 -5
- package/src/cli/commands/overview.ts +14 -10
- package/src/cli/commands/search.ts +84 -25
- 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 +6 -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/glossary.ts +2 -1
- package/src/cli/help.ts +1 -1
- package/src/cli/history-export.ts +22 -2
- package/src/cli/history-rows.ts +189 -11
- package/src/cli/index.ts +18 -1
- package/src/cli/known-gaps.ts +51 -5
- package/src/cli/listing-arg.ts +63 -10
- 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 +49 -6
- 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 +51 -6
- package/src/components/command-bar/selection-runtime.ts +12 -29
- package/src/components/command-bar/surface/index.tsx +9 -3
- package/src/components/company-logo.tsx +2 -1
- package/src/components/layout/detached-pane-shell.tsx +2 -2
- package/src/components/layout/header.tsx +10 -5
- package/src/components/layout/market-summary.ts +25 -7
- package/src/components/layout/pane/footer/index.tsx +8 -2
- package/src/components/layout/pane/footer/model.ts +73 -6
- package/src/components/layout/pane/header.tsx +2 -2
- package/src/components/layout/pane/status-footer.ts +2 -1
- 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 +4 -2
- package/src/components/onboarding/onboarding-keyboard.ts +8 -5
- package/src/components/onboarding/onboarding-wizard.tsx +60 -26
- 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/display.tsx +16 -5
- package/src/components/ui/external-link.tsx +3 -6
- package/src/components/ui/icon.tsx +16 -3
- package/src/components/ui/logo-mark.tsx +8 -5
- package/src/components/ui/stat-grid.tsx +263 -19
- package/src/core/app-services.ts +11 -2
- package/src/data/app-persistence.ts +9 -7
- package/src/data/config/store/node.ts +11 -5
- package/src/data/config/store/normalize.ts +16 -3
- package/src/data/plugin-cache.ts +15 -0
- package/src/data/plugin-state-store.ts +81 -24
- package/src/data/profile-permissions.ts +47 -0
- package/src/data/resource-store.ts +165 -90
- package/src/data/session-store.ts +31 -8
- package/src/data/sqlite/access.ts +324 -0
- package/src/data/sqlite/checkpointer.ts +285 -0
- package/src/data/sqlite/database.ts +80 -4
- package/src/data/sqlite/retry.ts +50 -9
- package/src/data/ticker-store.ts +57 -23
- 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/market-data/realized-volatility.ts +4 -2
- 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/auto-update-node.ts +10 -6
- 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/central-bank-rates/series.ts +2 -3
- package/src/plugins/builtin/changelog/index.tsx +3 -2
- package/src/plugins/builtin/chart-composer/cli-options.ts +16 -0
- package/src/plugins/builtin/chart-composer/headless-schema.ts +10 -0
- 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 +30 -2
- package/src/plugins/builtin/chart-composer/series-expression.ts +3 -2
- package/src/plugins/builtin/chart-composer/session-range.ts +5 -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/client.ts +4 -1
- 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/client.ts +28 -2
- package/src/plugins/builtin/cot/headless.ts +4 -1
- package/src/plugins/builtin/cot/index.tsx +5 -4
- package/src/plugins/builtin/cot/model.ts +58 -7
- package/src/plugins/builtin/cot/pane.tsx +6 -2
- package/src/plugins/builtin/cpi/client.ts +6 -5
- 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/series.ts +3 -4
- package/src/plugins/builtin/credit-boards/sovr-pane.tsx +9 -4
- package/src/plugins/builtin/credit-conditions/client.ts +22 -14
- package/src/plugins/builtin/crypto-board/bitcoin-network.ts +143 -0
- package/src/plugins/builtin/crypto-board/client.ts +5 -5
- 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 +6 -4
- 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/debt-maturities/series.ts +3 -3
- 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/client.ts +6 -5
- package/src/plugins/builtin/doe/headless.ts +16 -3
- package/src/plugins/builtin/doe/index.tsx +5 -4
- package/src/plugins/builtin/doe/prices.ts +2 -3
- package/src/plugins/builtin/doe/series.ts +4 -4
- package/src/plugins/builtin/earnings/board.tsx +2 -1
- package/src/plugins/builtin/earnings/history.tsx +2 -1
- package/src/plugins/builtin/earnings-calls/calendar.tsx +10 -2
- package/src/plugins/builtin/earnings-calls/data.ts +19 -11
- package/src/plugins/builtin/earnings-calls/pane.tsx +27 -14
- 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/detail-view.tsx +16 -2
- 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/executives/data.ts +6 -1
- package/src/plugins/builtin/executives/pane.tsx +9 -21
- package/src/plugins/builtin/exposure/holdings.ts +35 -13
- package/src/plugins/builtin/exposure/index.tsx +1 -2
- package/src/plugins/builtin/fear-greed/cache.ts +4 -0
- 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/fear-greed/series.ts +6 -4
- 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 +19 -3
- 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/gpu/series.ts +2 -3
- package/src/plugins/builtin/help/index.tsx +1 -1
- package/src/plugins/builtin/holders/beneficial-view.tsx +1 -2
- 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/client.ts +4 -1
- 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/client.ts +1 -0
- package/src/plugins/builtin/market-movers/index.tsx +16 -5
- package/src/plugins/builtin/market-movers/screener.ts +23 -6
- package/src/plugins/builtin/market-movers/session-body.tsx +6 -2
- 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/money-markets/series.ts +3 -5
- 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/gas-client.ts +2 -1
- package/src/plugins/builtin/power/index.tsx +1 -2
- package/src/plugins/builtin/power/prices-client.ts +3 -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/risk-factors/data.ts +8 -4
- package/src/plugins/builtin/risk-factors/index.tsx +3 -1
- package/src/plugins/builtin/risk-factors/pane.tsx +5 -8
- 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/scanner/lock-note.ts +26 -3
- 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 +73 -8
- 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/fred-points.ts +6 -1
- package/src/plugins/builtin/shared/fx-rate-freshness.ts +17 -0
- package/src/plugins/builtin/shared/pro-lock-note.ts +23 -8
- package/src/plugins/builtin/shared/series-detail-chart.tsx +4 -2
- package/src/plugins/builtin/shared/series-warning.ts +13 -4
- 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/short-volume/series.ts +2 -3
- package/src/plugins/builtin/social-mentions/client.ts +15 -10
- package/src/plugins/builtin/social-mentions/index.tsx +1 -2
- package/src/plugins/builtin/social-mentions/pane.tsx +2 -1
- package/src/plugins/builtin/social-mentions/series.ts +2 -3
- 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 +127 -29
- package/src/plugins/builtin/thirteenf/data.ts +165 -35
- package/src/plugins/builtin/thirteenf/index.tsx +2 -4
- package/src/plugins/builtin/thirteenf/model.ts +2 -0
- package/src/plugins/builtin/thirteenf/overlap-pane.tsx +5 -1
- package/src/plugins/builtin/thirteenf/pane.tsx +41 -16
- package/src/plugins/builtin/thirteenf/types.ts +14 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +22 -6
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +81 -11
- package/src/plugins/builtin/ticker-detail/financials/model.ts +35 -2
- package/src/plugins/builtin/ticker-detail/financials/ratios.ts +53 -18
- package/src/plugins/builtin/ticker-detail/headless.ts +70 -11
- 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/cache.ts +20 -8
- package/src/plugins/builtin/treasury-auctions/client.ts +3 -3
- package/src/plugins/builtin/treasury-auctions/headless.ts +3 -1
- package/src/plugins/builtin/treasury-auctions/pane.tsx +10 -4
- 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/client.ts +43 -16
- package/src/plugins/builtin/volatility/headless.ts +5 -2
- package/src/plugins/builtin/volatility/index.tsx +1 -2
- package/src/plugins/builtin/volatility/model.ts +17 -6
- package/src/plugins/builtin/volatility/pane.tsx +6 -2
- package/src/plugins/builtin/volatility/series.ts +2 -1
- 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/client.ts +4 -6
- 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 +64 -42
- 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 +5 -2
- 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/detached-windows.ts +23 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +12 -3
- 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/attention.ts +54 -0
- package/src/renderers/electrobun/bun/window/create.ts +6 -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/electrobun/view/ui-host.tsx +9 -2
- 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/resolve.ts +2 -1
- package/src/series/standalone.ts +10 -1
- package/src/series/types.ts +12 -0
- package/src/series/validate.ts +11 -2
- package/src/sources/gloomberb-cloud/fred-series.ts +5 -3
- 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 +25 -9
- package/src/telemetry/stall-reports.ts +218 -13
- package/src/test-support/outage.ts +8 -0
- package/src/test-support/preload.ts +9 -0
- package/src/tickers/company-name-listing.ts +59 -29
- package/src/tickers/company-name.ts +84 -1
- package/src/tickers/listing-fate.ts +14 -3
- package/src/tickers/saved-instrument.ts +17 -0
- package/src/tickers/search/home-listing.ts +104 -8
- package/src/tickers/search/index.ts +5 -2
- 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/market.ts +5 -3
- package/src/time-series/official-close.ts +159 -0
- package/src/time-series/price-comparison.ts +75 -8
- package/src/time-series/resolve.ts +32 -4
- 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/time-series/types.ts +7 -0
- package/src/types/config.ts +18 -2
- package/src/types/data-provider.ts +23 -0
- package/src/types/financials.ts +40 -3
- package/src/types/headless.ts +42 -3
- package/src/types/plugin.ts +32 -3
- package/src/ui/host.tsx +17 -1
- 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/financial-statements.ts +73 -16
- package/src/utils/fundamentals.ts +17 -5
- package/src/utils/futures-generic.ts +4 -4
- package/src/utils/http-proxy-upstream.ts +124 -0
- package/src/utils/lease-liabilities.ts +54 -0
- package/src/utils/main-thread-stall.ts +122 -5
- package/src/utils/perf-marks.ts +58 -12
- package/src/utils/price-history-integrity.ts +47 -1
- 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/time-series/studies.ts +0 -1628
package/src/cli/listing-arg.ts
CHANGED
|
@@ -15,9 +15,9 @@ import {
|
|
|
15
15
|
type ListingVenue,
|
|
16
16
|
} from "../tickers/listing-venues";
|
|
17
17
|
import { findUsListingOfCompany, type UsListing } from "../tickers/us-listing";
|
|
18
|
-
import { findListingOfCompanyName, isCompanyNameInput, readTerminalCodeArg, type CompanyNameListing } from "../tickers/company-name-listing";
|
|
18
|
+
import { findListingOfCompanyName, isCompanyNameInput, marksAnotherListing, readTerminalCodeArg, type CompanyNameListing } from "../tickers/company-name-listing";
|
|
19
19
|
import { movedAwayChange, startTickerChangeLookup, type MovedTickerChange } from "../tickers/ticker-changes";
|
|
20
|
-
import { lineMayHaveMoved, loadListingFate, MovedSymbolError, type ListingFate } from "../tickers/listing-fate";
|
|
20
|
+
import { lineMayHaveMoved, listingChangeLine, loadListingFate, MovedSymbolError, SUCCESSOR_CHANGE_WAIT_MS, type ListingFate } from "../tickers/listing-fate";
|
|
21
21
|
import { quotedListingName } from "../tickers/listing-name";
|
|
22
22
|
import { cliStyles } from "../utils/cli-output";
|
|
23
23
|
import { groupByCompany, namesDepositaryReceipt, sameCompany, sameListedName, shortCompanyName } from "../tickers/company-name";
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
canonicalExchange,
|
|
26
26
|
exchangeCodeVenues,
|
|
27
27
|
exchangeLabel,
|
|
28
|
+
exchangeName,
|
|
28
29
|
isKnownExchangeCode,
|
|
29
30
|
isSharedExchangeCode,
|
|
30
31
|
isUsListingExchange,
|
|
@@ -36,7 +37,7 @@ import { withMarketData } from "./scoped-context";
|
|
|
36
37
|
import { failWithFields } from "./errors";
|
|
37
38
|
import { stripStrayEdges } from "./symbol-args";
|
|
38
39
|
import { isNoProviderMessage, isNoSourceAnswer, isProviderBusy } from "../sources/provider-errors";
|
|
39
|
-
import { dashedCoinPair, exchangeLineCoinListing, isSpotCommodityOrCurrencyPair, MAJOR_COIN_NAMES } from "../utils/crypto-pair";
|
|
40
|
+
import { dashedCoinPair, exchangeLineCoinListing, isSpotCommodityOrCurrencyPair, MAJOR_COIN_NAMES, TOP_COIN_NAMES } from "../utils/crypto-pair";
|
|
40
41
|
import { boardCoinFor, primeBoardCoins } from "./board-coins";
|
|
41
42
|
import { knownGapMessage } from "./known-gaps";
|
|
42
43
|
import { currencyPairSpelling } from "../utils/currency-pair";
|
|
@@ -60,7 +61,7 @@ import {
|
|
|
60
61
|
import { listingAbroadVenue } from "../utils/sec";
|
|
61
62
|
import { savedAbroadForBareSymbol, savedUsListingOf } from "../tickers/search/bare-symbol";
|
|
62
63
|
import { listingSuffixCandidate, listingSuffixVenue, tickerHasListingSuffix } from "../sources/listing-symbols";
|
|
63
|
-
import { notTheCoinNote } from "./commands/crypto-hints";
|
|
64
|
+
import { coinElsewhereNote, notTheCoinNote } from "./commands/crypto-hints";
|
|
64
65
|
|
|
65
66
|
/** The `--exchange` option of every command that takes a ticker. */
|
|
66
67
|
export const EXCHANGE_OPTION = {
|
|
@@ -414,9 +415,15 @@ export function listingChoiceNote(
|
|
|
414
415
|
.filter((exchange) => exchange !== chosen.exchange);
|
|
415
416
|
if (others.length === 0) return null;
|
|
416
417
|
const more = others.length - MAX_OTHER_LISTINGS;
|
|
417
|
-
const named = `${others.slice(0, MAX_OTHER_LISTINGS).join(", ")}${more > 0 ? ` and ${more} more: gloom search ${symbol}` : ""}`;
|
|
418
|
+
const named = `${others.slice(0, MAX_OTHER_LISTINGS).map(venueInProse).join(", ")}${more > 0 ? ` and ${more} more: gloom search ${symbol}` : ""}`;
|
|
418
419
|
const which = others.length === 1 ? "a different company" : "different companies";
|
|
419
|
-
return `${symbol} = ${name ? `${shortCompanyName(name)}, ` : ""}${chosen.exchange} (${which} on ${named})`;
|
|
420
|
+
return `${symbol} = ${name ? `${shortCompanyName(name)}, ` : ""}${exchangeName(chosen.exchange)} (${which} on ${named})`;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/** A venue as a sentence names it, in full: "the Warsaw Stock Exchange", "Xetra", "NASDAQ" (a name that is its code). */
|
|
424
|
+
function venueInProse(code: string): string {
|
|
425
|
+
const name = exchangeName(code);
|
|
426
|
+
return /\b(?:Exchange|Bourse|Market)$/.test(name) ? `the ${name}` : name;
|
|
420
427
|
}
|
|
421
428
|
|
|
422
429
|
// Quotes of these never name a company's listing, so they are never a choice between companies.
|
|
@@ -454,6 +461,19 @@ export function coinListingNotes(
|
|
|
454
461
|
return note ? [note] : [];
|
|
455
462
|
}
|
|
456
463
|
|
|
464
|
+
/**
|
|
465
|
+
* `coinListingNotes` for each listing of a list (CORR RIOT,BTC), asked only
|
|
466
|
+
* of a bare top coin code, whose quote alone says whether it is the coin.
|
|
467
|
+
*/
|
|
468
|
+
export async function listCoinNotes(
|
|
469
|
+
listings: ReadonlyArray<Pick<CliListing, "symbol" | "exchange" | "request">>,
|
|
470
|
+
deps: Pick<ListingDeps, "dataProvider">,
|
|
471
|
+
): Promise<string[]> {
|
|
472
|
+
const bare = listings.filter((listing) => !listing.exchange && TOP_COIN_NAMES.has(listing.symbol));
|
|
473
|
+
const quotes = await Promise.all(bare.map((listing) => loadListingQuote(deps.dataProvider, listing)));
|
|
474
|
+
return bare.flatMap((listing, index) => coinListingNotes(listing, quotes[index]));
|
|
475
|
+
}
|
|
476
|
+
|
|
457
477
|
/**
|
|
458
478
|
* `listingChoiceNote` for a listing a command resolved, from the quote it was
|
|
459
479
|
* read on: only a bare symbol went where the data service chose. A named
|
|
@@ -636,8 +656,12 @@ function describeOtherListings(
|
|
|
636
656
|
// Every other listing was asked and had nothing: they are named as such, with nothing to try.
|
|
637
657
|
const heading = choose ? "Listings" : lines.length === 0 ? `No ${request.noun} on its other listings either` : "Other listings";
|
|
638
658
|
const named = lines.length === 0 ? without : offered;
|
|
639
|
-
const
|
|
659
|
+
const listed = lines.length === 0 ? `${heading}: ${without.map((venue) => venueKey(listing.symbol, venue)).join(", ")}.`
|
|
640
660
|
: lines.length === 1 ? `${heading}: ${lines[0]}` : [`${heading}:`, ...lines.map((line) => ` ${line}`)].join("\n");
|
|
661
|
+
// A top coin's code (HYPE, SOL) none of the listings is: the coin may be what was meant.
|
|
662
|
+
const coin = coinElsewhereNote(listing.symbol, [...resolved ? [resolved] : [], ...others]
|
|
663
|
+
.map((venue) => ({ key: venueKey(listing.symbol, venue), name: venue.name })));
|
|
664
|
+
const details = coin ? `${listed}\n${coin}` : listed;
|
|
641
665
|
return {
|
|
642
666
|
// The symbol went to no venue, so none of them is said to lack the data.
|
|
643
667
|
message: choose
|
|
@@ -786,6 +810,11 @@ export interface ReadListing {
|
|
|
786
810
|
name: string | null;
|
|
787
811
|
/** A bare coin ticker read as a listing that is not the coin (`coinListingNotes`); null otherwise. */
|
|
788
812
|
coinNote: string | null;
|
|
813
|
+
/**
|
|
814
|
+
* What became of the company that had the symbol, as `quote` says it ("GOGL was Golden Ocean Group until
|
|
815
|
+
* 2025, now Cmb.Tech: CMBT"), when asked for (`successor`); null otherwise.
|
|
816
|
+
*/
|
|
817
|
+
successorNote?: string | null;
|
|
789
818
|
}
|
|
790
819
|
|
|
791
820
|
/**
|
|
@@ -801,13 +830,19 @@ export async function readBareListing(
|
|
|
801
830
|
symbol: string,
|
|
802
831
|
deps: ListingDeps,
|
|
803
832
|
request: ListingDataRequest,
|
|
804
|
-
|
|
833
|
+
/** `successor`: also say what became of the company that had the symbol, looked up beside its quote. */
|
|
834
|
+
{ refresh = false, successor = false }: { refresh?: boolean; successor?: boolean } = {},
|
|
805
835
|
): Promise<ReadListing | null> {
|
|
806
836
|
const listing = await resolveCliListing(symbol, null, deps);
|
|
807
837
|
if (listing.exchange) return null;
|
|
838
|
+
const changes = successor ? startTickerChangeLookup(deps.dataProvider, listing.symbol, listing.exchange) : null;
|
|
808
839
|
const answer = await loadListingQuoteAnswer(deps.dataProvider, listing);
|
|
809
840
|
if (answer.quote) {
|
|
810
|
-
|
|
841
|
+
const successorNote = changes
|
|
842
|
+
? listingChangeLine(await loadListingFate(listing, deps.dataProvider, { quote: answer.quote, changes, graceMs: SUCCESSOR_CHANGE_WAIT_MS }))
|
|
843
|
+
: null;
|
|
844
|
+
return { symbol: listing.symbol, exchange: listing.request.exchange, name: answer.quote.name?.trim() || null, coinNote: coinListingNotes(listing, answer.quote)[0] ?? null,
|
|
845
|
+
...successorNote ? { successorNote } : {} };
|
|
811
846
|
}
|
|
812
847
|
if (!isNoProviderError(answer.error)) return null;
|
|
813
848
|
const other = await quoteBareListing(listing, deps, request, { refresh });
|
|
@@ -861,10 +896,12 @@ export function listingFateLoader(
|
|
|
861
896
|
listing: Pick<CliListing, "symbol" | "exchange" | "request">,
|
|
862
897
|
deps: Pick<ListingDeps, "dataProvider">,
|
|
863
898
|
quote: Promise<Quote | null>,
|
|
899
|
+
/** `successor`: the command says what became of the company too (GOGL's merger), so the lookup is waited for. */
|
|
900
|
+
{ successor = false }: { successor?: boolean } = {},
|
|
864
901
|
): () => Promise<ListingFate> {
|
|
865
902
|
const changes = startTickerChangeLookup(deps.dataProvider, listing.symbol, listing.exchange);
|
|
866
903
|
let fate: Promise<ListingFate> | null = null;
|
|
867
|
-
return () => fate ??= loadListingFate(listing, deps.dataProvider, { quote, changes });
|
|
904
|
+
return () => fate ??= loadListingFate(listing, deps.dataProvider, { quote, changes, ...successor ? { graceMs: SUCCESSOR_CHANGE_WAIT_MS } : {} });
|
|
868
905
|
}
|
|
869
906
|
|
|
870
907
|
/**
|
|
@@ -1338,6 +1375,22 @@ export async function oneWordCompanyName(typed: string, deps: Pick<ListingDeps,
|
|
|
1338
1375
|
return found ? companyListingArg(typed, found) : null;
|
|
1339
1376
|
}
|
|
1340
1377
|
|
|
1378
|
+
/**
|
|
1379
|
+
* A word the service marks as a company's name (`searchAliases`), read as
|
|
1380
|
+
* that company's listing as `oneWordCompanyName` reads a word, for a bare
|
|
1381
|
+
* symbol no source quotes, before it is read on the symbol's listings abroad:
|
|
1382
|
+
* "siemens" is SIE on XETRA (Siemens AG), not SIEMENS on NSE (Siemens Ltd.).
|
|
1383
|
+
* Null when the service marks no listing with the word, or marks the word's
|
|
1384
|
+
* own symbol, and when search names no company or is too busy to say.
|
|
1385
|
+
*/
|
|
1386
|
+
export async function serviceNamedCompany(typed: string, deps: Pick<ListingDeps, "dataProvider">): Promise<ListingArg | null> {
|
|
1387
|
+
// Most symbols are no company's name: one search says so before any listing is weighed or quoted.
|
|
1388
|
+
if (!ONE_WORD_NAME.test(typed.trim()) || !await marksAnotherListing(deps.dataProvider, typed)) return null;
|
|
1389
|
+
const found = await findOneWordCompany(typed, deps);
|
|
1390
|
+
if (!found?.named || found.symbol.toUpperCase() === typed.trim().toUpperCase()) return null;
|
|
1391
|
+
return companyListingArg(typed, found);
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1341
1394
|
/** The company `oneWordCompanyName` reads a word as, before it is read as a listing. */
|
|
1342
1395
|
async function findOneWordCompany(typed: string, deps: Pick<ListingDeps, "dataProvider">): Promise<CompanyNameListing | null> {
|
|
1343
1396
|
const word = typed.trim();
|
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
|
},
|