gloomberb 0.16.3 → 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/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/commands/crypto-hints.ts +12 -4
- package/src/cli/commands/market.ts +359 -99
- package/src/cli/commands/options-chain.ts +172 -0
- package/src/cli/commands/options-leaps.ts +422 -0
- package/src/cli/commands/overview.ts +164 -26
- 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 +62 -30
- package/src/cli/desktop-pane-shot.ts +97 -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 +14 -1
- package/src/cli/index-roots.ts +51 -0
- package/src/cli/index.ts +9 -6
- package/src/cli/listing-arg.ts +211 -3
- package/src/cli/not-a-ticker.ts +37 -0
- package/src/cli/options.ts +50 -6
- package/src/cli/pane-functions/capabilities.ts +8 -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 +21 -13
- package/src/cli/pane-functions/freshness.ts +205 -26
- package/src/cli/pane-functions/function-help.ts +67 -22
- package/src/cli/pane-functions/headless.ts +5 -4
- package/src/cli/pane-functions/index.ts +3 -0
- 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 +4 -0
- package/src/cli/pane-functions/resolver.ts +4 -6
- package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
- package/src/cli/pane-functions/screenshot.ts +105 -23
- package/src/cli/registry.ts +2 -1
- package/src/cli/result.ts +50 -13
- 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/view.tsx +28 -9
- 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 +1 -1
- package/src/components/layout/shell/drag/index.ts +4 -0
- package/src/components/layout/shell/drag/live.ts +76 -5
- package/src/components/layout/shell/drag/runtime.ts +8 -8
- package/src/components/layout/shell/index.tsx +47 -6
- package/src/components/layout/shell/layout-state.ts +5 -11
- package/src/components/layout/shell/menu.ts +28 -1
- package/src/components/layout/shell/pane/actions.ts +2 -1
- package/src/components/layout/shell/pane/layers.tsx +51 -10
- 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/visible-layout.ts +44 -1
- 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/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 +118 -18
- 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/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/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/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/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-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/headless.ts +6 -1
- package/src/plugins/builtin/holders/pane.tsx +3 -0
- 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 +109 -39
- 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/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/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/cli/portfolio-command.ts +71 -36
- package/src/plugins/builtin/portfolio-list/cli/render.ts +87 -18
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +2 -16
- package/src/plugins/builtin/portfolio-list/headless.ts +38 -7
- 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/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/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 +4 -4
- 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/supply-chain/model.ts +1 -1
- package/src/plugins/builtin/ticker-detail/headless.ts +43 -21
- 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/geo-series.ts +1 -1
- package/src/plugins/builtin/world-venue-map/index.ts +1 -1
- 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/dom/desktop/icons.tsx +14 -0
- package/src/renderers/dom/desktop/query-bar.tsx +59 -32
- package/src/renderers/dom/host/box.tsx +1 -1
- package/src/renderers/dom/host/drag-shield.ts +17 -6
- package/src/renderers/dom/host/live-frame.ts +10 -2
- package/src/renderers/dom/input-host.tsx +6 -1
- package/src/renderers/dom/styles.css +13 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +5 -1
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +12 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -1
- package/src/renderers/electrobun/shared/protocol.ts +2 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +101 -5
- package/src/renderers/electrobun/view/main.tsx +4 -1
- package/src/renderers/opentui/input-host.tsx +6 -1
- package/src/renderers/opentui/start.tsx +9 -0
- package/src/shares/portable-layout.ts +16 -6
- package/src/sources/gloomberb-cloud/index.ts +19 -10
- package/src/sources/gloomberb-cloud/normalizers.ts +4 -1
- package/src/sources/listing-symbols.ts +11 -5
- package/src/sources/provider-errors.ts +88 -3
- package/src/sources/provider-router/cached-routes.ts +8 -4
- package/src/sources/provider-router/financial-routes.ts +11 -5
- package/src/sources/provider-router/financials.ts +42 -15
- 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 +23 -5
- package/src/sources/sec-edgar.ts +68 -8
- 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/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/resolve.ts +1 -14
- package/src/types/config.ts +61 -1
- 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 +8 -4
- package/src/ui/index.tsx +2 -0
- package/src/utils/cli-output.ts +14 -1
- package/src/utils/exchanges.ts +13 -0
- package/src/utils/format.ts +2 -1
- package/src/utils/fx-market-hours.ts +34 -0
- package/src/utils/option-expiry.ts +126 -0
- 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
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
isPaneDocked,
|
|
9
9
|
} from "../../layout/pane-manager";
|
|
10
10
|
import type { PluginRegistry } from "../../plugins/registry";
|
|
11
|
+
import { PluginOffError, notifyPluginOff } from "../../plugins/plugin-off";
|
|
11
12
|
import { findFixedTickerPaneForSymbol } from "../../layout/ticker-navigation";
|
|
12
13
|
import type { AppAction, AppState } from "../../state/app/context";
|
|
13
14
|
import { TICKER_RESEARCH_PANE_ID, normalizePaneId } from "../../types/config";
|
|
@@ -98,10 +99,23 @@ export function useAppTickerOpenRuntime({
|
|
|
98
99
|
}
|
|
99
100
|
}, [dispatch, pluginRegistry.events, stateRef]);
|
|
100
101
|
|
|
102
|
+
/**
|
|
103
|
+
* A ticker opens in a pane of its plugin, which is added hidden while that
|
|
104
|
+
* plugin is off, so the open is refused with an offer to turn it on.
|
|
105
|
+
*/
|
|
106
|
+
const refuseWhileOwnerOff = useCallback((symbol: string, options: PinTickerOptions | undefined, reopen: () => void) => {
|
|
107
|
+
const paneType = normalizePaneId(options?.paneType ?? TICKER_RESEARCH_PANE_ID);
|
|
108
|
+
const owner = pluginRegistry.getDisabledPaneOwner(paneType, stateRef.current.config.disabledPlugins);
|
|
109
|
+
if (!owner) return false;
|
|
110
|
+
notifyPluginOff(pluginRegistry, new PluginOffError(owner, symbol), reopen);
|
|
111
|
+
return true;
|
|
112
|
+
}, [pluginRegistry, stateRef]);
|
|
113
|
+
|
|
101
114
|
const placePinnedTickerTarget = useCallback((target: TickerOpenTarget, options?: PinTickerOptions) => {
|
|
102
115
|
const paneType = normalizePaneId(options?.paneType ?? TICKER_RESEARCH_PANE_ID);
|
|
103
116
|
const paneDef = pluginRegistry.panes.get(paneType);
|
|
104
117
|
if (!paneDef) return;
|
|
118
|
+
if (refuseWhileOwnerOff(target.symbol, options, () => placePinnedTickerTarget(target, options))) return;
|
|
105
119
|
|
|
106
120
|
publishTickerOpenTarget(target);
|
|
107
121
|
const symbol = target.symbol;
|
|
@@ -182,10 +196,13 @@ export function useAppTickerOpenRuntime({
|
|
|
182
196
|
persistLayout,
|
|
183
197
|
pluginRegistry,
|
|
184
198
|
publishTickerOpenTarget,
|
|
199
|
+
refuseWhileOwnerOff,
|
|
185
200
|
stateRef,
|
|
186
201
|
]);
|
|
187
202
|
|
|
188
203
|
const openPinnedTicker = useCallback(async (rawSymbol: string, options?: PinTickerOptions) => {
|
|
204
|
+
// Before resolving, so a refused open adds no ticker either.
|
|
205
|
+
if (refuseWhileOwnerOff(rawSymbol, options, () => { void openPinnedTicker(rawSymbol, options); })) return;
|
|
189
206
|
const recordAttention = captureAttentionAction();
|
|
190
207
|
const selectedTicker = options?.instrument !== undefined && (options.instrument || options.listing) ? await tickerRepository.loadTicker(rawSymbol) : null;
|
|
191
208
|
const target = selectedTicker
|
|
@@ -197,7 +214,7 @@ export function useAppTickerOpenRuntime({
|
|
|
197
214
|
if (action && pluginRegistry.panes.has(options?.paneType ?? TICKER_RESEARCH_PANE_ID)) {
|
|
198
215
|
recordAttention(publicTickerKey(target.symbol, target.listing?.exchange ?? target.ticker.metadata.exchange), action);
|
|
199
216
|
}
|
|
200
|
-
}, [placePinnedTickerTarget, pluginRegistry, resolveOpenTickerTarget, tickerRepository]);
|
|
217
|
+
}, [placePinnedTickerTarget, pluginRegistry, refuseWhileOwnerOff, resolveOpenTickerTarget, tickerRepository]);
|
|
201
218
|
|
|
202
219
|
return {
|
|
203
220
|
openPinnedTicker,
|
|
@@ -15,6 +15,7 @@ import { openTeamPane } from "../../plugins/builtin/cloud/team/pane-request";
|
|
|
15
15
|
import { chatController } from "../../plugins/builtin/chat/controller";
|
|
16
16
|
import { getShare } from "../../shares/api";
|
|
17
17
|
import { openPaneShare } from "../../shares/pane";
|
|
18
|
+
import { PluginOffError, notifyPluginOff } from "../../plugins/plugin-off";
|
|
18
19
|
import { materializeMarketplaceLayout } from "../../shares/portable-layout";
|
|
19
20
|
|
|
20
21
|
type CloudDeepLinkRoute = {
|
|
@@ -564,6 +565,10 @@ export function handleDesktopDeepLink(rawUrl: string, options: DesktopDeepLinkHa
|
|
|
564
565
|
return;
|
|
565
566
|
case "open-share":
|
|
566
567
|
void handleOpenShare(action, options.pluginRegistry).catch((error) => {
|
|
568
|
+
if (error instanceof PluginOffError) {
|
|
569
|
+
notifyPluginOff(options.pluginRegistry, error, () => handleDesktopDeepLink(rawUrl, options));
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
567
572
|
notifyError(options.pluginRegistry, error instanceof Error ? error.message : "Could not open shared pane.");
|
|
568
573
|
});
|
|
569
574
|
return;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { StarPromptConfig } from "../../types/config";
|
|
2
|
+
import { isRecord } from "../../utils/guards";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The one-time line in the terminal's status bar asking to star the
|
|
6
|
+
* repository. It waits for the third distinct day the terminal app is opened
|
|
7
|
+
* on, then for a minute on screen that day, shows once, and never again:
|
|
8
|
+
* opening the repository, dismissing it and its timeout all end it, and so
|
|
9
|
+
* does quitting while it shows. `starPrompt.enabled: false` turns it off.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export const STAR_PROMPT_REPO_URL = "https://github.com/gloom-sh/gloomberb";
|
|
13
|
+
/** The line waits for this many distinct days of use, today included. */
|
|
14
|
+
const STAR_PROMPT_SESSION_DAYS = 3;
|
|
15
|
+
/** On-screen time on the due day before the line shows. */
|
|
16
|
+
export const STAR_PROMPT_DELAY_MS = 60_000;
|
|
17
|
+
/** On-screen time the line stays before it times out. */
|
|
18
|
+
export const STAR_PROMPT_VISIBLE_MS = 5 * 60_000;
|
|
19
|
+
|
|
20
|
+
type StarPromptOutcome = NonNullable<StarPromptConfig["outcome"]>;
|
|
21
|
+
|
|
22
|
+
const DAY_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
|
|
23
|
+
const OUTCOMES = new Set<StarPromptOutcome>(["opened", "dismissed", "expired"]);
|
|
24
|
+
|
|
25
|
+
/** The local calendar day of `date`, as `YYYY-MM-DD`. */
|
|
26
|
+
export function localDayKey(date: Date): string {
|
|
27
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
28
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
29
|
+
return `${date.getFullYear()}-${month}-${day}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function isOff(state: StarPromptConfig | undefined): boolean {
|
|
33
|
+
return state?.enabled === false || !!state?.shownAt;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Adds `day` to the days of use. Returns the same object when nothing changes:
|
|
38
|
+
* the line is off or already shown, the day is known, or enough days are.
|
|
39
|
+
*/
|
|
40
|
+
export function recordStarPromptDay(state: StarPromptConfig | undefined, day: string): StarPromptConfig | undefined {
|
|
41
|
+
if (isOff(state)) return state;
|
|
42
|
+
const days = state?.days ?? [];
|
|
43
|
+
if (days.includes(day) || days.length >= STAR_PROMPT_SESSION_DAYS) return state;
|
|
44
|
+
return { ...state, days: [...days, day] };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Whether the line is waiting to show: on, never shown, and used on enough days. */
|
|
48
|
+
export function isStarPromptDue(state: StarPromptConfig | undefined): boolean {
|
|
49
|
+
return !isOff(state) && (state?.days?.length ?? 0) >= STAR_PROMPT_SESSION_DAYS;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Records that the line showed. The days are no longer needed once it has. */
|
|
53
|
+
export function markStarPromptShown(state: StarPromptConfig | undefined, at: Date): StarPromptConfig {
|
|
54
|
+
const { days: _days, ...rest } = state ?? {};
|
|
55
|
+
return { ...rest, shownAt: at.toISOString() };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function finishStarPrompt(state: StarPromptConfig | undefined, outcome: StarPromptOutcome): StarPromptConfig {
|
|
59
|
+
return { ...state, outcome };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Only the fields that hold a valid value survive; an empty object is the same as none. */
|
|
63
|
+
export function sanitizeStarPrompt(value: unknown): StarPromptConfig | undefined {
|
|
64
|
+
if (!isRecord(value)) return undefined;
|
|
65
|
+
const days = Array.isArray(value.days)
|
|
66
|
+
? [...new Set(value.days.filter((day): day is string => typeof day === "string" && DAY_PATTERN.test(day)))]
|
|
67
|
+
.slice(0, STAR_PROMPT_SESSION_DAYS)
|
|
68
|
+
: [];
|
|
69
|
+
const state: StarPromptConfig = {
|
|
70
|
+
...(typeof value.enabled === "boolean" ? { enabled: value.enabled } : {}),
|
|
71
|
+
...(days.length > 0 ? { days } : {}),
|
|
72
|
+
...(typeof value.shownAt === "string" && value.shownAt ? { shownAt: value.shownAt } : {}),
|
|
73
|
+
...(typeof value.outcome === "string" && OUTCOMES.has(value.outcome as StarPromptOutcome)
|
|
74
|
+
? { outcome: value.outcome as StarPromptOutcome }
|
|
75
|
+
: {}),
|
|
76
|
+
};
|
|
77
|
+
return Object.keys(state).length > 0 ? state : undefined;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function isSet(value: string | undefined): boolean {
|
|
81
|
+
const normalized = value?.trim().toLowerCase();
|
|
82
|
+
return !!normalized && normalized !== "0" && normalized !== "false";
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Whether this process is someone sitting at the terminal: both ends of the
|
|
87
|
+
* terminal are a TTY, and it is neither a CI job nor a test run. Bots, CI,
|
|
88
|
+
* scripts and smoke runs that pipe the app never see the line.
|
|
89
|
+
*/
|
|
90
|
+
export function starPromptEnvironmentAllows(input: {
|
|
91
|
+
env: Record<string, string | undefined>;
|
|
92
|
+
stdinIsTTY: boolean | undefined;
|
|
93
|
+
stdoutIsTTY: boolean | undefined;
|
|
94
|
+
}): boolean {
|
|
95
|
+
if (input.stdinIsTTY !== true || input.stdoutIsTTY !== true) return false;
|
|
96
|
+
if (isSet(input.env.CI)) return false;
|
|
97
|
+
return input.env.NODE_ENV !== "test";
|
|
98
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Off everywhere until the terminal app's entry point allows it, after
|
|
3
|
+
* `starPromptEnvironmentAllows`: the desktop app, the web terminal, CLI
|
|
4
|
+
* commands, `shot` and tests never record days or show the line.
|
|
5
|
+
*/
|
|
6
|
+
let allowed = false;
|
|
7
|
+
|
|
8
|
+
export function allowStarPrompt(value: boolean): void {
|
|
9
|
+
allowed = value;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function isStarPromptAllowed(): boolean {
|
|
13
|
+
return allowed;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface StarPromptKeyHandlers {
|
|
17
|
+
open(): void;
|
|
18
|
+
dismiss(): void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** What the notification keys do while the line shows; null otherwise. */
|
|
22
|
+
let keyHandlers: StarPromptKeyHandlers | null = null;
|
|
23
|
+
|
|
24
|
+
/** Hands the notification keys to the line while it shows; returns the release. */
|
|
25
|
+
export function bindStarPromptKeys(handlers: StarPromptKeyHandlers): () => void {
|
|
26
|
+
keyHandlers = handlers;
|
|
27
|
+
return () => {
|
|
28
|
+
if (keyHandlers === handlers) keyHandlers = null;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Runs the line's open or dismiss for the notification keys. False when the
|
|
34
|
+
* line is not showing, so the key goes on to whatever else wants it.
|
|
35
|
+
*/
|
|
36
|
+
export function pressStarPromptKey(kind: "open" | "dismiss"): boolean {
|
|
37
|
+
if (!keyHandlers) return false;
|
|
38
|
+
if (kind === "open") keyHandlers.open();
|
|
39
|
+
else keyHandlers.dismiss();
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
import { Box, Span, Text, useActionShortcut, useRendererHost } from "../../ui";
|
|
3
|
+
import { Button } from "../../components/ui/button";
|
|
4
|
+
import {
|
|
5
|
+
STATUS_WIDGET_COLUMNS,
|
|
6
|
+
useStatusWidgetClaim,
|
|
7
|
+
useStatusWidgetRoom,
|
|
8
|
+
} from "../../components/layout/status-widget-space";
|
|
9
|
+
import { t } from "../../i18n";
|
|
10
|
+
import { useAppLanguage } from "../../i18n/react";
|
|
11
|
+
import { useAppActive } from "../../state/app/activity";
|
|
12
|
+
import { useAppDispatch, useAppGetState, useAppSelector } from "../../state/app/context";
|
|
13
|
+
import { scheduleConfigSave } from "../../state/config-save-scheduler";
|
|
14
|
+
import { useThemeColors } from "../../theme/theme-context";
|
|
15
|
+
import type { StarPromptConfig } from "../../types/config";
|
|
16
|
+
import { displayWidth } from "../../utils/format";
|
|
17
|
+
import {
|
|
18
|
+
finishStarPrompt,
|
|
19
|
+
isStarPromptDue,
|
|
20
|
+
localDayKey,
|
|
21
|
+
markStarPromptShown,
|
|
22
|
+
recordStarPromptDay,
|
|
23
|
+
STAR_PROMPT_DELAY_MS,
|
|
24
|
+
STAR_PROMPT_REPO_URL,
|
|
25
|
+
STAR_PROMPT_VISIBLE_MS,
|
|
26
|
+
} from "./model";
|
|
27
|
+
import { bindStarPromptKeys, isStarPromptAllowed } from "./runtime";
|
|
28
|
+
|
|
29
|
+
/** A session left open past midnight counts the new day too. */
|
|
30
|
+
const DAY_CHECK_INTERVAL_MS = 10 * 60_000;
|
|
31
|
+
const STAR = "★ ";
|
|
32
|
+
/** Between the star action and the dismiss one. */
|
|
33
|
+
const GAP = " ";
|
|
34
|
+
|
|
35
|
+
interface StarPromptCopy {
|
|
36
|
+
lead: string;
|
|
37
|
+
columns: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The longest lead the status bar has room for beside its other widgets, or
|
|
42
|
+
* null when not even the short one fits; the line then waits for a wider
|
|
43
|
+
* terminal rather than show cut off.
|
|
44
|
+
*/
|
|
45
|
+
function starPromptCopy(widgetRoom: number, openKey: string, dismissKey: string): StarPromptCopy | null {
|
|
46
|
+
const spare = widgetRoom - STATUS_WIDGET_COLUMNS;
|
|
47
|
+
const keys = (openKey ? 1 + displayWidth(openKey) : 0)
|
|
48
|
+
+ GAP.length
|
|
49
|
+
+ 1 + (dismissKey ? 1 + displayWidth(dismissKey) : 0)
|
|
50
|
+
// The chip padding after the line.
|
|
51
|
+
+ 1;
|
|
52
|
+
for (const lead of [t("Enjoying Gloomberb? Star it on GitHub"), t("Star on GitHub")]) {
|
|
53
|
+
const columns = displayWidth(STAR + lead) + keys;
|
|
54
|
+
if (spare >= columns) return { lead, columns };
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
type Phase = "waiting" | "showing" | "done";
|
|
60
|
+
|
|
61
|
+
interface StarPromptStatusLineProps {
|
|
62
|
+
delayMs?: number;
|
|
63
|
+
visibleMs?: number;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* One line in the terminal's status bar, once, asking to star the repository:
|
|
68
|
+
* the notification action key opens it in the browser, the dismiss key or the
|
|
69
|
+
* × hides it, and it times out on its own. It never takes focus and sits in
|
|
70
|
+
* the status bar's own row, so it covers nothing. See `./model.ts` for when.
|
|
71
|
+
*/
|
|
72
|
+
export function StarPromptStatusLine(props: StarPromptStatusLineProps) {
|
|
73
|
+
if (!isStarPromptAllowed()) return null;
|
|
74
|
+
return <StarPromptLine {...props} />;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function StarPromptLine({ delayMs = STAR_PROMPT_DELAY_MS, visibleMs = STAR_PROMPT_VISIBLE_MS }: StarPromptStatusLineProps) {
|
|
78
|
+
useAppLanguage();
|
|
79
|
+
const colors = useThemeColors();
|
|
80
|
+
const dispatch = useAppDispatch();
|
|
81
|
+
const getState = useAppGetState();
|
|
82
|
+
const rendererHost = useRendererHost();
|
|
83
|
+
const onScreen = useAppActive();
|
|
84
|
+
const widgetRoom = useStatusWidgetRoom();
|
|
85
|
+
const openKey = useActionShortcut("notification-action");
|
|
86
|
+
const dismissKey = useActionShortcut("notification-dismiss");
|
|
87
|
+
const starPrompt = useAppSelector((state) => state.config.starPrompt);
|
|
88
|
+
// Days of use count from the first one past setup.
|
|
89
|
+
const onboarded = useAppSelector((state) => state.config.onboardingComplete === true && !state.config.onboardingProgress);
|
|
90
|
+
const [phase, setPhase] = useState<Phase>("waiting");
|
|
91
|
+
const waitedMs = useRef(0);
|
|
92
|
+
const shownMs = useRef(0);
|
|
93
|
+
const copy = starPromptCopy(widgetRoom, openKey, dismissKey);
|
|
94
|
+
const fits = copy !== null;
|
|
95
|
+
const due = isStarPromptDue(starPrompt);
|
|
96
|
+
|
|
97
|
+
const update = useCallback((change: (state: StarPromptConfig | undefined) => StarPromptConfig | undefined) => {
|
|
98
|
+
const current = getState().config.starPrompt;
|
|
99
|
+
const next = change(current);
|
|
100
|
+
if (next === current) return;
|
|
101
|
+
dispatch({ type: "SET_STAR_PROMPT", starPrompt: next });
|
|
102
|
+
// Assembled when the write fires, recent tickers included, as the app's own saves are.
|
|
103
|
+
scheduleConfigSave(() => {
|
|
104
|
+
const state = getState();
|
|
105
|
+
return { ...state.config, recentTickers: state.recentTickers };
|
|
106
|
+
});
|
|
107
|
+
}, [dispatch, getState]);
|
|
108
|
+
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
if (!onboarded) return;
|
|
111
|
+
const record = () => update((state) => recordStarPromptDay(state, localDayKey(new Date())));
|
|
112
|
+
record();
|
|
113
|
+
const timer = setInterval(record, DAY_CHECK_INTERVAL_MS);
|
|
114
|
+
return () => clearInterval(timer);
|
|
115
|
+
}, [onboarded, update]);
|
|
116
|
+
|
|
117
|
+
// Counts only time on screen with room for the line, so it never shows to
|
|
118
|
+
// a terminal in the background or too narrow to read it.
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
if (phase !== "waiting" || !due || !onScreen || !fits) return;
|
|
121
|
+
const startedAt = Date.now();
|
|
122
|
+
const timer = setTimeout(() => {
|
|
123
|
+
if (!isStarPromptDue(getState().config.starPrompt)) {
|
|
124
|
+
setPhase("done");
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
// Recorded as it appears, so quitting while it shows also ends it.
|
|
128
|
+
update((state) => markStarPromptShown(state, new Date()));
|
|
129
|
+
setPhase("showing");
|
|
130
|
+
}, Math.max(0, delayMs - waitedMs.current));
|
|
131
|
+
return () => {
|
|
132
|
+
clearTimeout(timer);
|
|
133
|
+
waitedMs.current += Date.now() - startedAt;
|
|
134
|
+
};
|
|
135
|
+
}, [delayMs, due, fits, getState, onScreen, phase, update]);
|
|
136
|
+
|
|
137
|
+
const finish = useCallback((outcome: NonNullable<StarPromptConfig["outcome"]>) => {
|
|
138
|
+
update((state) => finishStarPrompt(state, outcome));
|
|
139
|
+
setPhase("done");
|
|
140
|
+
}, [update]);
|
|
141
|
+
const open = useCallback(() => {
|
|
142
|
+
void rendererHost.openExternal(STAR_PROMPT_REPO_URL);
|
|
143
|
+
finish("opened");
|
|
144
|
+
}, [finish, rendererHost]);
|
|
145
|
+
const dismiss = useCallback(() => finish("dismissed"), [finish]);
|
|
146
|
+
|
|
147
|
+
useEffect(() => {
|
|
148
|
+
if (phase !== "showing" || !onScreen) return;
|
|
149
|
+
const startedAt = Date.now();
|
|
150
|
+
const timer = setTimeout(() => finish("expired"), Math.max(0, visibleMs - shownMs.current));
|
|
151
|
+
return () => {
|
|
152
|
+
clearTimeout(timer);
|
|
153
|
+
shownMs.current += Date.now() - startedAt;
|
|
154
|
+
};
|
|
155
|
+
}, [finish, onScreen, phase, visibleMs]);
|
|
156
|
+
|
|
157
|
+
const showing = phase === "showing" && fits;
|
|
158
|
+
useEffect(() => (showing ? bindStarPromptKeys({ open, dismiss }) : undefined), [dismiss, open, showing]);
|
|
159
|
+
// The version chip gives way to the line.
|
|
160
|
+
useStatusWidgetClaim("star-prompt", showing && copy ? copy.columns : 0);
|
|
161
|
+
|
|
162
|
+
if (!showing || !copy) return null;
|
|
163
|
+
return (
|
|
164
|
+
<Box flexDirection="row" flexShrink={0} paddingRight={1} data-gloom-role="star-prompt">
|
|
165
|
+
<Button
|
|
166
|
+
label={t("Star Gloomberb on GitHub")}
|
|
167
|
+
variant="plain"
|
|
168
|
+
compact
|
|
169
|
+
shortcut={openKey || undefined}
|
|
170
|
+
stopPropagation
|
|
171
|
+
onPress={open}
|
|
172
|
+
>
|
|
173
|
+
<Text fg={colors.text}>
|
|
174
|
+
<Span fg={colors.warning}>{STAR}</Span>
|
|
175
|
+
{copy.lead}
|
|
176
|
+
</Text>
|
|
177
|
+
</Button>
|
|
178
|
+
<Text>{GAP}</Text>
|
|
179
|
+
<Button
|
|
180
|
+
label={t("Dismiss")}
|
|
181
|
+
displayLabel="×"
|
|
182
|
+
variant="plain"
|
|
183
|
+
compact
|
|
184
|
+
shortcut={dismissKey || undefined}
|
|
185
|
+
stopPropagation
|
|
186
|
+
onPress={dismiss}
|
|
187
|
+
/>
|
|
188
|
+
</Box>
|
|
189
|
+
);
|
|
190
|
+
}
|
package/src/app.tsx
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import { bindAppActivity, useAppActive, useAppVisible } from "./state/app/activity";
|
|
13
13
|
import { Header } from "./components/layout/header";
|
|
14
14
|
import { StatusBar } from "./components/layout/status-bar";
|
|
15
|
+
import { useAppChromeShown } from "./components/layout/presentation";
|
|
15
16
|
import { useLinkedLayoutSync } from "./layout-marketplace/linked-sync";
|
|
16
17
|
import { useTeamCollectionsSync } from "./plugins/builtin/cloud/team/collections-sync";
|
|
17
18
|
import { Shell } from "./components/layout/shell";
|
|
@@ -20,6 +21,7 @@ import { TransientLayoutProvider } from "./components/layout/transient-layout";
|
|
|
20
21
|
import { CommandBar } from "./components/command-bar/surface";
|
|
21
22
|
import { OnboardingWizard } from "./components/onboarding/onboarding-wizard";
|
|
22
23
|
import { CompanyPickerHost } from "./plugins/builtin/cloud/company-picker";
|
|
24
|
+
import { TerminalRelayHost } from "./plugins/builtin/cloud/terminal-relay/host";
|
|
23
25
|
import { SignInGate } from "./components/sign-in-gate";
|
|
24
26
|
import { useDialog } from "./ui/dialog";
|
|
25
27
|
import { PluginRegistry } from "./plugins/registry";
|
|
@@ -400,6 +402,7 @@ function AppInner({
|
|
|
400
402
|
}
|
|
401
403
|
}, [focusedTickerSymbol]);
|
|
402
404
|
|
|
405
|
+
const chrome = useAppChromeShown();
|
|
403
406
|
const keybindingHost = useUiHost().kind === "opentui" ? "terminal" : "desktop";
|
|
404
407
|
const keybindings = useResolvedKeybindings(state.config.keybindings, keybindingHost);
|
|
405
408
|
useAppGlobalShortcuts({
|
|
@@ -451,13 +454,15 @@ function AppInner({
|
|
|
451
454
|
desktopWindowBridge={desktopWindowBridge}
|
|
452
455
|
>
|
|
453
456
|
<ThemedAppRoot>
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
457
|
+
{chrome.header && (
|
|
458
|
+
<Header
|
|
459
|
+
onOpenHelp={() => {
|
|
460
|
+
recordFunctionOpen({ shortcut: "HELP", externalPluginId: null });
|
|
461
|
+
pluginRegistry.showPane("help");
|
|
462
|
+
}}
|
|
463
|
+
onRestartForUpdate={updatesEnabled && !isDetachedWindow ? restartToApplyUpdate : undefined}
|
|
464
|
+
/>
|
|
465
|
+
)}
|
|
461
466
|
<TransientLayoutProvider>
|
|
462
467
|
<Shell
|
|
463
468
|
pluginRegistry={pluginRegistry}
|
|
@@ -476,6 +481,7 @@ function AppInner({
|
|
|
476
481
|
/>
|
|
477
482
|
</TransientLayoutProvider>
|
|
478
483
|
{!onboardingActive ? <CompanyPickerHost pluginRegistry={pluginRegistry} /> : null}
|
|
484
|
+
<TerminalRelayHost device={remoteControlAdapter?.terminalDevice} />
|
|
479
485
|
{onboardingActive && onOnboardingComplete ? (
|
|
480
486
|
<OnboardingWizard
|
|
481
487
|
pluginRegistry={pluginRegistry}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"src/api-client/askg.ts": ["cloud"],
|
|
3
|
+
"src/app.tsx": ["cloud"],
|
|
4
|
+
"src/app/global-shortcuts.ts": ["help"],
|
|
5
|
+
"src/app/pane-runtime/plugin-bindings.ts": ["broker-manager","layout-manager","plugin-marketplace"],
|
|
6
|
+
"src/app/runtime/broker-import.ts": ["portfolio-list"],
|
|
7
|
+
"src/app/runtime/desktop-deeplink.ts": ["account-management","chat","cloud"],
|
|
8
|
+
"src/app/runtime/startup.ts": ["chat","plugin-marketplace"],
|
|
9
|
+
"src/brokers/signed-in/sign-in-dialog.tsx": ["cloud"],
|
|
10
|
+
"src/cli/commands/market.ts": ["holders","research","sec"],
|
|
11
|
+
"src/cli/commands/options-chain.ts": ["options","options-calculator"],
|
|
12
|
+
"src/cli/commands/options-leaps.ts": ["options","vol-surface"],
|
|
13
|
+
"src/cli/commands/overview.ts": ["correlation","econ","market-movers","sectors","world-indices"],
|
|
14
|
+
"src/cli/commands/ticker.ts": ["notes","portfolio-list"],
|
|
15
|
+
"src/cli/desktop-pane-shot.ts": ["market-valuation","time-sales"],
|
|
16
|
+
"src/cli/pane-functions/data.ts": ["chart-composer","correlation","seasonality","ticker-detail"],
|
|
17
|
+
"src/cli/pane-functions/financial-ratio-shot.ts": ["ticker-detail"],
|
|
18
|
+
"src/cli/pane-functions/headless.ts": ["portfolio-list"],
|
|
19
|
+
"src/cli/pane-functions/options.ts": ["ticker-detail"],
|
|
20
|
+
"src/cli/pane-functions/resolver.ts": ["chart-composer"],
|
|
21
|
+
"src/cli/pane-functions/screenshot-evidence.ts": ["attention","awards","catalysts","company-attention","company-kpis","credit-documents","exposure","market-heatmap","options-calculator","options-scenario","power","realized-vol","supply-chain","vol-surface","volatility","world-venue-map"],
|
|
22
|
+
"src/cli/pane-functions/screenshot.ts": ["chart-composer","econ-statistics","market-valuation","portfolio-list","ticker-detail","time-sales"],
|
|
23
|
+
"src/components/command-bar/commands/collection.ts": ["portfolio-list"],
|
|
24
|
+
"src/components/command-bar/commands/direct/index.ts": ["broker-manager","portfolio-list"],
|
|
25
|
+
"src/components/command-bar/routes/root/command-items.ts": ["portfolio-list"],
|
|
26
|
+
"src/components/command-bar/routes/root/help-items.ts": ["help"],
|
|
27
|
+
"src/components/command-bar/routes/root/plugin-install.ts": ["plugin-marketplace"],
|
|
28
|
+
"src/components/command-bar/routes/root/shortcut-items.ts": ["portfolio-list"],
|
|
29
|
+
"src/components/command-bar/workflow/builtin.ts": ["cloud","portfolio-list"],
|
|
30
|
+
"src/components/command-bar/workflow/collection-actions.ts": ["cloud","portfolio-list"],
|
|
31
|
+
"src/components/command-bar/workflow/ops.ts": ["correlation","portfolio-list","ticker-detail"],
|
|
32
|
+
"src/components/command-bar/workflow/tickers.ts": ["portfolio-list"],
|
|
33
|
+
"src/components/feedback-dialog.tsx": ["cloud"],
|
|
34
|
+
"src/components/form-modal/routes.ts": ["portfolio-list"],
|
|
35
|
+
"src/components/index.ts": ["portfolio-list"],
|
|
36
|
+
"src/components/layout/missing-pane.tsx": ["plugin-marketplace"],
|
|
37
|
+
"src/components/layout/shell/index.tsx": ["cloud"],
|
|
38
|
+
"src/components/layout/status-bar-groups.ts": ["cloud"],
|
|
39
|
+
"src/components/layout/status-bar.tsx": ["cloud"],
|
|
40
|
+
"src/components/onboarding/account-step/form-panel.tsx": ["cloud"],
|
|
41
|
+
"src/components/onboarding/account-step/index.tsx": ["cloud"],
|
|
42
|
+
"src/components/onboarding/account-step/qr-panel.tsx": ["cloud"],
|
|
43
|
+
"src/components/onboarding/account-step/signed-in-panel.tsx": ["cloud"],
|
|
44
|
+
"src/components/onboarding/onboarding-keyboard.ts": ["account-management"],
|
|
45
|
+
"src/components/onboarding/onboarding-wizard.tsx": ["account-management","cloud"],
|
|
46
|
+
"src/components/onboarding/use-onboarding-upgrade.ts": ["account-management","chat","cloud"],
|
|
47
|
+
"src/components/onboarding/wizard-account.ts": ["cloud"],
|
|
48
|
+
"src/components/onboarding/wizard-model.ts": ["portfolio-list"],
|
|
49
|
+
"src/components/onboarding/wizard-positions.ts": ["portfolio-list"],
|
|
50
|
+
"src/components/sign-in-gate.tsx": ["cloud"],
|
|
51
|
+
"src/layout-marketplace/gallery.tsx": ["cloud","plugin-marketplace"],
|
|
52
|
+
"src/layout-marketplace/linked-sync.ts": ["cloud"],
|
|
53
|
+
"src/layout/desks.ts": ["chart-composer"],
|
|
54
|
+
"src/plugins/auto-update-node.ts": ["plugin-marketplace"],
|
|
55
|
+
"src/plugins/auto-update.ts": ["plugin-marketplace"],
|
|
56
|
+
"src/plugins/catalog-browser.ts": ["alerts","analytics","attention","awards","backtest","bond-calculator","catalysts","cds","central-bank-rates","changelog","chart-composer","clinical-trials","cloud","comment-letters","company-attention","company-kpis","connections","correlation","cot","cpi","credit-boards","credit-conditions","credit-documents","crypto-board","debt-maturities","dividend-yield","doe","earnings-calls","earnings-ripple","econ","econ-statistics","equity-screener","estimate-revisions","executives","exposure","fear-greed","filing-events","futures","futures-curve","fx-matrix","gpu","help","insider","ipo-calendar","iv-history","jobs","kelly-sizer","layout-manager","macro-day","market-halts","market-heatmap","market-valuation","members","mna","money-markets","news","openfda","options","options-calculator","options-positioning","options-scenario","pe-band","perps","portfolio-list","power","rate-path","realized-vol","relative-rotation","research","research-search","revenue-breakdown","reverse-dcf","risk-factors","scanner","seasonality","sec","sectors","short-interest","short-volume","social-mentions","supply-chain","ticker-detail","time-sales","treasury-auctions","vol-surface","volatility","world-indices","world-venue-map","yield-curve"],
|
|
57
|
+
"src/plugins/catalog-ui.ts": ["alerts","clinical-trials","cloud","comment-letters","custom-view","fear-greed","ipo-calendar","market-halts","market-heatmap","members","news","notes","openfda","research-search"],
|
|
58
|
+
"src/plugins/catalog.ts": ["debug"],
|
|
59
|
+
"src/plugins/installer.ts": ["plugin-marketplace"],
|
|
60
|
+
"src/plugins/manager-node.ts": ["plugin-marketplace"],
|
|
61
|
+
"src/remote/controller.ts": ["custom-view"],
|
|
62
|
+
"src/renderers/browser/main.tsx": ["plugin-marketplace"],
|
|
63
|
+
"src/renderers/electrobun/bun/core-capabilities.ts": ["notes"],
|
|
64
|
+
"src/renderers/electrobun/shared/protocol.ts": ["plugin-marketplace"],
|
|
65
|
+
"src/renderers/electrobun/view/cli-pane-shot-entry.tsx": ["econ-statistics","market-valuation","time-sales"],
|
|
66
|
+
"src/renderers/electrobun/view/main.tsx": ["notes","plugin-marketplace"],
|
|
67
|
+
"src/renderers/electrobun/view/remote/connection-health.ts": ["connections"],
|
|
68
|
+
"src/renderers/opentui/start.tsx": ["plugin-marketplace"],
|
|
69
|
+
"src/sync/core-contributors.ts": ["analytics","portfolio-list"]
|
|
70
|
+
}
|
|
@@ -23,11 +23,38 @@ import { SIGNED_IN_BROKER_TYPE, signedInBrokerId } from "./profile";
|
|
|
23
23
|
|
|
24
24
|
const METHOD = "Sign in";
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* The message Gloom wrote for the client. The request error's own `message`
|
|
28
|
+
* has the error code appended to it, so this reads the body's field first.
|
|
29
|
+
*/
|
|
30
|
+
function writtenMessage(error: ApiRequestError): string | null {
|
|
31
|
+
const written = error.details?.message;
|
|
32
|
+
if (typeof written === "string" && written.trim()) return written.trim();
|
|
33
|
+
const { message, code } = error;
|
|
34
|
+
const text = code && message.endsWith(` ${code}`) ? message.slice(0, -(code.length + 1)) : message;
|
|
35
|
+
return text.trim() || null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Why the broker ended a sign-in, as Gloom stores it, without the OAuth code
|
|
40
|
+
* in front: "invalid_grant: Authorization grant has expired" reads
|
|
41
|
+
* "Authorization grant has expired".
|
|
42
|
+
*/
|
|
43
|
+
function brokerReason(lastError: string | null | undefined): string | null {
|
|
44
|
+
const text = lastError?.trim();
|
|
45
|
+
if (!text) return null;
|
|
46
|
+
const described = /^[a-z_]+:\s*(\S[\s\S]*)$/.exec(text)?.[1] ?? text;
|
|
47
|
+
return described.replace(/[\s.]+$/, "").slice(0, 200) || null;
|
|
48
|
+
}
|
|
49
|
+
|
|
26
50
|
/** What to tell the user when Gloom answers a broker call with an error. */
|
|
27
51
|
function describeSignedInBrokerError(error: unknown, brokerName: string): string {
|
|
28
52
|
const status = error instanceof ApiRequestError ? error.status : undefined;
|
|
29
53
|
if (status === 401) return `Sign in to Gloom first, then connect ${brokerName}.`;
|
|
30
|
-
|
|
54
|
+
const signInAgain = `${brokerName} needs you to sign in again. Press Connect in Brokers.`;
|
|
55
|
+
// A sign-in the broker ended says why, in Gloom's words.
|
|
56
|
+
if (status === 409) return (error instanceof ApiRequestError && writtenMessage(error)) || signInAgain;
|
|
57
|
+
if (status === 404) return signInAgain;
|
|
31
58
|
if (status === 502) return `${brokerName} is not responding. Try again shortly.`;
|
|
32
59
|
return error instanceof Error && error.message ? error.message : String(error);
|
|
33
60
|
}
|
|
@@ -215,7 +242,11 @@ export function createSignedInBrokerAdapter(overrides: Partial<SignedInBrokerAda
|
|
|
215
242
|
await track(instance, async () => {
|
|
216
243
|
const connection = await get<SignedInBrokerConnection>(instance, "");
|
|
217
244
|
if (connection.status !== "connected") {
|
|
218
|
-
|
|
245
|
+
const name = brokerName(instance);
|
|
246
|
+
const reason = brokerReason(connection.lastError);
|
|
247
|
+
throw new Error(reason
|
|
248
|
+
? `${name} needs you to sign in again: ${reason}. Press Connect in Brokers.`
|
|
249
|
+
: `Press Connect in Brokers to sign in to ${name}.`);
|
|
219
250
|
}
|
|
220
251
|
});
|
|
221
252
|
},
|
|
@@ -31,6 +31,16 @@ export interface SignedInBrokerConnection {
|
|
|
31
31
|
connectedAt: string | null;
|
|
32
32
|
refreshedAt: string | null;
|
|
33
33
|
syncedAt: string | null;
|
|
34
|
+
/**
|
|
35
|
+
* When the broker ends this sign-in on its own clock, however often it was
|
|
36
|
+
* refreshed. Set only while connected and only for a broker that does so.
|
|
37
|
+
* The three fields below are absent from a Gloom server that predates them.
|
|
38
|
+
*/
|
|
39
|
+
expiresAt?: string | null;
|
|
40
|
+
/** Within a day of `expiresAt`, or past it: time to connect again. */
|
|
41
|
+
expiresSoon?: boolean;
|
|
42
|
+
/** Why the broker ended the sign-in, in its own words. Null while connected. */
|
|
43
|
+
lastError?: string | null;
|
|
34
44
|
}
|
|
35
45
|
|
|
36
46
|
/** Public: the list does not depend on the user, so Add Broker can show it signed out. */
|