@gloom-sh/terminal 0.18.5 → 0.19.1
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/package.json +1 -1
- package/patches/electrobun@1.18.1.patch +163 -8
- package/src/api-client/app-attention.ts +3 -0
- package/src/api-client/beneficial-owners.ts +3 -0
- package/src/api-client/company-kpis.ts +3 -0
- package/src/api-client/cot.ts +6 -2
- package/src/api-client/credit-documents.ts +6 -0
- package/src/api-client/data.ts +19 -7
- package/src/api-client/equity-screener.ts +24 -0
- package/src/api-client/fund-facts.ts +45 -4
- package/src/api-client/hiring.ts +3 -0
- package/src/api-client/index.ts +15 -0
- package/src/api-client/ipo.ts +24 -1
- package/src/api-client/market-discovery.ts +10 -0
- package/src/api-client/market-movers.ts +7 -0
- package/src/api-client/members.ts +1 -1
- package/src/api-client/mna.ts +3 -0
- package/src/api-client/paths.ts +9 -1
- package/src/api-client/perps.ts +43 -0
- package/src/api-client/research-activity.ts +3 -2
- package/src/api-client/roadmap.ts +85 -0
- package/src/api-client/types.ts +82 -2
- package/src/app/pane-runtime/plugin-bindings.ts +9 -5
- package/src/app/runtime/broker-import.ts +0 -2
- package/src/app/runtime/plugin-bindings.ts +73 -56
- package/src/architecture/core-builtin-allowlist.json +2 -2
- package/src/architecture/pane-tabs-allowlist.json +3 -0
- package/src/architecture/ttl-caches-allowlist.json +19 -0
- package/src/brokers/sync-broker-instance.ts +2 -8
- package/src/capabilities/chart-series.ts +1 -1
- package/src/cli/commands/crypto-hints.ts +40 -24
- package/src/cli/commands/market.ts +107 -38
- package/src/cli/commands/news-search.ts +22 -0
- package/src/cli/commands/options-chain.ts +48 -7
- package/src/cli/commands/options-leaps.ts +9 -3
- package/src/cli/commands/overview.ts +147 -32
- package/src/cli/commands/search.ts +21 -1
- package/src/cli/commands/themes.ts +11 -2
- package/src/cli/commands/ticker.ts +87 -36
- package/src/cli/company-name-hint.ts +41 -0
- package/src/cli/earnings-calendar.ts +1 -1
- package/src/cli/errors.ts +25 -2
- package/src/cli/glossary.ts +31 -2
- package/src/cli/history-rows.ts +57 -9
- package/src/cli/index-roots.ts +0 -7
- package/src/cli/index.ts +2 -0
- package/src/cli/listing-arg.ts +235 -60
- package/src/cli/output-file.ts +68 -0
- package/src/cli/pane-functions/capabilities.ts +4 -0
- package/src/cli/pane-functions/catalog.ts +80 -7
- package/src/cli/pane-functions/discovery.ts +21 -1
- package/src/cli/pane-functions/dom.ts +13 -3
- package/src/cli/pane-functions/freshness.ts +93 -4
- package/src/cli/pane-functions/function-help.ts +20 -10
- package/src/cli/pane-functions/headless.ts +17 -7
- package/src/cli/pane-functions/index.ts +54 -16
- package/src/cli/pane-functions/market-session.ts +66 -4
- package/src/cli/pane-functions/options.ts +19 -1
- package/src/cli/pane-functions/resolver.ts +19 -8
- package/src/cli/pane-functions/screenshot-assessment.ts +6 -4
- package/src/cli/pane-functions/screenshot-types.ts +5 -0
- package/src/cli/quote-answer.ts +22 -11
- package/src/cli/saved-copy-persistence.ts +88 -0
- package/src/cli/ticker-resolution.ts +3 -2
- package/src/components/chart/composite/composite-chart.tsx +4 -0
- package/src/components/chart/composite/interactions.ts +6 -0
- package/src/components/chart/composite/legend.tsx +45 -7
- package/src/components/chart/composite/panel-gestures.ts +33 -0
- package/src/components/chart/composite/panel-surface.tsx +52 -3
- package/src/components/chart/composite/rasterizer.ts +24 -13
- package/src/components/chart/composite/scene.ts +39 -4
- package/src/components/chart/composite/series-cues.ts +14 -0
- package/src/components/chart/composite/text-renderer.ts +9 -2
- package/src/components/chart/composite/tool-catalog.ts +36 -0
- package/src/components/chart/composite/tools.ts +203 -44
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +11 -4
- package/src/components/command-bar/assist/inventory.ts +2 -1
- package/src/components/command-bar/commands/direct/index.ts +28 -13
- package/src/components/command-bar/list/model.ts +5 -0
- package/src/components/command-bar/pane-templates/items.ts +3 -2
- package/src/components/command-bar/routes/root/runtime.ts +6 -7
- package/src/components/command-bar/selection-runtime.ts +52 -3
- package/src/components/command-bar/surface/index.tsx +2 -0
- package/src/components/command-bar/workflow/collection-actions.ts +3 -3
- package/src/components/layout/pane/capture-stamp.ts +2 -2
- package/src/components/layout/pane/footer/index.tsx +22 -6
- package/src/components/layout/pane/footer/model.ts +83 -15
- package/src/components/layout/pane/status-footer.ts +35 -2
- package/src/components/layout/status-widget-space.ts +9 -0
- package/src/components/onboarding/onboarding-wizard.tsx +4 -1
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +12 -7
- package/src/components/onboarding/wizard-broker-sync.ts +0 -1
- package/src/components/onboarding/wizard-positions.ts +3 -3
- package/src/components/ticker/list-table-view.tsx +8 -21
- package/src/components/ui/choice-dialog.tsx +23 -18
- package/src/components/ui/choice-groups.ts +18 -0
- package/src/components/ui/data-table/opentui/index.tsx +9 -7
- package/src/components/ui/data-table/opentui/model.ts +26 -1
- package/src/components/ui/data-table/types.ts +2 -0
- package/src/components/ui/display.tsx +18 -3
- package/src/components/ui/icon.tsx +4 -1
- package/src/components/ui/list-view.tsx +8 -4
- package/src/components/ui/query-bar-keys.tsx +2 -0
- package/src/components/ui/query-bar.tsx +1 -0
- package/src/components/ui/select-button.tsx +5 -1
- package/src/components/ui/select-field.tsx +1 -0
- package/src/components/ui/table-layout.ts +8 -5
- package/src/core/app-runtime.ts +2 -0
- package/src/core/app-services.ts +2 -2
- package/src/data/config/chart-settings.ts +1 -1
- package/src/data/json-ticker-repository.ts +17 -8
- package/src/data/plugin-cache.ts +5 -3
- package/src/data/saved-copies.ts +8 -0
- package/src/data/ticker-repository.ts +16 -9
- package/src/data/ticker-writes.ts +81 -0
- package/src/data/ttl-cache.ts +165 -0
- package/src/docs/snapshot.json +103 -142
- package/src/i18n/es.ts +20 -6
- package/src/i18n/ja.ts +20 -6
- package/src/i18n/ko.ts +20 -6
- package/src/i18n/zh-cn.ts +20 -6
- package/src/i18n/zh-tw.ts +20 -6
- package/src/market-data/depositary-pair.ts +27 -3
- package/src/market-data/fund-facts.ts +50 -0
- package/src/market-data/market/change-basis.ts +16 -3
- package/src/market-data/market/format.ts +25 -0
- package/src/market-data/market/freshness.ts +2 -1
- package/src/market-data/options-alternatives.ts +81 -4
- package/src/market-data/quotes/metadata.ts +7 -0
- package/src/news/aggregator.ts +119 -9
- package/src/news/cloud-session.ts +21 -0
- package/src/news/hooks.ts +1 -0
- package/src/news/news-model.ts +1 -0
- package/src/news/types.ts +17 -0
- package/src/plugins/builtin/alerts/alert-engine.ts +20 -1
- package/src/plugins/builtin/alerts/alert-log.ts +33 -0
- package/src/plugins/builtin/alerts/calendar-events.ts +10 -4
- package/src/plugins/builtin/alerts/cli-forms.ts +216 -0
- package/src/plugins/builtin/alerts/cli.ts +362 -80
- package/src/plugins/builtin/alerts/command.ts +25 -1
- package/src/plugins/builtin/alerts/event-rows.ts +24 -3
- package/src/plugins/builtin/alerts/events-pane.tsx +34 -10
- package/src/plugins/builtin/alerts/fired-log.ts +73 -9
- package/src/plugins/builtin/alerts/format.ts +75 -5
- package/src/plugins/builtin/alerts/headless.ts +34 -12
- package/src/plugins/builtin/alerts/history-rows.ts +3 -2
- package/src/plugins/builtin/alerts/history.ts +1 -1
- package/src/plugins/builtin/alerts/index.tsx +79 -16
- package/src/plugins/builtin/alerts/metric-command.ts +77 -4
- package/src/plugins/builtin/alerts/metric-data.ts +54 -13
- package/src/plugins/builtin/alerts/metric-model.ts +163 -14
- package/src/plugins/builtin/alerts/metric-parity-fixture.json +1 -1
- package/src/plugins/builtin/alerts/pane.tsx +61 -23
- package/src/plugins/builtin/alerts/quotes.ts +6 -0
- package/src/plugins/builtin/alerts/storage.ts +12 -8
- package/src/plugins/builtin/alerts/types.ts +4 -0
- package/src/plugins/builtin/analytics/index.tsx +2 -1
- package/src/plugins/builtin/analytics/risk-client.ts +16 -5
- package/src/plugins/builtin/analytics/risk-fx.ts +70 -15
- package/src/plugins/builtin/analytics/risk-headless.ts +27 -0
- package/src/plugins/builtin/analytics/risk-model.ts +55 -9
- package/src/plugins/builtin/analytics/risk-pane.tsx +8 -2
- package/src/plugins/builtin/attention/index.tsx +2 -1
- package/src/plugins/builtin/attention/listing.ts +14 -0
- package/src/plugins/builtin/broker-manager/index.tsx +7 -3
- package/src/plugins/builtin/buildout/cells.tsx +12 -4
- package/src/plugins/builtin/buildout/format.ts +38 -0
- package/src/plugins/builtin/buildout/model/normalizers.ts +36 -1
- package/src/plugins/builtin/buildout/pane/index.tsx +4 -1
- package/src/plugins/builtin/buildout/table-model.ts +23 -2
- package/src/plugins/builtin/builtin-plugin-meta.ts +6 -2
- package/src/plugins/builtin/cds/client.ts +142 -30
- package/src/plugins/builtin/cds/headless.ts +35 -8
- package/src/plugins/builtin/cds/model.ts +145 -18
- package/src/plugins/builtin/cds/pane.tsx +16 -5
- package/src/plugins/builtin/changelog/index.tsx +9 -6
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +3 -0
- package/src/plugins/builtin/chart-composer/cli-options.ts +4 -0
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +7 -0
- package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -2
- package/src/plugins/builtin/chart-composer/follow-binding.ts +14 -2
- package/src/plugins/builtin/chart-composer/headless-schema.ts +7 -1
- package/src/plugins/builtin/chart-composer/headless.ts +6 -1
- package/src/plugins/builtin/chart-composer/index.tsx +5 -6
- package/src/plugins/builtin/chart-composer/pane.tsx +37 -8
- package/src/plugins/builtin/chart-composer/settings.ts +27 -0
- package/src/plugins/builtin/chat/content/command-suggestions.ts +1 -0
- package/src/plugins/builtin/chat/controller/index.ts +5 -1
- package/src/plugins/builtin/chat/controller/notifications.ts +33 -3
- package/src/plugins/builtin/chat/controller/state.ts +25 -2
- package/src/plugins/builtin/chat/controller/unread-people.ts +89 -23
- package/src/plugins/builtin/chat/controller/utils.ts +7 -2
- package/src/plugins/builtin/chat/pane-links/commands.ts +7 -1
- package/src/plugins/builtin/chat/status-preview.ts +79 -0
- package/src/plugins/builtin/chat/status-widget.tsx +147 -10
- package/src/plugins/builtin/chat/unread-badge.ts +51 -10
- package/src/plugins/builtin/clinical-trials/client.ts +49 -4
- package/src/plugins/builtin/clinical-trials/model.ts +86 -31
- package/src/plugins/builtin/clinical-trials/pane.tsx +61 -49
- package/src/plugins/builtin/clinical-trials/sponsor-listing.ts +90 -0
- package/src/plugins/builtin/clinical-trials/sponsor-tickers.ts +95 -15
- package/src/plugins/builtin/clinical-trials/trial-pages.ts +50 -0
- package/src/plugins/builtin/cloud/askg/manifest.ts +2 -0
- package/src/plugins/builtin/company-attention/building.tsx +5 -1
- package/src/plugins/builtin/company-attention/client.ts +8 -9
- package/src/plugins/builtin/company-attention/evidence.ts +4 -1
- package/src/plugins/builtin/company-attention/headless.ts +2 -1
- package/src/plugins/builtin/company-attention/moves.tsx +5 -1
- package/src/plugins/builtin/company-attention/pane.tsx +12 -2
- package/src/plugins/builtin/company-attention/signals.tsx +5 -1
- package/src/plugins/builtin/company-kpis/headless.ts +8 -3
- package/src/plugins/builtin/company-kpis/model.ts +73 -5
- package/src/plugins/builtin/company-kpis/pane.tsx +15 -7
- package/src/plugins/builtin/composite-plugins.ts +2 -1
- package/src/plugins/builtin/correlation/headless.ts +13 -5
- package/src/plugins/builtin/correlation/history.ts +22 -0
- package/src/plugins/builtin/cot/client.ts +22 -18
- package/src/plugins/builtin/cot/headless.ts +15 -10
- package/src/plugins/builtin/cot/model.ts +14 -1
- package/src/plugins/builtin/cot/pane.tsx +22 -14
- package/src/plugins/builtin/credit-boards/client.ts +6 -10
- package/src/plugins/builtin/credit-conditions/headless.ts +8 -2
- package/src/plugins/builtin/credit-conditions/index.tsx +5 -1
- package/src/plugins/builtin/credit-conditions/model.ts +4 -0
- package/src/plugins/builtin/credit-conditions/series.ts +3 -1
- package/src/plugins/builtin/credit-documents/detail.tsx +2 -2
- package/src/plugins/builtin/credit-documents/export.ts +173 -0
- package/src/plugins/builtin/credit-documents/headless.ts +10 -10
- package/src/plugins/builtin/credit-documents/model.ts +104 -14
- package/src/plugins/builtin/credit-documents/pane.tsx +12 -5
- package/src/plugins/builtin/custom-view/sources.ts +2 -0
- package/src/plugins/builtin/dividend-yield/client.ts +131 -23
- package/src/plugins/builtin/dividend-yield/headless.ts +44 -16
- package/src/plugins/builtin/dividend-yield/model.ts +8 -5
- package/src/plugins/builtin/dividend-yield/pane.tsx +38 -13
- package/src/plugins/builtin/dividend-yield/ranking.ts +37 -14
- package/src/plugins/builtin/dividend-yield/types.ts +20 -2
- package/src/plugins/builtin/dividend-yield/view.ts +30 -2
- package/src/plugins/builtin/docs/targets.ts +5 -1
- package/src/plugins/builtin/doe/headless.ts +3 -2
- package/src/plugins/builtin/doe/pane.tsx +13 -3
- package/src/plugins/builtin/earnings/board-model.ts +16 -15
- package/src/plugins/builtin/earnings/board.tsx +62 -71
- package/src/plugins/builtin/earnings/headless.ts +40 -4
- package/src/plugins/builtin/earnings/scope.ts +31 -43
- package/src/plugins/builtin/earnings-calls/calendar.tsx +2 -2
- package/src/plugins/builtin/earnings-calls/data.ts +18 -6
- package/src/plugins/builtin/earnings-calls/format.ts +31 -2
- package/src/plugins/builtin/earnings-calls/headless.ts +20 -5
- package/src/plugins/builtin/earnings-calls/model.ts +6 -1
- package/src/plugins/builtin/earnings-calls/pane.tsx +12 -4
- package/src/plugins/builtin/econ/calendar-model.ts +48 -1
- package/src/plugins/builtin/econ/calendar-source.ts +4 -2
- package/src/plugins/builtin/econ/detail-view.tsx +2 -2
- package/src/plugins/builtin/econ/figures.ts +48 -0
- package/src/plugins/builtin/econ/index.tsx +14 -5
- package/src/plugins/builtin/econ/print-watch.ts +3 -1
- package/src/plugins/builtin/econ/types.ts +2 -0
- package/src/plugins/builtin/econ-statistics/client.ts +11 -0
- package/src/plugins/builtin/econ-statistics/defs.ts +6 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +16 -6
- package/src/plugins/builtin/econ-statistics/pane.tsx +8 -4
- package/src/plugins/builtin/econ-statistics/stats.ts +39 -9
- package/src/plugins/builtin/equity-screener/categories.ts +179 -0
- package/src/plugins/builtin/equity-screener/client.ts +4 -2
- package/src/plugins/builtin/equity-screener/headless.ts +144 -13
- package/src/plugins/builtin/equity-screener/ideas.ts +49 -0
- package/src/plugins/builtin/equity-screener/model.ts +99 -10
- package/src/plugins/builtin/equity-screener/pane.tsx +68 -13
- package/src/plugins/builtin/fixed-income/pane.tsx +2 -1
- package/src/plugins/builtin/futures/use-board-terms.ts +42 -28
- package/src/plugins/builtin/futures/use-front-returns.ts +45 -28
- package/src/plugins/builtin/fx-matrix/client.ts +6 -3
- package/src/plugins/builtin/fx-matrix/headless.ts +1 -1
- package/src/plugins/builtin/fx-matrix/index.tsx +4 -2
- package/src/plugins/builtin/fx-matrix/live-legs.ts +42 -3
- package/src/plugins/builtin/gpu/headless.ts +8 -2
- package/src/plugins/builtin/help/function-index.ts +4 -1
- package/src/plugins/builtin/help/index.tsx +62 -59
- package/src/plugins/builtin/help/shortcut-model.ts +1 -1
- package/src/plugins/builtin/help/shortcut-table.tsx +5 -6
- package/src/plugins/builtin/help/table-cells.tsx +13 -2
- package/src/plugins/builtin/holders/beneficial-client.ts +5 -1
- package/src/plugins/builtin/holders/beneficial-view.tsx +3 -0
- package/src/plugins/builtin/holders/fund-holders.ts +51 -0
- package/src/plugins/builtin/holders/headless.ts +22 -3
- package/src/plugins/builtin/holders/pane.tsx +3 -0
- package/src/plugins/builtin/holders/report-rows.ts +4 -1
- package/src/plugins/builtin/insider/headless.ts +2 -2
- package/src/plugins/builtin/ipo-calendar/client.ts +18 -2
- package/src/plugins/builtin/ipo-calendar/headless.ts +75 -11
- package/src/plugins/builtin/ipo-calendar/listing-ipo.ts +160 -0
- package/src/plugins/builtin/ipo-calendar/model.ts +98 -2
- package/src/plugins/builtin/iv-history/client.ts +52 -11
- package/src/plugins/builtin/iv-history/format.ts +36 -23
- package/src/plugins/builtin/iv-history/headless.ts +33 -18
- package/src/plugins/builtin/iv-history/index.tsx +2 -2
- package/src/plugins/builtin/iv-history/model.ts +163 -27
- package/src/plugins/builtin/iv-history/pane.tsx +10 -6
- package/src/plugins/builtin/iv-history/screen-pane.tsx +22 -15
- package/src/plugins/builtin/iv-history/universe.ts +5 -1
- package/src/plugins/builtin/jobs/client.ts +25 -29
- package/src/plugins/builtin/kelly-sizer/model.ts +12 -8
- package/src/plugins/builtin/kelly-sizer/pane.tsx +9 -9
- package/src/plugins/builtin/kelly-sizer/sections.tsx +19 -10
- package/src/plugins/builtin/kelly-sizer/types.ts +10 -4
- package/src/plugins/builtin/macro-day/headless.ts +12 -5
- package/src/plugins/builtin/macro-day/index.tsx +1 -1
- package/src/plugins/builtin/macro-day/model.ts +39 -5
- package/src/plugins/builtin/macro-day/pane.tsx +27 -19
- package/src/plugins/builtin/macro-day/release-table.ts +2 -2
- package/src/plugins/builtin/market-heatmap/data.ts +8 -33
- package/src/plugins/builtin/market-movers/client.ts +27 -7
- package/src/plugins/builtin/market-movers/headless.ts +34 -12
- package/src/plugins/builtin/market-movers/index.tsx +26 -14
- package/src/plugins/builtin/market-movers/min-float.ts +74 -0
- package/src/plugins/builtin/market-movers/model.ts +4 -1
- package/src/plugins/builtin/market-movers/screener.ts +22 -4
- package/src/plugins/builtin/market-movers/session-body.tsx +13 -8
- package/src/plugins/builtin/market-movers/session-table.ts +4 -3
- package/src/plugins/builtin/market-movers/table.ts +17 -5
- package/src/plugins/builtin/members/breadth-pane.tsx +2 -1
- package/src/plugins/builtin/mna/headless.ts +2 -0
- package/src/plugins/builtin/mna/pane.tsx +3 -1
- package/src/plugins/builtin/news/headless.ts +3 -1
- package/src/plugins/builtin/news/index.tsx +4 -0
- package/src/plugins/builtin/news/wire/categories.ts +19 -3
- package/src/plugins/builtin/news/wire/industry-pane.tsx +1 -0
- package/src/plugins/builtin/news/wire/news/footer.ts +31 -5
- package/src/plugins/builtin/news/wire/news/preset-pane.tsx +6 -1
- package/src/plugins/builtin/news/wire/news/table.tsx +2 -2
- package/src/plugins/builtin/openfda/client.ts +14 -2
- package/src/plugins/builtin/openfda/index.tsx +3 -2
- package/src/plugins/builtin/openfda/model.ts +9 -0
- package/src/plugins/builtin/openfda/pane.tsx +42 -6
- package/src/plugins/builtin/options/analytics.ts +29 -5
- package/src/plugins/builtin/options/enrichment.ts +17 -5
- package/src/plugins/builtin/options/table.ts +5 -2
- package/src/plugins/builtin/options/types.ts +2 -0
- package/src/plugins/builtin/options/view.tsx +17 -4
- package/src/plugins/builtin/options-positioning/client.ts +11 -0
- package/src/plugins/builtin/options-positioning/headless.ts +21 -8
- package/src/plugins/builtin/options-positioning/index.tsx +1 -1
- package/src/plugins/builtin/options-positioning/model.ts +78 -9
- package/src/plugins/builtin/options-positioning/pane.tsx +21 -6
- package/src/plugins/builtin/options-scenario/client.ts +116 -47
- package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +142 -10
- package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +206 -55
- package/src/plugins/builtin/options-scenario/csp-screen.ts +63 -23
- package/src/plugins/builtin/options-scenario/csp.ts +8 -2
- package/src/plugins/builtin/options-scenario/index.tsx +9 -7
- package/src/plugins/builtin/options-scenario/strategy-screen.ts +532 -0
- package/src/plugins/builtin/pe-band/model.ts +12 -49
- package/src/plugins/builtin/perps/cascade-tabs.tsx +161 -0
- package/src/plugins/builtin/perps/cascade.ts +236 -0
- package/src/plugins/builtin/perps/client.ts +56 -2
- package/src/plugins/builtin/perps/headless.ts +65 -9
- package/src/plugins/builtin/perps/index.tsx +7 -5
- package/src/plugins/builtin/perps/model.ts +18 -4
- package/src/plugins/builtin/perps/pane.tsx +19 -22
- package/src/plugins/builtin/perps/status-line.ts +25 -0
- package/src/plugins/builtin/plugin-module.ts +5 -1
- package/src/plugins/builtin/portfolio-list/cached-account.ts +3 -1
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +2 -8
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +4 -4
- package/src/plugins/builtin/portfolio-list/cli/render.ts +7 -5
- package/src/plugins/builtin/portfolio-list/pane/futures-front.ts +40 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +6 -7
- package/src/plugins/builtin/portfolio-list/pane/streaming.ts +5 -2
- package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +3 -2
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +0 -14
- package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +5 -2
- package/src/plugins/builtin/portfolio-list/table.tsx +15 -9
- package/src/plugins/builtin/primary-dealers/client.ts +13 -38
- package/src/plugins/builtin/realized-vol/client.ts +13 -5
- package/src/plugins/builtin/realized-vol/evidence.ts +29 -4
- package/src/plugins/builtin/realized-vol/headless.ts +8 -4
- package/src/plugins/builtin/realized-vol/index.tsx +2 -2
- package/src/plugins/builtin/realized-vol/model.ts +37 -6
- package/src/plugins/builtin/realized-vol/pane.tsx +11 -9
- package/src/plugins/builtin/relative-rotation/client.ts +18 -4
- package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
- package/src/plugins/builtin/relative-rotation/index.tsx +2 -1
- package/src/plugins/builtin/relative-rotation/model.ts +16 -40
- package/src/plugins/builtin/relative-rotation/pane.tsx +3 -2
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +3 -2
- package/src/plugins/builtin/research/event-model.ts +40 -12
- package/src/plugins/builtin/research/headless.ts +1 -1
- package/src/plugins/builtin/research/index.tsx +7 -3
- package/src/plugins/builtin/research/relative-valuation-headless.ts +13 -26
- package/src/plugins/builtin/research/relative-valuation-model.ts +31 -3
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +59 -20
- package/src/plugins/builtin/research/relative-valuation-peers.ts +217 -20
- package/src/plugins/builtin/research/relative-valuation-settings.ts +44 -0
- package/src/plugins/builtin/reverse-dcf/headless.ts +5 -3
- package/src/plugins/builtin/reverse-dcf/model.ts +61 -6
- package/src/plugins/builtin/reverse-dcf/pane.tsx +7 -4
- package/src/plugins/builtin/risk-factors/data.ts +4 -2
- package/src/plugins/builtin/risk-factors/headless.ts +5 -2
- package/src/plugins/builtin/roadmap/index.tsx +28 -0
- package/src/plugins/builtin/roadmap/model.ts +67 -0
- package/src/plugins/builtin/roadmap/pane.tsx +244 -0
- package/src/plugins/builtin/scanner/flow-model.ts +50 -4
- package/src/plugins/builtin/scanner/flow-pane.tsx +367 -65
- package/src/plugins/builtin/scanner/flow-session.ts +146 -0
- package/src/plugins/builtin/scanner/headless.ts +204 -35
- package/src/plugins/builtin/scanner/index.ts +16 -5
- package/src/plugins/builtin/scanner/live-headless.ts +48 -5
- package/src/plugins/builtin/scanner/live-model.ts +11 -0
- package/src/plugins/builtin/scanner/live-pane.tsx +3 -3
- package/src/plugins/builtin/scanner/lock-note.ts +3 -2
- package/src/plugins/builtin/seasonality/headless.ts +10 -1
- package/src/plugins/builtin/sec/fund-facts-view.tsx +5 -2
- package/src/plugins/builtin/sec/fund-facts.ts +116 -34
- package/src/plugins/builtin/sec/headless.ts +4 -2
- package/src/plugins/builtin/sec/index.tsx +3 -0
- package/src/plugins/builtin/series-inventory.ts +2 -0
- package/src/plugins/builtin/shared/cloud-resource.ts +16 -7
- package/src/plugins/builtin/shared/cloud-upgrade.ts +4 -3
- package/src/plugins/builtin/shared/earnings-calendar.ts +6 -2
- package/src/plugins/builtin/shared/earnings-report.ts +2 -2
- package/src/plugins/builtin/shared/headless-market-data.ts +2 -2
- package/src/plugins/builtin/shared/job-posting.ts +1 -0
- package/src/plugins/builtin/shared/members-menu.tsx +3 -2
- package/src/plugins/builtin/shared/pro-lock-note.ts +12 -12
- package/src/plugins/builtin/shared/report-freshness.ts +11 -2
- package/src/plugins/builtin/shared/research-cells.tsx +1 -1
- package/src/plugins/builtin/shared/series-cache.ts +4 -4
- package/src/plugins/builtin/shared/ticker-choice.tsx +2 -1
- package/src/plugins/builtin/shared/ticker-company.ts +77 -0
- package/src/plugins/builtin/shared/use-quote-board.ts +2 -1
- package/src/plugins/builtin/shared/volatility/live-session.ts +34 -8
- package/src/plugins/builtin/shared/volatility/pricing.ts +19 -0
- package/src/plugins/builtin/shared/wall-view-lifecycle.ts +3 -1
- package/src/plugins/builtin/themes/model.ts +16 -7
- package/src/plugins/builtin/themes/pane.tsx +5 -5
- package/src/plugins/builtin/thirteenf/api.ts +12 -1
- package/src/plugins/builtin/thirteenf/data.ts +7 -7
- package/src/plugins/builtin/thirteenf/headless.ts +31 -4
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +43 -18
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +3 -2
- package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +62 -0
- package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +83 -46
- package/src/plugins/builtin/ticker-detail/headless.ts +31 -16
- package/src/plugins/builtin/ticker-detail/overview/model.ts +11 -3
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +2 -1
- package/src/plugins/builtin/ticker-detail/pane.tsx +14 -8
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +2 -1
- package/src/plugins/builtin/ticker-detail/settings.ts +1 -0
- package/src/plugins/builtin/time-sales/pane.tsx +31 -19
- package/src/plugins/builtin/treasury-auctions/headless.ts +21 -12
- package/src/plugins/builtin/treasury-auctions/pane.tsx +9 -3
- package/src/plugins/builtin/treasury-daily/client.ts +41 -5
- package/src/plugins/builtin/treasury-daily/headless.ts +2 -2
- package/src/plugins/builtin/treasury-daily/index.tsx +1 -1
- package/src/plugins/builtin/treasury-daily/model.ts +50 -3
- package/src/plugins/builtin/treasury-daily/pane.tsx +81 -2
- package/src/plugins/builtin/vol-surface/client.ts +3 -13
- package/src/plugins/builtin/vol-surface/headless.ts +3 -3
- package/src/plugins/builtin/vol-surface/index.tsx +1 -1
- package/src/plugins/builtin/vol-surface/pane.tsx +7 -5
- package/src/plugins/builtin/volatility/index.tsx +2 -2
- package/src/plugins/builtin/volatility/pane.tsx +7 -4
- package/src/plugins/builtin/world-venue-map/headless.ts +3 -3
- package/src/plugins/builtin/yield-curve/client.ts +61 -1
- package/src/plugins/builtin/yield-curve/headless.ts +9 -6
- package/src/plugins/builtin/yield-curve/index.tsx +34 -10
- package/src/plugins/builtin/yield-curve/swaps.tsx +9 -5
- package/src/plugins/catalog-browser.ts +2 -1
- package/src/plugins/catalog-manifest.ts +2 -1
- package/src/plugins/host-link.ts +1 -1
- package/src/plugins/marketplace/model.ts +18 -5
- package/src/portfolio/column-values.ts +11 -7
- package/src/portfolio/futures-positions.ts +6 -3
- package/src/portfolio/position-quantity.ts +15 -9
- package/src/remote/resources.ts +2 -1
- package/src/renderers/dom/data-table/row.tsx +26 -0
- package/src/renderers/dom/desktop/icons.tsx +7 -0
- package/src/renderers/dom/desktop/list-view.tsx +13 -10
- package/src/renderers/dom/desktop/query-bar.tsx +4 -2
- package/src/renderers/dom/desktop/select-field.tsx +4 -2
- package/src/renderers/dom/host/chart-surface.tsx +21 -0
- package/src/renderers/electrobun/bun/desktop/app-name.ts +3 -3
- package/src/renderers/electrobun/bun/desktop/backend.ts +21 -10
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +15 -0
- package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -0
- package/src/renderers/electrobun/bun/desktop/installer-folder.ts +731 -0
- package/src/renderers/electrobun/bun/desktop/relaunch.ts +102 -10
- package/src/renderers/electrobun/bun/desktop/update.ts +115 -14
- package/src/renderers/electrobun/bun/desktop/view-ids.ts +52 -0
- package/src/renderers/electrobun/bun/desktop/windows-script.ts +92 -0
- package/src/renderers/electrobun/bun/index.ts +26 -2
- package/src/renderers/electrobun/bun/window/create.ts +43 -4
- package/src/renderers/electrobun/bun/window/events.ts +20 -0
- package/src/renderers/electrobun/bun/window/windows-custom-chrome.ts +9 -2
- package/src/renderers/electrobun/bun/window/windows-native.ts +78 -0
- package/src/renderers/electrobun/bun/window/windows-quit.ts +57 -0
- package/src/renderers/electrobun/shared/app-name.ts +13 -0
- package/src/renderers/electrobun/shared/protocol.ts +12 -0
- package/src/renderers/electrobun/view/backend-rpc.ts +6 -0
- package/src/renderers/electrobun/view/main.tsx +24 -1
- package/src/renderers/electrobun/view/news-source.ts +5 -1
- package/src/renderers/electrobun/view/remote/ticker-repository.ts +14 -7
- package/src/renderers/electrobun/view/ui-host.tsx +8 -0
- package/src/renderers/electrobun/view/view-ids.ts +85 -0
- package/src/renderers/opentui/start.tsx +5 -0
- package/src/series/registry.ts +1 -0
- package/src/series/types.ts +6 -0
- package/src/series/validate.ts +1 -0
- package/src/sources/gloomberb-cloud/fred-series.ts +3 -1
- package/src/sources/gloomberb-cloud/index.ts +43 -8
- package/src/sources/gloomberb-cloud/news.ts +47 -7
- package/src/sources/provider-router/financials.ts +15 -3
- package/src/sources/provider-router/index.ts +8 -5
- package/src/state/ticker-cleanup.ts +50 -0
- package/src/sync/controller.ts +4 -3
- package/src/sync/core-contributors.ts +90 -31
- package/src/telemetry/stall-reports-dom.ts +38 -0
- package/src/telemetry/stall-reports-node.ts +75 -0
- package/src/telemetry/stall-reports.ts +214 -0
- package/src/test-support/preload.ts +14 -0
- package/src/theme/themes.ts +10 -0
- package/src/tickers/company-name-listing.ts +53 -13
- package/src/tickers/company-name.ts +50 -4
- package/src/tickers/index-roots.ts +7 -0
- package/src/tickers/listing-fate.ts +2 -2
- package/src/tickers/listing-venues.ts +15 -3
- package/src/tickers/search/index.ts +6 -2
- package/src/tickers/search/ranking.ts +5 -1
- package/src/tickers/search/upsert.ts +13 -0
- package/src/tickers/terminal-codes.ts +19 -0
- package/src/tickers/ticker-changes.ts +8 -4
- package/src/time-series/alignment.ts +1 -1
- package/src/time-series/economic.ts +18 -4
- package/src/time-series/field-catalog.ts +1 -1
- package/src/time-series/filed-trailing-eps.ts +197 -0
- package/src/time-series/fundamentals.ts +44 -1
- package/src/time-series/ice-credit.ts +3 -0
- package/src/time-series/price-comparison.ts +30 -2
- package/src/time-series/resolve-context.ts +3 -1
- package/src/time-series/resolve.ts +56 -4
- package/src/time-series/session-bar.ts +11 -0
- package/src/time-series/spec.ts +3 -2
- package/src/time-series/studies.ts +8 -2
- package/src/time-series/total-return.ts +160 -0
- package/src/time-series/transforms.ts +2 -3
- package/src/time-series/types.ts +22 -1
- package/src/types/company-from.ts +40 -0
- package/src/types/data-provider.ts +7 -0
- package/src/types/financials.ts +59 -1
- package/src/types/headless.ts +27 -3
- package/src/types/news-source.ts +1 -0
- package/src/types/plugin.ts +9 -0
- package/src/ui/host.tsx +3 -0
- package/src/updater/failure.ts +4 -1
- package/src/utils/cli-output.ts +42 -1
- package/src/utils/crypto-pair.ts +165 -7
- package/src/utils/declared-dividends.ts +1 -1
- package/src/utils/forward-dividend.ts +2 -0
- package/src/utils/fundamentals.ts +60 -8
- package/src/utils/fx-market-hours.ts +26 -3
- package/src/utils/main-thread-stall.ts +35 -2
- package/src/utils/market-capitalization.ts +24 -1
- package/src/utils/price-history.ts +7 -1
- package/src/utils/shell-word.ts +8 -0
- package/src/utils/trailing-dividend.ts +53 -4
- package/src/version.ts +2 -2
- package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +0 -17
|
@@ -79,6 +79,14 @@ function builtInPanePrefixes(paneId: string): string[] {
|
|
|
79
79
|
return command ? getCommandPrefixes(command) : [];
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
/**
|
|
83
|
+
* What a user types for a function, as the catalog lists it and every error names it: a template's
|
|
84
|
+
* shortcut or id, a pane opened by a built-in command (LAY) by that command's mnemonic, else the pane's id.
|
|
85
|
+
*/
|
|
86
|
+
export function paneFunctionCode(template: PaneTemplateDef | undefined, pane: PaneDef): string {
|
|
87
|
+
return template?.shortcut?.prefix ?? template?.id ?? builtInPanePrefixes(pane.id)[0] ?? pane.id;
|
|
88
|
+
}
|
|
89
|
+
|
|
82
90
|
function registerResolverToken(
|
|
83
91
|
lookup: Map<string, PaneTemplateDef | PaneDef>,
|
|
84
92
|
token: string | undefined,
|
|
@@ -195,7 +203,8 @@ export function nearFunctionCodes(
|
|
|
195
203
|
const near = new Map<PaneTemplateDef, string>();
|
|
196
204
|
for (const template of registry.paneTemplates.values()) {
|
|
197
205
|
const prefix = template.shortcut?.prefix;
|
|
198
|
-
|
|
206
|
+
// An unlisted function is never offered for a typo.
|
|
207
|
+
if (!prefix || template.listed === false) continue;
|
|
199
208
|
const code = [prefix, ...template.shortcut?.aliases ?? []].find((candidate) => {
|
|
200
209
|
const known = normalizeLookupToken(candidate);
|
|
201
210
|
return (!commandWord || known[0] === wanted[0]) && typoDistance(wanted, known) === 1;
|
|
@@ -215,6 +224,7 @@ export function suggestedFunctionCodes(registry: PaneFunctionCatalog, name: stri
|
|
|
215
224
|
const wanted = normalizeLookupToken(name);
|
|
216
225
|
if (!wanted) return [];
|
|
217
226
|
return [...registry.paneTemplates.values()].flatMap((template) => {
|
|
227
|
+
if (template.listed === false) return [];
|
|
218
228
|
const pane = registry.panes.get(template.paneId);
|
|
219
229
|
const words = pane ? getHeadlessPaneDefinition(template, pane)?.discovery?.suggestFor ?? [] : [];
|
|
220
230
|
const code = template.shortcut?.prefix;
|
|
@@ -277,9 +287,15 @@ async function buildTemplateCatalogEntry(
|
|
|
277
287
|
};
|
|
278
288
|
}
|
|
279
289
|
|
|
290
|
+
/**
|
|
291
|
+
* The functions `gloom catalog` and search list. An unlisted one (`listed:
|
|
292
|
+
* false`) is left out, and its pane is not listed in its place; `unlisted`
|
|
293
|
+
* keeps it, for its own help (`fn ATTN --help`).
|
|
294
|
+
*/
|
|
280
295
|
export async function buildPaneCatalogEntries(
|
|
281
296
|
registry: PaneFunctionCatalog,
|
|
282
297
|
context: MarketContext,
|
|
298
|
+
{ unlisted = false }: { unlisted?: boolean } = {},
|
|
283
299
|
): Promise<PaneCatalogEntry[]> {
|
|
284
300
|
const entries: PaneCatalogEntry[] = [];
|
|
285
301
|
const templatedPaneIds = new Set<string>();
|
|
@@ -288,6 +304,7 @@ export async function buildPaneCatalogEntries(
|
|
|
288
304
|
const pane = registry.panes.get(template.paneId);
|
|
289
305
|
if (!pane) continue;
|
|
290
306
|
templatedPaneIds.add(pane.id);
|
|
307
|
+
if (template.listed === false && !unlisted) continue;
|
|
291
308
|
entries.push(await buildTemplateCatalogEntry(template, pane, context));
|
|
292
309
|
}
|
|
293
310
|
|
|
@@ -296,7 +313,7 @@ export async function buildPaneCatalogEntries(
|
|
|
296
313
|
const [shortcut, ...aliases] = builtInPanePrefixes(pane.id);
|
|
297
314
|
const argument = paneFunctionArgument(undefined, pane);
|
|
298
315
|
entries.push({
|
|
299
|
-
token:
|
|
316
|
+
token: paneFunctionCode(undefined, pane),
|
|
300
317
|
label: pane.name,
|
|
301
318
|
description: `Open the ${pane.name} pane.`,
|
|
302
319
|
paneId: pane.id,
|
|
@@ -333,6 +350,14 @@ const ALL_WORDS_WITH_FLAGS_BAND = 1000;
|
|
|
333
350
|
const PER_MATCHED_WORD = 100;
|
|
334
351
|
/** Loose matches (no function carries every word) listed before the rest are left to a refined query. */
|
|
335
352
|
const LOOSE_MATCH_LIMIT = 5;
|
|
353
|
+
/** Loose matches a word of the query names (in the function's code, name or aliases) are all listed, up to this many. */
|
|
354
|
+
const LOOSE_NAMED_LIMIT = 8;
|
|
355
|
+
/** A query word found in what the function is called (its code, name or aliases) outweighs one found in its keywords or description. */
|
|
356
|
+
const PER_WORD_IN_NAME = 3;
|
|
357
|
+
/** A query word that begins a function's code (`vol` for VOLS, `fx` for FXC) is the start of typing it. */
|
|
358
|
+
const PER_WORD_STARTING_CODE = 3;
|
|
359
|
+
/** A query word that is one of the function's own keywords (`vol` for the volatility functions, which also say volume's) names it. */
|
|
360
|
+
const PER_WORD_IS_KEYWORD = 3;
|
|
336
361
|
|
|
337
362
|
function phraseBand(entry: PaneCatalogEntry, phrase: string): number {
|
|
338
363
|
const lower = (values: Array<string | undefined>) => values
|
|
@@ -375,6 +400,12 @@ function nameAndDescription(entry: PaneCatalogEntry): string {
|
|
|
375
400
|
return nameAndDescriptionFields(entry).join(" ");
|
|
376
401
|
}
|
|
377
402
|
|
|
403
|
+
/** What a function is called: its code, name and aliases, apart from the keywords and description that say what it covers. */
|
|
404
|
+
function identityFields(entry: PaneCatalogEntry): string[] {
|
|
405
|
+
return [entry.token, entry.label, entry.paneName, entry.shortcut, ...entry.aliases]
|
|
406
|
+
.filter((value): value is string => !!value).map((value) => value.toLowerCase().replace(/\s+/g, " "));
|
|
407
|
+
}
|
|
408
|
+
|
|
378
409
|
function flagText(entry: PaneCatalogEntry): string {
|
|
379
410
|
return [
|
|
380
411
|
entry.argKind,
|
|
@@ -394,12 +425,14 @@ interface CatalogMatchScore {
|
|
|
394
425
|
terms: number;
|
|
395
426
|
/** Those found in the function's name, keywords or description. */
|
|
396
427
|
named: number;
|
|
428
|
+
/** Those found in what the function is called: its code, name or aliases. */
|
|
429
|
+
called: number;
|
|
397
430
|
}
|
|
398
431
|
|
|
399
432
|
function scorePaneCatalogEntry(entry: PaneCatalogEntry, query: string): CatalogMatchScore {
|
|
400
433
|
const terms = queryTerms(query);
|
|
401
|
-
if (terms.length === 0) return { score: 1, terms: 0, named: 0 };
|
|
402
|
-
const none = { score: 0, terms: terms.length, named: 0 };
|
|
434
|
+
if (terms.length === 0) return { score: 1, terms: 0, named: 0, called: 0 };
|
|
435
|
+
const none = { score: 0, terms: terms.length, named: 0, called: 0 };
|
|
403
436
|
|
|
404
437
|
const exactTokens = [
|
|
405
438
|
entry.token,
|
|
@@ -414,6 +447,8 @@ function scorePaneCatalogEntry(entry: PaneCatalogEntry, query: string): CatalogM
|
|
|
414
447
|
const named = nameAndDescription(entry);
|
|
415
448
|
const flags = flagText(entry);
|
|
416
449
|
const wholeQuery = query.toLowerCase().trim().replace(/\s+/g, " ");
|
|
450
|
+
const called = identityFields(entry);
|
|
451
|
+
const codes = [entry.token, entry.shortcut, ...entry.aliases].filter((value): value is string => !!value).map((value) => normalizeLookupToken(value));
|
|
417
452
|
|
|
418
453
|
let score = containsPhrase(`${named} ${flags}`, wholeQuery) ? 12 : 0;
|
|
419
454
|
// A query that is one of the function's own keywords ("hedge" for OSA) beats one found inside a
|
|
@@ -423,9 +458,16 @@ function scorePaneCatalogEntry(entry: PaneCatalogEntry, query: string): CatalogM
|
|
|
423
458
|
if (keywords.includes(wholeQuery)) score += 4;
|
|
424
459
|
let matchedTerms = 0;
|
|
425
460
|
let matchedNamed = 0;
|
|
461
|
+
let matchedCalled = 0;
|
|
426
462
|
let matchedFlagKeys = 0;
|
|
427
463
|
for (const term of terms) {
|
|
428
464
|
const normalized = normalizeLookupToken(term);
|
|
465
|
+
if (called.some((field) => containsPhrase(field, term))) {
|
|
466
|
+
score += PER_WORD_IN_NAME;
|
|
467
|
+
matchedCalled += 1;
|
|
468
|
+
}
|
|
469
|
+
if (codes.some((code) => normalized.length >= 2 && code.startsWith(normalized))) score += PER_WORD_STARTING_CODE;
|
|
470
|
+
if (keywords.includes(term)) score += PER_WORD_IS_KEYWORD;
|
|
429
471
|
// A term starts a word: "rate" is found in "rates" but not in "separate", nor "budget" in "budgetBps".
|
|
430
472
|
if (exactTokens.includes(normalized)) {
|
|
431
473
|
score += 8;
|
|
@@ -455,12 +497,13 @@ function scorePaneCatalogEntry(entry: PaneCatalogEntry, query: string): CatalogM
|
|
|
455
497
|
score += Math.round((matchedTerms / terms.length) * 8);
|
|
456
498
|
if (entry.capability.botSafe) score += 2;
|
|
457
499
|
// One word has no phrase to prefer: it keeps the plain term scores.
|
|
458
|
-
if (terms.length === 1) return { score, terms: 1, named: matchedNamed };
|
|
500
|
+
if (terms.length === 1) return { score, terms: 1, named: matchedNamed, called: matchedCalled };
|
|
459
501
|
const allWords = matchedNamed === terms.length ? ALL_WORDS_BAND : matchedTerms === terms.length ? ALL_WORDS_WITH_FLAGS_BAND : 0;
|
|
460
502
|
return {
|
|
461
503
|
score: score + matchedTerms * PER_MATCHED_WORD + (phraseBand(entry, wholeQuery) || allWords),
|
|
462
504
|
terms: terms.length,
|
|
463
505
|
named: matchedNamed,
|
|
506
|
+
called: matchedCalled,
|
|
464
507
|
};
|
|
465
508
|
}
|
|
466
509
|
|
|
@@ -535,8 +578,14 @@ export function selectPaneCatalogMatches(ranked: PaneCatalogEntry[], query: stri
|
|
|
535
578
|
const shown = every(complete).slice(0, limit);
|
|
536
579
|
return { shown, hidden: ranked.length - shown.length, loose: false };
|
|
537
580
|
}
|
|
581
|
+
// No function carries every word: the ones a word names come first, the code or name of a function being what a
|
|
582
|
+
// reader types ("fx vol" is FXC, whose name has fx, and VOLS, whose name has vol), ahead of one that mentions a word
|
|
583
|
+
// in its keywords ("implied fx" in ADR) or its flags, and however many of the words a weaker match has.
|
|
538
584
|
const named = scored.filter(({ named }) => named > 0);
|
|
539
|
-
const
|
|
585
|
+
const pool = named.length > 0 ? named : scored;
|
|
586
|
+
const leading = pool.filter((item) => item.called > 0).slice(0, LOOSE_NAMED_LIMIT);
|
|
587
|
+
const rest = pool.filter((item) => !leading.includes(item)).slice(0, Math.max(0, LOOSE_MATCH_LIMIT - leading.length));
|
|
588
|
+
const shown = every([...leading, ...rest]).slice(0, limit);
|
|
540
589
|
return { shown, hidden: ranked.length - shown.length, loose: true };
|
|
541
590
|
}
|
|
542
591
|
|
|
@@ -576,7 +625,7 @@ function optionDescription(option: PaneFunctionOptionDef): string {
|
|
|
576
625
|
const choices = optionChoices(option);
|
|
577
626
|
const parts = [option.description.replace(/\.$/, "")];
|
|
578
627
|
// An enum that also reads other values (a bar size of any length) lists its values as examples.
|
|
579
|
-
if (choices.join("|").length > MAX_INLINE_CHOICES) parts.push(`${option.normalize ? "Such as" : "One of"} ${choices.join(", ")}`);
|
|
628
|
+
if (choices.join("|").length > MAX_INLINE_CHOICES) parts.push(`${option.list ? "Each one of" : option.normalize ? "Such as" : "One of"} ${choices.join(", ")}`);
|
|
580
629
|
if (option.defaultValue !== undefined && option.defaultValue !== "") parts.push(`Default ${String(option.defaultValue)}`);
|
|
581
630
|
return `${parts.join(". ")}.`;
|
|
582
631
|
}
|
|
@@ -587,6 +636,26 @@ export function limitationSentence(text: string): string {
|
|
|
587
636
|
return !trimmed || /[.!?]["')\]]*$/.test(trimmed) ? trimmed : `${trimmed}.`;
|
|
588
637
|
}
|
|
589
638
|
|
|
639
|
+
/**
|
|
640
|
+
* Names as lines of at most `width`, each name whole and the names apart by
|
|
641
|
+
* semicolons, since a name may hold a comma (Furnishings, Fixtures & Appliances).
|
|
642
|
+
*/
|
|
643
|
+
function packNames(names: readonly string[], width: number): string[] {
|
|
644
|
+
const lines: string[] = [];
|
|
645
|
+
let line = "";
|
|
646
|
+
names.forEach((name, index) => {
|
|
647
|
+
const word = index < names.length - 1 ? `${name};` : name;
|
|
648
|
+
if (line && line.length + 1 + word.length > width) {
|
|
649
|
+
lines.push(line);
|
|
650
|
+
line = word;
|
|
651
|
+
} else {
|
|
652
|
+
line = line ? `${line} ${word}` : word;
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
if (line) lines.push(line);
|
|
656
|
+
return lines;
|
|
657
|
+
}
|
|
658
|
+
|
|
590
659
|
function renderCatalogEntry(entry: PaneCatalogEntry): string {
|
|
591
660
|
const width = Math.min(cliTerminalWidth() ?? CATALOG_TEXT_WIDTH, CATALOG_TEXT_WIDTH);
|
|
592
661
|
const capability = entry.capability;
|
|
@@ -620,6 +689,10 @@ function renderCatalogEntry(entry: PaneCatalogEntry): string {
|
|
|
620
689
|
));
|
|
621
690
|
}
|
|
622
691
|
|
|
692
|
+
for (const { title, items } of capability.reference ?? []) {
|
|
693
|
+
lines.push("", renderSection(title), ...packNames(items, width - 2).map((line) => ` ${line}`));
|
|
694
|
+
}
|
|
695
|
+
|
|
623
696
|
lines.push("", renderSection("Examples"));
|
|
624
697
|
if (capability.reportReadiness !== "unsupported") {
|
|
625
698
|
lines.push(...wrapCommandLine(`gloom fn ${invocation}`, width));
|
|
@@ -12,7 +12,9 @@ import type {
|
|
|
12
12
|
PluginPersistence,
|
|
13
13
|
} from "../../types/plugin";
|
|
14
14
|
import { createPluginTeamState } from "../../plugins/team-state";
|
|
15
|
+
import { bindPluginContextNamespaces } from "../../plugins/registry/plugin-state";
|
|
15
16
|
import type { MarketContext } from "../types";
|
|
17
|
+
import { createCommandPluginPersistence } from "../saved-copy-persistence";
|
|
16
18
|
import type { PaneFunctionCatalog } from "./catalog";
|
|
17
19
|
|
|
18
20
|
export interface PaneDiscoveryOptions {
|
|
@@ -173,23 +175,41 @@ export async function createPaneCatalog(context: MarketContext, plugins: GloomPl
|
|
|
173
175
|
brokers,
|
|
174
176
|
});
|
|
175
177
|
|
|
178
|
+
// Each plugin's caches save what a command fetches where the app keeps them, so a failed refresh answers from them.
|
|
179
|
+
const resources = context.persistence?.resources;
|
|
180
|
+
const persistences: Array<ReturnType<typeof createCommandPluginPersistence>> = [];
|
|
181
|
+
const commandPersistence = (stateId: string) => {
|
|
182
|
+
const persistence = createCommandPluginPersistence(resources, `plugin:${stateId}`);
|
|
183
|
+
persistences.push(persistence);
|
|
184
|
+
return persistence;
|
|
185
|
+
};
|
|
186
|
+
|
|
176
187
|
const destroy = () => {
|
|
177
188
|
let failure: unknown;
|
|
178
189
|
for (const plugin of setupPlugins.splice(0).reverse()) {
|
|
179
190
|
try { plugin.dispose?.(); } catch (error) { failure ??= error; }
|
|
180
191
|
}
|
|
192
|
+
// A plugin that keeps its persistence past dispose must not reach a store the command closes.
|
|
193
|
+
for (const persistence of persistences.splice(0)) persistence.release();
|
|
181
194
|
brokers.clear();
|
|
182
195
|
if (context.resolveBroker === resolveBroker) context.resolveBroker = previousResolver;
|
|
183
196
|
if (failure) throw failure;
|
|
184
197
|
};
|
|
185
198
|
|
|
199
|
+
const namespaced = (stateId: string) => ({
|
|
200
|
+
persistence: commandPersistence(stateId),
|
|
201
|
+
resume: discoveryContext.resume,
|
|
202
|
+
configState: discoveryContext.configState,
|
|
203
|
+
teamState: discoveryContext.teamState,
|
|
204
|
+
});
|
|
186
205
|
try {
|
|
187
206
|
for (const plugin of plugins) {
|
|
188
207
|
for (const pane of plugin.panes ?? []) panes.set(pane.id, pane);
|
|
189
208
|
for (const template of plugin.paneTemplates ?? []) paneTemplates.set(template.id, template);
|
|
190
209
|
if (plugin.setup) {
|
|
191
210
|
setupPlugins.push(plugin);
|
|
192
|
-
|
|
211
|
+
const stateId = plugin.stateId ?? plugin.id;
|
|
212
|
+
await plugin.setup(bindPluginContextNamespaces({ ...discoveryContext, ...namespaced(stateId) }, namespaced));
|
|
193
213
|
}
|
|
194
214
|
}
|
|
195
215
|
} catch (error) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DesktopPaneShotRenderedRow } from "../desktop-pane-shot";
|
|
2
2
|
import { cliStyles, cliTerminalWidth, renderSection, renderTable, wrapText } from "../../utils/cli-output";
|
|
3
|
-
import { formatUtcTime } from "../../utils/utc-time";
|
|
3
|
+
import { formatUtcTime, parseReportTime } from "../../utils/utc-time";
|
|
4
4
|
import type { MarketContext } from "../types";
|
|
5
5
|
import type { PaneFunctionReport } from "./report";
|
|
6
6
|
import type { ResolvedPaneFunction } from "./resolver";
|
|
@@ -83,12 +83,22 @@ function domCellKeys(row: DesktopPaneShotRenderedRow): string[] {
|
|
|
83
83
|
});
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
const DAY_MS = 86_400_000;
|
|
87
|
+
/** A time of day in what a cell draws: `11:27`, `9am`. */
|
|
88
|
+
const DRAWN_CLOCK = /\d{1,2}:\d{2}|\b\d{1,2}\s?[ap]m\b/i;
|
|
89
|
+
|
|
86
90
|
/**
|
|
87
91
|
* A pane may shorten a time to fit ("Wed 11:27", "Oct 2"); the report prints
|
|
88
|
-
* the instant behind it with its date and zone instead.
|
|
92
|
+
* the instant behind it with its date and zone instead. An instant at exactly
|
|
93
|
+
* 00:00 UTC that the cell draws without a time of day (a filing's date, an
|
|
94
|
+
* all-day event) is a day, not a midnight: it prints as the date, as a
|
|
95
|
+
* date-only value does. The CSV and JSON keep the instant.
|
|
89
96
|
*/
|
|
90
97
|
function cellText(cell: DesktopPaneShotRenderedRow["cells"][number]): string {
|
|
91
|
-
|
|
98
|
+
if (!cell.instant) return cell.text;
|
|
99
|
+
const time = parseReportTime(cell.instant);
|
|
100
|
+
if (time && !time.dateOnly && time.time % DAY_MS === 0 && !DRAWN_CLOCK.test(cell.text)) return formatUtcTime({ ...time, dateOnly: true });
|
|
101
|
+
return formatUtcTime(cell.instant) || cell.text;
|
|
92
102
|
}
|
|
93
103
|
|
|
94
104
|
interface DomTable {
|
|
@@ -11,7 +11,15 @@ import type {
|
|
|
11
11
|
import { localTimeSuffix, parseReportTime, type ReportTime } from "../../utils/utc-time";
|
|
12
12
|
import { isRecord } from "../../utils/guards";
|
|
13
13
|
import { latestRegularSessionClose, readIndexSession } from "../../market-data/market/freshness";
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
reportMarketSession,
|
|
16
|
+
reportVenueMarkets,
|
|
17
|
+
reportVenueSessionDates,
|
|
18
|
+
type ReportMarket,
|
|
19
|
+
type SessionObservation,
|
|
20
|
+
type VenueMarket,
|
|
21
|
+
type VenueSessionDate,
|
|
22
|
+
} from "./market-session";
|
|
15
23
|
import { savedCopyShownAt } from "../../data/saved-copies";
|
|
16
24
|
import { releasedText } from "../../utils/release-date";
|
|
17
25
|
|
|
@@ -77,6 +85,13 @@ export interface ReportFreshness {
|
|
|
77
85
|
tradingDayMarket?: string;
|
|
78
86
|
/** Where the venues of a quote report stand now, from their session calendars. */
|
|
79
87
|
market?: ReportMarket;
|
|
88
|
+
/**
|
|
89
|
+
* With a declared `datesEachVenue`, when the rows trade on two or three
|
|
90
|
+
* markets that do not all stand alike: where each stands and when it opens,
|
|
91
|
+
* which the status line gives in place of `market` (`LSE opens 08:00 UTC ·
|
|
92
|
+
* US 13:30 UTC`).
|
|
93
|
+
*/
|
|
94
|
+
markets?: VenueMarket[];
|
|
80
95
|
/**
|
|
81
96
|
* With a declared `datesEachVenue`, when the rows trade on more than one
|
|
82
97
|
* market: each market's session date, which the status line gives in place
|
|
@@ -108,6 +123,8 @@ export interface ReportFreshness {
|
|
|
108
123
|
ageOnly?: true;
|
|
109
124
|
/** What the newest observation is, said before its time: `newest story Tue 29 Sep 2026 20:17 UTC`. */
|
|
110
125
|
asOfLabel?: string;
|
|
126
|
+
/** The line says when the report was retrieved after the newest observation's date (`retrieved Wed 28 Oct 2026 19:07 UTC`). */
|
|
127
|
+
retrievedToo?: true;
|
|
111
128
|
/** What the figures are, said after the status: `funding = current estimate, pays 08:00 UTC`. */
|
|
112
129
|
note?: string;
|
|
113
130
|
/** Shorter forms of `note`, in the order a capture's line too long for it tries them. */
|
|
@@ -534,6 +551,9 @@ function resolveFreshness({ declared, signals, observations, now }: FreshnessInp
|
|
|
534
551
|
}
|
|
535
552
|
const { market, closeDate, closeMarket } = reportMarketSession(signals.sessions, now);
|
|
536
553
|
const venueSessions = declared.datesEachVenue && !declaredAsOf ? reportVenueSessionDates(signals.sessions, now) : [];
|
|
554
|
+
// Each market's own state and open, when they are not all one: `LSE opens 08:00 UTC · US 13:30 UTC`.
|
|
555
|
+
const venueMarkets = declared.datesEachVenue ? reportVenueMarkets(signals.sessions, now) : [];
|
|
556
|
+
const markets = venueMarkets.length > 0 && !sameMarketText(venueMarkets, now) ? venueMarkets : [];
|
|
537
557
|
// The close wording dates the newest observation, so only when that is what `asOf` is.
|
|
538
558
|
const asOfClose = closeDate && asOf && !declaredAsOf ? closeDate : null;
|
|
539
559
|
const tradingDayMarket = asOfClose ? closeMarket
|
|
@@ -584,6 +604,7 @@ function resolveFreshness({ declared, signals, observations, now }: FreshnessInp
|
|
|
584
604
|
...(asOfClose ? { asOfClose } : {}),
|
|
585
605
|
...(tradingDayMarket ? { tradingDayMarket } : {}),
|
|
586
606
|
...(market ? { market } : {}),
|
|
607
|
+
...(markets.length > 0 ? { markets } : {}),
|
|
587
608
|
...(venueSessions.length > 0 ? { venueSessions } : {}),
|
|
588
609
|
...(lagDays != null ? { lagDays } : {}),
|
|
589
610
|
...(observation ? { observation } : {}),
|
|
@@ -591,6 +612,7 @@ function resolveFreshness({ declared, signals, observations, now }: FreshnessInp
|
|
|
591
612
|
...(oldestAgeMinutes != null ? { oldestAgeMinutes } : {}),
|
|
592
613
|
...(status === "unreported" && declared.ageOnly ? { ageOnly: true as const } : {}),
|
|
593
614
|
...(asOfLabel ? { asOfLabel } : {}),
|
|
615
|
+
...(asOf && declared.retrievedToo ? { retrievedToo: true as const } : {}),
|
|
594
616
|
...(note ? { note } : {}),
|
|
595
617
|
...(noteVariants.length > 0 ? { noteVariants } : {}),
|
|
596
618
|
...(schedule ? { schedule } : {}),
|
|
@@ -857,6 +879,21 @@ function venueSessionsText(sessions: readonly VenueSessionDate[]): string {
|
|
|
857
879
|
return groups.map(({ markets, date, close }) => `${listText(markets)} ${dayText(date)} ${close ? "close" : "session"}`).join(", ");
|
|
858
880
|
}
|
|
859
881
|
|
|
882
|
+
/**
|
|
883
|
+
* An as-of the feed stamped at exactly 00:00:00.000 UTC reads as the day it
|
|
884
|
+
* names, as a date-only value does: a daily close, a filing's date or a
|
|
885
|
+
* published report's has no time of day, so `Mon 26 Oct 2026 00:00 UTC` would
|
|
886
|
+
* claim one. Quotes keep their time, as does anything a feed or a venue's
|
|
887
|
+
* sessions date, and bars of a size under a day, whose midnight bar opens then.
|
|
888
|
+
*/
|
|
889
|
+
function asOfAsDay(freshness: ReportFreshness, time: ReportTime | null): ReportTime | null {
|
|
890
|
+
if (!time || time.dateOnly || time.time % DAY_MS !== 0) return time;
|
|
891
|
+
const feed = freshness.status === "live" || freshness.status === "delayed" || freshness.feed != null;
|
|
892
|
+
const intradayBars = freshness.basis === "intraday bars";
|
|
893
|
+
return feed || intradayBars || freshness.market || freshness.sources?.length || freshness.oldestAgeMinutes != null
|
|
894
|
+
? time : { ...time, dateOnly: true };
|
|
895
|
+
}
|
|
896
|
+
|
|
860
897
|
/**
|
|
861
898
|
* The dated as-of: a session close, a UTC time, a date, or when the report was
|
|
862
899
|
* retrieved; with the oldest observation unless `short`, or when the line says
|
|
@@ -868,7 +905,7 @@ function asOfText(freshness: ReportFreshness, short: boolean, local: boolean, un
|
|
|
868
905
|
if (freshness.venueSessions?.length) return venueSessionsText(freshness.venueSessions);
|
|
869
906
|
const market = freshness.tradingDayMarket;
|
|
870
907
|
const period = freshness.periodicity;
|
|
871
|
-
const time = parseReportTime(freshness.asOf);
|
|
908
|
+
const time = asOfAsDay(freshness, parseReportTime(freshness.asOf));
|
|
872
909
|
const reference = freshness.referencePeriod;
|
|
873
910
|
// `Sep 2026, released Tue 20 Oct`: the period the figure covers, then when it was released.
|
|
874
911
|
const released = reference ? releasedText(freshness.asOf, reference) : null;
|
|
@@ -949,6 +986,53 @@ function marketText(market: ReportMarket, now: number, short: boolean, local: bo
|
|
|
949
986
|
}
|
|
950
987
|
}
|
|
951
988
|
|
|
989
|
+
/** Whether every market of a mixed report reads the same (`markets closed until Mon`): one line then says it for all. */
|
|
990
|
+
function sameMarketText(markets: readonly VenueMarket[], now: number): boolean {
|
|
991
|
+
return new Set(markets.map((market) => marketText(market, now, false, false))).size === 1;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
/**
|
|
995
|
+
* Where each market of a report that mixes them stands, one after another:
|
|
996
|
+
* the open ones first, then those in an extended session, then the closed ones
|
|
997
|
+
* by when they open. `markets closed · LSE opens 08:00 UTC · US 13:30 UTC`
|
|
998
|
+
* while all are closed, else each its own (`LSE open · US pre-market, opens
|
|
999
|
+
* 13:30 UTC`). A time is the regular session's open, as `marketText` says it;
|
|
1000
|
+
* `short` leaves out `markets closed`.
|
|
1001
|
+
*/
|
|
1002
|
+
function marketsText(markets: readonly VenueMarket[], now: number, short: boolean, local: boolean): string {
|
|
1003
|
+
const opensAt = (market: VenueMarket) => market.reopensAt ? Date.parse(market.reopensAt) : Number.POSITIVE_INFINITY;
|
|
1004
|
+
const rank = (market: VenueMarket) => market.state === "open" ? 0 : market.state === "closed" ? 2 : 1;
|
|
1005
|
+
const ordered = [...markets].sort((left, right) => rank(left) - rank(right) || opensAt(left) - opensAt(right));
|
|
1006
|
+
// `LSE opens 08:00 UTC · US 13:30 UTC`: a verb is said once for the timed opens that follow each other
|
|
1007
|
+
// with it; a week's first trade after a session's open says its own (`reopens 22:00 UTC`).
|
|
1008
|
+
let previousVerb: string | null = null;
|
|
1009
|
+
const parts = ordered.map((market) => {
|
|
1010
|
+
const reopen = reopenText(market, now, local);
|
|
1011
|
+
const verb = market.state === "closed" && reopen?.time ? market.firstTrade ? "reopens" : "opens" : null;
|
|
1012
|
+
const said = (() => {
|
|
1013
|
+
switch (market.state) {
|
|
1014
|
+
case "open":
|
|
1015
|
+
return `${market.market} open`;
|
|
1016
|
+
case "after-hours":
|
|
1017
|
+
return `${market.market} after hours`;
|
|
1018
|
+
case "pre-market":
|
|
1019
|
+
return reopen?.time ? `${market.market} pre-market, opens ${reopen.text}` : `${market.market} pre-market`;
|
|
1020
|
+
case "closed":
|
|
1021
|
+
if (!reopen) return `${market.market} closed`;
|
|
1022
|
+
if (!reopen.time) return `${market.market} closed until ${reopen.text}`;
|
|
1023
|
+
return `${market.market} ${verb === previousVerb ? "" : `${verb} `}${reopen.text}`;
|
|
1024
|
+
default: {
|
|
1025
|
+
const _exhaustive: never = market.state;
|
|
1026
|
+
return _exhaustive;
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
})();
|
|
1030
|
+
previousVerb = verb;
|
|
1031
|
+
return said;
|
|
1032
|
+
});
|
|
1033
|
+
return ordered.every((market) => market.state === "closed") && !short ? ["markets closed", ...parts].join(" · ") : parts.join(" · ");
|
|
1034
|
+
}
|
|
1035
|
+
|
|
952
1036
|
interface StatusLineDetail {
|
|
953
1037
|
/** Leave out the oldest observation. */
|
|
954
1038
|
asOf?: "short";
|
|
@@ -980,14 +1064,19 @@ function statusLineParts(freshness: ReportFreshness, detail: StatusLineDetail =
|
|
|
980
1064
|
const undated = detail.date === "none";
|
|
981
1065
|
return [
|
|
982
1066
|
...(freshness.sources?.length ? sourcesAsOfParts(freshness, freshness.sources, undated)
|
|
983
|
-
:
|
|
1067
|
+
// Undated, a saved copy is not "retrieved" now: its own part says when it was saved.
|
|
1068
|
+
: (freshness.unreached || freshness.savedAt) && !freshness.asOf ? []
|
|
984
1069
|
: [asOfText(freshness, detail.asOf === "short", local, undated)]),
|
|
1070
|
+
// A list dated by its newest filing says when it was read as well.
|
|
1071
|
+
...(freshness.retrievedToo && freshness.asOf && !freshness.savedAt ? [`retrieved ${timeText(freshness.retrievedAt, local)}`] : []),
|
|
985
1072
|
...(freshness.schedule && detail.schedule !== "none"
|
|
986
1073
|
? [typeof detail.schedule === "number" ? freshness.scheduleVariants?.[detail.schedule] ?? freshness.schedule : freshness.schedule] : []),
|
|
987
1074
|
...(freshness.oldestAgeMinutes != null ? [`oldest ${ageText(freshness.oldestAgeMinutes)}`] : []),
|
|
988
1075
|
...(freshness.savedAt ? [savedCopyText(freshness.savedAt, freshness.retrievedAt, local)]
|
|
989
1076
|
: [statusText(detail.basis === "none" ? { ...freshness, basis: undefined } : freshness, detail.status === "short")].filter(Boolean)),
|
|
990
|
-
...(
|
|
1077
|
+
...(detail.market === "none" ? []
|
|
1078
|
+
: freshness.markets?.length ? [marketsText(freshness.markets, now, detail.market === "short", local)]
|
|
1079
|
+
: freshness.market ? [marketText(freshness.market, now, detail.market === "short", local)] : []),
|
|
991
1080
|
...(freshness.note && detail.note !== "none" ? [typeof detail.note === "number" ? freshness.noteVariants?.[detail.note] ?? freshness.note : freshness.note] : []),
|
|
992
1081
|
];
|
|
993
1082
|
}
|
|
@@ -234,9 +234,10 @@ 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, short interest, insider activity and 13F holders, then rank the matches by any metric. "
|
|
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."
|
|
239
|
-
|
|
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. "
|
|
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). Ideas holds ready technical screens.",
|
|
240
|
+
usage: ["EQS", "gloom fn EQS --preset golden-cross"],
|
|
240
241
|
keys: [key("a", "dd criterion"), key("m", "etric"), key("t", "check ticker"), key("s", "ave screen"), key("o", "pen research")],
|
|
241
242
|
data: same("Daily snapshot, statements as filed"),
|
|
242
243
|
bloomberg: ["EQS"],
|
|
@@ -285,8 +286,10 @@ export const FUNCTION_HELP: Readonly<Record<string, FunctionHelp>> = {
|
|
|
285
286
|
},
|
|
286
287
|
CSP: {
|
|
287
288
|
summary: "Which names pay most to sell a put? For each, the put nearest a delta (0.30) on the expiry nearest a date or a number of days out (30), "
|
|
288
|
-
+ "ranked by annualised yield on cash at the bid, with % out of the money, delta, IV rank, the spread (marked wide, never left out) and an earnings flag."
|
|
289
|
-
|
|
289
|
+
+ "ranked by annualised yield on cash at the bid, with % out of the money, delta, IV rank, the spread (marked wide, never left out) and an earnings flag. "
|
|
290
|
+
+ "--strategy screens covered calls, verticals, iron condors, straddles, strangles and calendars the same way, with the trade, credit or debit, "
|
|
291
|
+
+ "max gain and loss per contract, break-evens, probability of profit, and an income trade's annualised return or a debit trade's reward to risk.",
|
|
292
|
+
usage: ["CSP JPM, GS, KO", "gloom fn CSP JPM GS KO AAPL --delta 0.20 --days 45", "gloom fn CSP JPM GS KO --strategy iron-condor"],
|
|
290
293
|
keys: [key("Enter", " open in OSA")],
|
|
291
294
|
data: OPTIONS,
|
|
292
295
|
bloomberg: [],
|
|
@@ -713,8 +716,8 @@ export const FUNCTION_HELP: Readonly<Record<string, FunctionHelp>> = {
|
|
|
713
716
|
|
|
714
717
|
// Watch markets
|
|
715
718
|
MOST: {
|
|
716
|
-
summary: "Today's top gainers, losers, most active and trending tickers with price, change, volume against average and market cap, and the pre-market and after-hours movers. On Pro, the gaps at the open.",
|
|
717
|
-
usage: ["MOST"],
|
|
719
|
+
summary: "Today's top gainers, losers, most active and trending tickers with price, change, volume against average and market cap, and the pre-market and after-hours movers. On Pro, the gaps at the open. Min float keeps the names with at least that many shares in the float.",
|
|
720
|
+
usage: ["MOST", "gloom fn MOST --list gainers --min-float 10M"],
|
|
718
721
|
keys: [TABS, OPEN],
|
|
719
722
|
data: { free: DELAYED, pro: REAL_TIME },
|
|
720
723
|
bloomberg: ["MOST"],
|
|
@@ -902,9 +905,9 @@ export const FUNCTION_HELP: Readonly<Record<string, FunctionHelp>> = {
|
|
|
902
905
|
bloomberg: [],
|
|
903
906
|
},
|
|
904
907
|
FLOW: {
|
|
905
|
-
summary: "Sweeps, blocks and large premium prints
|
|
906
|
-
usage: ["FLOW"],
|
|
907
|
-
keys: [OPEN],
|
|
908
|
+
summary: "Sweeps, blocks and large premium prints, and the session's net premium tide.",
|
|
909
|
+
usage: ["FLOW", "FLOW NVDA"],
|
|
910
|
+
keys: [TABS, OPEN],
|
|
908
911
|
data: pro(REAL_TIME),
|
|
909
912
|
access: "pro",
|
|
910
913
|
bloomberg: ["FLOW"],
|
|
@@ -1423,6 +1426,13 @@ export const FUNCTION_HELP: Readonly<Record<string, FunctionHelp>> = {
|
|
|
1423
1426
|
data: null,
|
|
1424
1427
|
bloomberg: [],
|
|
1425
1428
|
},
|
|
1429
|
+
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.",
|
|
1431
|
+
usage: ["ROADMAP"],
|
|
1432
|
+
keys: [OPEN, key("v", "ote")],
|
|
1433
|
+
data: null,
|
|
1434
|
+
bloomberg: [],
|
|
1435
|
+
},
|
|
1426
1436
|
HELP: {
|
|
1427
1437
|
summary: "Help and the function reference. HELP with a function opens its card, F1 opens the focused pane's, and HELP HELP reaches support.",
|
|
1428
1438
|
usage: ["HELP", "HELP OMON", "HELP HELP"],
|
|
@@ -42,6 +42,7 @@ import type { ResolvedPaneFunction } from "./resolver";
|
|
|
42
42
|
import { isRecord } from "../../utils/guards";
|
|
43
43
|
import { splitSymbolWords } from "../symbol-args";
|
|
44
44
|
import { formatUtcTime, localTimeSuffix } from "../../utils/utc-time";
|
|
45
|
+
import { formatCompact } from "../../utils/format";
|
|
45
46
|
import { deriveHeadlessFreshness, formatFreshnessLine, staleRowsText, withSavedCopy, type ReportFreshness } from "./freshness";
|
|
46
47
|
import { DATA_SERVICE_UNREACHABLE_MESSAGE } from "../../utils/network-failure";
|
|
47
48
|
import { accessGateStatus, errorsAccessGate, isProLock, reportGateText } from "./access-gate";
|
|
@@ -235,7 +236,12 @@ export function createHeadlessPaneContext(
|
|
|
235
236
|
command, noun: "a quote", retry: (key) => `gloom ${command} ${argumentWith(key)}`,
|
|
236
237
|
}, { refresh: !!context.refresh });
|
|
237
238
|
if (!read) return null;
|
|
238
|
-
return {
|
|
239
|
+
return {
|
|
240
|
+
symbol: read.symbol,
|
|
241
|
+
...read.exchange ? { exchange: read.exchange } : {},
|
|
242
|
+
...read.name ? { name: read.name } : {},
|
|
243
|
+
...read.coinNote ? { coinNote: read.coinNote } : {},
|
|
244
|
+
};
|
|
239
245
|
},
|
|
240
246
|
};
|
|
241
247
|
}
|
|
@@ -369,8 +375,8 @@ export function serializeHeadlessPaneResult(
|
|
|
369
375
|
}
|
|
370
376
|
case "series": {
|
|
371
377
|
const series = result as HeadlessSeriesResult;
|
|
372
|
-
// `textDecimals` only
|
|
373
|
-
return { ...common, series: series.series.map(({ textDecimals:
|
|
378
|
+
// `textDecimals` and `textCompact` only shape the text report; JSON keeps every digit and does not carry them.
|
|
379
|
+
return { ...common, series: series.series.map(({ textDecimals: _decimals, textCompact: _compact, ...kept }) => kept), ...(series.stats ? { stats: series.stats } : {}) };
|
|
374
380
|
}
|
|
375
381
|
case "snapshot": {
|
|
376
382
|
const snapshot = result as HeadlessSnapshotResult;
|
|
@@ -380,6 +386,7 @@ export function serializeHeadlessPaneResult(
|
|
|
380
386
|
asOf: snapshot.asOf,
|
|
381
387
|
columns: serializableColumns(columns),
|
|
382
388
|
items: snapshot.items,
|
|
389
|
+
...(snapshot.empty && snapshot.items.length === 0 ? { empty: snapshot.empty } : {}),
|
|
383
390
|
};
|
|
384
391
|
}
|
|
385
392
|
default: {
|
|
@@ -495,14 +502,16 @@ function seriesPointExportDate(series: HeadlessSeries, date: SeriesPointDate, da
|
|
|
495
502
|
* points, multiples and
|
|
496
503
|
* ratios (P/E, EV/EBITDA, one series over another, VIX 3M / VIX) to two
|
|
497
504
|
* decimals, which a ratio under 0.1 trades for three significant digits so it
|
|
498
|
-
* is not flattened to 0.03, and a 0 to 100 score to a tenth of a point.
|
|
499
|
-
*
|
|
500
|
-
*
|
|
505
|
+
* is not flattened to 0.03, and a 0 to 100 score to a tenth of a point. A
|
|
506
|
+
* company's reported total (`textCompact`) reads as the tables print one:
|
|
507
|
+
* 63.33B. The exports keep every digit. Any other unit prints as loaded,
|
|
508
|
+
* without float noise.
|
|
501
509
|
*/
|
|
502
510
|
function seriesValue(series: HeadlessSeries, value: number | null): string {
|
|
503
511
|
if (value == null) return "-";
|
|
504
512
|
if (!Number.isFinite(value)) return displayNumber(value);
|
|
505
513
|
if (series.textDecimals != null) return value.toFixed(series.textDecimals);
|
|
514
|
+
if (series.textCompact) return formatCompact(value);
|
|
506
515
|
const unit = series.unit?.trim().toLowerCase();
|
|
507
516
|
if (unit === "%" || unit === "pp") return value.toFixed(2);
|
|
508
517
|
if (unit === "x" || unit === "ratio") return value !== 0 && Math.abs(value) < 0.1 ? value.toPrecision(3) : value.toFixed(2);
|
|
@@ -701,6 +710,7 @@ function emptyReportReason(
|
|
|
701
710
|
const bundleReason = definition.shape === "bundle" ? (result as HeadlessBundleResult).empty : undefined;
|
|
702
711
|
if (bundleReason) return bundleReason;
|
|
703
712
|
const ownReason = definition.shape === "rows" ? !!(result as HeadlessRowsResult).empty
|
|
713
|
+
: definition.shape === "snapshot" ? !!(result as HeadlessSnapshotResult).empty
|
|
704
714
|
: definition.shape === "bundle" && (result as HeadlessBundleResult).sections.some((section) => "empty" in section && !!section.empty && !isLockedSection(section));
|
|
705
715
|
const { failed } = splitErrors(result);
|
|
706
716
|
if (ownReason || failed.length) return null;
|
|
@@ -909,7 +919,7 @@ export function renderHeadlessPaneText(
|
|
|
909
919
|
case "snapshot": {
|
|
910
920
|
const snapshot = result as HeadlessSnapshotResult;
|
|
911
921
|
// The closing source line carries the snapshot's as-of, so it is not printed twice.
|
|
912
|
-
lines.push(renderRows(snapshot.items, undefined, definition.columns));
|
|
922
|
+
lines.push(renderRows(snapshot.items, undefined, definition.columns, snapshot.empty));
|
|
913
923
|
break;
|
|
914
924
|
}
|
|
915
925
|
default: {
|