gloomberb 0.18.3 → 0.18.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/README.md +8 -8
- package/README.zh-CN.md +11 -11
- package/bin/{gloomberb → gloom} +3 -1
- package/package.json +6 -2
- package/src/account/checkout-handoff.tsx +225 -0
- package/src/account/device-signin-dialog.tsx +2 -2
- package/src/account/device-signin.ts +2 -2
- package/src/account/upgrade-dialog.tsx +1 -1
- package/src/api-client/askg.ts +2 -2
- package/src/api-client/auth.ts +2 -2
- package/src/api-client/central-bank-rates.ts +6 -0
- package/src/api-client/collections.ts +5 -1
- package/src/api-client/cot.ts +2 -0
- package/src/api-client/crypto-etf-flows.ts +37 -0
- package/src/api-client/crypto-markets.ts +60 -0
- package/src/api-client/data.ts +84 -5
- package/src/api-client/doe.ts +15 -0
- package/src/api-client/equity-screener.ts +28 -0
- package/src/api-client/exchange-announcements.ts +38 -0
- package/src/api-client/fund-facts.ts +39 -0
- package/src/api-client/futures-curve.ts +9 -1
- package/src/api-client/hiring.ts +301 -0
- package/src/api-client/index.ts +22 -5
- package/src/api-client/market-discovery.ts +14 -0
- package/src/api-client/members.ts +6 -0
- package/src/api-client/mna.ts +6 -0
- package/src/api-client/paths.ts +18 -1
- package/src/api-client/request.ts +21 -4
- package/src/api-client/short-side-publications.ts +37 -0
- package/src/api-client/socket.ts +64 -4
- package/src/api-client/swap-curve.ts +35 -0
- package/src/api-client/themes.ts +7 -1
- package/src/api-client/types.ts +90 -2
- package/src/app/pane-runtime/plugin-bindings.ts +9 -2
- package/src/app/runtime/desktop-deeplink.ts +5 -5
- package/src/app/runtime/plugin-bindings.ts +2 -2
- package/src/app/runtime/startup.ts +13 -0
- package/src/app/star-prompt/status-line.tsx +2 -2
- package/src/architecture/core-builtin-allowlist.json +5 -2
- package/src/architecture/ui-literals-allowlist.json +3 -3
- package/src/architecture/ui-tokens-allowlist.json +1 -1
- package/src/brokers/broker-portfolio-sync.ts +37 -0
- package/src/brokers/directory.ts +11 -0
- package/src/brokers/logos.ts +3 -1
- package/src/brokers/signed-in/adapter.ts +304 -26
- package/src/brokers/signed-in/client.ts +14 -2
- package/src/brokers/signed-in/connect.ts +10 -2
- package/src/brokers/sync-broker-instance.ts +9 -1
- package/src/capabilities/chart-series.ts +22 -6
- package/src/cli/bank-section.ts +1 -1
- package/src/cli/base-converter.ts +23 -14
- package/src/cli/central-bank-events.ts +1 -1
- package/src/cli/command-options.ts +59 -4
- package/src/cli/commands/api.ts +9 -6
- package/src/cli/commands/broker.ts +2 -2
- package/src/cli/commands/command-utils.ts +2 -2
- package/src/cli/commands/crypto-hints.ts +7 -20
- package/src/cli/commands/fred-series.ts +4 -2
- package/src/cli/commands/keybindings.ts +2 -2
- package/src/cli/commands/market.ts +1117 -264
- package/src/cli/commands/news-hints.ts +2 -2
- package/src/cli/commands/news-search.ts +59 -6
- package/src/cli/commands/options-leaps.ts +41 -26
- package/src/cli/commands/overview.ts +121 -48
- package/src/cli/commands/plugins.ts +9 -9
- package/src/cli/commands/remote.ts +13 -10
- package/src/cli/commands/search.ts +64 -44
- package/src/cli/commands/system.ts +27 -19
- package/src/cli/commands/themes.ts +1 -1
- package/src/cli/commands/ticker.ts +192 -47
- package/src/cli/context.ts +3 -2
- package/src/cli/desktop-pane-shot-view.ts +2 -2
- package/src/cli/desktop-pane-shot.ts +1 -1
- package/src/cli/earnings-calendar.ts +4 -4
- package/src/cli/entry.ts +18 -1
- package/src/cli/errors.ts +20 -2
- package/src/cli/exit-codes.ts +1 -1
- package/src/cli/export-source.ts +10 -4
- package/src/cli/freshness.ts +2 -8
- package/src/cli/fx-forward.ts +130 -0
- package/src/cli/fx-pair.ts +10 -9
- package/src/cli/glossary.ts +64 -20
- package/src/cli/help.ts +19 -13
- package/src/cli/history-export.ts +126 -0
- package/src/cli/history-rows.ts +196 -43
- package/src/cli/index-roots.ts +5 -45
- package/src/cli/index.ts +24 -18
- package/src/cli/known-gaps.ts +118 -25
- package/src/cli/listing-arg.ts +300 -41
- package/src/cli/name-entries.ts +30 -18
- package/src/cli/native-smoke.ts +2 -0
- package/src/cli/not-a-ticker.ts +19 -9
- package/src/cli/opentui-libc.ts +5 -0
- package/src/cli/options.ts +12 -0
- package/src/cli/pane-functions/capabilities.ts +75 -20
- package/src/cli/pane-functions/catalog.ts +24 -23
- package/src/cli/pane-functions/discovery.ts +1 -1
- package/src/cli/pane-functions/dom.ts +10 -7
- package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
- package/src/cli/pane-functions/freshness.ts +174 -23
- package/src/cli/pane-functions/function-help.ts +66 -27
- package/src/cli/pane-functions/headless.ts +24 -11
- package/src/cli/pane-functions/index.ts +18 -16
- package/src/cli/pane-functions/options.ts +22 -2
- package/src/cli/pane-functions/report-notices.ts +12 -4
- package/src/cli/pane-functions/report.ts +5 -5
- package/src/cli/pane-functions/resolver.ts +47 -10
- package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
- package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
- package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
- package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
- package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
- package/src/cli/pane-functions/screenshot-payload.ts +453 -0
- package/src/cli/pane-functions/screenshot-render.ts +316 -0
- package/src/cli/pane-functions/screenshot-types.ts +162 -0
- package/src/cli/pane-functions/shot-options.ts +8 -3
- package/src/cli/peso-dollar-rates.ts +79 -0
- package/src/cli/quote-answer.ts +38 -3
- package/src/cli/report-tables.ts +61 -16
- package/src/cli/restore-plugins.ts +29 -14
- package/src/cli/result.ts +111 -22
- package/src/cli/series-search.ts +5 -5
- package/src/cli/statement-filings.ts +19 -0
- package/src/cli/suffixed-listing-rows.ts +49 -0
- package/src/cli/symbol-args.ts +50 -15
- package/src/cli/symbol-cells.ts +120 -0
- package/src/cli/symbol-list.ts +198 -68
- package/src/cli/symbol-rows.ts +131 -25
- package/src/cli/ticker-resolution.ts +108 -11
- package/src/cli/treasury-yields.ts +5 -5
- package/src/cli/types.ts +2 -0
- package/src/cli/uncovered-instrument.ts +3 -3
- package/src/cli/unknown-command.ts +6 -6
- package/src/components/chart/composite/chart-layout.ts +131 -0
- package/src/components/chart/composite/composite-chart.tsx +373 -16
- package/src/components/chart/composite/interactions.ts +7 -2
- package/src/components/chart/composite/legend.tsx +75 -3
- package/src/components/chart/composite/levels.ts +5 -0
- package/src/components/chart/composite/panel-gestures.ts +41 -0
- package/src/components/chart/composite/panel-labels.ts +2 -1
- package/src/components/chart/composite/panel-surface.tsx +305 -11
- package/src/components/chart/composite/price-axis-labels.tsx +27 -3
- package/src/components/chart/composite/rasterizer.ts +44 -19
- package/src/components/chart/composite/scene.ts +16 -4
- package/src/components/chart/composite/text-renderer.ts +48 -21
- package/src/components/chart/composite/toolbar.tsx +52 -5
- package/src/components/chart/composite/types.ts +13 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
- package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
- package/src/components/chart/composite/use-composite-viewport.ts +12 -3
- package/src/components/chart/composite/value-scale.ts +149 -0
- package/src/components/chart/composite/volume-profile-paint.ts +6 -3
- package/src/components/chart/core/pointer.ts +2 -0
- package/src/components/chart-table/index.ts +2 -0
- package/src/components/chart-table/read.tsx +74 -0
- package/src/components/command-bar/commands/collection-list.ts +41 -19
- package/src/components/command-bar/commands/collection.ts +9 -3
- package/src/components/command-bar/commands/direct/index.ts +1 -1
- package/src/components/command-bar/commands/direct/runtime.ts +3 -2
- package/src/components/command-bar/pane-templates/items.ts +59 -6
- package/src/components/command-bar/pane-templates/workflow.ts +10 -1
- package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
- package/src/components/command-bar/routes/root/provider-search.ts +42 -11
- package/src/components/command-bar/routes/root/results.ts +18 -4
- package/src/components/command-bar/routes/root/runtime.ts +15 -3
- package/src/components/command-bar/routes/root/search-providers.ts +25 -2
- package/src/components/command-bar/routes/root/selection.ts +6 -1
- package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
- package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
- package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
- package/src/components/command-bar/selection-runtime.ts +50 -10
- package/src/components/command-bar/surface/index.tsx +24 -2
- package/src/components/command-bar/view-model.ts +7 -0
- package/src/components/command-bar/workflow/broker.ts +2 -2
- package/src/components/command-bar/workflow/collection-actions.ts +46 -7
- package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
- package/src/components/command-bar/workflow/fields.ts +8 -2
- package/src/components/command-bar/workflow/ops.ts +18 -4
- package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
- package/src/components/command-bar/workflow/submit.ts +3 -2
- package/src/components/command-bar/workflow/tickers.ts +5 -1
- package/src/components/company-logo.tsx +39 -0
- package/src/components/data-table/sections.ts +4 -2
- package/src/components/form-modal/confirm.tsx +2 -1
- package/src/components/form-modal/request.ts +5 -0
- package/src/components/form-modal/routes.ts +4 -1
- package/src/components/index.ts +12 -6
- package/src/components/layout/header.tsx +7 -6
- package/src/components/layout/market-summary.ts +9 -6
- package/src/components/layout/pane/capture-status.ts +1 -1
- package/src/components/layout/pane/footer/model.ts +11 -5
- package/src/components/layout/shell/chrome.ts +19 -6
- package/src/components/layout/shell/index.tsx +2 -1
- package/src/components/layout/shell/pane/layers.tsx +19 -1
- package/src/components/layout/status-bar.tsx +2 -2
- package/src/components/market-board/index.tsx +11 -3
- package/src/components/onboarding/onboarding-wizard.tsx +1 -0
- package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
- package/src/components/onboarding/wizard-broker-sync.ts +4 -1
- package/src/components/pane-settings-dialog/desktop.tsx +20 -7
- package/src/components/pane-settings-dialog/tui.tsx +17 -9
- package/src/components/pane-settings-dialog/value.ts +8 -1
- package/src/components/pane-settings-dialog.tsx +44 -13
- package/src/components/sign-in-code-panel.tsx +27 -19
- package/src/components/ui/column-grid.tsx +48 -4
- package/src/components/ui/country-flag-art.tsx +180 -0
- package/src/components/ui/country-flag.tsx +118 -12
- package/src/components/ui/data-table/opentui/index.tsx +61 -2
- package/src/components/ui/data-table/opentui/model.ts +109 -2
- package/src/components/ui/data-table/types.ts +1 -1
- package/src/components/ui/display.tsx +5 -1
- package/src/components/ui/index.ts +3 -1
- package/src/components/ui/logo-mark.tsx +11 -2
- package/src/components/ui/query-bar.tsx +1 -1
- package/src/components/ui/row-notes.ts +79 -0
- package/src/core/state/app/layout.ts +4 -4
- package/src/data/cached-query.ts +8 -1
- package/src/data/config/chart-settings.ts +3 -3
- package/src/data/config/home.ts +10 -2
- package/src/data/config/layout.ts +4 -1
- package/src/data/config/store/node.ts +4 -0
- package/src/data/config/store/normalize.ts +13 -3
- package/src/data/config/store/portfolio-as-of-column.ts +2 -2
- package/src/data/json-storage.ts +2 -0
- package/src/data/saved-copies.ts +84 -0
- package/src/docs/snapshot.json +65 -32
- package/src/i18n/es.ts +29 -12
- package/src/i18n/ja.ts +29 -12
- package/src/i18n/ko.ts +29 -12
- package/src/i18n/zh-cn.ts +29 -12
- package/src/i18n/zh-tw.ts +29 -12
- package/src/layout/desks.ts +1 -1
- package/src/layout/launch-layout.ts +1 -1
- package/src/layout/pane-manager/floating-actions.ts +5 -3
- package/src/layout/pane-manager/floating.ts +43 -1
- package/src/layout/pane-manager/index.ts +2 -0
- package/src/layout/selected-ticker.ts +74 -0
- package/src/market-data/depositary-pair.ts +251 -0
- package/src/market-data/futures-board.ts +1 -1
- package/src/market-data/futures-contract.ts +124 -40
- package/src/market-data/fx-closes.ts +17 -2
- package/src/market-data/hooks.tsx +19 -11
- package/src/market-data/market/change-basis.ts +49 -7
- package/src/market-data/market/freshness.ts +34 -5
- package/src/market-data/market/period-return.ts +163 -0
- package/src/market-data/market/trading-sessions.ts +13 -0
- package/src/market-data/market/year-to-date.ts +8 -13
- package/src/market-data/performance.ts +20 -14
- package/src/market-data/perpetual-premium.ts +32 -0
- package/src/market-data/published-apac-sessions.ts +2 -1
- package/src/market-data/published-futures-sessions.ts +69 -0
- package/src/market-data/quotes/contributions.ts +5 -1
- package/src/market-data/quotes/freshness.ts +42 -0
- package/src/market-data/quotes/intraday-bar.ts +37 -0
- package/src/market-data/quotes/regular-session-valuation.ts +13 -8
- package/src/market-data/quotes/resolution.ts +4 -2
- package/src/market-data/tax-equivalent.ts +1 -1
- package/src/market-data/ticker-price-returns.ts +3 -1
- package/src/news/aggregator.ts +5 -1
- package/src/news/news-model.ts +4 -0
- package/src/news/types.ts +11 -0
- package/src/notifications/app-notifier.ts +1 -1
- package/src/plugins/auto-update.ts +2 -2
- package/src/plugins/builtin/account-management/index.tsx +1 -0
- package/src/plugins/builtin/account-management/pane.tsx +9 -8
- package/src/plugins/builtin/alerts/alert-engine.ts +29 -19
- package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
- package/src/plugins/builtin/alerts/cli.ts +485 -76
- package/src/plugins/builtin/alerts/command.ts +5 -10
- package/src/plugins/builtin/alerts/event-rows.ts +9 -5
- package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
- package/src/plugins/builtin/alerts/events.ts +107 -5
- package/src/plugins/builtin/alerts/fired-log.ts +78 -0
- package/src/plugins/builtin/alerts/format.ts +2 -1
- package/src/plugins/builtin/alerts/headless.ts +100 -39
- package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
- package/src/plugins/builtin/alerts/history-rows.ts +89 -0
- package/src/plugins/builtin/alerts/index.tsx +45 -18
- package/src/plugins/builtin/alerts/iv-level.ts +365 -0
- package/src/plugins/builtin/alerts/levels.ts +3 -3
- package/src/plugins/builtin/alerts/pane.tsx +97 -29
- package/src/plugins/builtin/alerts/price.ts +35 -0
- package/src/plugins/builtin/alerts/quotes.ts +24 -0
- package/src/plugins/builtin/alerts/research-builder.ts +84 -11
- package/src/plugins/builtin/alerts/research-rules.ts +76 -3
- package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
- package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
- package/src/plugins/builtin/alerts/scheduled.ts +188 -29
- package/src/plugins/builtin/alerts/storage.ts +13 -10
- package/src/plugins/builtin/alerts/targets.ts +12 -3
- package/src/plugins/builtin/analytics/index.tsx +8 -2
- package/src/plugins/builtin/analytics/metrics.ts +1 -1
- package/src/plugins/builtin/analytics/risk-book.ts +215 -0
- package/src/plugins/builtin/analytics/risk-client.ts +13 -6
- package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
- package/src/plugins/builtin/analytics/risk-math.ts +6 -3
- package/src/plugins/builtin/analytics/risk-model.ts +297 -104
- package/src/plugins/builtin/analytics/risk-options.ts +17 -2
- package/src/plugins/builtin/analytics/risk-pane.tsx +97 -36
- package/src/plugins/builtin/attention/pane.tsx +6 -2
- package/src/plugins/builtin/awards/headless.ts +7 -3
- package/src/plugins/builtin/awards/model.ts +18 -0
- package/src/plugins/builtin/awards/pane.tsx +6 -3
- package/src/plugins/builtin/backtest/headless.ts +3 -3
- package/src/plugins/builtin/backtest/rules.ts +41 -5
- package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
- package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
- package/src/plugins/builtin/broker-manager/footer.ts +27 -11
- package/src/plugins/builtin/broker-manager/index.tsx +21 -12
- package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
- package/src/plugins/builtin/broker-manager/model.ts +12 -2
- package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
- package/src/plugins/builtin/broker-manager/table.ts +28 -12
- package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
- package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
- package/src/plugins/builtin/broker-trading/controller.ts +45 -13
- package/src/plugins/builtin/broker-trading/dock.tsx +22 -4
- package/src/plugins/builtin/broker-trading/headless.ts +2 -1
- package/src/plugins/builtin/broker-trading/index.tsx +7 -1
- package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
- package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
- package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
- package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
- package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
- package/src/plugins/builtin/broker-trading/pane.tsx +110 -23
- package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
- package/src/plugins/builtin/broker-trading/ticket.tsx +112 -31
- package/src/plugins/builtin/buildout/cells.tsx +4 -0
- package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
- package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
- package/src/plugins/builtin/buildout/pane/index.tsx +25 -12
- package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
- package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
- package/src/plugins/builtin/catalysts/detail.tsx +3 -2
- package/src/plugins/builtin/catalysts/index.tsx +1 -1
- package/src/plugins/builtin/catalysts/model.ts +49 -4
- package/src/plugins/builtin/catalysts/pane.tsx +6 -8
- package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
- package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
- package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
- package/src/plugins/builtin/changelog/index.tsx +1 -0
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
- package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
- package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
- package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
- package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
- package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
- package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
- package/src/plugins/builtin/chart-composer/headless.ts +253 -35
- package/src/plugins/builtin/chart-composer/index.tsx +12 -2
- package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
- package/src/plugins/builtin/chart-composer/pane.tsx +127 -28
- package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
- package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
- package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
- package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
- package/src/plugins/builtin/chart-composer/settings.ts +31 -19
- package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
- package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
- package/src/plugins/builtin/chat/attachments/model.ts +3 -1
- package/src/plugins/builtin/chat/content/index.tsx +1 -1
- package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
- package/src/plugins/builtin/chat/people.ts +1 -1
- package/src/plugins/builtin/clinical-trials/client.ts +5 -2
- package/src/plugins/builtin/clinical-trials/model.ts +13 -4
- package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
- package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
- package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
- package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
- package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
- package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
- package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
- package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
- package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
- package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
- package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
- package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
- package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
- package/src/plugins/builtin/commodity-balances/pane.tsx +11 -4
- package/src/plugins/builtin/company-attention/app-rank.tsx +7 -5
- package/src/plugins/builtin/company-attention/building-model.ts +222 -0
- package/src/plugins/builtin/company-attention/building.tsx +172 -0
- package/src/plugins/builtin/company-attention/client.ts +117 -1
- package/src/plugins/builtin/company-attention/evidence.ts +16 -3
- package/src/plugins/builtin/company-attention/headless.ts +101 -5
- package/src/plugins/builtin/company-attention/index.tsx +6 -3
- package/src/plugins/builtin/company-attention/model.ts +33 -7
- package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
- package/src/plugins/builtin/company-attention/moves.tsx +159 -0
- package/src/plugins/builtin/company-attention/pane.tsx +79 -23
- package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
- package/src/plugins/builtin/company-attention/signals.tsx +160 -0
- package/src/plugins/builtin/company-kpis/headless.ts +3 -2
- package/src/plugins/builtin/company-kpis/model.ts +2 -2
- package/src/plugins/builtin/company-kpis/pane.tsx +1 -1
- package/src/plugins/builtin/composite-plugins.ts +2 -1
- package/src/plugins/builtin/congress-trades/headless.ts +1 -1
- package/src/plugins/builtin/connections/index.ts +1 -0
- package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
- package/src/plugins/builtin/correlation/headless.ts +5 -3
- package/src/plugins/builtin/cot/headless.ts +28 -6
- package/src/plugins/builtin/cot/model.ts +12 -0
- package/src/plugins/builtin/cot/pane.tsx +3 -2
- package/src/plugins/builtin/cpi/headless.ts +5 -1
- package/src/plugins/builtin/cpi/pane.tsx +11 -9
- package/src/plugins/builtin/credit-boards/model.ts +2 -0
- package/src/plugins/builtin/credit-documents/headless.ts +1 -1
- package/src/plugins/builtin/crypto-board/client.ts +86 -0
- package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
- package/src/plugins/builtin/crypto-board/defi.ts +239 -0
- package/src/plugins/builtin/crypto-board/headless.ts +117 -6
- package/src/plugins/builtin/crypto-board/index.tsx +8 -3
- package/src/plugins/builtin/crypto-board/model.ts +40 -8
- package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
- package/src/plugins/builtin/crypto-board/series.ts +19 -1
- package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
- package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
- package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
- package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
- package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
- package/src/plugins/builtin/debug/index.tsx +1 -0
- package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
- package/src/plugins/builtin/docs/index.tsx +1 -1
- package/src/plugins/builtin/docs/pane.tsx +2 -2
- package/src/plugins/builtin/docs/targets.ts +1 -1
- package/src/plugins/builtin/doe/client.ts +5 -1
- package/src/plugins/builtin/doe/headless.ts +12 -6
- package/src/plugins/builtin/doe/model.ts +43 -6
- package/src/plugins/builtin/doe/pane.tsx +18 -11
- package/src/plugins/builtin/earnings/board-model.ts +13 -6
- package/src/plugins/builtin/earnings/board-table.ts +4 -1
- package/src/plugins/builtin/earnings/board.tsx +253 -50
- package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
- package/src/plugins/builtin/earnings/calendar.tsx +338 -0
- package/src/plugins/builtin/earnings/client.ts +4 -3
- package/src/plugins/builtin/earnings/headless.ts +53 -15
- package/src/plugins/builtin/earnings/history-model.ts +53 -36
- package/src/plugins/builtin/earnings/index.tsx +15 -22
- package/src/plugins/builtin/earnings/model.ts +17 -12
- package/src/plugins/builtin/earnings/scope.ts +89 -0
- package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
- package/src/plugins/builtin/earnings-calls/data.ts +146 -2
- package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
- package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
- package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
- package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
- package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
- package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
- package/src/plugins/builtin/econ/calendar-model.ts +132 -20
- package/src/plugins/builtin/econ/detail-view.tsx +48 -10
- package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
- package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
- package/src/plugins/builtin/econ/index.tsx +112 -25
- package/src/plugins/builtin/econ/print-watch.ts +2 -1
- package/src/plugins/builtin/econ/types.ts +32 -1
- package/src/plugins/builtin/econ-statistics/client.ts +16 -3
- package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
- package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
- package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
- package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
- package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
- package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
- package/src/plugins/builtin/econ-statistics/view.ts +16 -1
- package/src/plugins/builtin/equity-screener/client.ts +21 -3
- package/src/plugins/builtin/equity-screener/headless.ts +68 -6
- package/src/plugins/builtin/equity-screener/live.ts +1 -1
- package/src/plugins/builtin/equity-screener/model.ts +6 -0
- package/src/plugins/builtin/equity-screener/pane.tsx +45 -10
- package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
- package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
- package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
- package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
- package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
- package/src/plugins/builtin/exposure/headless.ts +51 -6
- package/src/plugins/builtin/exposure/index.tsx +28 -2
- package/src/plugins/builtin/exposure/model.ts +7 -0
- package/src/plugins/builtin/exposure/pane.tsx +6 -1
- package/src/plugins/builtin/fear-greed/index.tsx +1 -1
- package/src/plugins/builtin/filing-events/index.tsx +1 -1
- package/src/plugins/builtin/futures/model.ts +10 -9
- package/src/plugins/builtin/futures/returns.ts +8 -36
- package/src/plugins/builtin/futures/table.tsx +1 -1
- package/src/plugins/builtin/futures-curve/client.ts +40 -9
- package/src/plugins/builtin/futures-curve/headless.ts +39 -17
- package/src/plugins/builtin/futures-curve/model.ts +258 -69
- package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
- package/src/plugins/builtin/fx-matrix/client.ts +15 -8
- package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
- package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
- package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
- package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
- package/src/plugins/builtin/gpu/headless.ts +9 -4
- package/src/plugins/builtin/help/index.tsx +13 -3
- package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
- package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
- package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
- package/src/plugins/builtin/holders/client.ts +13 -1
- package/src/plugins/builtin/holders/format.ts +28 -17
- package/src/plugins/builtin/holders/headless.ts +46 -7
- package/src/plugins/builtin/holders/index-holders.ts +264 -0
- package/src/plugins/builtin/holders/pane.tsx +79 -15
- package/src/plugins/builtin/holders/report-rows.ts +35 -7
- package/src/plugins/builtin/holders/table-model.ts +2 -1
- package/src/plugins/builtin/holders/treemap.tsx +2 -2
- package/src/plugins/builtin/insider/headless.ts +1 -1
- package/src/plugins/builtin/insider/signals-client.ts +1 -1
- package/src/plugins/builtin/insider/signals.tsx +1 -1
- package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
- package/src/plugins/builtin/iv-history/client.ts +20 -0
- package/src/plugins/builtin/iv-history/headless.ts +4 -4
- package/src/plugins/builtin/iv-history/index.tsx +1 -1
- package/src/plugins/builtin/iv-history/model.ts +13 -4
- package/src/plugins/builtin/iv-history/series.ts +3 -1
- package/src/plugins/builtin/jobs/lock-note.ts +1 -1
- package/src/plugins/builtin/jobs/model.ts +4 -15
- package/src/plugins/builtin/jobs/pane.tsx +7 -5
- package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
- package/src/plugins/builtin/jodi/pane.tsx +10 -4
- package/src/plugins/builtin/layout-manager/index.tsx +1 -0
- package/src/plugins/builtin/macro-day/headless.ts +20 -7
- package/src/plugins/builtin/macro-day/index.tsx +3 -2
- package/src/plugins/builtin/macro-day/model.ts +29 -8
- package/src/plugins/builtin/macro-day/pane.tsx +46 -10
- package/src/plugins/builtin/macro-day/releases.ts +55 -13
- package/src/plugins/builtin/market-heatmap/data.ts +9 -2
- package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
- package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
- package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
- package/src/plugins/builtin/market-heatmap/model.ts +10 -7
- package/src/plugins/builtin/market-movers/client.ts +33 -19
- package/src/plugins/builtin/market-movers/headless.ts +8 -2
- package/src/plugins/builtin/market-movers/index.tsx +16 -10
- package/src/plugins/builtin/market-movers/screener.ts +29 -8
- package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
- package/src/plugins/builtin/market-movers/session-table.ts +4 -2
- package/src/plugins/builtin/market-movers/table.ts +4 -1
- package/src/plugins/builtin/market-valuation/headless.ts +2 -0
- package/src/plugins/builtin/market-valuation/view.ts +5 -0
- package/src/plugins/builtin/members/headless.ts +6 -5
- package/src/plugins/builtin/members/pane.tsx +11 -4
- package/src/plugins/builtin/mna/client.ts +1 -0
- package/src/plugins/builtin/mna/detail.tsx +20 -32
- package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
- package/src/plugins/builtin/mna/distress/model.ts +3 -2
- package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
- package/src/plugins/builtin/mna/headless.ts +6 -13
- package/src/plugins/builtin/mna/model.ts +93 -15
- package/src/plugins/builtin/mna/pane.tsx +5 -4
- package/src/plugins/builtin/news/headless.ts +12 -6
- package/src/plugins/builtin/news/index.tsx +10 -1
- package/src/plugins/builtin/news/wire/index.tsx +3 -2
- package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
- package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
- package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
- package/src/plugins/builtin/notes/cli.ts +49 -14
- package/src/plugins/builtin/openfda/pane.tsx +1 -1
- package/src/plugins/builtin/options/carry.ts +2 -2
- package/src/plugins/builtin/options/index.tsx +1 -1
- package/src/plugins/builtin/options/view.tsx +10 -10
- package/src/plugins/builtin/options-calculator/headless.ts +46 -7
- package/src/plugins/builtin/options-scenario/client.ts +123 -28
- package/src/plugins/builtin/options-scenario/collar.ts +8 -6
- package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
- package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
- package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
- package/src/plugins/builtin/options-scenario/csp.ts +101 -21
- package/src/plugins/builtin/options-scenario/headless.ts +36 -15
- package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
- package/src/plugins/builtin/options-scenario/index.tsx +28 -3
- package/src/plugins/builtin/options-scenario/model.ts +13 -0
- package/src/plugins/builtin/options-scenario/pane.tsx +9 -5
- package/src/plugins/builtin/perps/equity-row.tsx +11 -3
- package/src/plugins/builtin/perps/freshness.ts +8 -5
- package/src/plugins/builtin/perps/headless.ts +3 -1
- package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
- package/src/plugins/builtin/perps/live-rows.ts +161 -0
- package/src/plugins/builtin/perps/markets-section.tsx +154 -0
- package/src/plugins/builtin/perps/pane.tsx +36 -17
- package/src/plugins/builtin/perps/venue-markets.ts +96 -0
- package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +143 -59
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +72 -24
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
- package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
- package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
- package/src/plugins/builtin/portfolio-list/income.ts +13 -2
- package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
- package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
- package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
- package/src/plugins/builtin/power/client.ts +4 -1
- package/src/plugins/builtin/power/evidence.ts +22 -7
- package/src/plugins/builtin/power/gas.tsx +5 -1
- package/src/plugins/builtin/power/pane.tsx +8 -1
- package/src/plugins/builtin/power/prices.tsx +10 -3
- package/src/plugins/builtin/research/analyst-headless.ts +25 -8
- package/src/plugins/builtin/research/analyst-model.ts +68 -3
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
- package/src/plugins/builtin/research/event-model.ts +3 -1
- package/src/plugins/builtin/research/event-sources.ts +12 -4
- package/src/plugins/builtin/research/index.tsx +2 -1
- package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
- package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
- package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
- package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
- package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
- package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
- package/src/plugins/builtin/reverse-dcf/model.ts +6 -2
- package/src/plugins/builtin/risk-factors/index.tsx +2 -2
- package/src/plugins/builtin/scanner/lock-note.ts +1 -1
- package/src/plugins/builtin/sec/forms.ts +13 -0
- package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
- package/src/plugins/builtin/sec/fund-facts.ts +68 -8
- package/src/plugins/builtin/sec/headless.ts +85 -8
- package/src/plugins/builtin/sec/index.tsx +58 -12
- package/src/plugins/builtin/sectors/client.ts +2 -1
- package/src/plugins/builtin/sectors/sector-model.ts +11 -15
- package/src/plugins/builtin/series-inventory.ts +2 -0
- package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
- package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
- package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
- package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
- package/src/plugins/builtin/shared/earnings-report.ts +3 -3
- package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
- package/src/plugins/builtin/shared/job-posting.ts +129 -0
- package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
- package/src/plugins/builtin/shared/report-freshness.ts +3 -0
- package/src/plugins/builtin/shared/research-trading.tsx +21 -0
- package/src/plugins/builtin/shared/series-cache.ts +2 -0
- package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
- package/src/plugins/builtin/short-interest/client.ts +2 -0
- package/src/plugins/builtin/short-interest/headless.ts +41 -12
- package/src/plugins/builtin/short-interest/index.tsx +23 -1
- package/src/plugins/builtin/short-interest/model.ts +70 -19
- package/src/plugins/builtin/short-interest/pane.tsx +19 -2
- package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
- package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
- package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
- package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
- package/src/plugins/builtin/short-interest/schedule.ts +35 -2
- package/src/plugins/builtin/short-interest/surface.tsx +11 -4
- package/src/plugins/builtin/short-interest/types.ts +9 -0
- package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
- package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
- package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
- package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
- package/src/plugins/builtin/supply-chain/model.ts +51 -3
- package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
- package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
- package/src/plugins/builtin/themes/headless.ts +8 -5
- package/src/plugins/builtin/themes/model.ts +14 -4
- package/src/plugins/builtin/themes/pane.tsx +24 -5
- package/src/plugins/builtin/thirteenf/headless.ts +5 -5
- package/src/plugins/builtin/thirteenf/signals.ts +3 -1
- package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
- package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
- package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
- package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
- package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
- package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
- package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
- package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
- package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
- package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
- package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
- package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
- package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
- package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
- package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
- package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
- package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
- package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
- package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
- package/src/plugins/builtin/vol-surface/client.ts +5 -4
- package/src/plugins/builtin/vol-surface/headless.ts +12 -3
- package/src/plugins/builtin/vol-surface/model.ts +4 -2
- package/src/plugins/builtin/volatility/model.ts +5 -10
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
- package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
- package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
- package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
- package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
- package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
- package/src/plugins/builtin/world-venue-map/index.ts +3 -26
- package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
- package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
- package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
- package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
- package/src/plugins/builtin/yield-curve/client.ts +25 -0
- package/src/plugins/builtin/yield-curve/curves.ts +7 -4
- package/src/plugins/builtin/yield-curve/headless.ts +38 -4
- package/src/plugins/builtin/yield-curve/history.ts +4 -3
- package/src/plugins/builtin/yield-curve/index.tsx +12 -6
- package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
- package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
- package/src/plugins/bundle.ts +1 -1
- package/src/plugins/catalog-browser.ts +2 -1
- package/src/plugins/compat.ts +3 -3
- package/src/plugins/dependencies.ts +75 -14
- package/src/plugins/extracted-plugins.ts +132 -34
- package/src/plugins/host-link.ts +149 -34
- package/src/plugins/installer.ts +35 -10
- package/src/plugins/loader.ts +206 -38
- package/src/plugins/manager-node.ts +2 -2
- package/src/plugins/marketplace/deactivation.ts +22 -0
- package/src/plugins/marketplace/model.ts +2 -2
- package/src/plugins/marketplace/packs.ts +1 -1
- package/src/plugins/ownership.ts +1 -1
- package/src/plugins/peer-retry.ts +155 -0
- package/src/plugins/registry/contributions.ts +3 -1
- package/src/plugins/registry/index.ts +4 -3
- package/src/plugins/registry/plugin-state.ts +3 -0
- package/src/plugins/seed-notice.ts +20 -0
- package/src/plugins/shortcut-argument.ts +39 -0
- package/src/portfolio/allocation.ts +1 -1
- package/src/portfolio/collection-name.ts +31 -0
- package/src/portfolio/column-values.ts +10 -8
- package/src/portfolio/cost-fx.ts +296 -19
- package/src/portfolio/manual-lots.ts +75 -0
- package/src/portfolio/mutations.ts +60 -22
- package/src/portfolio/suffixed-listings.ts +209 -0
- package/src/portfolio/totals-currency.ts +24 -0
- package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
- package/src/public/time-series.ts +11 -8
- package/src/remote/schema.ts +1 -1
- package/src/renderers/browser/config-host.ts +3 -0
- package/src/renderers/browser/main.tsx +23 -3
- package/src/renderers/dom/boot-frame-page.ts +187 -0
- package/src/renderers/dom/boot-frame.ts +237 -0
- package/src/renderers/dom/build-assets.ts +46 -8
- package/src/renderers/dom/dom-ui-host.tsx +4 -29
- package/src/renderers/dom/host/ascii-text.ts +16 -2
- package/src/renderers/dom/host/box.tsx +43 -2
- package/src/renderers/dom/host/chart-surface.tsx +2 -0
- package/src/renderers/dom/host/hls.chunk.ts +3 -0
- package/src/renderers/dom/host/image-surface.tsx +49 -0
- package/src/renderers/dom/host/media-surface.tsx +24 -18
- package/src/renderers/dom/host/mouse.ts +30 -0
- package/src/renderers/dom/host/size-observer.ts +1 -1
- package/src/renderers/dom/host/style.ts +1 -1
- package/src/renderers/dom/styles.css +76 -0
- package/src/renderers/dom/test-utils.tsx +2 -1
- package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +46 -3
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
- package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
- package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
- package/src/renderers/electrobun/bun/index.ts +11 -1
- package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
- package/src/renderers/electrobun/bun/window/create.ts +4 -1
- package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
- package/src/renderers/electrobun/shared/protocol.ts +6 -1
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
- package/src/renderers/electrobun/view/config-host.ts +3 -0
- package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
- package/src/renderers/electrobun/view/main.tsx +30 -4
- package/src/renderers/electrobun/view/news-source.ts +5 -5
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -1
- package/src/renderers/electrobun/view/ui-host.tsx +1 -1
- package/src/renderers/opentui/browser-open.ts +88 -0
- package/src/renderers/opentui/host.tsx +5 -14
- package/src/renderers/opentui/image/loader.ts +3 -2
- package/src/renderers/opentui/native-smoke.ts +10 -1
- package/src/renderers/opentui/pane-image/index.ts +2 -1
- package/src/renderers/opentui/render-lib.ts +253 -0
- package/src/renderers/opentui/render-timing-smoke.ts +1 -1
- package/src/renderers/opentui/start.tsx +1 -1
- package/src/renderers/share/layout-view.tsx +2 -2
- package/src/renderers/share/main.tsx +4 -4
- package/src/renderers/share/view.tsx +1 -1
- package/src/series/resolve.ts +22 -6
- package/src/series/standalone.ts +30 -2
- package/src/series/types.ts +8 -1
- package/src/shares/api.ts +4 -1
- package/src/shares/pane.ts +1 -1
- package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
- package/src/sources/gloomberb-cloud/index.ts +32 -16
- package/src/sources/gloomberb-cloud/news.ts +39 -0
- package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
- package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
- package/src/sources/listing-symbols.ts +37 -0
- package/src/sources/provider-errors.ts +16 -2
- package/src/sources/provider-router/financial-routes.ts +21 -3
- package/src/sources/provider-router/financials.ts +15 -2
- package/src/sources/provider-router/history.ts +30 -8
- package/src/sources/provider-router/primary.ts +1 -1
- package/src/state/app/bootstrap.ts +23 -0
- package/src/state/hooks/inline-tickers.ts +30 -5
- package/src/sync/controller.ts +1 -1
- package/src/sync/core-contributors.ts +46 -14
- package/src/team/collections-sync.ts +2 -1
- package/src/team/collections.ts +178 -17
- package/src/telemetry/crash-reports.ts +17 -4
- package/src/test-support/builtin-panes.ts +1 -1
- package/src/theme/colors.ts +3 -30
- package/src/theme/ui-tokens.ts +37 -1
- package/src/tickers/company-name-listing.ts +210 -33
- package/src/tickers/index-roots.ts +47 -0
- package/src/tickers/instrument-label.ts +5 -1
- package/src/tickers/metadata.ts +10 -0
- package/src/tickers/perpetual-listing.ts +5 -2
- package/src/tickers/search/home-listing.ts +75 -0
- package/src/tickers/search/index.ts +76 -27
- package/src/tickers/search/ranking.ts +54 -4
- package/src/tickers/search/upsert.ts +29 -0
- package/src/tickers/terminal-codes.ts +416 -40
- package/src/time-series/bar-aggregation.ts +243 -0
- package/src/time-series/base-series.ts +307 -0
- package/src/time-series/chart-bounds.ts +349 -0
- package/src/time-series/chart-seed.ts +142 -0
- package/src/time-series/economic.ts +5 -0
- package/src/time-series/fundamentals.ts +18 -3
- package/src/time-series/history-acquisition.ts +499 -0
- package/src/time-series/leverage.ts +100 -0
- package/src/time-series/market-resolution.ts +4 -2
- package/src/time-series/market.ts +2 -1
- package/src/time-series/price-comparison.ts +175 -30
- package/src/time-series/range.ts +9 -1
- package/src/time-series/resolution.ts +174 -16
- package/src/time-series/resolve-context.ts +157 -0
- package/src/time-series/resolve.ts +126 -1577
- package/src/time-series/series-name.ts +38 -0
- package/src/time-series/series-presentation.ts +208 -0
- package/src/time-series/spec.ts +11 -6
- package/src/time-series/studies.ts +109 -12
- package/src/time-series/tail-reconcile.ts +121 -0
- package/src/time-series/types.ts +29 -2
- package/src/time-series/use-chart-resolution.ts +4 -5
- package/src/types/broker.ts +10 -0
- package/src/types/config.ts +14 -0
- package/src/types/data-provider.ts +14 -0
- package/src/types/exchange-rate.ts +6 -0
- package/src/types/financials.ts +104 -7
- package/src/types/headless.ts +76 -6
- package/src/types/instrument.ts +3 -0
- package/src/types/plugin.ts +65 -8
- package/src/types/price-history.ts +2 -0
- package/src/types/ticker.ts +13 -0
- package/src/types/trading.ts +59 -1
- package/src/ui/ascii-font.ts +13 -1
- package/src/ui/host.tsx +6 -1
- package/src/updater/command-names.ts +175 -0
- package/src/updater/index.ts +10 -5
- package/src/utils/calendar-date.ts +32 -15
- package/src/utils/cash-runway.ts +241 -0
- package/src/utils/central-banks.ts +42 -0
- package/src/utils/cli-output.ts +259 -80
- package/src/utils/contract-month.ts +16 -0
- package/src/utils/crypto-pair.ts +61 -3
- package/src/utils/currency-units.ts +29 -0
- package/src/utils/datetime-format.ts +10 -0
- package/src/utils/debug-log.ts +1 -1
- package/src/utils/decimal-comma.ts +39 -6
- package/src/utils/exchange-announcements.ts +71 -0
- package/src/utils/exchange-rate-snapshot.ts +10 -0
- package/src/utils/financial-statements.ts +83 -4
- package/src/utils/format.ts +34 -16
- package/src/utils/fundamentals.ts +150 -34
- package/src/utils/fx-market-hours.ts +10 -1
- package/src/utils/latest-financial-period.ts +8 -0
- package/src/utils/linux-libc.ts +54 -0
- package/src/utils/market-capitalization.ts +111 -15
- package/src/utils/max-drawdown.ts +64 -0
- package/src/utils/network-failure.ts +83 -0
- package/src/utils/option-expiry.ts +139 -7
- package/src/utils/price-earnings.ts +11 -5
- package/src/utils/price-history.ts +18 -8
- package/src/utils/price-window.ts +131 -0
- package/src/utils/release-date.ts +47 -0
- package/src/utils/sec.ts +3 -0
- package/src/utils/throttled-fetch.ts +11 -4
- package/src/utils/trailing-eps.ts +67 -0
- package/src/utils/typed-text.ts +21 -0
- package/src/utils/utc-time.ts +24 -1
- package/src/version.ts +6 -0
- package/src/cli/pane-functions/screenshot.ts +0 -2122
package/src/utils/cli-output.ts
CHANGED
|
@@ -4,24 +4,39 @@ export interface CliTableColumn {
|
|
|
4
4
|
header: string;
|
|
5
5
|
align?: CliAlign;
|
|
6
6
|
width?: number;
|
|
7
|
-
/** Cap for this column when the table is fitted to a terminal. Piped output stays whole. */
|
|
7
|
+
/** Cap for this column when the table is fitted to a terminal: longer cells are cut there. Piped output stays whole. */
|
|
8
8
|
maxWidth?: number;
|
|
9
|
-
/** The narrowest a text column
|
|
9
|
+
/** The narrowest a text column wraps to (MIN_WRAPPED_COLUMN_WIDTH unless set), or a `shrink: true` column is cut to; a narrower table moves columns under their rows. */
|
|
10
10
|
minWidth?: number;
|
|
11
|
-
/** Dropped, rightmost first, before
|
|
11
|
+
/** Dropped, rightmost first, before any column is cut or moved to fit a terminal. */
|
|
12
12
|
optional?: boolean;
|
|
13
13
|
/** Among optional columns, a higher priority is dropped sooner; equal ones go rightmost first. */
|
|
14
14
|
dropPriority?: number;
|
|
15
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* By default a fitted table never cuts a cell, so a date, a figure, a
|
|
17
|
+
* symbol or a title stays whole: text wraps in its cell and columns move
|
|
18
|
+
* under their rows. False keeps the column on one line. True is the
|
|
19
|
+
* explicit opt-out: the table cuts the column's cells, down to its header
|
|
20
|
+
* and `minWidth`, before columns move, for free text that names nothing,
|
|
21
|
+
* such as a description.
|
|
22
|
+
*/
|
|
16
23
|
shrink?: boolean;
|
|
17
24
|
/**
|
|
18
|
-
* When the table
|
|
19
|
-
*
|
|
20
|
-
*
|
|
25
|
+
* When the table does not fit, columns move to lines under their row, each
|
|
26
|
+
* value whole after its header: first the ones too wide to sit beside the
|
|
27
|
+
* first column, then a higher priority sooner, then long text, then
|
|
28
|
+
* rightmost first. The first column stays.
|
|
21
29
|
*/
|
|
22
30
|
stackPriority?: number;
|
|
23
31
|
/** Once moved under the rows, only the first `stackRows` rows print the column; 0 leaves it out. */
|
|
24
32
|
stackRows?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Left out of a table fitted to fewer terminal columns than this, whether
|
|
35
|
+
* or not it would fit: a detail a narrow table has no room for beside what
|
|
36
|
+
* it is about (a filing's acceptance time beside its filed date). Piped
|
|
37
|
+
* output keeps it.
|
|
38
|
+
*/
|
|
39
|
+
minTableWidth?: number;
|
|
25
40
|
}
|
|
26
41
|
|
|
27
42
|
export interface CliTableOptions {
|
|
@@ -43,6 +58,8 @@ const COLUMN_GAP = 2;
|
|
|
43
58
|
const MIN_SHRUNK_COLUMN_WIDTH = 8;
|
|
44
59
|
// Text columns first shrink right to left down to this width, then all shrink together.
|
|
45
60
|
const SOFT_MIN_COLUMN_WIDTH = 20;
|
|
61
|
+
// Text wraps in its cell down to this width, or its longest word, before columns move under the rows.
|
|
62
|
+
const MIN_WRAPPED_COLUMN_WIDTH = 16;
|
|
46
63
|
// Cells that say "no value": a moved column prints nothing for them.
|
|
47
64
|
const EMPTY_CELL = /^(?:|-{1,2}|—|–)$/;
|
|
48
65
|
// A date, or a date and time, as reports print them (`2026-10-09`, `2026-10`, `2026-10-09 20:15 UTC`).
|
|
@@ -50,20 +67,93 @@ const DATE_CELL = /^\d{4}-\d{2}(?:-\d{2})?(?:[ T]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)
|
|
|
50
67
|
// A number with its sign, currency, unit or range (`-1.0bp`, `$1,200`, `3.75-4.00%`, `481.75c`).
|
|
51
68
|
const NUMBER_PART = String.raw`[+\-−±]?[$€£¥]?\d[\d,]*(?:\.\d+)?`;
|
|
52
69
|
const NUMBER_TOKEN = new RegExp(String.raw`^\(?${NUMBER_PART}(?:[-–]${NUMBER_PART})?(?:%|¢|[a-zA-Z]{1,3})?\)?$`);
|
|
53
|
-
// What may sit between the numbers of one cell (`3.875% 82% / 4.125% 18%`, `+25bp
|
|
54
|
-
const NUMBER_JOINER = /^(?:\/|·|→|↑|↓|[-–])$/;
|
|
70
|
+
// What may sit between the numbers of one cell (`3.875% 82% / 4.125% 18%`, `+25bp ↑`, plain `+25bp up`).
|
|
71
|
+
const NUMBER_JOINER = /^(?:\/|·|→|↑|↓|[-–]|to|up|down)$/;
|
|
72
|
+
// What a plain table writes in a cell with no value.
|
|
73
|
+
const PLAIN_EMPTY_CELL = "—";
|
|
55
74
|
let colorEnabledOverride: boolean | null = null;
|
|
56
75
|
let widthOverride: number | null = null;
|
|
76
|
+
let plainOverride: boolean | null = null;
|
|
57
77
|
|
|
58
78
|
function colorEnabled(): boolean {
|
|
59
79
|
if (colorEnabledOverride != null) return colorEnabledOverride;
|
|
60
|
-
|
|
80
|
+
if (plainOverride === true) return false;
|
|
81
|
+
return !!process.stdout.isTTY && !process.env.NO_COLOR && process.env.TERM !== "dumb";
|
|
61
82
|
}
|
|
62
83
|
|
|
63
84
|
export function setCliColorEnabledOverride(value: boolean | null): void {
|
|
64
85
|
colorEnabledOverride = value;
|
|
65
86
|
}
|
|
66
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Plain output, for a screen reader, very large text or a pipe: tables have
|
|
90
|
+
* no rule under their header, keep every column they have with "—" in an
|
|
91
|
+
* empty cell, and say their arrows in words (`plainWords`), as do the
|
|
92
|
+
* markers the CLI writes itself (`cliArrow`); a user's own text is never
|
|
93
|
+
* rewritten. Colour is off unless `--color` asks for it. The CLI turns it on
|
|
94
|
+
* for NO_COLOR and output that is not a terminal (`plainByDefault`), and
|
|
95
|
+
* `--plain` / `--no-plain` decide it either way; unset, it is off.
|
|
96
|
+
*/
|
|
97
|
+
export function setCliPlainOverride(value: boolean | null): void {
|
|
98
|
+
plainOverride = value;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function cliPlainEnabled(): boolean {
|
|
102
|
+
return plainOverride === true;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Whether output is plain without `--plain` or `--no-plain`: NO_COLOR is set
|
|
107
|
+
* to a value (an empty one is unset, as the convention says), or stdout is
|
|
108
|
+
* not a terminal.
|
|
109
|
+
*/
|
|
110
|
+
export function plainByDefault(env: Record<string, string | undefined> = process.env, stdout: { isTTY?: boolean } = process.stdout): boolean {
|
|
111
|
+
return !!env.NO_COLOR || !stdout.isTTY;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const ARROW_WORDS: Record<string, string> = { "→": "to", "←": "from", "↑": "up", "↓": "down", "▲": "up", "▼": "down" };
|
|
115
|
+
const ARROW = /[←→↑↓▲▼]/;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* An arrow the CLI writes itself, beside text it did not (`gold → gold's
|
|
119
|
+
* market news`), in words when output is plain: "to" for `→`. Table cells
|
|
120
|
+
* and headers are worded by `renderTable`; nothing else is rewritten.
|
|
121
|
+
*/
|
|
122
|
+
export function cliArrow(arrow: "→" | "←" | "↑" | "↓"): string {
|
|
123
|
+
return cliPlainEnabled() ? ARROW_WORDS[arrow]! : arrow;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Arrows as the words they stand for, so a screen reader says them: a range
|
|
128
|
+
* `2026-04-03 → 04-06` reads "2026-04-03 to 04-06", `+25bp ↑` "+25bp up",
|
|
129
|
+
* the keys `←/→` "left/right". Text without an arrow is returned as it is.
|
|
130
|
+
* For a plain table's cells and headers, never a whole output.
|
|
131
|
+
*/
|
|
132
|
+
export function plainWords(text: string): string {
|
|
133
|
+
if (!ARROW.test(text)) return text;
|
|
134
|
+
return text
|
|
135
|
+
.replace(/←\s*\/\s*→/g, "left/right")
|
|
136
|
+
.replace(/↑\s*\/\s*↓/g, "up/down")
|
|
137
|
+
.replace(/([ \t]*)([←→↑↓▲▼])([ \t]*)/g, (match: string, lead: string, arrow: string, _trail: string, offset: number, whole: string) => {
|
|
138
|
+
// An arrow that starts a line keeps the line's indent; one that ends it leaves no space after its word.
|
|
139
|
+
const atStart = offset === 0 || whole[offset - 1] === "\n";
|
|
140
|
+
const end = offset + match.length;
|
|
141
|
+
const atEnd = end === whole.length || whole[end] === "\n";
|
|
142
|
+
return `${atStart ? lead : " "}${ARROW_WORDS[arrow]}${atEnd ? "" : " "}`;
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** A table header's sort mark in words: `MKT VAL ▼` is "MKT VAL (sorted descending)". */
|
|
147
|
+
function plainHeader(header: string): string {
|
|
148
|
+
const sorted = header.replace(/\s*([▲▼])\s*$/, (_match, mark: string) => ` (sorted ${mark === "▲" ? "ascending" : "descending"})`);
|
|
149
|
+
return plainWords(sorted.trimStart());
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** A plain table's cell: arrows in words, and "—" for no value. */
|
|
153
|
+
function plainCell(cell: string): string {
|
|
154
|
+
return EMPTY_CELL.test(stripAnsi(cell).trim()) ? PLAIN_EMPTY_CELL : plainWords(cell);
|
|
155
|
+
}
|
|
156
|
+
|
|
67
157
|
function applyAnsi(text: string, code: string): string {
|
|
68
158
|
if (!colorEnabled()) return text;
|
|
69
159
|
return `\x1b[${code}m${text}\x1b[0m`;
|
|
@@ -341,95 +431,132 @@ interface TableEntry {
|
|
|
341
431
|
column: CliTableColumn;
|
|
342
432
|
index: number;
|
|
343
433
|
width: number;
|
|
344
|
-
/** The narrowest the column may
|
|
434
|
+
/** The narrowest the column may get. */
|
|
345
435
|
floor: number;
|
|
346
|
-
/**
|
|
347
|
-
|
|
436
|
+
/** Text that wraps onto more lines of its cell rather than being cut. */
|
|
437
|
+
wraps: boolean;
|
|
438
|
+
/** Words rather than dates, figures or fixed-width values. */
|
|
439
|
+
text: boolean;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* How narrow a column may get. Cells are whole by default: a date, a figure,
|
|
444
|
+
* a symbol, a name or a title cut short reads as another one. Text wraps in
|
|
445
|
+
* its cell down to its longest word or `minWidth` (MIN_WRAPPED_COLUMN_WIDTH
|
|
446
|
+
* unless set); `shrink: false` keeps it on one line. Only free text marked
|
|
447
|
+
* `shrink: true` is cut, to its header and `minWidth`.
|
|
448
|
+
*/
|
|
449
|
+
function columnFloor(column: CliTableColumn, width: number, cells: readonly string[], capped: boolean): Pick<TableEntry, "floor" | "wraps" | "text"> {
|
|
450
|
+
if (column.width != null || column.align === "right" || isWholeColumn(cells)) return { floor: width, wraps: false, text: false };
|
|
451
|
+
// Cut at its `maxWidth`, as the column asks.
|
|
452
|
+
if (capped) return { floor: width, wraps: false, text: true };
|
|
453
|
+
if (column.shrink === true) {
|
|
454
|
+
return { floor: Math.min(width, Math.max(MIN_SHRUNK_COLUMN_WIDTH, visibleLength(column.header), column.minWidth ?? 0)), wraps: false, text: true };
|
|
455
|
+
}
|
|
456
|
+
if (column.shrink === false) return { floor: width, wraps: false, text: true };
|
|
457
|
+
const words = cells.flatMap((cell) => stripAnsi(cell).split(/\s+/));
|
|
458
|
+
const longestWord = Math.max(visibleLength(column.header), ...words.map((word) => visibleLength(word)));
|
|
459
|
+
return { floor: Math.min(width, Math.max(longestWord, column.minWidth ?? MIN_WRAPPED_COLUMN_WIDTH)), wraps: true, text: true };
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/** A cell's text wrapped to `width`, each line closing the colour it opens and the next reopening it, so it never bleeds into the next column. */
|
|
463
|
+
function wrapCell(text: string, width: number): string[] {
|
|
464
|
+
const lines = wrapText(text, width);
|
|
465
|
+
if (lines.length < 2 || !text.includes("\x1b[")) return lines;
|
|
466
|
+
let open = "";
|
|
467
|
+
return lines.map((line) => {
|
|
468
|
+
const carried = open;
|
|
469
|
+
for (const code of line.match(ANSI_PATTERN) ?? []) open = code === "\x1b[0m" ? "" : `${open}${code}`;
|
|
470
|
+
return `${carried}${line}${open ? "\x1b[0m" : ""}`;
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
interface TableLayout {
|
|
475
|
+
kept: TableEntry[];
|
|
476
|
+
stacked: TableEntry[];
|
|
348
477
|
}
|
|
349
478
|
|
|
350
|
-
/**
|
|
351
|
-
function
|
|
352
|
-
|
|
353
|
-
return
|
|
479
|
+
/** Which of two columns moves under the rows sooner: by the first value that differs. */
|
|
480
|
+
function movesSooner(left: readonly number[], right: readonly number[]): boolean {
|
|
481
|
+
const at = left.findIndex((value, index) => value !== right[index]);
|
|
482
|
+
return at >= 0 && left[at]! > right[at]!;
|
|
354
483
|
}
|
|
355
484
|
|
|
356
485
|
/**
|
|
357
|
-
* The
|
|
358
|
-
*
|
|
359
|
-
*
|
|
360
|
-
* the
|
|
361
|
-
*
|
|
486
|
+
* The ways a table too wide can fit `available`, each moving one more column
|
|
487
|
+
* under the rows, where its values print whole. In each, text wraps in its
|
|
488
|
+
* cell and free text marked `shrink: true` is cut, down to their floors.
|
|
489
|
+
* Columns move in this order: the ones too wide to ever sit beside the first
|
|
490
|
+
* column (a long headline, a note), then by `stackPriority`, then long text
|
|
491
|
+
* (a name, a title) before dates and figures, then rightmost first. The
|
|
492
|
+
* first column stays. The list ends at the first layout that keeps every
|
|
493
|
+
* column it shows whole on one line: moving more only adds lines.
|
|
362
494
|
*/
|
|
363
|
-
function
|
|
364
|
-
const fit = (kept: TableEntry[]
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
495
|
+
function tableLayouts(entries: TableEntry[], available: number): TableLayout[] {
|
|
496
|
+
const fit = (kept: TableEntry[]) => fitColumnWidths(kept.map((entry) => entry.width), kept.map((entry) => entry.floor), available);
|
|
497
|
+
const first = entries[0]!;
|
|
498
|
+
const room = available - first.floor - COLUMN_GAP;
|
|
499
|
+
const order = (entry: TableEntry) => [
|
|
500
|
+
entry.floor > room ? 1 : 0,
|
|
501
|
+
entry.column.stackPriority ?? 0,
|
|
502
|
+
entry.text && entry.width > SOFT_MIN_COLUMN_WIDTH ? 1 : 0,
|
|
503
|
+
entry.index,
|
|
504
|
+
];
|
|
505
|
+
const layouts: TableLayout[] = [];
|
|
369
506
|
let kept = entries;
|
|
370
507
|
const stacked: TableEntry[] = [];
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
(
|
|
376
|
-
|
|
508
|
+
for (;;) {
|
|
509
|
+
const widths = fit(kept);
|
|
510
|
+
if (widths) {
|
|
511
|
+
layouts.push({ kept: kept.map((entry, position) => ({ ...entry, width: widths[position]! })), stacked: [...stacked] });
|
|
512
|
+
if (widths.every((width, position) => width >= kept[position]!.width)) break;
|
|
513
|
+
}
|
|
514
|
+
if (kept.length === 1) break;
|
|
515
|
+
const moved = kept.slice(1).reduce((pick, entry) => (movesSooner(order(entry), order(pick)) ? entry : pick));
|
|
377
516
|
kept = kept.filter((entry) => entry !== moved);
|
|
378
517
|
stacked.push(moved);
|
|
379
|
-
widths = fit(kept, true);
|
|
380
518
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
519
|
+
// The first column alone is wider than the table may be: text wraps and free text is cut to the
|
|
520
|
+
// whole width; a symbol or a figure stays whole.
|
|
521
|
+
if (layouts.length === 0) layouts.push({ kept: [{ ...first, width: first.wraps || first.column.shrink === true ? available : first.width }], stacked });
|
|
522
|
+
return layouts;
|
|
384
523
|
}
|
|
385
524
|
|
|
386
|
-
|
|
525
|
+
function renderTableLayout(
|
|
526
|
+
columns: CliTableColumn[],
|
|
527
|
+
rows: string[][],
|
|
528
|
+
options: CliTableOptions,
|
|
529
|
+
shown: readonly TableEntry[],
|
|
530
|
+
stacked: readonly TableEntry[],
|
|
531
|
+
available: number | null,
|
|
532
|
+
/** Cells wrap or are cut to their column's width: the table was fitted to `available`. */
|
|
533
|
+
fitted: boolean,
|
|
534
|
+
): string {
|
|
387
535
|
const indent = " ".repeat(options.indent ?? 0);
|
|
388
|
-
const maxWidth = options.maxWidth === undefined ? cliTerminalWidth() : options.maxWidth;
|
|
389
|
-
const available = maxWidth == null ? null : maxWidth - indent.length;
|
|
390
|
-
let shown = columns.map((column, index) => {
|
|
391
|
-
const cellWidths = rows.map((row) => visibleLength(row[index] ?? ""));
|
|
392
|
-
return { column, index, width: column.width ?? Math.max(visibleLength(column.header), ...cellWidths) };
|
|
393
|
-
});
|
|
394
|
-
let stacked: Array<(typeof shown)[number]> = [];
|
|
395
|
-
// Cells are only cut when the table was fitted to a terminal; piped output keeps them whole.
|
|
396
|
-
let truncate = false;
|
|
397
|
-
if (available != null && tableWidth(shown.map((entry) => entry.width)) > available) {
|
|
398
|
-
while (tableWidth(shown.map((entry) => entry.width)) > available) {
|
|
399
|
-
const dropped = shown.reduce<(typeof shown)[number] | undefined>((pick, entry) => (
|
|
400
|
-
entry.column.optional && (!pick || (entry.column.dropPriority ?? 0) >= (pick.column.dropPriority ?? 0)) ? entry : pick
|
|
401
|
-
), undefined);
|
|
402
|
-
if (!dropped) break;
|
|
403
|
-
shown = shown.filter((entry) => entry !== dropped);
|
|
404
|
-
}
|
|
405
|
-
const layout = fitTableLayout(shown.map((entry) => {
|
|
406
|
-
const width = entry.column.maxWidth == null
|
|
407
|
-
? entry.width
|
|
408
|
-
: Math.min(entry.width, Math.max(entry.column.maxWidth, visibleLength(entry.column.header)));
|
|
409
|
-
return { ...entry, width, floor: columnFloor(entry.column, width), figures: isWholeColumn(rows.map((row) => row[entry.index] ?? "")) };
|
|
410
|
-
}), available);
|
|
411
|
-
// A first column that cannot fit even alone keeps every cell whole rather than losing data and overflowing anyway.
|
|
412
|
-
if (layout) {
|
|
413
|
-
shown = layout.kept;
|
|
414
|
-
stacked = layout.stacked.filter((entry) => entry.column.stackRows !== 0).sort((left, right) => left.index - right.index);
|
|
415
|
-
truncate = true;
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
536
|
const renderRow = (cells: string[], style?: (text: string) => string) => {
|
|
420
|
-
const
|
|
421
|
-
const cell =
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
? cell
|
|
425
|
-
: padDisplay(cell, width, column.align ?? "left");
|
|
426
|
-
return style ? style(padded) : padded;
|
|
537
|
+
const columnLines = shown.map(({ index, width, wraps }) => {
|
|
538
|
+
const cell = cells[index] ?? "";
|
|
539
|
+
if (!fitted) return [cell];
|
|
540
|
+
return wraps ? wrapCell(cell, width) : [truncateDisplay(cell, width)];
|
|
427
541
|
});
|
|
428
|
-
|
|
542
|
+
// A cell that wraps makes its row taller; the other cells sit on the row's first line.
|
|
543
|
+
const height = Math.max(1, ...columnLines.map((lines) => lines.length));
|
|
544
|
+
return Array.from({ length: height }, (_, line) => {
|
|
545
|
+
const rendered = shown.map(({ column, width }, position) => {
|
|
546
|
+
const cell = columnLines[position]![line] ?? "";
|
|
547
|
+
// The last left-aligned column is not padded so lines carry no trailing spaces.
|
|
548
|
+
const padded = position === shown.length - 1 && (column.align ?? "left") === "left"
|
|
549
|
+
? cell
|
|
550
|
+
: padDisplay(cell, width, column.align ?? "left");
|
|
551
|
+
return style && (line === 0 || cell) ? style(padded) : padded;
|
|
552
|
+
});
|
|
553
|
+
return `${indent}${rendered.join(" ".repeat(COLUMN_GAP))}`.trimEnd();
|
|
554
|
+
}).join("\n");
|
|
429
555
|
};
|
|
430
556
|
|
|
431
557
|
const header = renderRow(columns.map((column) => column.header), cliStyles.bold);
|
|
432
|
-
|
|
558
|
+
// A plain table has no rule under its header: a screen reader reads it as a row of dashes.
|
|
559
|
+
const divider = cliPlainEnabled() ? [] : [`${indent}${shown.map(({ width }) => cliStyles.muted("─".repeat(width))).join(" ".repeat(COLUMN_GAP))}`];
|
|
433
560
|
const belowIndent = `${indent}${" ".repeat(COLUMN_GAP)}`;
|
|
434
561
|
const belowWidth = Math.max(1, (available ?? 0) - COLUMN_GAP);
|
|
435
562
|
const renderBelow = (index: number) => (options.below?.[index] ?? []).flatMap((line) => (
|
|
@@ -463,5 +590,57 @@ export function renderTable(columns: CliTableColumn[], rows: string[][], options
|
|
|
463
590
|
if (line) lines.push(line);
|
|
464
591
|
return lines.map((text) => `${belowIndent}${text}`.trimEnd());
|
|
465
592
|
};
|
|
466
|
-
return [header, divider, ...rows.flatMap((row, index) => [renderRow(row), ...renderStacked(row, index), ...renderBelow(index)])].join("\n");
|
|
593
|
+
return [header, ...divider, ...rows.flatMap((row, index) => [renderRow(row), ...renderStacked(row, index), ...renderBelow(index)])].join("\n");
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* A table fitted to the terminal (or `--width`), or whole when output is
|
|
598
|
+
* piped. A table too wide never cuts a cell short, unless its column is free
|
|
599
|
+
* text marked `shrink: true`: text wraps in its cell and columns move under
|
|
600
|
+
* their rows, each value whole after its header. Of the ways that fit, the
|
|
601
|
+
* one with the fewest lines prints, the one that moves fewer columns on a tie.
|
|
602
|
+
* Plain output (`setCliPlainOverride`) has no rule under the header, words
|
|
603
|
+
* for arrows and "—" in every empty cell.
|
|
604
|
+
*/
|
|
605
|
+
export function renderTable(columns: CliTableColumn[], rows: string[][], options: CliTableOptions = {}): string {
|
|
606
|
+
if (cliPlainEnabled()) {
|
|
607
|
+
columns = columns.map((column) => ({ ...column, header: plainHeader(column.header) }));
|
|
608
|
+
rows = rows.map((row) => columns.map((_, index) => plainCell(row[index] ?? "")));
|
|
609
|
+
if (options.below) options = { ...options, below: options.below.map((lines) => lines?.map(plainWords)) };
|
|
610
|
+
}
|
|
611
|
+
const maxWidth = options.maxWidth === undefined ? cliTerminalWidth() : options.maxWidth;
|
|
612
|
+
const available = maxWidth == null ? null : maxWidth - (options.indent ?? 0);
|
|
613
|
+
let shown = columns.map((column, index) => {
|
|
614
|
+
const cellWidths = rows.map((row) => visibleLength(row[index] ?? ""));
|
|
615
|
+
return { column, index, width: column.width ?? Math.max(visibleLength(column.header), ...cellWidths), floor: 0, wraps: false, text: false };
|
|
616
|
+
}).filter(({ column }) => maxWidth == null || column.minTableWidth == null || maxWidth >= column.minTableWidth);
|
|
617
|
+
// Cells are only cut or wrapped when the table is fitted to a terminal; piped output keeps them whole.
|
|
618
|
+
if (available == null || tableWidth(shown.map((entry) => entry.width)) <= available) {
|
|
619
|
+
return renderTableLayout(columns, rows, options, shown, [], available, false);
|
|
620
|
+
}
|
|
621
|
+
while (tableWidth(shown.map((entry) => entry.width)) > available) {
|
|
622
|
+
const dropped = shown.reduce<(typeof shown)[number] | undefined>((pick, entry) => (
|
|
623
|
+
entry.column.optional && (!pick || (entry.column.dropPriority ?? 0) >= (pick.column.dropPriority ?? 0)) ? entry : pick
|
|
624
|
+
), undefined);
|
|
625
|
+
if (!dropped) break;
|
|
626
|
+
shown = shown.filter((entry) => entry !== dropped);
|
|
627
|
+
}
|
|
628
|
+
const entries = shown.map((entry) => {
|
|
629
|
+
const width = entry.column.maxWidth == null
|
|
630
|
+
? entry.width
|
|
631
|
+
: Math.min(entry.width, Math.max(entry.column.maxWidth, visibleLength(entry.column.header)));
|
|
632
|
+
return { ...entry, width, ...columnFloor(entry.column, width, rows.map((row) => row[entry.index] ?? ""), width < entry.width) };
|
|
633
|
+
});
|
|
634
|
+
let best = "";
|
|
635
|
+
let bestLines = Infinity;
|
|
636
|
+
for (const layout of tableLayouts(entries, available)) {
|
|
637
|
+
const stacked = layout.stacked.filter((entry) => entry.column.stackRows !== 0).sort((left, right) => left.index - right.index);
|
|
638
|
+
const text = renderTableLayout(columns, rows, options, layout.kept, stacked, available, true);
|
|
639
|
+
const lines = text.split("\n").length;
|
|
640
|
+
if (lines < bestLines) {
|
|
641
|
+
best = text;
|
|
642
|
+
bestLines = lines;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
return best;
|
|
467
646
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A futures contract month as every pane and report writes it, "Oct 2026":
|
|
5
|
+
* "Oct 26" reads as the 26th of October. `month` is 0-11; a two-digit year
|
|
6
|
+
* (the 26 of HGZ26) is in this century.
|
|
7
|
+
*/
|
|
8
|
+
export function contractMonthLabel(year: number, month: number): string {
|
|
9
|
+
return `${MONTHS[month] ?? String(month + 1).padStart(2, "0")} ${year < 100 ? 2000 + year : year}`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** A delivery month, "2026-10", "2026-10-01" or a broker's "202610", as contractMonthLabel writes it; null when it is no month. */
|
|
13
|
+
export function deliveryMonthLabel(deliveryMonth: string | null | undefined): string | null {
|
|
14
|
+
const match = /^(\d{4})-?(0[1-9]|1[0-2])(?:$|-)/.exec(deliveryMonth ?? "");
|
|
15
|
+
return match ? contractMonthLabel(Number(match[1]), Number(match[2]) - 1) : null;
|
|
16
|
+
}
|
package/src/utils/crypto-pair.ts
CHANGED
|
@@ -9,6 +9,8 @@ const FIAT_CURRENCY_CODES = new Set([
|
|
|
9
9
|
]);
|
|
10
10
|
|
|
11
11
|
const USD_COIN_PAIR = /^([A-Z0-9]+)[-/]USD$/;
|
|
12
|
+
// The other currencies and coins the crypto venue quotes a coin in (BTC-EUR, ETH-BTC).
|
|
13
|
+
const QUOTED_COIN_PAIR = /^([A-Z0-9]+)[-/](?:USDT|USDC|EUR|GBP|BTC|ETH)$/;
|
|
12
14
|
|
|
13
15
|
/** A coin quoted in dollars (BTC-USD, ETH/USD). EUR-USD is spot FX, not a coin. */
|
|
14
16
|
function isUsdCoinPair(symbol: string): boolean {
|
|
@@ -16,15 +18,24 @@ function isUsdCoinPair(symbol: string): boolean {
|
|
|
16
18
|
return base !== undefined && !FIAT_CURRENCY_CODES.has(base);
|
|
17
19
|
}
|
|
18
20
|
|
|
21
|
+
/** A coin quoted in another currency or coin (BTC-EUR, ETH-BTC). EUR-GBP is spot FX, not a coin. */
|
|
22
|
+
function isQuotedCoinPair(symbol: string): boolean {
|
|
23
|
+
const base = QUOTED_COIN_PAIR.exec(symbol.trim().toUpperCase())?.[1];
|
|
24
|
+
return base !== undefined && !isIsoCurrencyCode(base);
|
|
25
|
+
}
|
|
26
|
+
|
|
19
27
|
/**
|
|
20
28
|
* A series that trades around the clock: anything on the crypto venue (CCC), or
|
|
21
29
|
* a coin quoted in dollars whether or not the caller named that venue. A bare
|
|
22
|
-
* BTC-USD is the coin, not a US listing; a bare BTC (no quote) is a US fund.
|
|
30
|
+
* BTC-USD is the coin, not a US listing; a bare BTC (no quote) is a US fund. A
|
|
31
|
+
* bare coin quoted in euros or in another coin (BTC-EUR) is the coin too, never
|
|
32
|
+
* a US listing whose session closed at 16:00 New York.
|
|
23
33
|
*/
|
|
24
34
|
export function isRoundTheClockCoin(symbol?: string, exchange?: string): boolean {
|
|
25
35
|
const parsed = symbol ? parsePublicTickerKey(symbol) : null;
|
|
26
|
-
|
|
27
|
-
|
|
36
|
+
const venue = canonicalExchange(parsed?.exchange ?? exchange) || canonicalExchange(exchange);
|
|
37
|
+
if (venue === "CCC" || canonicalExchange(exchange) === "CCC") return true;
|
|
38
|
+
return !!parsed && (isUsdCoinPair(parsed.symbol) || (!venue && isQuotedCoinPair(parsed.symbol)));
|
|
28
39
|
}
|
|
29
40
|
|
|
30
41
|
const SLASH_COIN_PAIR = /^([A-Z0-9]{1,15})\/(USD|EUR|GBP|USDT|USDC|BTC)$/;
|
|
@@ -59,3 +70,50 @@ const CRYPTO_PAIR = /^[A-Z0-9]{1,15}-(?:USD|EUR|GBP|USDT|USDC|BTC)$/;
|
|
|
59
70
|
export function isCryptoPairSymbol(symbol: string): boolean {
|
|
60
71
|
return CRYPTO_PAIR.test(symbol);
|
|
61
72
|
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* The coins whose bare ticker is most often typed for the coin itself, with
|
|
76
|
+
* how stories and notes name each: the name a listing's own may not say
|
|
77
|
+
* plainly ("Bitcoin USD").
|
|
78
|
+
*/
|
|
79
|
+
export const MAJOR_COIN_NAMES: ReadonlyMap<string, string> = new Map([
|
|
80
|
+
["BTC", "bitcoin"],
|
|
81
|
+
["ETH", "ethereum"],
|
|
82
|
+
["SOL", "solana"],
|
|
83
|
+
["XRP", "XRP"],
|
|
84
|
+
["DOGE", "dogecoin"],
|
|
85
|
+
["ADA", "cardano"],
|
|
86
|
+
["LTC", "litecoin"],
|
|
87
|
+
["BCH", "bitcoin cash"],
|
|
88
|
+
["AVAX", "avalanche"],
|
|
89
|
+
["DOT", "polkadot"],
|
|
90
|
+
["LINK", "chainlink"],
|
|
91
|
+
["BNB", "BNB"],
|
|
92
|
+
]);
|
|
93
|
+
|
|
94
|
+
const COIN_PAIR = /^([A-Z0-9]{1,15})[-/](?:USD|EUR|GBP|USDT|USDC|BTC)$/;
|
|
95
|
+
// What a pair's listing name adds after the coin's: its quote currency, an id in brackets.
|
|
96
|
+
const PAIR_NAME_SUFFIX = /(?:\s*\([^)]*\))+$|\s+(?:USD|EUR|GBP|USDT|USDC|BTC|US Dollars?)$/i;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The coin a crypto pair trades, as stories name it: "bitcoin" for BTC-USD
|
|
100
|
+
* (or BTC-USD on CCC), from the major coins' names, else the listing's name
|
|
101
|
+
* without its quote currency ("Hyperliquid USD" is "hyperliquid"). Null for a
|
|
102
|
+
* symbol that is not a coin pair, and for a coin with no name to search for:
|
|
103
|
+
* its code alone (TON, UNI) is too often a word.
|
|
104
|
+
*/
|
|
105
|
+
export function coinSearchName(symbol: string | undefined, exchange?: string, listingName?: string | null): string | null {
|
|
106
|
+
if (!symbol || !isRoundTheClockCoin(symbol, exchange)) return null;
|
|
107
|
+
const parsed = parsePublicTickerKey(symbol).symbol.trim().toUpperCase();
|
|
108
|
+
const code = COIN_PAIR.exec(parsed)?.[1] ?? parsed;
|
|
109
|
+
if (isIsoCurrencyCode(code)) return null;
|
|
110
|
+
const major = MAJOR_COIN_NAMES.get(code);
|
|
111
|
+
if (major) return major;
|
|
112
|
+
let name = listingName?.trim() ?? "";
|
|
113
|
+
for (let previous = ""; previous !== name;) {
|
|
114
|
+
previous = name;
|
|
115
|
+
name = name.replace(PAIR_NAME_SUFFIX, "").trim();
|
|
116
|
+
}
|
|
117
|
+
if (name.length < 3 || name.toUpperCase() === code || !/\p{L}/u.test(name)) return null;
|
|
118
|
+
return name === name.toUpperCase() ? name : name.toLowerCase();
|
|
119
|
+
}
|
|
@@ -104,6 +104,25 @@ export function heldCurrencyUnit(currency?: string | null): CurrencyUnitInfo {
|
|
|
104
104
|
return currency?.trim().toUpperCase() === US_CENTS ? { currency: "USD", divisor: 100 } : resolveCurrencyUnit(currency);
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
/**
|
|
108
|
+
* The codes whose USD rates convert money held in `currencies`: each as a
|
|
109
|
+
* rate is asked for (upper-cased), and a minor unit's major currency too,
|
|
110
|
+
* which convertCurrency reads a hundredth of when the unit has no rate of its
|
|
111
|
+
* own. Gloom Cloud serves none for GBX or ILA, and ZAc and GBp are kept in
|
|
112
|
+
* their own case, which no upper-cased rate matches.
|
|
113
|
+
*/
|
|
114
|
+
export function fxRateCurrencies(currencies: Iterable<string | null | undefined>): string[] {
|
|
115
|
+
const codes = new Set<string>();
|
|
116
|
+
for (const currency of currencies) {
|
|
117
|
+
const raw = currency?.trim();
|
|
118
|
+
if (!raw) continue;
|
|
119
|
+
codes.add(raw.toUpperCase());
|
|
120
|
+
const unit = heldCurrencyUnit(raw);
|
|
121
|
+
if (unit.divisor !== 1 && unit.currency) codes.add(unit.currency);
|
|
122
|
+
}
|
|
123
|
+
return [...codes].sort((left, right) => left.localeCompare(right));
|
|
124
|
+
}
|
|
125
|
+
|
|
107
126
|
interface ExchangeSubUnitOptions {
|
|
108
127
|
allowDefaultCurrency?: boolean;
|
|
109
128
|
allowMissingCurrency?: boolean;
|
|
@@ -114,6 +133,16 @@ function normalizeExchange(value?: string | null): string {
|
|
|
114
133
|
return (value ?? "").trim().toUpperCase();
|
|
115
134
|
}
|
|
116
135
|
|
|
136
|
+
/**
|
|
137
|
+
* A currency code as a position saves it: upper-cased, except a minor unit
|
|
138
|
+
* whose code is written in its own case (GBp, ZAc), which stays as typed so
|
|
139
|
+
* pence are not read as pounds. GBX and gbp read as pence and pounds.
|
|
140
|
+
*/
|
|
141
|
+
export function normalizeHeldCurrencyCode(code: string | null | undefined): string {
|
|
142
|
+
const raw = (code ?? "").trim();
|
|
143
|
+
return SUB_UNIT_CURRENCIES[raw] && raw !== raw.toUpperCase() ? raw : raw.toUpperCase();
|
|
144
|
+
}
|
|
145
|
+
|
|
117
146
|
export function resolveCurrencyUnit(currency?: string | null): CurrencyUnitInfo {
|
|
118
147
|
const raw = (currency ?? "").trim();
|
|
119
148
|
if (!raw) {
|
|
@@ -39,6 +39,16 @@ export function formatRelativeAge(timestamp: number | undefined, now = Date.now(
|
|
|
39
39
|
return elapsed ? `${elapsed.count}${elapsed.unit} ago` : "just now";
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/** Time until something scheduled, on the same ladder: "in <1m", "in 25m", "in 3h", "in 3h 20m". */
|
|
43
|
+
export function formatCountdown(ms: number): string {
|
|
44
|
+
if (ms <= 60_000) return "in <1m";
|
|
45
|
+
const totalMin = Math.floor(ms / 60_000);
|
|
46
|
+
if (totalMin < 60) return `in ${totalMin}m`;
|
|
47
|
+
const h = Math.floor(totalMin / 60);
|
|
48
|
+
const m = totalMin % 60;
|
|
49
|
+
return m > 0 ? `in ${h}h ${m}m` : `in ${h}h`;
|
|
50
|
+
}
|
|
51
|
+
|
|
42
52
|
// Reuse the locale formatter when a feed contains older items. Constructing
|
|
43
53
|
// one for every row dominates opening a long transcript, even without edits.
|
|
44
54
|
const olderRelativeDateFormatter = new Intl.DateTimeFormat("en-US", {
|
package/src/utils/debug-log.ts
CHANGED
|
@@ -146,7 +146,7 @@ class DebugLog {
|
|
|
146
146
|
exportAsText(filter?: { level?: LogLevel; source?: string }): string {
|
|
147
147
|
const entries = this.getEntries(filter);
|
|
148
148
|
const lines: string[] = [
|
|
149
|
-
`
|
|
149
|
+
`Gloom Debug Log — exported ${new Date().toISOString()}`,
|
|
150
150
|
`Total entries: ${entries.length}`,
|
|
151
151
|
"=".repeat(80),
|
|
152
152
|
"",
|