gloomberb 0.16.2 → 0.16.4
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/package.json +4 -1
- package/src/api-client/askg.ts +43 -0
- package/src/api-client/auth.ts +15 -0
- package/src/api-client/beneficial-owners.ts +4 -0
- package/src/api-client/chat.ts +19 -0
- package/src/api-client/company-kpis.ts +14 -2
- package/src/api-client/data.ts +34 -16
- package/src/api-client/index.ts +12 -0
- package/src/api-client/normalizers.ts +27 -0
- package/src/api-client/paths.ts +88 -23
- package/src/api-client/request.ts +2 -1
- package/src/api-client/research-activity.ts +31 -0
- package/src/api-client/socket.ts +39 -8
- package/src/api-client/types.ts +57 -1
- package/src/api-client/upgrade-experiment.ts +90 -0
- package/src/app/global-shortcuts.ts +11 -1
- package/src/app/keybindings/actions.ts +10 -0
- package/src/app/pane-runtime/index.tsx +8 -0
- package/src/app/pane-runtime/pane-template-runtime.ts +5 -0
- package/src/app/pane-runtime/plugin-bindings.ts +65 -25
- package/src/app/pane-runtime/ticker-inspector-runtime.ts +12 -0
- package/src/app/pane-runtime/ticker-open-runtime.ts +18 -1
- package/src/app/runtime/desktop-deeplink.ts +5 -0
- package/src/app/star-prompt/model.ts +98 -0
- package/src/app/star-prompt/runtime.ts +41 -0
- package/src/app/star-prompt/status-line.tsx +190 -0
- package/src/app.tsx +13 -7
- package/src/architecture/core-builtin-allowlist.json +70 -0
- package/src/brokers/account-cache.ts +45 -0
- package/src/brokers/signed-in/adapter.ts +33 -2
- package/src/brokers/signed-in/client.ts +10 -0
- package/src/brokers/signed-in/sign-in-dialog.tsx +23 -9
- package/src/brokers/signed-in/sign-in.ts +62 -5
- package/src/capabilities/registry.ts +8 -1
- package/src/capabilities/types.ts +2 -0
- package/src/cli/command-options.ts +74 -0
- package/src/cli/commands/command-utils.ts +29 -0
- package/src/cli/commands/crypto-hints.ts +12 -4
- package/src/cli/commands/market.ts +524 -148
- package/src/cli/commands/options-chain.ts +172 -0
- package/src/cli/commands/options-leaps.ts +422 -0
- package/src/cli/commands/overview.ts +223 -42
- package/src/cli/commands/search.ts +29 -8
- package/src/cli/commands/system.ts +99 -19
- package/src/cli/commands/themes.ts +64 -0
- package/src/cli/commands/ticker.ts +200 -73
- package/src/cli/desktop-pane-shot.ts +100 -16
- package/src/cli/errors.ts +25 -2
- package/src/cli/freshness.ts +7 -4
- package/src/cli/fx-pair.ts +57 -0
- package/src/cli/help.ts +40 -7
- package/src/cli/history-rows.ts +187 -15
- package/src/cli/index-roots.ts +51 -0
- package/src/cli/index.ts +21 -13
- package/src/cli/listing-arg.ts +211 -3
- package/src/cli/not-a-ticker.ts +37 -0
- package/src/cli/options.ts +55 -7
- package/src/cli/pane-functions/capabilities.ts +13 -2
- package/src/cli/pane-functions/catalog.ts +13 -2
- package/src/cli/pane-functions/data.ts +36 -5
- package/src/cli/pane-functions/dom.ts +89 -28
- package/src/cli/pane-functions/freshness.ts +205 -26
- package/src/cli/pane-functions/function-help.ts +71 -24
- package/src/cli/pane-functions/headless.ts +168 -35
- package/src/cli/pane-functions/index.ts +12 -2
- package/src/cli/pane-functions/market-session.ts +133 -0
- package/src/cli/pane-functions/options.ts +15 -4
- package/src/cli/pane-functions/report-notices.ts +63 -0
- package/src/cli/pane-functions/report.ts +12 -1
- package/src/cli/pane-functions/resolver.ts +32 -8
- package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
- package/src/cli/pane-functions/screenshot.ts +109 -23
- package/src/cli/registry.ts +8 -4
- package/src/cli/report-tables.ts +460 -0
- package/src/cli/result.ts +63 -16
- package/src/cli/row-window.ts +76 -0
- package/src/cli/scroll-truncation.ts +34 -0
- package/src/components/chart/composite/composite-chart.tsx +43 -4
- package/src/components/chart/composite/legend.tsx +39 -6
- package/src/components/chart/composite/rasterizer.ts +64 -4
- package/src/components/chart/composite/series-cues.ts +71 -0
- package/src/components/chart/composite/text-renderer.ts +16 -8
- package/src/components/chart/composite/types.ts +3 -0
- package/src/components/command-bar/commands/direct/index.ts +9 -1
- package/src/components/command-bar/commands/plugin/items.ts +3 -1
- package/src/components/command-bar/commands/registry.ts +7 -0
- package/src/components/command-bar/layout-items/focused-pane.ts +38 -0
- package/src/components/command-bar/pane-templates/workflow.ts +5 -0
- package/src/components/command-bar/routes/root/command-items.ts +2 -0
- package/src/components/command-bar/routes/root/plugin-turn-on.ts +92 -0
- package/src/components/command-bar/routes/root/results.ts +40 -10
- package/src/components/command-bar/routes/root/runtime.ts +8 -0
- package/src/components/command-bar/routes/root/search-providers.ts +97 -14
- package/src/components/command-bar/surface/index.tsx +18 -4
- package/src/components/command-bar/theme-picker.tsx +48 -13
- package/src/components/command-bar/workflow/ops.ts +5 -3
- package/src/components/data-table/export.ts +6 -51
- package/src/components/data-table/view.tsx +31 -10
- package/src/components/layout/floating-pane.tsx +6 -2
- package/src/components/layout/market-summary.ts +23 -9
- package/src/components/layout/pane/content.tsx +46 -29
- package/src/components/layout/pane/cycle-order.ts +2 -11
- package/src/components/layout/pane/header.tsx +2 -1
- package/src/components/layout/pane/title.ts +1 -1
- package/src/components/layout/presentation.ts +22 -0
- package/src/components/layout/shell/active-drag.ts +67 -35
- package/src/components/layout/shell/cursor-occlusion.ts +6 -5
- package/src/components/layout/shell/drag/index.ts +16 -7
- package/src/components/layout/shell/drag/live.ts +193 -0
- package/src/components/layout/shell/drag/overlays.tsx +179 -35
- package/src/components/layout/shell/drag/runtime.ts +62 -50
- package/src/components/layout/shell/drag/slide.ts +10 -0
- package/src/components/layout/shell/index.tsx +84 -57
- package/src/components/layout/shell/layout-state.ts +5 -11
- package/src/components/layout/shell/menu.ts +28 -1
- package/src/components/layout/shell/native/pointer-runtime.ts +13 -13
- package/src/components/layout/shell/native/surfaces.ts +30 -14
- package/src/components/layout/shell/pane/actions.ts +2 -1
- package/src/components/layout/shell/pane/layers.tsx +461 -180
- package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
- package/src/components/layout/shell/pane/new-layout.ts +116 -0
- package/src/components/layout/shell/shortcuts.ts +5 -2
- package/src/components/layout/shell/terminal-pointer-runtime.ts +18 -18
- package/src/components/layout/shell/visible-layout.ts +44 -1
- package/src/components/layout/shell/window-mode/overlays.tsx +12 -4
- package/src/components/layout/status-bar.tsx +4 -1
- package/src/components/markdown-text.tsx +9 -5
- package/src/components/metric-treemap/heat-surface.tsx +27 -8
- package/src/components/metric-treemap/heat-tiles.ts +48 -17
- package/src/components/onboarding/onboarding-frame.tsx +33 -10
- package/src/components/onboarding/onboarding-wizard.tsx +49 -40
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +5 -2
- package/src/components/onboarding/pro-step-layout.ts +86 -0
- package/src/components/onboarding/use-onboarding-upgrade.ts +6 -2
- package/src/components/ui/button.tsx +10 -0
- package/src/components/ui/data-table/index.tsx +38 -0
- package/src/components/ui/data-table/types.ts +8 -1
- package/src/components/ui/data-table/visible-range.ts +2 -0
- package/src/components/ui/icon.tsx +11 -2
- package/src/components/ui/index.ts +1 -1
- package/src/core/connection-health.ts +1 -1
- package/src/core/state/app/layout-reducer.ts +89 -3
- package/src/core/state/app/state.ts +8 -5
- package/src/core/state/app/types.ts +13 -2
- package/src/data/config/layout.ts +55 -21
- package/src/data/config/store/fold-panes.ts +149 -0
- package/src/data/config/store/migrations.ts +7 -0
- package/src/data/config/store/node.ts +27 -6
- package/src/data/config/store/normalize.ts +37 -3
- package/src/data/json-persistence.ts +17 -3
- package/src/data/json-storage.ts +2 -0
- package/src/data/memory-resource-store.ts +46 -0
- package/src/i18n/es.ts +14 -1
- package/src/i18n/ja.ts +14 -1
- package/src/i18n/ko.ts +14 -1
- package/src/i18n/zh-cn.ts +14 -1
- package/src/i18n/zh-tw.ts +14 -1
- package/src/layout/desks.ts +1 -2
- package/src/layout/pane-layout-move.ts +264 -0
- package/src/layout/pane-manager/hidden-panes.ts +160 -0
- package/src/layout/pane-manager/index.ts +1 -0
- package/src/market-data/coordinator/entries.ts +7 -1
- package/src/market-data/coordinator/quotes.ts +2 -2
- package/src/market-data/market/freshness.ts +156 -11
- package/src/market-data/market/status.ts +40 -0
- package/src/market-data/options-alternatives.ts +69 -0
- package/src/market-data/quotes/contributions.ts +19 -2
- package/src/market-data/quotes/freshness.ts +5 -0
- package/src/market-data/quotes/metadata.ts +16 -0
- package/src/market-data/quotes/screener-live-quotes.ts +56 -5
- package/src/plugins/builtin/account-management/keyboard.ts +3 -0
- package/src/plugins/builtin/account-management/model.ts +1 -0
- package/src/plugins/builtin/account-management/navigation.ts +1 -1
- package/src/plugins/builtin/account-management/pane.tsx +31 -4
- package/src/plugins/builtin/alerts/quotes.ts +3 -0
- package/src/plugins/builtin/analytics/pane-model.ts +10 -6
- package/src/plugins/builtin/analytics/risk-headless.ts +3 -1
- package/src/plugins/builtin/analytics/risk-model.ts +37 -8
- package/src/plugins/builtin/analytics/risk-pane.tsx +8 -4
- package/src/plugins/builtin/attention/pane.tsx +1 -1
- package/src/plugins/builtin/backtest/pane.tsx +1 -1
- package/src/plugins/builtin/broker-manager/detail.tsx +4 -0
- package/src/plugins/builtin/broker-manager/index.tsx +7 -3
- package/src/plugins/builtin/broker-manager/model.ts +8 -0
- package/src/plugins/builtin/broker-manager/pane-actions.tsx +8 -2
- package/src/plugins/builtin/broker-manager/sign-in-end.ts +82 -0
- package/src/plugins/builtin/broker-manager/table.ts +5 -0
- package/src/plugins/builtin/builtin-plugin-meta.ts +121 -11
- package/src/plugins/builtin/catalysts/detail.tsx +1 -1
- package/src/plugins/builtin/chart-composer/pane.tsx +1 -1
- package/src/plugins/builtin/chat/channels.ts +34 -36
- package/src/plugins/builtin/chat/command-bar.ts +138 -0
- package/src/plugins/builtin/chat/composer-commands.ts +21 -1
- package/src/plugins/builtin/chat/content/composer-runtime.ts +11 -1
- package/src/plugins/builtin/chat/content/footer.tsx +5 -3
- package/src/plugins/builtin/chat/content/index.tsx +21 -1
- package/src/plugins/builtin/chat/content/mentions.ts +2 -1
- package/src/plugins/builtin/chat/content/user-map.ts +3 -1
- package/src/plugins/builtin/chat/controller/index.ts +48 -0
- package/src/plugins/builtin/chat/conversations.ts +256 -0
- package/src/plugins/builtin/chat/discord-command.ts +91 -0
- package/src/plugins/builtin/chat/edit-window.ts +12 -6
- package/src/plugins/builtin/chat/ghost-user.ts +14 -0
- package/src/plugins/builtin/chat/index.tsx +40 -2
- package/src/plugins/builtin/chat/layout.ts +2 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +2 -1
- package/src/plugins/builtin/chat/message/header.tsx +24 -15
- package/src/plugins/builtin/chat/message/profile-popover.tsx +2 -1
- package/src/plugins/builtin/chat/message/render-state.ts +3 -0
- package/src/plugins/builtin/chat/pane-requests.ts +60 -0
- package/src/plugins/builtin/chat/pane-state.ts +32 -2
- package/src/plugins/builtin/chat/pane.tsx +8 -0
- package/src/plugins/builtin/cloud/askg/controller.ts +112 -4
- package/src/plugins/builtin/cloud/askg/conversation-store.ts +21 -0
- package/src/plugins/builtin/cloud/askg/manifest.ts +1 -0
- package/src/plugins/builtin/cloud/askg/model.ts +129 -70
- package/src/plugins/builtin/cloud/askg/pane.tsx +772 -377
- package/src/plugins/builtin/cloud/askg/protocol.ts +40 -2
- package/src/plugins/builtin/cloud/askg/tool-display.ts +437 -0
- package/src/plugins/builtin/cloud/askg/tool-timeline.tsx +403 -0
- package/src/plugins/builtin/cloud/company-picker.tsx +1 -9
- package/src/plugins/builtin/cloud/mcp-connect/command.ts +24 -0
- package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +360 -0
- package/src/plugins/builtin/cloud/mcp-connect/model.ts +135 -0
- package/src/plugins/builtin/cloud/mcp-connect/sections.ts +62 -0
- package/src/plugins/builtin/cloud/plugin.tsx +36 -1
- package/src/plugins/builtin/cloud/starter-symbols.ts +8 -0
- package/src/plugins/builtin/cloud/terminal-relay/acm-tab.tsx +89 -0
- package/src/plugins/builtin/cloud/terminal-relay/client.ts +97 -0
- package/src/plugins/builtin/cloud/terminal-relay/connect-section.tsx +57 -0
- package/src/plugins/builtin/cloud/terminal-relay/engine.ts +666 -0
- package/src/plugins/builtin/cloud/terminal-relay/grants.ts +137 -0
- package/src/plugins/builtin/cloud/terminal-relay/host.tsx +81 -0
- package/src/plugins/builtin/cloud/terminal-relay/indicator.tsx +82 -0
- package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +234 -0
- package/src/plugins/builtin/cloud/terminal-relay/policy.ts +153 -0
- package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +168 -0
- package/src/plugins/builtin/cloud/terminal-relay/redact.ts +73 -0
- package/src/plugins/builtin/cloud/terminal-relay/summary.ts +62 -0
- package/src/plugins/builtin/cloud/upgrade-dialog.tsx +26 -2
- package/src/plugins/builtin/cloud/upgrade-personalization.ts +57 -0
- package/src/plugins/builtin/cloud/upgrade-tickers.ts +124 -0
- package/src/plugins/builtin/comment-letters/client.ts +1 -3
- package/src/plugins/builtin/company-attention/pane.tsx +1 -1
- package/src/plugins/builtin/company-kpis/client.ts +23 -8
- package/src/plugins/builtin/company-kpis/headless.ts +3 -1
- package/src/plugins/builtin/company-kpis/pane.tsx +15 -7
- package/src/plugins/builtin/company-kpis/screenshot-evidence.ts +10 -3
- package/src/plugins/builtin/composite-plugins.ts +107 -64
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +4 -4
- package/src/plugins/builtin/credit-boards/index.tsx +21 -21
- package/src/plugins/builtin/credit-boards/model.ts +0 -1
- package/src/plugins/builtin/credit-boards/pane.tsx +30 -0
- package/src/plugins/builtin/credit-boards/sovr-pane.tsx +4 -4
- package/src/plugins/builtin/debt-maturities/client.ts +37 -9
- package/src/plugins/builtin/debt-maturities/headless.ts +3 -1
- package/src/plugins/builtin/debt-maturities/pane.tsx +5 -4
- package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
- package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
- package/src/plugins/builtin/earnings-calls/data.ts +28 -7
- package/src/plugins/builtin/earnings-calls/headless.ts +3 -2
- package/src/plugins/builtin/earnings-calls/pane.tsx +10 -5
- package/src/plugins/builtin/econ/calendar-model.ts +42 -17
- package/src/plugins/builtin/econ/detail-view.tsx +2 -2
- package/src/plugins/builtin/econ/index.tsx +68 -22
- package/src/plugins/builtin/econ-statistics/headless.ts +12 -2
- package/src/plugins/builtin/econ-statistics/pane.tsx +1 -1
- package/src/plugins/builtin/econ-statistics/view.ts +17 -0
- package/src/plugins/builtin/executives/data.ts +17 -6
- package/src/plugins/builtin/executives/pane.tsx +16 -7
- package/src/plugins/builtin/filing-events/pane.tsx +22 -5
- package/src/plugins/builtin/fx-matrix/freshness.ts +65 -0
- package/src/plugins/builtin/fx-matrix/index.tsx +22 -1
- package/src/plugins/builtin/fx-matrix/pairs.ts +1 -1
- package/src/plugins/builtin/fx-matrix/settings.ts +42 -2
- package/src/plugins/builtin/gpu/headless.ts +9 -3
- package/src/plugins/builtin/gpu/model.ts +14 -5
- package/src/plugins/builtin/help/index.tsx +1 -0
- package/src/plugins/builtin/holders/beneficial-client.ts +29 -7
- package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
- package/src/plugins/builtin/holders/client.ts +3 -6
- package/src/plugins/builtin/holders/format.ts +31 -1
- package/src/plugins/builtin/holders/headless.ts +32 -6
- package/src/plugins/builtin/holders/pane.tsx +25 -13
- package/src/plugins/builtin/holders/report-header.ts +46 -5
- package/src/plugins/builtin/insider/index.tsx +4 -4
- package/src/plugins/builtin/iv-history/charts.tsx +21 -7
- package/src/plugins/builtin/iv-history/client.ts +12 -2
- package/src/plugins/builtin/iv-history/format.ts +33 -2
- package/src/plugins/builtin/iv-history/headless.ts +22 -10
- package/src/plugins/builtin/iv-history/index.tsx +3 -3
- package/src/plugins/builtin/iv-history/model.ts +61 -13
- package/src/plugins/builtin/iv-history/pane.tsx +11 -3
- package/src/plugins/builtin/iv-history/screen-pane.tsx +42 -18
- package/src/plugins/builtin/jobs/pane.tsx +1 -1
- package/src/plugins/builtin/kelly-sizer/headless.ts +149 -0
- package/src/plugins/builtin/kelly-sizer/history.ts +80 -0
- package/src/plugins/builtin/kelly-sizer/index.tsx +2 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +121 -45
- package/src/plugins/builtin/kelly-sizer/portfolio.ts +25 -0
- package/src/plugins/builtin/kelly-sizer/sections.tsx +14 -0
- package/src/plugins/builtin/kelly-sizer/types.ts +9 -1
- package/src/plugins/builtin/layout-manager/index.tsx +9 -1
- package/src/plugins/builtin/macro-day/client.ts +24 -0
- package/src/plugins/builtin/macro-day/headless.ts +11 -8
- package/src/plugins/builtin/macro-day/index.tsx +3 -0
- package/src/plugins/builtin/macro-day/model.ts +11 -6
- package/src/plugins/builtin/macro-day/pane.tsx +12 -8
- package/src/plugins/builtin/macro-day/release-table.ts +40 -0
- package/src/plugins/builtin/macro-day/releases.ts +62 -44
- package/src/plugins/builtin/market-heatmap/data.ts +25 -5
- package/src/plugins/builtin/market-heatmap/evidence.ts +90 -0
- package/src/plugins/builtin/market-heatmap/index.tsx +144 -63
- package/src/plugins/builtin/market-heatmap/model.ts +94 -3
- package/src/plugins/builtin/market-heatmap/portfolio.ts +12 -2
- package/src/plugins/builtin/market-movers/headless.ts +31 -4
- package/src/plugins/builtin/market-movers/index.tsx +8 -1
- package/src/plugins/builtin/market-movers/model.ts +71 -17
- package/src/plugins/builtin/market-movers/table.ts +50 -23
- package/src/plugins/builtin/members/pane.tsx +10 -0
- package/src/plugins/builtin/news/headless.ts +9 -2
- package/src/plugins/builtin/news/wire/news/footer.ts +10 -0
- package/src/plugins/builtin/openfda/client.ts +1 -1
- package/src/plugins/builtin/options/carry.ts +95 -0
- package/src/plugins/builtin/options/index.tsx +58 -5
- package/src/plugins/builtin/options/strike-window.ts +183 -0
- package/src/plugins/builtin/options/table.ts +55 -3
- package/src/plugins/builtin/options/types.ts +8 -1
- package/src/plugins/builtin/options/view.tsx +161 -12
- package/src/plugins/builtin/options-positioning/headless.ts +4 -2
- package/src/plugins/builtin/options-scenario/charts.tsx +2 -2
- package/src/plugins/builtin/options-scenario/client.ts +73 -17
- package/src/plugins/builtin/options-scenario/headless.ts +71 -24
- package/src/plugins/builtin/options-scenario/hedge.ts +284 -0
- package/src/plugins/builtin/options-scenario/index.tsx +9 -2
- package/src/plugins/builtin/options-scenario/model.ts +33 -0
- package/src/plugins/builtin/options-scenario/pane.tsx +40 -16
- package/src/plugins/builtin/pe-band/model.ts +2 -2
- package/src/plugins/builtin/pe-band/report-dates.ts +11 -7
- package/src/plugins/builtin/perps/equity-row.tsx +8 -5
- package/src/plugins/builtin/perps/model.ts +16 -5
- package/src/plugins/builtin/perps/pane.tsx +1 -1
- package/src/plugins/builtin/plugin-marketplace/model.ts +64 -21
- package/src/plugins/builtin/plugin-marketplace/packs.ts +118 -0
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +344 -32
- package/src/plugins/builtin/plugin-marketplace/store.ts +7 -1
- package/src/plugins/builtin/plugin-module.ts +87 -4
- package/src/plugins/builtin/portfolio-list/account-metrics.ts +16 -1
- package/src/plugins/builtin/portfolio-list/allocation.ts +3 -0
- package/src/plugins/builtin/portfolio-list/cached-account.ts +18 -9
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +71 -36
- package/src/plugins/builtin/portfolio-list/cli/render.ts +89 -18
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +2 -16
- package/src/plugins/builtin/portfolio-list/headless.ts +40 -7
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +7 -4
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +22 -4
- package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +11 -1
- package/src/plugins/builtin/realized-vol/headless.ts +3 -0
- package/src/plugins/builtin/realized-vol/pane.tsx +1 -1
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +2 -2
- package/src/plugins/builtin/research/equity-diagnostic-pane.tsx +1 -1
- package/src/plugins/builtin/research/relative-valuation-model.ts +7 -3
- package/src/plugins/builtin/revenue-breakdown/client.ts +13 -6
- package/src/plugins/builtin/revenue-breakdown/headless.ts +4 -1
- package/src/plugins/builtin/revenue-breakdown/pane.tsx +7 -4
- package/src/plugins/builtin/reverse-dcf/headless.ts +5 -1
- package/src/plugins/builtin/reverse-dcf/model.ts +2 -1
- package/src/plugins/builtin/reverse-dcf/pane.tsx +1 -1
- package/src/plugins/builtin/risk-factors/data.ts +23 -9
- package/src/plugins/builtin/risk-factors/headless.ts +5 -2
- package/src/plugins/builtin/risk-factors/pane.tsx +6 -5
- package/src/plugins/builtin/seasonality/pane.tsx +1 -1
- package/src/plugins/builtin/sec/index.tsx +5 -5
- package/src/plugins/builtin/sectors/client.ts +10 -2
- package/src/plugins/builtin/sectors/headless.ts +35 -6
- package/src/plugins/builtin/sectors/index.tsx +18 -1
- package/src/plugins/builtin/sectors/sector-model.ts +150 -41
- package/src/plugins/builtin/shared/command-tab.ts +51 -0
- package/src/plugins/builtin/shared/headless-market-data.ts +33 -1
- package/src/plugins/builtin/shared/members-menu.tsx +260 -0
- package/src/plugins/builtin/shared/report-freshness.ts +50 -2
- package/src/plugins/builtin/shared/ticker-request.ts +25 -1
- package/src/plugins/builtin/shared/use-quote-board.ts +25 -5
- package/src/plugins/builtin/shared/volatility/options.ts +1 -46
- package/src/plugins/builtin/short-interest/index.tsx +19 -4
- package/src/plugins/builtin/short-interest/surface.tsx +4 -4
- package/src/plugins/builtin/short-volume/index.tsx +1 -10
- package/src/plugins/builtin/short-volume/pane.tsx +1 -1
- package/src/plugins/builtin/social-mentions/pane.tsx +1 -1
- package/src/plugins/builtin/supply-chain/model.ts +1 -1
- package/src/plugins/builtin/themes/pane.tsx +3 -0
- package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +4 -0
- package/src/plugins/builtin/ticker-detail/financials/model.ts +25 -2
- package/src/plugins/builtin/ticker-detail/headless.ts +63 -25
- package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -4
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +3 -2
- package/src/plugins/builtin/ticker-detail/pane.tsx +4 -5
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +94 -6
- package/src/plugins/builtin/treasury-auctions/cache.ts +5 -2
- package/src/plugins/builtin/treasury-auctions/client.ts +22 -8
- package/src/plugins/builtin/treasury-auctions/headless.ts +40 -4
- package/src/plugins/builtin/treasury-auctions/index.tsx +11 -9
- package/src/plugins/builtin/treasury-auctions/model.ts +197 -30
- package/src/plugins/builtin/treasury-auctions/pane.tsx +35 -11
- package/src/plugins/builtin/treasury-auctions/types.ts +11 -1
- package/src/plugins/builtin/vol-surface/charts.tsx +1 -3
- package/src/plugins/builtin/vol-surface/client.ts +6 -2
- package/src/plugins/builtin/vol-surface/evidence.ts +11 -6
- package/src/plugins/builtin/vol-surface/headless.ts +124 -20
- package/src/plugins/builtin/vol-surface/model.ts +23 -11
- package/src/plugins/builtin/vol-surface/pane.tsx +38 -27
- package/src/plugins/builtin/vol-surface/tables.ts +124 -0
- package/src/plugins/builtin/world-indices/client.ts +22 -4
- package/src/plugins/builtin/world-indices/headless.ts +54 -27
- package/src/plugins/builtin/world-indices/model.ts +4 -2
- package/src/plugins/builtin/world-indices/table.tsx +13 -2
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +2 -0
- package/src/plugins/builtin/world-venue-map/basemap.ts +18 -0
- package/src/plugins/builtin/world-venue-map/country-labels.ts +78 -0
- package/src/plugins/builtin/world-venue-map/geo-series.ts +1 -1
- package/src/plugins/builtin/world-venue-map/geo-svg.tsx +2 -1
- package/src/plugins/builtin/world-venue-map/index.ts +6 -6
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +27 -14
- package/src/plugins/builtin/world-venue-map/layers.ts +68 -10
- package/src/plugins/builtin/world-venue-map/map.tsx +198 -62
- package/src/plugins/builtin/world-venue-map/model.ts +16 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +3 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/labels.chunk.ts +244 -0
- package/src/plugins/builtin/world-venue-map/pane.tsx +16 -10
- package/src/plugins/builtin/yield-curve/index.tsx +1 -1
- package/src/plugins/builtin-editorial.ts +126 -0
- package/src/plugins/catalog-backend.ts +16 -9
- package/src/plugins/catalog-browser.ts +127 -63
- package/src/plugins/catalog-manifest.ts +73 -40
- package/src/plugins/catalog-ui.ts +26 -6
- package/src/plugins/extracted-plugins.ts +7 -1
- package/src/plugins/ownership.ts +150 -7
- package/src/plugins/plugin-functions.ts +54 -0
- package/src/plugins/plugin-off.ts +36 -0
- package/src/plugins/registry/host-actions.ts +16 -0
- package/src/plugins/registry/index.ts +84 -24
- package/src/plugins/registry/plugin-state.ts +25 -1
- package/src/plugins/runtime/context.tsx +29 -0
- package/src/react/input.ts +48 -1
- package/src/remote/app-host.tsx +5 -0
- package/src/remote/controller.ts +3 -53
- package/src/remote/matching.ts +69 -0
- package/src/remote/schema.ts +1 -1
- package/src/remote/semantic-tree.tsx +14 -0
- package/src/remote/types.ts +2 -0
- package/src/renderers/browser/app-services.ts +3 -1
- package/src/renderers/dom/data-table/dom.ts +31 -0
- package/src/renderers/dom/data-table/index.tsx +5 -0
- package/src/renderers/dom/desktop/icons.tsx +14 -0
- package/src/renderers/dom/desktop/query-bar.tsx +59 -32
- package/src/renderers/dom/host/box.tsx +113 -17
- package/src/renderers/dom/host/drag-shield.ts +35 -0
- package/src/renderers/dom/host/live-frame.ts +62 -0
- package/src/renderers/dom/host/mouse.ts +8 -1
- package/src/renderers/dom/host/scroll-box.tsx +6 -5
- package/src/renderers/dom/host/tabs.tsx +3 -2
- package/src/renderers/dom/input-host.tsx +6 -1
- package/src/renderers/dom/styles.css +26 -5
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +7 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +7 -1
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +12 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +15 -1
- package/src/renderers/electrobun/shared/protocol.ts +12 -1
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +4 -1
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +101 -5
- package/src/renderers/electrobun/view/host/native.ts +0 -10
- package/src/renderers/electrobun/view/host/window-move.ts +28 -0
- package/src/renderers/electrobun/view/main.tsx +4 -1
- package/src/renderers/electrobun/view/remote/persistence.ts +15 -2
- package/src/renderers/electrobun/view/ui-host.tsx +2 -5
- package/src/renderers/opentui/input-host.tsx +6 -1
- package/src/renderers/opentui/start.tsx +9 -0
- package/src/renderers/opentui/ui-host.tsx +7 -1
- package/src/shares/portable-layout.ts +16 -6
- package/src/sources/gloomberb-cloud/index.ts +19 -10
- package/src/sources/gloomberb-cloud/normalizers.ts +20 -21
- package/src/sources/listing-symbols.ts +11 -5
- package/src/sources/provider-errors.ts +88 -3
- package/src/sources/provider-router/batches.ts +3 -3
- package/src/sources/provider-router/cached-routes.ts +8 -4
- package/src/sources/provider-router/financial-routes.ts +13 -7
- package/src/sources/provider-router/financials.ts +106 -16
- package/src/sources/provider-router/history.ts +27 -11
- package/src/sources/provider-router/index.ts +1 -1
- package/src/sources/provider-router/primary.ts +24 -6
- package/src/sources/sec-edgar.ts +68 -8
- package/src/state/pane-scroll-registry.tsx +67 -35
- package/src/sync/core-contributors.ts +4 -3
- package/src/test-support/cli-context.ts +2 -1
- package/src/test-support/data-provider.ts +34 -0
- package/src/test-support/margin-account.ts +108 -0
- package/src/test-support/shell-pane-keys.tsx +1 -0
- package/src/theme/series-colors.ts +46 -0
- package/src/theme/themes.ts +149 -0
- package/src/tickers/search/index.ts +22 -2
- package/src/tickers/search/ranking.ts +45 -1
- package/src/tickers/search/types.ts +3 -1
- package/src/time-series/resolution.ts +15 -0
- package/src/time-series/resolve.ts +1 -14
- package/src/types/config.ts +61 -1
- package/src/types/financials.ts +32 -3
- package/src/types/headless.ts +11 -0
- package/src/types/instrument.ts +8 -0
- package/src/types/plugin.ts +49 -3
- package/src/ui/host.tsx +16 -0
- package/src/ui/index.tsx +10 -3
- package/src/ui/scroll-box-axis.ts +26 -0
- package/src/utils/cli-output.ts +14 -1
- package/src/utils/currency-units.ts +8 -3
- package/src/utils/depositary-receipt.ts +54 -10
- package/src/utils/display-number.ts +63 -0
- package/src/utils/exchanges.ts +13 -0
- package/src/utils/format.ts +2 -1
- package/src/utils/fundamentals.ts +17 -1
- package/src/utils/fx-market-hours.ts +34 -0
- package/src/utils/option-expiry.ts +126 -0
- package/src/utils/price-history-integrity.ts +19 -6
- package/src/utils/price-history.ts +39 -6
- package/src/utils/rpc-timeout-error.ts +6 -2
- package/src/utils/sec-eps-basis.ts +159 -30
- package/src/utils/sec.ts +38 -34
- package/src/utils/throttled-fetch.ts +51 -22
|
@@ -10,6 +10,7 @@ import type { ManualChartResolution } from "../time-series/resolution";
|
|
|
10
10
|
import type { SnapshotMarketData } from "../market-data/snapshot-provider";
|
|
11
11
|
import type { InstrumentRef } from "../market-data/request-types";
|
|
12
12
|
import type { TickerRecord } from "../types/ticker";
|
|
13
|
+
import type { BrokerAccount } from "../types/trading";
|
|
13
14
|
import type { PaneRuntimeState } from "../core/state/app/state";
|
|
14
15
|
import type { RemoteUiNodeSnapshot } from "../remote/types";
|
|
15
16
|
import type { DatedObservation } from "../plugins/builtin/market-valuation/series";
|
|
@@ -17,6 +18,7 @@ import type { DesktopExternalPluginBundle } from "../renderers/electrobun/shared
|
|
|
17
18
|
import type { HttpProxyRequestEnvelope, HttpProxyResponseEnvelope } from "../utils/http-proxy-response";
|
|
18
19
|
import type { PaneAccessGate } from "./pane-functions/access-gate";
|
|
19
20
|
import { readVisibleKeyValues } from "./visible-key-values";
|
|
21
|
+
import { scrollTruncationReasons } from "./scroll-truncation";
|
|
20
22
|
import { SHOT_API_PROXY_PREFIX, SHOT_HTTP_BRIDGE_PATH, SHOT_MARKET_BRIDGE_PATH } from "./desktop-pane-shot-routes";
|
|
21
23
|
import { SESSION_COOKIE_NAMES } from "../api-client/session-cookie";
|
|
22
24
|
import {
|
|
@@ -53,7 +55,14 @@ export interface DesktopPaneShotPayload {
|
|
|
53
55
|
deviceScaleFactor?: number;
|
|
54
56
|
/** Label drawn at the right edge of the pane title bar; null draws nothing. */
|
|
55
57
|
watermark?: string | null;
|
|
58
|
+
/**
|
|
59
|
+
* The pane footer keeps a row for the capture's dated status line, filled
|
|
60
|
+
* once the pane has loaded. Absent for `--no-status` and for reports.
|
|
61
|
+
*/
|
|
62
|
+
statusLine?: boolean;
|
|
56
63
|
tickers: TickerRecord[];
|
|
64
|
+
/** Broker accounts as last synced, by profile, so a broker portfolio shows its equity and cash. */
|
|
65
|
+
brokerAccounts?: Record<string, BrokerAccount[]>;
|
|
57
66
|
financials: Array<[string, TickerFinancials]>;
|
|
58
67
|
instrumentFinancials?: SnapshotMarketData["instrumentFinancials"];
|
|
59
68
|
historyVariants?: SnapshotMarketData["historyVariants"];
|
|
@@ -108,6 +117,14 @@ export interface DesktopPaneShotRenderedRow {
|
|
|
108
117
|
|
|
109
118
|
export interface DesktopPaneShotRenderResult {
|
|
110
119
|
visibleText: string;
|
|
120
|
+
/**
|
|
121
|
+
* The rows a report reads, when a table reports every row (an option chain's
|
|
122
|
+
* strike window) rather than those in the viewport; `rows` stays what the
|
|
123
|
+
* capture shows. Absent when every table is read from the viewport.
|
|
124
|
+
*/
|
|
125
|
+
reportRows?: DesktopPaneShotRenderedRow[];
|
|
126
|
+
/** `truncationReasons` without the cuts of tables whose every row is in `reportRows`. */
|
|
127
|
+
reportTruncationReasons?: string[];
|
|
111
128
|
/** Text of the pane footers, where a pane says whether its data is live, delayed or stale. */
|
|
112
129
|
footerText?: string;
|
|
113
130
|
visibleKeyValues?: Array<{ label: string; text: string }>;
|
|
@@ -122,8 +139,16 @@ export interface DesktopPaneShotRenderResult {
|
|
|
122
139
|
/** A wall that needs an account, or a Pro lock on part of the pane. */
|
|
123
140
|
accessGate?: PaneAccessGate | null;
|
|
124
141
|
semanticUi: RemoteUiNodeSnapshot[];
|
|
142
|
+
/** The status line drawn in the capture's footer, as it fit the width. */
|
|
143
|
+
statusLine?: string | null;
|
|
125
144
|
}
|
|
126
145
|
|
|
146
|
+
/**
|
|
147
|
+
* The status line variants for a capture, longest first, worked out from what
|
|
148
|
+
* the pane rendered; null leaves the footer row empty.
|
|
149
|
+
*/
|
|
150
|
+
type ShotStatusLine = (rendered: DesktopPaneShotRenderResult) => readonly string[] | null | Promise<readonly string[] | null>;
|
|
151
|
+
|
|
127
152
|
type CdpResponse = {
|
|
128
153
|
id?: number;
|
|
129
154
|
result?: unknown;
|
|
@@ -160,7 +185,7 @@ export async function renderDesktopPaneScreenshot(
|
|
|
160
185
|
payload: DesktopPaneShotPayload,
|
|
161
186
|
outputPath: string,
|
|
162
187
|
apiProxy: DesktopPaneShotApiProxy,
|
|
163
|
-
options: { captureImage?: boolean; bridge?: DesktopPaneShotBridge } = {},
|
|
188
|
+
options: { captureImage?: boolean; bridge?: DesktopPaneShotBridge; statusLine?: ShotStatusLine } = {},
|
|
164
189
|
): Promise<DesktopPaneShotRenderResult> {
|
|
165
190
|
const tempDir = await mkdtemp(join(tmpdir(), "gloom-pane-shot-"));
|
|
166
191
|
let server: ReturnType<typeof Bun.serve> | null = null;
|
|
@@ -179,6 +204,7 @@ export async function renderDesktopPaneScreenshot(
|
|
|
179
204
|
deviceScaleFactor: payload.deviceScaleFactor ?? DEFAULT_DEVICE_SCALE_FACTOR,
|
|
180
205
|
userDataDir: join(tempDir, "chrome-profile"),
|
|
181
206
|
captureImage: options.captureImage !== false,
|
|
207
|
+
statusLine: payload.statusLine ? options.statusLine : undefined,
|
|
182
208
|
});
|
|
183
209
|
} finally {
|
|
184
210
|
server?.stop(true);
|
|
@@ -399,6 +425,7 @@ async function capturePageScreenshot({
|
|
|
399
425
|
deviceScaleFactor,
|
|
400
426
|
userDataDir,
|
|
401
427
|
captureImage,
|
|
428
|
+
statusLine,
|
|
402
429
|
}: {
|
|
403
430
|
chrome: string;
|
|
404
431
|
url: string;
|
|
@@ -408,6 +435,7 @@ async function capturePageScreenshot({
|
|
|
408
435
|
deviceScaleFactor: number;
|
|
409
436
|
userDataDir: string;
|
|
410
437
|
captureImage: boolean;
|
|
438
|
+
statusLine?: ShotStatusLine;
|
|
411
439
|
}): Promise<DesktopPaneShotRenderResult> {
|
|
412
440
|
await mkdir(userDataDir, { recursive: true });
|
|
413
441
|
const port = 43000 + Math.floor(Math.random() * 10000);
|
|
@@ -454,6 +482,10 @@ async function capturePageScreenshot({
|
|
|
454
482
|
});
|
|
455
483
|
await waitForShotReady(session);
|
|
456
484
|
const rendered = await readRenderedPaneState(session);
|
|
485
|
+
if (captureImage && statusLine) {
|
|
486
|
+
const variants = await statusLine(rendered);
|
|
487
|
+
rendered.statusLine = variants?.length ? await fitShotStatusLine(session, variants) : null;
|
|
488
|
+
}
|
|
457
489
|
if (captureImage) {
|
|
458
490
|
const screenshot = await session.send("Page.captureScreenshot", {
|
|
459
491
|
format: "png",
|
|
@@ -512,6 +544,8 @@ const EMPTY_STATE_PATTERNS = [
|
|
|
512
544
|
/\bNo transcribed calls(?: for [^.]+)? yet\b/gi,
|
|
513
545
|
/\bNo short interest (?:data|found)\b/gi,
|
|
514
546
|
/\bNo (?:House PTR |insider )?(?:trades|members|transactions|filings)\b/gi,
|
|
547
|
+
// OMON on an expiry the chain does not list, with the dates nearest it.
|
|
548
|
+
/\bNo (?:option contracts returned for )?expiry \d{4}-\d{2}-\d{2}(?:; (?:available|nearest others): \d{4}-\d{2}-\d{2}(?:, \d{4}-\d{2}-\d{2})*(?: \(\+\d+ more\))?|; the chain lists no expiries)?/gi,
|
|
515
549
|
];
|
|
516
550
|
|
|
517
551
|
function stateMarkers(text: string, patterns: RegExp[]): string[] {
|
|
@@ -538,26 +572,39 @@ async function readRenderedPaneState(session: CdpSession): Promise<DesktopPaneSh
|
|
|
538
572
|
const semanticTables = semanticUi.filter((node) => node && node.role === "table");
|
|
539
573
|
const rows = [];
|
|
540
574
|
const truncationReasons = new Set();
|
|
575
|
+
const scrollReasons = (${scrollTruncationReasons.toString()});
|
|
576
|
+
const visibleTables = [...root.querySelectorAll('[data-gloom-role="data-table"]')].filter(isVisible);
|
|
577
|
+
// A table that publishes every row has nothing cut from a report, whatever the viewport shows.
|
|
578
|
+
const reportedRowsOf = (tableIndex) => {
|
|
579
|
+
const metadata = semanticTables[tableIndex] && semanticTables[tableIndex].metadata;
|
|
580
|
+
return metadata && Array.isArray(metadata.rows) ? metadata.rows : null;
|
|
581
|
+
};
|
|
582
|
+
const reportedTables = new Set(visibleTables.filter((_table, tableIndex) => reportedRowsOf(tableIndex)));
|
|
583
|
+
const reportRows = [];
|
|
584
|
+
const reportTruncationReasons = new Set();
|
|
585
|
+
const inReportedTable = (element) => {
|
|
586
|
+
const table = element.closest('[data-gloom-role="data-table"]');
|
|
587
|
+
return !!table && reportedTables.has(table);
|
|
588
|
+
};
|
|
541
589
|
const markScrollTruncation = (element) => {
|
|
542
590
|
if (!(element instanceof HTMLElement) || !isVisible(element)) return;
|
|
543
|
-
|
|
544
|
-
element.
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
element.getAttribute("data-gloom-scrollbar-
|
|
551
|
-
|
|
552
|
-
)
|
|
553
|
-
|
|
554
|
-
|
|
591
|
+
const reasons = scrollReasons({
|
|
592
|
+
scrollTop: element.scrollTop,
|
|
593
|
+
scrollHeight: element.scrollHeight,
|
|
594
|
+
clientHeight: element.clientHeight,
|
|
595
|
+
scrollLeft: element.scrollLeft,
|
|
596
|
+
scrollWidth: element.scrollWidth,
|
|
597
|
+
clientWidth: element.clientWidth,
|
|
598
|
+
scrollbarY: element.getAttribute("data-gloom-scrollbar-y") === "visible",
|
|
599
|
+
scrollbarX: element.getAttribute("data-gloom-scrollbar-x") === "visible",
|
|
600
|
+
});
|
|
601
|
+
reasons.forEach((reason) => truncationReasons.add(reason));
|
|
602
|
+
if (!inReportedTable(element)) reasons.forEach((reason) => reportTruncationReasons.add(reason));
|
|
555
603
|
};
|
|
556
604
|
[...root.querySelectorAll(
|
|
557
605
|
'[data-gloom-scrollbar-x="visible"], [data-gloom-scrollbar-y="visible"], [data-gloom-role="data-table-body-scroll"]',
|
|
558
606
|
)].forEach(markScrollTruncation);
|
|
559
|
-
|
|
560
|
-
.filter(isVisible)
|
|
607
|
+
visibleTables
|
|
561
608
|
.forEach((table, tableIndex) => {
|
|
562
609
|
const tableMetadata = semanticTables[tableIndex] && semanticTables[tableIndex].metadata || {};
|
|
563
610
|
const semanticColumns = Array.isArray(tableMetadata.columns) ? tableMetadata.columns : [];
|
|
@@ -583,6 +630,7 @@ async function readRenderedPaneState(session: CdpSession): Promise<DesktopPaneSh
|
|
|
583
630
|
))
|
|
584
631
|
) {
|
|
585
632
|
truncationReasons.add("one or more cells are visibly clipped");
|
|
633
|
+
if (!reportedTables.has(table)) reportTruncationReasons.add("one or more cells are visibly clipped");
|
|
586
634
|
}
|
|
587
635
|
const instant = cell.getAttribute("data-gloom-cell-instant");
|
|
588
636
|
return {
|
|
@@ -595,12 +643,27 @@ async function readRenderedPaneState(session: CdpSession): Promise<DesktopPaneSh
|
|
|
595
643
|
};
|
|
596
644
|
}).filter((cell) => cell.text.length > 0);
|
|
597
645
|
if (cells.length === 0) return;
|
|
598
|
-
|
|
646
|
+
const captured = {
|
|
599
647
|
tableIndex,
|
|
600
648
|
rowIndex,
|
|
601
649
|
...(rowKey ? { key: rowKey } : {}),
|
|
602
650
|
selected: row.getAttribute("data-selected") === "true",
|
|
603
651
|
cells,
|
|
652
|
+
};
|
|
653
|
+
rows.push(captured);
|
|
654
|
+
if (!reportedTables.has(table)) reportRows.push(captured);
|
|
655
|
+
});
|
|
656
|
+
const reported = reportedRowsOf(tableIndex);
|
|
657
|
+
if (!reported) return;
|
|
658
|
+
reported.forEach((row, rowIndex) => {
|
|
659
|
+
const cells = Array.isArray(row && row.cells) ? row.cells.filter((cell) => cell && cell.text) : [];
|
|
660
|
+
if (cells.length === 0) return;
|
|
661
|
+
reportRows.push({
|
|
662
|
+
tableIndex,
|
|
663
|
+
rowIndex,
|
|
664
|
+
...(typeof row.key === "string" ? { key: row.key } : {}),
|
|
665
|
+
selected: row.selected === true,
|
|
666
|
+
cells,
|
|
604
667
|
});
|
|
605
668
|
});
|
|
606
669
|
});
|
|
@@ -639,6 +702,7 @@ async function readRenderedPaneState(session: CdpSession): Promise<DesktopPaneSh
|
|
|
639
702
|
rows,
|
|
640
703
|
truncated: truncationReasons.size > 0,
|
|
641
704
|
truncationReasons: [...truncationReasons],
|
|
705
|
+
...(reportedTables.size > 0 ? { reportRows, reportTruncationReasons: [...reportTruncationReasons] } : {}),
|
|
642
706
|
semanticUi,
|
|
643
707
|
};
|
|
644
708
|
})()`,
|
|
@@ -657,6 +721,8 @@ async function readRenderedPaneState(session: CdpSession): Promise<DesktopPaneSh
|
|
|
657
721
|
rows?: DesktopPaneShotRenderedRow[];
|
|
658
722
|
truncated?: boolean;
|
|
659
723
|
truncationReasons?: string[];
|
|
724
|
+
reportRows?: DesktopPaneShotRenderedRow[];
|
|
725
|
+
reportTruncationReasons?: string[];
|
|
660
726
|
semanticUi?: RemoteUiNodeSnapshot[];
|
|
661
727
|
};
|
|
662
728
|
};
|
|
@@ -684,6 +750,10 @@ async function readRenderedPaneState(session: CdpSession): Promise<DesktopPaneSh
|
|
|
684
750
|
rows,
|
|
685
751
|
truncated: value?.truncated === true || textShowsEllipsis,
|
|
686
752
|
truncationReasons,
|
|
753
|
+
...(Array.isArray(value?.reportRows) ? {
|
|
754
|
+
reportRows: value.reportRows,
|
|
755
|
+
reportTruncationReasons: (value.reportTruncationReasons ?? []).filter((reason): reason is string => typeof reason === "string"),
|
|
756
|
+
} : {}),
|
|
687
757
|
loadingStateDetected: value?.loadingStateDetected === true || loadingStateMarkers.length > 0,
|
|
688
758
|
errorStateDetected: value?.errorStateDetected === true || errorStateMarkers.length > 0,
|
|
689
759
|
errorStateMarkers,
|
|
@@ -694,6 +764,20 @@ async function readRenderedPaneState(session: CdpSession): Promise<DesktopPaneSh
|
|
|
694
764
|
};
|
|
695
765
|
}
|
|
696
766
|
|
|
767
|
+
/** Draws the first variant that fits the pane footer, and returns what it drew. */
|
|
768
|
+
async function fitShotStatusLine(session: CdpSession, variants: readonly string[]): Promise<string | null> {
|
|
769
|
+
const result = await session.send("Runtime.evaluate", {
|
|
770
|
+
expression: `(() => {
|
|
771
|
+
const fit = window.__GLOOM_CLI_SHOT_FIT_STATUS__;
|
|
772
|
+
return fit ? fit(${JSON.stringify(variants)}) : null;
|
|
773
|
+
})()`,
|
|
774
|
+
awaitPromise: true,
|
|
775
|
+
returnByValue: true,
|
|
776
|
+
}) as { result?: { value?: unknown } };
|
|
777
|
+
const value = result.result?.value;
|
|
778
|
+
return typeof value === "string" ? value : null;
|
|
779
|
+
}
|
|
780
|
+
|
|
697
781
|
async function waitForPageWebSocket(port: number, targetUrl: string): Promise<string> {
|
|
698
782
|
for (let attempt = 0; attempt < CHROME_POLL_ATTEMPTS; attempt += 1) {
|
|
699
783
|
try {
|
package/src/cli/errors.ts
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import type { AppPersistence } from "../data/app-persistence";
|
|
2
|
+
import { ApiRequestError } from "../api-client/errors";
|
|
2
3
|
import { DEFAULT_CLI_OPTIONS, type CliGlobalOptions } from "./options";
|
|
3
4
|
import { serializeCliError, type CliErrorObject } from "./result";
|
|
4
5
|
import { cliStyles, cliTerminalWidth, wrapText } from "../utils/cli-output";
|
|
6
|
+
import { withSearchHints } from "./not-a-ticker";
|
|
5
7
|
|
|
6
8
|
const USAGE_PREFIX = "Usage: ";
|
|
9
|
+
/** The code of every error a command fails with: bad input, nothing found, an option it does not take. */
|
|
10
|
+
const CLI_ERROR_CODE = "cli_error";
|
|
7
11
|
|
|
8
12
|
export interface CliErrorContext {
|
|
9
13
|
/** The command that failed, used to point at its help. */
|
|
10
14
|
command?: string;
|
|
15
|
+
/** What the user typed after the command, so a hint can repeat their own spelling of a symbol. */
|
|
16
|
+
args?: readonly string[];
|
|
11
17
|
}
|
|
12
18
|
|
|
13
19
|
class CliFailure extends Error {
|
|
@@ -15,7 +21,7 @@ class CliFailure extends Error {
|
|
|
15
21
|
readonly details?: unknown;
|
|
16
22
|
readonly retryable?: boolean;
|
|
17
23
|
|
|
18
|
-
constructor(message: string, details?: unknown, code =
|
|
24
|
+
constructor(message: string, details?: unknown, code = CLI_ERROR_CODE, retryable?: boolean) {
|
|
19
25
|
super(message);
|
|
20
26
|
this.name = "CliFailure";
|
|
21
27
|
this.code = code;
|
|
@@ -37,6 +43,11 @@ function isCliFailure(error: unknown): error is CliFailure {
|
|
|
37
43
|
return error instanceof CliFailure;
|
|
38
44
|
}
|
|
39
45
|
|
|
46
|
+
/** A global option that does not parse is a usage error like any other, not an unexpected one. */
|
|
47
|
+
export function asUsageError(error: unknown): Error {
|
|
48
|
+
return isCliFailure(error) ? error : new CliFailure(error instanceof Error ? error.message : String(error));
|
|
49
|
+
}
|
|
50
|
+
|
|
40
51
|
function cliErrorObject(error: unknown): CliErrorObject {
|
|
41
52
|
if (isCliFailure(error)) {
|
|
42
53
|
return {
|
|
@@ -46,6 +57,10 @@ function cliErrorObject(error: unknown): CliErrorObject {
|
|
|
46
57
|
retryable: error.retryable,
|
|
47
58
|
};
|
|
48
59
|
}
|
|
60
|
+
// Gloom Cloud refused what was asked (an unknown series, a bad date): the input was wrong, not the program.
|
|
61
|
+
if (error instanceof ApiRequestError && error.status === 400) {
|
|
62
|
+
return { code: CLI_ERROR_CODE, message: error.message };
|
|
63
|
+
}
|
|
49
64
|
return {
|
|
50
65
|
code: "unexpected_error",
|
|
51
66
|
message: error instanceof Error ? error.message : String(error),
|
|
@@ -87,10 +102,18 @@ function formatCliErrorText(error: CliErrorObject, context: CliErrorContext): st
|
|
|
87
102
|
].join("\n");
|
|
88
103
|
}
|
|
89
104
|
|
|
105
|
+
function hintedError(error: CliErrorObject, args: readonly string[]): CliErrorObject {
|
|
106
|
+
return {
|
|
107
|
+
...error,
|
|
108
|
+
message: withSearchHints(error.message, args),
|
|
109
|
+
...(typeof error.details === "string" ? { details: withSearchHints(error.details, args) } : {}),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
90
113
|
export function printCliError(error: unknown, options: CliGlobalOptions, context: CliErrorContext = {}): void {
|
|
91
114
|
if (options.quiet && options.format === "text") return;
|
|
92
115
|
const errorObject = cliErrorObject(error);
|
|
93
116
|
console.error(options.format === "text"
|
|
94
|
-
? formatCliErrorText(errorObject, context)
|
|
117
|
+
? formatCliErrorText(hintedError(errorObject, context.args ?? []), context)
|
|
95
118
|
: serializeCliError(errorObject, options));
|
|
96
119
|
}
|
package/src/cli/freshness.ts
CHANGED
|
@@ -25,17 +25,20 @@ export function rowsFreshness(
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/** One row per quote shown, as `fn` quote reports carry them: live, delayed or stale for its session. */
|
|
28
|
-
function quoteFreshnessRow(quote: Quote): HeadlessPaneRow {
|
|
29
|
-
return { ...quoteFreshnessFields(quote), updatedAt: quote.lastUpdated };
|
|
28
|
+
function quoteFreshnessRow(quote: Quote, now: number): HeadlessPaneRow {
|
|
29
|
+
return { ...quoteFreshnessFields(quote, now), updatedAt: quote.lastUpdated };
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* Worst of across the quotes shown, dated by the newest, with their delay and
|
|
34
|
+
* where their markets stand. Quotes that failed to load say nothing.
|
|
35
|
+
*/
|
|
33
36
|
export function quotesFreshness(
|
|
34
37
|
quotes: Iterable<Quote | null | undefined>,
|
|
35
38
|
declared?: HeadlessPaneFreshness,
|
|
36
39
|
now = Date.now(),
|
|
37
40
|
): ReportFreshness | undefined {
|
|
38
|
-
const rows = [...quotes].filter((quote): quote is Quote => quote != null).map(quoteFreshnessRow);
|
|
41
|
+
const rows = [...quotes].filter((quote): quote is Quote => quote != null).map((quote) => quoteFreshnessRow(quote, now));
|
|
39
42
|
return rows.length > 0 ? rowsFreshness(rows, declared, undefined, now) : undefined;
|
|
40
43
|
}
|
|
41
44
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What `gloomberb fx` is asked for. A bare code is one unit of it in the base
|
|
3
|
+
* currency (`NGN`: USD per 1 NGN). A pair is market convention, BASE/QUOTE:
|
|
4
|
+
* `USD/NGN` is how many NGN one USD buys, and `ZAR/NGN` a cross of two codes
|
|
5
|
+
* with neither in USD.
|
|
6
|
+
*/
|
|
7
|
+
export interface FxRequest {
|
|
8
|
+
/** The currency one unit of which is priced: NGN in `NGN`, USD in `USD/NGN`. */
|
|
9
|
+
currency: string;
|
|
10
|
+
/** The currency the price is in: the base currency for a bare code, the quote of a pair. */
|
|
11
|
+
baseCurrency: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const CURRENCY_CODE = /^[A-Z]{3}$/;
|
|
15
|
+
|
|
16
|
+
/** The request, or the sentence saying what is wrong with the argument. */
|
|
17
|
+
export function parseFxRequest(raw: string, baseCurrency: string): FxRequest | { error: string } {
|
|
18
|
+
const text = raw.trim().toUpperCase();
|
|
19
|
+
const parts = text.split("/").map((part) => part.trim());
|
|
20
|
+
if (parts.length > 2 || parts.some((part) => !part)) return { error: `"${raw}" is not a currency or a pair such as USD/NGN.` };
|
|
21
|
+
const bad = parts.filter((part) => !CURRENCY_CODE.test(part));
|
|
22
|
+
if (bad.length > 0) return { error: `${bad.join(" and ")} ${bad.length > 1 ? "are not currency codes" : "is not a currency code"}; use three letters such as NGN.` };
|
|
23
|
+
return parts.length === 2
|
|
24
|
+
? { currency: parts[0]!, baseCurrency: parts[1]! }
|
|
25
|
+
: { currency: parts[0]!, baseCurrency: baseCurrency.trim().toUpperCase() };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The rate of `currency` in `baseCurrency` from each one's USD value (USD per
|
|
30
|
+
* unit), the way every cross is built. NaN when a leg is missing or unusable.
|
|
31
|
+
*/
|
|
32
|
+
export function crossRate(currencyInUsd: number | null | undefined, baseInUsd: number | null | undefined): number {
|
|
33
|
+
if (!isUsableRate(currencyInUsd) || !isUsableRate(baseInUsd)) return Number.NaN;
|
|
34
|
+
return currencyInUsd / baseInUsd;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function isUsableRate(value: number | null | undefined): value is number {
|
|
38
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* A rate to six significant digits, so a tiny one keeps its figures
|
|
43
|
+
* (0.000752791) and float noise goes; from 1000 up, to the cent (1328.39).
|
|
44
|
+
* Never in exponent notation, and without trailing zeros.
|
|
45
|
+
*/
|
|
46
|
+
export function formatFxRate(rate: number): string {
|
|
47
|
+
if (!Number.isFinite(rate)) return String(rate);
|
|
48
|
+
const size = Math.abs(rate);
|
|
49
|
+
const decimals = size >= 1000 || size === 0 ? 2 : Math.min(15, Math.max(0, 5 - Math.floor(Math.log10(size))));
|
|
50
|
+
const fixed = rate.toFixed(decimals);
|
|
51
|
+
return fixed.includes(".") ? fixed.replace(/\.?0+$/, "") : fixed;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Both directions on one line: `1 NGN = 0.000752791 USD (USD/NGN 1328.39)`. */
|
|
55
|
+
export function describeFxRate(request: FxRequest, rate: number): string {
|
|
56
|
+
return `1 ${request.currency} = ${formatFxRate(rate)} ${request.baseCurrency} (${request.baseCurrency}/${request.currency} ${formatFxRate(1 / rate)})`;
|
|
57
|
+
}
|
package/src/cli/help.ts
CHANGED
|
@@ -10,6 +10,12 @@ import {
|
|
|
10
10
|
wrapText,
|
|
11
11
|
} from "../utils/cli-output";
|
|
12
12
|
|
|
13
|
+
/** `--section` of a command whose report has several tables. */
|
|
14
|
+
export const TABLE_SECTION_OPTION = {
|
|
15
|
+
flags: "--section <title|n>",
|
|
16
|
+
description: "With --csv or --ndjson, write only that table, by its title or number",
|
|
17
|
+
};
|
|
18
|
+
|
|
13
19
|
/** Headings of `gloomberb help`, in display order. */
|
|
14
20
|
export const CLI_COMMAND_GROUPS = {
|
|
15
21
|
research: "Research",
|
|
@@ -28,13 +34,25 @@ const INDENT = 2;
|
|
|
28
34
|
const MAX_HELP_WIDTH = 100;
|
|
29
35
|
const PIPED_HELP_WIDTH = 80;
|
|
30
36
|
|
|
37
|
+
/** Commands that run as written, for someone who has just installed it. */
|
|
38
|
+
const START_HERE: Array<[string, string]> = [
|
|
39
|
+
["gloomberb search apple", "Find a ticker from a company name"],
|
|
40
|
+
["gloomberb quote AAPL", "Show the latest price"],
|
|
41
|
+
["gloomberb ticker AAPL", "Open the full research report"],
|
|
42
|
+
["gloomberb catalog earnings", "Find a function, then run it with fn"],
|
|
43
|
+
];
|
|
44
|
+
|
|
31
45
|
const GLOBAL_OPTIONS: Array<[string, string]> = [
|
|
32
|
-
["--json
|
|
33
|
-
["--
|
|
46
|
+
["--json", "Print the full result as JSON"],
|
|
47
|
+
["--csv", "Print rows as CSV under the columns the text shows; fn reports and fundamentals put each table under # section: and end with # source lines"],
|
|
48
|
+
["--ndjson", "Print one JSON object per table row"],
|
|
49
|
+
["--limit <n>", "Show at most n rows, the first n as printed"],
|
|
50
|
+
["--tail <n>", "Show the newest n rows of a dated series (history, fred, econ) in their printed order, or the last n of another list"],
|
|
34
51
|
["--refresh", "Fetch fresh data instead of reading the cache"],
|
|
35
52
|
["--dry-run", "Preview config, cache, notes, alerts, plugin on/off, and remote changes without saving"],
|
|
36
53
|
["-q, --quiet", "Print no results or errors in text mode, for commands that print results"],
|
|
37
54
|
["--color, --no-color", "Force or turn off colors (NO_COLOR=1 also turns them off)"],
|
|
55
|
+
["--width <n>", "Fit tables to n columns (default: the terminal width; piped output is not fitted). shot takes its own --width in pixels"],
|
|
38
56
|
];
|
|
39
57
|
|
|
40
58
|
export interface CliHelpEntry {
|
|
@@ -90,6 +108,9 @@ export function renderCliHelp(entries: CliHelpEntry[], version: string, descript
|
|
|
90
108
|
`${cliStyles.bold("gloomberb")} ${cliStyles.muted(version)}`,
|
|
91
109
|
...wrapText(description, width),
|
|
92
110
|
"",
|
|
111
|
+
renderSection("Start here"),
|
|
112
|
+
...renderDefinitions(START_HERE, { width, termStyle: cliStyles.command }),
|
|
113
|
+
"",
|
|
93
114
|
renderSection("Usage"),
|
|
94
115
|
...renderDefinitions([
|
|
95
116
|
["gloomberb", "Open the terminal UI"],
|
|
@@ -178,14 +199,10 @@ function editDistance(left: string, right: string): number {
|
|
|
178
199
|
return previous[right.length]!;
|
|
179
200
|
}
|
|
180
201
|
|
|
181
|
-
|
|
182
|
-
export function suggestCliCommand(token: string, candidates: Iterable<string>): string | null {
|
|
183
|
-
const needle = token.trim().toLowerCase();
|
|
184
|
-
if (!needle || needle.startsWith("-")) return null;
|
|
202
|
+
function closestName(needle: string, candidates: Iterable<string>): string | null {
|
|
185
203
|
const allowed = needle.length <= 4 ? 1 : 2;
|
|
186
204
|
let best: { name: string; score: number } | null = null;
|
|
187
205
|
for (const candidate of candidates) {
|
|
188
|
-
if (candidate.startsWith("-")) continue;
|
|
189
206
|
// A clear prefix ("tick" for "ticker") beats an edit of the same size.
|
|
190
207
|
const score = needle.length >= 3 && candidate.startsWith(needle)
|
|
191
208
|
? 0.5
|
|
@@ -195,3 +212,19 @@ export function suggestCliCommand(token: string, candidates: Iterable<string>):
|
|
|
195
212
|
}
|
|
196
213
|
return best?.name ?? null;
|
|
197
214
|
}
|
|
215
|
+
|
|
216
|
+
/** The closest command token to a mistyped one, or null when nothing is plausibly meant. */
|
|
217
|
+
export function suggestCliCommand(token: string, candidates: Iterable<string>): string | null {
|
|
218
|
+
const needle = token.trim().toLowerCase();
|
|
219
|
+
if (!needle || needle.startsWith("-")) return null;
|
|
220
|
+
return closestName(needle, [...candidates].filter((candidate) => !candidate.startsWith("-")));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** The closest of a command's options to a mistyped one (`--rnage` for `--range`), or null. */
|
|
224
|
+
export function suggestCliOption(flag: string, options: Iterable<string>): string | null {
|
|
225
|
+
const needle = flag.trim().toLowerCase().replace(/^-+/, "");
|
|
226
|
+
if (!needle) return null;
|
|
227
|
+
const byName = new Map([...options].map((option) => [option.replace(/^-+/, ""), option] as const));
|
|
228
|
+
const name = closestName(needle, byName.keys());
|
|
229
|
+
return name == null ? null : byName.get(name)!;
|
|
230
|
+
}
|