gloomberb 0.9.9 → 0.10.0
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 +41 -3
- package/README.zh-CN.md +294 -0
- package/package.json +10 -4
- package/patches/@opentui%2Fcore@0.3.2.patch +26 -69
- package/src/api-client/auth.ts +2 -0
- package/src/api-client/index.test.ts +4 -0
- package/src/api-client/types.ts +3 -0
- package/src/app/pane-runtime/pane-settings-runtime.tsx +1 -0
- package/src/app/pane-template-dialog-wizard.test.tsx +36 -0
- package/src/app/pane-template-dialog-wizard.tsx +10 -3
- package/src/app/runtime/desktop-deeplink.test.ts +15 -0
- package/src/app/runtime/desktop-deeplink.ts +21 -6
- package/src/app.tsx +40 -33
- package/src/capabilities/service-capabilities.ts +7 -2
- package/src/cli/commands/automation.test.ts +202 -0
- package/src/cli/commands/automation.ts +153 -36
- package/src/cli/commands/market.ts +1 -14
- package/src/cli/commands/system.ts +4 -1
- package/src/cli/context.ts +1 -1
- package/src/cli/desktop-pane-shot.ts +65 -4
- package/src/cli/entry.ts +1 -1
- package/src/cli/pane-functions/capabilities.ts +532 -0
- package/src/cli/pane-functions/catalog.ts +39 -4
- package/src/cli/pane-functions/data.test.ts +17 -0
- package/src/cli/pane-functions/data.ts +55 -13
- package/src/cli/pane-functions/discovery.ts +36 -9
- package/src/cli/pane-functions/index.test.ts +104 -1
- package/src/cli/pane-functions/index.ts +64 -5
- package/src/cli/pane-functions/options.ts +21 -6
- package/src/cli/pane-functions/report.ts +735 -72
- package/src/cli/pane-functions/resolver.ts +70 -6
- package/src/cli/pane-functions/screenshot.test.ts +431 -0
- package/src/cli/pane-functions/screenshot.ts +952 -8
- package/src/components/chart/composite/column-layout.ts +215 -0
- package/src/components/chart/composite/composite-chart.test.tsx +630 -0
- package/src/components/chart/composite/composite-chart.tsx +1148 -0
- package/src/components/chart/composite/format.test.ts +137 -0
- package/src/components/chart/composite/format.ts +135 -0
- package/src/components/chart/composite/index.ts +38 -0
- package/src/components/chart/composite/interactions.test.ts +109 -0
- package/src/components/chart/composite/interactions.ts +247 -0
- package/src/components/chart/composite/price-series.test.ts +39 -0
- package/src/components/chart/composite/price-series.ts +78 -0
- package/src/components/chart/composite/rasterizer.ts +359 -0
- package/src/components/chart/composite/renderers.test.ts +610 -0
- package/src/components/chart/composite/scene.test.ts +464 -0
- package/src/components/chart/composite/scene.ts +553 -0
- package/src/components/chart/composite/text-renderer.ts +285 -0
- package/src/components/chart/composite/time-scale.test.ts +88 -0
- package/src/components/chart/composite/time-scale.ts +217 -0
- package/src/components/chart/composite/types.ts +141 -0
- package/src/components/chart/core/data.ts +81 -5
- package/src/components/chart/core/index.test.ts +128 -43
- package/src/components/chart/core/resolution.ts +0 -6
- package/src/components/chart/native/chart-rasterizer.ts +1 -3
- package/src/components/chart/native/kitty/index.test.ts +99 -120
- package/src/components/chart/native/kitty/manager.ts +3 -0
- package/src/components/chart/native/kitty/protocol.ts +4 -1
- package/src/components/chart/native/raster/crosshair.ts +79 -46
- package/src/components/chart/native/raster/types.ts +2 -11
- package/src/components/chart/native/surface/manager.ts +48 -3
- package/src/components/chart/price-axis-labels.tsx +18 -4
- package/src/components/command-bar/commands/direct/index.ts +25 -0
- package/src/components/command-bar/commands/registry.ts +9 -0
- package/src/components/command-bar/helpers.test.ts +4 -1
- package/src/components/command-bar/list/view.tsx +18 -6
- package/src/components/command-bar/multi-select-picker.tsx +6 -5
- package/src/components/command-bar/pane-settings.test.ts +141 -0
- package/src/components/command-bar/pane-settings.ts +61 -1
- package/src/components/command-bar/panel/body.tsx +7 -6
- package/src/components/command-bar/routes/root/command-items.ts +4 -4
- package/src/components/command-bar/routes/root/results.ts +10 -1
- package/src/components/command-bar/routes/root/selection.test.ts +54 -0
- package/src/components/command-bar/routes/root/selection.ts +13 -0
- package/src/components/command-bar/routing/actions.ts +18 -2
- package/src/components/command-bar/routing/list-state.ts +2 -1
- package/src/components/command-bar/surface/index.test.tsx +36 -4
- package/src/components/command-bar/surface/pane.test.tsx +93 -0
- package/src/components/command-bar/theme-picker.tsx +2 -1
- package/src/components/command-bar/view-model.ts +19 -20
- package/src/components/command-bar/workflow/body.tsx +2 -1
- package/src/components/command-bar/workflow/field-row.tsx +3 -2
- package/src/components/command-bar/workflow/fields.ts +4 -2
- package/src/components/command-bar/workflow/ops.test.ts +161 -0
- package/src/components/command-bar/workflow/ops.ts +20 -50
- package/src/components/command-bar/workflow/route-actions.test.ts +34 -0
- package/src/components/command-bar/workflow/route-actions.ts +4 -0
- package/src/components/command-bar/workflow/types.ts +1 -0
- package/src/components/feed-data-table/stack-view.tsx +6 -5
- package/src/components/index.ts +13 -1
- package/src/components/layout/detached-pane-shell.tsx +2 -1
- package/src/components/layout/floating-pane.tsx +3 -0
- package/src/components/layout/header.tsx +15 -8
- package/src/components/layout/pane/footer/index.test.tsx +22 -3
- package/src/components/layout/pane/footer/index.tsx +3 -1
- package/src/components/layout/pane/footer/model.ts +9 -2
- package/src/components/layout/pane/header.tsx +4 -6
- package/src/components/layout/pane/index.tsx +3 -0
- package/src/components/layout/pane/sidebar.test.tsx +100 -0
- package/src/components/layout/pane/sidebar.tsx +239 -0
- package/src/components/layout/pane/title.ts +4 -3
- package/src/components/layout/shell/action-menu-overlay.tsx +5 -3
- package/src/components/layout/shell/drag/runtime.ts +2 -0
- package/src/components/layout/shell/menu.test.ts +19 -0
- package/src/components/layout/shell/menu.ts +8 -5
- package/src/components/layout/shell/native/pointer-runtime.ts +4 -1
- package/src/components/layout/shell/pane/layers.tsx +2 -2
- package/src/components/layout/status-bar.tsx +8 -7
- package/src/components/layout/window-controls.tsx +4 -3
- package/src/components/metric-treemap/index.tsx +3 -2
- package/src/components/onboarding/onboarding-steps.tsx +30 -29
- package/src/components/onboarding/onboarding-wizard.tsx +5 -4
- package/src/components/onboarding/portfolio-step/broker-fields-panel.tsx +15 -12
- package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +17 -16
- package/src/components/onboarding/portfolio-step/broker-sync-panel.tsx +6 -5
- package/src/components/onboarding/portfolio-step/choose-panel.tsx +5 -4
- package/src/components/pane-settings-dialog/desktop.tsx +25 -3
- package/src/components/pane-settings-dialog/field-dialogs.tsx +5 -4
- package/src/components/pane-settings-dialog/tui.tsx +11 -9
- package/src/components/pane-settings-dialog/value.ts +8 -5
- package/src/components/pane-settings-dialog.test.tsx +235 -0
- package/src/components/pane-settings-dialog.tsx +24 -0
- package/src/components/pane-template-wizard.tsx +6 -2
- package/src/components/ticker/list-table-view.tsx +3 -2
- package/src/components/ui/button.tsx +3 -1
- package/src/components/ui/choice-dialog.tsx +6 -1
- package/src/components/ui/confirm-dialog.tsx +3 -2
- package/src/components/ui/fields.tsx +10 -1
- package/src/components/ui/frame.tsx +4 -1
- package/src/components/ui/index.ts +5 -0
- package/src/components/ui/inline-quick-add.tsx +104 -0
- package/src/components/ui/list-view.tsx +5 -4
- package/src/components/ui/loading.tsx +2 -1
- package/src/components/ui/multi-select/dialog.tsx +188 -44
- package/src/components/ui/popover.tsx +10 -0
- package/src/components/ui/shortcut-hint.tsx +2 -0
- package/src/components/ui/status.tsx +4 -3
- package/src/components/ui/tabs.tsx +19 -8
- package/src/components/ui/toggle.tsx +44 -3
- package/src/components/ui/ui.test.tsx +67 -5
- package/src/core/app-services.ts +4 -6
- package/src/core/state/session-persistence.ts +3 -2
- package/src/data/config/chart-settings.ts +712 -0
- package/src/data/config/layout.ts +24 -5
- package/src/data/config/store/index.test.ts +377 -14
- package/src/data/config/store/normalize.ts +79 -65
- package/src/data/fred-series.ts +137 -0
- package/src/i18n/index.test.ts +114 -0
- package/src/i18n/index.ts +147 -0
- package/src/i18n/ja.ts +1013 -0
- package/src/i18n/ko.ts +1011 -0
- package/src/i18n/languages.test.ts +31 -0
- package/src/i18n/languages.ts +72 -0
- package/src/i18n/zh-cn.ts +1013 -0
- package/src/i18n/zh-tw.ts +1013 -0
- package/src/plugins/builtin/account-management/footer.ts +3 -2
- package/src/plugins/builtin/account-management/form-components.tsx +3 -2
- package/src/plugins/builtin/account-management/keyboard.ts +6 -0
- package/src/plugins/builtin/account-management/model.ts +25 -21
- package/src/plugins/builtin/account-management/navigation.test.ts +27 -0
- package/src/plugins/builtin/account-management/navigation.ts +24 -0
- package/src/plugins/builtin/account-management/pane.tsx +120 -85
- package/src/plugins/builtin/account-management/password-dialog.tsx +10 -9
- package/src/plugins/builtin/ai/agent-history.ts +139 -0
- package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +133 -51
- package/src/plugins/builtin/ai/ask-ai.test.tsx +83 -22
- package/src/plugins/builtin/ai/index.test.ts +302 -0
- package/src/plugins/builtin/ai/index.tsx +374 -40
- package/src/plugins/builtin/ai/pane-settings.test.ts +155 -0
- package/src/plugins/builtin/ai/pane-settings.ts +319 -0
- package/src/plugins/builtin/ai/pi/credential-store.test.ts +80 -0
- package/src/plugins/builtin/ai/pi/credential-store.ts +138 -0
- package/src/plugins/builtin/ai/pi/file-store.ts +138 -0
- package/src/plugins/builtin/ai/pi/host.test.ts +500 -0
- package/src/plugins/builtin/ai/pi/host.ts +564 -0
- package/src/plugins/builtin/ai/pi/index.ts +5 -0
- package/src/plugins/builtin/ai/pi/models-store.test.ts +44 -0
- package/src/plugins/builtin/ai/pi/models-store.ts +141 -0
- package/src/plugins/builtin/ai/pi/providers.ts +68 -0
- package/src/plugins/builtin/ai/pi/runtime.test.ts +240 -0
- package/src/plugins/builtin/ai/pi/runtime.ts +635 -0
- package/src/plugins/builtin/ai/providers.test.ts +68 -0
- package/src/plugins/builtin/ai/providers.ts +163 -38
- package/src/plugins/builtin/ai/runner-selection.test.ts +174 -0
- package/src/plugins/builtin/ai/runner-selection.ts +193 -0
- package/src/plugins/builtin/ai/runner-selector.tsx +153 -0
- package/src/plugins/builtin/ai/runner.test.ts +198 -0
- package/src/plugins/builtin/ai/runner.ts +276 -73
- package/src/plugins/builtin/ai/screener/contract.test.ts +26 -73
- package/src/plugins/builtin/ai/screener/contract.ts +14 -52
- package/src/plugins/builtin/ai/screener/editor-runtime.ts +55 -5
- package/src/plugins/builtin/ai/screener/editor.tsx +42 -36
- package/src/plugins/builtin/ai/screener/footer.ts +82 -67
- package/src/plugins/builtin/ai/screener/keyboard.ts +27 -11
- package/src/plugins/builtin/ai/screener/model.test.ts +24 -0
- package/src/plugins/builtin/ai/screener/model.ts +9 -3
- package/src/plugins/builtin/ai/screener/pane.test.tsx +142 -55
- package/src/plugins/builtin/ai/screener/pane.tsx +95 -97
- package/src/plugins/builtin/ai/screener/results-view.tsx +8 -41
- package/src/plugins/builtin/ai/screener/runner.ts +41 -25
- package/src/plugins/builtin/ai/screener/tabs-bar.tsx +2 -2
- package/src/plugins/builtin/ai/use-runtime-providers.ts +28 -0
- package/src/plugins/builtin/ai/workspace/model.test.ts +227 -0
- package/src/plugins/builtin/ai/workspace/model.ts +308 -0
- package/src/plugins/builtin/ai/workspace/pane.test.tsx +197 -0
- package/src/plugins/builtin/ai/workspace/pane.tsx +896 -0
- package/src/plugins/builtin/analytics/index.test.tsx +3 -3
- package/src/plugins/builtin/analytics/index.tsx +3 -8
- package/src/plugins/builtin/broker-manager/detail.tsx +25 -24
- package/src/plugins/builtin/broker-manager/index.test.tsx +1 -1
- package/src/plugins/builtin/broker-manager/index.tsx +9 -11
- package/src/plugins/builtin/broker-manager/model.ts +11 -10
- package/src/plugins/builtin/broker-manager/pane-actions.tsx +22 -21
- package/src/plugins/builtin/broker-manager/table.ts +9 -8
- package/src/plugins/builtin/changelog/index.tsx +3 -8
- package/src/plugins/builtin/chart-composer/chart-spec.ts +89 -0
- package/src/plugins/builtin/chart-composer/cli-options.ts +98 -0
- package/src/plugins/builtin/chart-composer/date-window-dialog.tsx +120 -0
- package/src/plugins/builtin/chart-composer/editor.test.tsx +332 -0
- package/src/plugins/builtin/chart-composer/editor.tsx +1107 -0
- package/src/plugins/builtin/chart-composer/index.tsx +228 -0
- package/src/plugins/builtin/chart-composer/pane.tsx +645 -0
- package/src/plugins/builtin/chart-composer/presets.test.ts +561 -0
- package/src/plugins/builtin/chart-composer/presets.ts +759 -0
- package/src/plugins/builtin/chart-composer/quick-add.test.tsx +245 -0
- package/src/plugins/builtin/chart-composer/quick-add.tsx +409 -0
- package/src/plugins/builtin/chart-composer/semantic.ts +86 -0
- package/src/plugins/builtin/chart-composer/series-catalog.test.ts +65 -0
- package/src/plugins/builtin/chart-composer/series-catalog.ts +295 -0
- package/src/plugins/builtin/chart-composer/settings.test.ts +163 -0
- package/src/plugins/builtin/chart-composer/settings.ts +397 -0
- package/src/plugins/builtin/chart-composer/shortcuts.test.ts +44 -0
- package/src/plugins/builtin/chart-composer/shortcuts.ts +35 -0
- package/src/plugins/builtin/chart-composer/use-series-catalog.ts +103 -0
- package/src/plugins/builtin/chat/channel-labels.ts +5 -4
- package/src/plugins/builtin/chat/channels.ts +12 -11
- package/src/plugins/builtin/chat/chat.test.tsx +32 -0
- package/src/plugins/builtin/chat/content/composer-runtime.ts +6 -1
- package/src/plugins/builtin/chat/content/composer.tsx +9 -8
- package/src/plugins/builtin/chat/content/index.tsx +36 -1
- package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +8 -7
- package/src/plugins/builtin/chat/content/transcript.tsx +9 -3
- package/src/plugins/builtin/chat/controller/utils.ts +10 -9
- package/src/plugins/builtin/chat/message/desktop.tsx +17 -10
- package/src/plugins/builtin/chat/message/profile-popover.test.tsx +122 -3
- package/src/plugins/builtin/chat/message/profile-popover.tsx +38 -1
- package/src/plugins/builtin/chat/message/terminal.tsx +19 -10
- package/src/plugins/builtin/chat/pane-state.test.ts +31 -0
- package/src/plugins/builtin/chat/pane-state.ts +30 -0
- package/src/plugins/builtin/chat/pane.tsx +27 -4
- package/src/plugins/builtin/chat/profile-popover.ts +62 -5
- package/src/plugins/builtin/chat/sidebar.test.tsx +4 -7
- package/src/plugins/builtin/chat/sidebar.tsx +107 -168
- package/src/plugins/builtin/chat/test-harness.tsx +6 -0
- package/src/plugins/builtin/cloud/auth-actions.tsx +5 -4
- package/src/plugins/builtin/cloud/plugin.tsx +150 -127
- package/src/plugins/builtin/composite-plugins.ts +71 -0
- package/src/plugins/builtin/correlation/index.test.tsx +4 -4
- package/src/plugins/builtin/correlation/index.tsx +3 -8
- package/src/plugins/builtin/earnings/index.tsx +37 -21
- package/src/plugins/builtin/earnings/model.test.ts +52 -0
- package/src/plugins/builtin/earnings/model.ts +32 -0
- package/src/plugins/builtin/econ/detail-view.tsx +17 -4
- package/src/plugins/builtin/econ/fred-cache.test.ts +57 -11
- package/src/plugins/builtin/econ/index.tsx +16 -20
- package/src/plugins/builtin/fear-greed/index.tsx +2 -8
- package/src/plugins/builtin/fx-matrix/index.tsx +3 -8
- package/src/plugins/builtin/help/components.tsx +5 -4
- package/src/plugins/builtin/help/index.tsx +14 -17
- package/src/plugins/builtin/holders/index.tsx +2 -8
- package/src/plugins/builtin/insider/index.tsx +2 -7
- package/src/plugins/builtin/kelly-sizer/index.test.tsx +2 -2
- package/src/plugins/builtin/kelly-sizer/index.tsx +3 -7
- package/src/plugins/builtin/kelly-sizer/test-support.tsx +3 -3
- package/src/plugins/builtin/layout-manager/index.tsx +3 -7
- package/src/plugins/builtin/market-heatmap/index.tsx +3 -8
- package/src/plugins/builtin/market-movers/index.tsx +3 -8
- package/src/plugins/builtin/news/index.tsx +12 -16
- package/src/plugins/builtin/news/wire/breaking/pane.test.tsx +3 -3
- package/src/plugins/builtin/news/wire/index.tsx +83 -73
- package/src/plugins/builtin/options/index.tsx +2 -8
- package/src/plugins/builtin/plugin-module.test.ts +89 -0
- package/src/plugins/builtin/plugin-module.ts +116 -0
- package/src/plugins/builtin/portfolio-list/header.tsx +4 -3
- package/src/plugins/builtin/portfolio-list/index.test.ts +17 -0
- package/src/plugins/builtin/portfolio-list/index.tsx +3 -5
- package/src/plugins/builtin/portfolio-list/pane/index.test.tsx +3 -3
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +53 -53
- package/src/plugins/builtin/portfolio-list/settings.ts +5 -3
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +4 -3
- package/src/plugins/builtin/research/index.tsx +2 -8
- package/src/plugins/builtin/sec/index.tsx +2 -8
- package/src/plugins/builtin/sectors/index.tsx +3 -8
- package/src/plugins/builtin/thirteenf/index.tsx +3 -8
- package/src/plugins/builtin/thirteenf/pane.test.tsx +1 -1
- package/src/plugins/builtin/ticker-detail/chart-tab-switch.test.tsx +49 -23
- package/src/plugins/builtin/ticker-detail/index.test.tsx +15 -136
- package/src/plugins/builtin/ticker-detail/index.tsx +2 -93
- package/src/plugins/builtin/ticker-detail/overview/components.tsx +6 -5
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +41 -17
- package/src/plugins/builtin/ticker-detail/pane.tsx +4 -3
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.test.tsx +1 -1
- package/src/plugins/builtin/ticker-detail/settings.ts +3 -50
- package/src/plugins/builtin/ticker-research-backend-plugin.ts +17 -0
- package/src/plugins/builtin/ticker-research-plugin.ts +27 -0
- package/src/plugins/builtin/tv/channels.ts +27 -0
- package/src/plugins/builtin/tv/index.tsx +40 -0
- package/src/plugins/builtin/tv/pane.tsx +286 -0
- package/src/plugins/builtin/tv/youtube-stream.ts +100 -0
- package/src/plugins/builtin/world-indices/index.tsx +3 -8
- package/src/plugins/builtin/yield-curve/index.tsx +8 -8
- package/src/plugins/catalog-backend.test.ts +21 -0
- package/src/plugins/catalog-backend.ts +42 -0
- package/src/plugins/catalog-ui.ts +6 -14
- package/src/plugins/ibkr/instance-selection.test.ts +0 -1
- package/src/plugins/ownership.ts +143 -0
- package/src/plugins/prediction-markets/backend-plugin.ts +19 -0
- package/src/plugins/prediction-markets/chart.test.tsx +7 -5
- package/src/plugins/prediction-markets/chart.tsx +25 -7
- package/src/plugins/registry/index.test.ts +51 -0
- package/src/plugins/registry/index.ts +8 -0
- package/src/plugins/registry/pane-settings.ts +1 -1
- package/src/plugins/runtime/index.test.tsx +2 -2
- package/src/remote/app-host.tsx +16 -3
- package/src/remote/controller.test.ts +102 -1
- package/src/remote/controller.ts +122 -0
- package/src/remote/types.ts +11 -0
- package/src/renderers/electrobun/bun/core-capabilities.ts +123 -27
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +5 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +5 -1
- package/src/renderers/electrobun/bun/desktop/media.ts +15 -0
- package/src/renderers/electrobun/bun/desktop/window-style.ts +4 -1
- package/src/renderers/electrobun/bun/desktop/workspace/index.test.ts +32 -1
- package/src/renderers/electrobun/bun/desktop/workspace/index.ts +10 -0
- package/src/renderers/electrobun/bun/index.ts +5 -0
- package/src/renderers/electrobun/bun/tui-entry.ts +1 -6
- package/src/renderers/electrobun/view/ai-host.ts +124 -19
- package/src/renderers/electrobun/view/backend-rpc.ts +4 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +151 -39
- package/src/renderers/electrobun/view/desktop/popover.tsx +166 -0
- package/src/renderers/electrobun/view/dialog-host.test.ts +25 -0
- package/src/renderers/electrobun/view/dialog-host.tsx +75 -12
- package/src/renderers/electrobun/view/host/box.tsx +5 -0
- package/src/renderers/electrobun/view/host/chart-surface.tsx +10 -9
- package/src/renderers/electrobun/view/host/input.tsx +9 -19
- package/src/renderers/electrobun/view/host/media-surface.tsx +170 -0
- package/src/renderers/electrobun/view/host/mouse.ts +1 -0
- package/src/renderers/electrobun/view/host/style.ts +1 -1
- package/src/renderers/electrobun/view/host/tabs.tsx +4 -3
- package/src/renderers/electrobun/view/main.tsx +10 -3
- package/src/renderers/electrobun/view/styles.css +17 -0
- package/src/renderers/electrobun/view/ui-host.tsx +7 -0
- package/src/renderers/opentui/chart-surface.test.tsx +52 -6
- package/src/renderers/opentui/chart-surface.tsx +95 -11
- package/src/renderers/opentui/dialog-host.tsx +36 -5
- package/src/renderers/opentui/host.tsx +39 -0
- package/src/renderers/opentui/start.tsx +30 -0
- package/src/renderers/opentui/ui-host.tsx +2 -0
- package/src/sources/provider-router/index.test.ts +43 -0
- package/src/sources/provider-router/index.ts +4 -0
- package/src/sources/provider-router/supplemental.ts +46 -0
- package/src/sources/sec-edgar.test.ts +203 -2
- package/src/sources/sec-edgar.ts +70 -15
- package/src/state/app/context/index.tsx +13 -1
- package/src/state/app/context/selector.test.tsx +62 -1
- package/src/state/session-persistence.test.ts +13 -2
- package/src/sync/controller.test.ts +190 -3
- package/src/sync/controller.ts +76 -45
- package/src/sync/core-contributors.test.ts +121 -0
- package/src/sync/core-contributors.ts +104 -27
- package/src/sync/react.ts +6 -8
- package/src/sync/types.ts +3 -0
- package/src/time-series/alignment.ts +158 -0
- package/src/time-series/economic.ts +49 -0
- package/src/time-series/field-catalog.ts +306 -0
- package/src/time-series/fundamentals.test.ts +505 -0
- package/src/time-series/fundamentals.ts +842 -0
- package/src/time-series/hooks.ts +45 -0
- package/src/time-series/index.ts +14 -0
- package/src/time-series/live-quotes.test.ts +219 -0
- package/src/time-series/live-quotes.ts +203 -0
- package/src/time-series/market-resolution.ts +53 -0
- package/src/time-series/market.ts +125 -0
- package/src/time-series/reporting.ts +98 -0
- package/src/time-series/resolve.test.ts +1281 -0
- package/src/time-series/resolve.ts +783 -0
- package/src/time-series/spec-studies.test.ts +400 -0
- package/src/time-series/spec.ts +487 -0
- package/src/time-series/studies.ts +563 -0
- package/src/time-series/transforms.test.ts +105 -0
- package/src/time-series/transforms.ts +152 -0
- package/src/time-series/types.ts +162 -0
- package/src/time-series/use-chart-resolution.ts +166 -0
- package/src/types/config.ts +9 -11
- package/src/types/desktop-window.ts +1 -0
- package/src/types/financials.ts +4 -0
- package/src/types/media.ts +17 -0
- package/src/types/plugin.ts +32 -1
- package/src/ui/context-menu.tsx +15 -3
- package/src/ui/dialog.tsx +14 -2
- package/src/ui/host.tsx +40 -1
- package/src/ui/index.tsx +9 -0
- package/src/utils/exchanges.test.ts +13 -1
- package/src/utils/exchanges.ts +10 -0
- package/src/utils/financial-statements.test.ts +138 -0
- package/src/utils/financial-statements.ts +115 -8
- package/src/utils/format.test.ts +11 -1
- package/src/utils/format.ts +7 -0
- package/src/version.ts +1 -1
- package/src/components/chart/bar-chart-renderer.test.ts +0 -233
- package/src/components/chart/bar-chart-renderer.ts +0 -445
- package/src/components/chart/comparison/data.test.ts +0 -159
- package/src/components/chart/comparison/data.ts +0 -302
- package/src/components/chart/comparison/renderer.test.ts +0 -187
- package/src/components/chart/comparison/renderer.ts +0 -282
- package/src/components/chart/comparison/scene.ts +0 -178
- package/src/components/chart/comparison-stock-chart/axis-width.ts +0 -99
- package/src/components/chart/comparison-stock-chart/canvas.ts +0 -148
- package/src/components/chart/comparison-stock-chart/controls.ts +0 -252
- package/src/components/chart/comparison-stock-chart/helpers.ts +0 -101
- package/src/components/chart/comparison-stock-chart/interactions.ts +0 -208
- package/src/components/chart/comparison-stock-chart/layout-metrics.ts +0 -62
- package/src/components/chart/comparison-stock-chart/layout.tsx +0 -155
- package/src/components/chart/comparison-stock-chart/legend.tsx +0 -74
- package/src/components/chart/comparison-stock-chart/native-surfaces.ts +0 -89
- package/src/components/chart/comparison-stock-chart/render-data.ts +0 -227
- package/src/components/chart/comparison-stock-chart/render-output.ts +0 -140
- package/src/components/chart/comparison-stock-chart/selection-runtime.ts +0 -128
- package/src/components/chart/comparison-stock-chart/sources.ts +0 -51
- package/src/components/chart/comparison-stock-chart/surface-runtime.ts +0 -159
- package/src/components/chart/comparison-stock-chart/toolbar.tsx +0 -117
- package/src/components/chart/comparison-stock-chart/types.ts +0 -22
- package/src/components/chart/comparison-stock-chart/view.tsx +0 -572
- package/src/components/chart/comparison-stock-chart/viewport-runtime.ts +0 -239
- package/src/components/chart/comparison-stock-chart.tsx +0 -24
- package/src/components/chart/core/axis-measure.ts +0 -33
- package/src/components/chart/core/controller.test.ts +0 -157
- package/src/components/chart/core/controller.ts +0 -349
- package/src/components/chart/core/indicator-selector.tsx +0 -75
- package/src/components/chart/core/keyboard.ts +0 -24
- package/src/components/chart/core/pane-settings.test.ts +0 -52
- package/src/components/chart/core/pane-settings.ts +0 -141
- package/src/components/chart/core/scroll.test.ts +0 -64
- package/src/components/chart/core/scroll.ts +0 -82
- package/src/components/chart/core/window-viewport.test.ts +0 -69
- package/src/components/chart/core/window-viewport.ts +0 -162
- package/src/components/chart/display-cursor.ts +0 -153
- package/src/components/chart/indicators/bands.test.ts +0 -36
- package/src/components/chart/indicators/bands.ts +0 -29
- package/src/components/chart/indicators/moving-averages.test.ts +0 -39
- package/src/components/chart/indicators/moving-averages.ts +0 -42
- package/src/components/chart/indicators/options.test.ts +0 -32
- package/src/components/chart/indicators/options.ts +0 -107
- package/src/components/chart/indicators/oscillators.test.ts +0 -58
- package/src/components/chart/indicators/oscillators.ts +0 -92
- package/src/components/chart/native/canvas-bitmaps.ts +0 -140
- package/src/components/chart/native/raster/comparison-chart.ts +0 -162
- package/src/components/chart/native/surface/hooks.ts +0 -144
- package/src/components/chart/native/surface/rendering.ts +0 -211
- package/src/components/chart/static/bar-chart-surface.test.tsx +0 -101
- package/src/components/chart/static/bar-chart-surface.tsx +0 -292
- package/src/components/chart/stock-chart/auto.ts +0 -216
- package/src/components/chart/stock-chart/axis-width.ts +0 -146
- package/src/components/chart/stock-chart/bitmaps.ts +0 -22
- package/src/components/chart/stock-chart/canvas.ts +0 -202
- package/src/components/chart/stock-chart/controls.tsx +0 -149
- package/src/components/chart/stock-chart/cursor.ts +0 -60
- package/src/components/chart/stock-chart/data-runtime.ts +0 -128
- package/src/components/chart/stock-chart/footer.test.ts +0 -65
- package/src/components/chart/stock-chart/footer.ts +0 -303
- package/src/components/chart/stock-chart/geometry.ts +0 -160
- package/src/components/chart/stock-chart/index.test.ts +0 -532
- package/src/components/chart/stock-chart/index.tsx +0 -29
- package/src/components/chart/stock-chart/indicators.ts +0 -226
- package/src/components/chart/stock-chart/interaction-runtime.ts +0 -44
- package/src/components/chart/stock-chart/interactions.ts +0 -300
- package/src/components/chart/stock-chart/keyboard.ts +0 -373
- package/src/components/chart/stock-chart/layout-metrics.ts +0 -62
- package/src/components/chart/stock-chart/layout.tsx +0 -177
- package/src/components/chart/stock-chart/native-surfaces.ts +0 -121
- package/src/components/chart/stock-chart/presentation.ts +0 -67
- package/src/components/chart/stock-chart/renderer-switch.test.tsx +0 -263
- package/src/components/chart/stock-chart/rendering/bounds.ts +0 -116
- package/src/components/chart/stock-chart/rendering/candidates.ts +0 -145
- package/src/components/chart/stock-chart/rendering/data.ts +0 -370
- package/src/components/chart/stock-chart/rendering/invalidation.ts +0 -68
- package/src/components/chart/stock-chart/rendering/output.ts +0 -304
- package/src/components/chart/stock-chart/rendering/planning.ts +0 -122
- package/src/components/chart/stock-chart/rendering/projection.test.tsx +0 -98
- package/src/components/chart/stock-chart/rendering/projection.ts +0 -112
- package/src/components/chart/stock-chart/rendering/state.test.ts +0 -70
- package/src/components/chart/stock-chart/rendering/state.ts +0 -283
- package/src/components/chart/stock-chart/requests.ts +0 -337
- package/src/components/chart/stock-chart/resolution-support.ts +0 -96
- package/src/components/chart/stock-chart/resolved/runtime.ts +0 -289
- package/src/components/chart/stock-chart/resolved.tsx +0 -359
- package/src/components/chart/stock-chart/settings.ts +0 -81
- package/src/components/chart/stock-chart/surface-runtime.ts +0 -62
- package/src/components/chart/stock-chart/types.ts +0 -25
- package/src/components/chart/stock-chart/view.tsx +0 -155
- package/src/components/chart/stock-chart/viewport/effects.ts +0 -293
- package/src/components/chart/stock-chart/viewport/index.ts +0 -144
- package/src/components/chart/stock-chart/viewport/runtime.ts +0 -375
- package/src/components/chart/time-axis-label.tsx +0 -175
- package/src/plugins/builtin/ai/gloomberb-cli.ts +0 -71
- package/src/plugins/builtin/ai/screener/action-bar.tsx +0 -58
- package/src/plugins/builtin/comparison-chart/index.test.tsx +0 -848
- package/src/plugins/builtin/comparison-chart/index.tsx +0 -194
- package/src/plugins/builtin/econ/fred-cache.ts +0 -106
- package/src/plugins/builtin/plugin-groups.ts +0 -130
- package/src/plugins/builtin/ticker-detail/chart-pane.tsx +0 -91
- package/src/plugins/builtin/ticker-detail/chart-tab.tsx +0 -100
- package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/content.tsx +0 -296
- package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/data.ts +0 -62
- package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/model.ts +0 -608
- package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/settings.ts +0 -65
- package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/types.ts +0 -58
- package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph.tsx +0 -138
- package/src/plugins/builtin/ticker-detail/data-panes.test.ts +0 -220
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import type { TickerFinancials } from "../../types/financials";
|
|
1
|
+
import type { PricePoint, TickerFinancials } from "../../types/financials";
|
|
2
2
|
import type { TickerRecord } from "../../types/ticker";
|
|
3
|
-
import {
|
|
3
|
+
import type { TimeRange } from "../../components/chart/core/types";
|
|
4
|
+
import { subtractTimeRange } from "../../components/chart/core/date-window";
|
|
5
|
+
import { CHART_COMPOSER_PANE_ID, LEGACY_TICKER_DETAIL_PANE_ID } from "../../types/config";
|
|
6
|
+
import { parseChartSpec } from "../../plugins/builtin/chart-composer/chart-spec";
|
|
4
7
|
import { normalizeTickerInput } from "../../tickers/search";
|
|
5
8
|
import type { MarketContext } from "../types";
|
|
6
9
|
import { cleanTickerInput } from "./options";
|
|
10
|
+
import { parsePublicTickerKey, publicTickerKey } from "../../utils/exchanges";
|
|
7
11
|
import type { ResolvedPaneFunction } from "./resolver";
|
|
8
12
|
|
|
9
13
|
const SHOT_PRICE_HISTORY_RANGE = "5Y" as const;
|
|
@@ -13,12 +17,18 @@ const FINANCIAL_ANALYSIS_TEMPLATE_ID = "financial-analysis-pane";
|
|
|
13
17
|
export async function fetchTickerFinancials(
|
|
14
18
|
context: MarketContext,
|
|
15
19
|
symbol: string,
|
|
16
|
-
): Promise<{
|
|
20
|
+
): Promise<{
|
|
21
|
+
tickerFile: TickerRecord | null;
|
|
22
|
+
financials: TickerFinancials;
|
|
23
|
+
instrument: { symbol: string; exchange?: string };
|
|
24
|
+
}> {
|
|
17
25
|
const normalized = cleanTickerInput(symbol);
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
26
|
+
const instrument = parsePublicTickerKey(normalized);
|
|
27
|
+
const tickerFile = await context.store.loadTicker(normalized)
|
|
28
|
+
?? (instrument.symbol !== normalized ? await context.store.loadTicker(instrument.symbol) : null);
|
|
29
|
+
const exchange = instrument.exchange ?? tickerFile?.metadata.exchange ?? "";
|
|
30
|
+
const financials = await context.dataProvider.getTickerFinancials(instrument.symbol, exchange);
|
|
31
|
+
return { tickerFile, financials, instrument: { symbol: instrument.symbol, ...(exchange ? { exchange } : {}) } };
|
|
22
32
|
}
|
|
23
33
|
|
|
24
34
|
export async function withShotPriceHistory(
|
|
@@ -28,12 +38,14 @@ export async function withShotPriceHistory(
|
|
|
28
38
|
financials: TickerFinancials,
|
|
29
39
|
): Promise<TickerFinancials> {
|
|
30
40
|
if (financials.priceHistory?.length) return financials;
|
|
31
|
-
const
|
|
41
|
+
const instrument = parsePublicTickerKey(symbol);
|
|
42
|
+
const exchange = instrument.exchange
|
|
43
|
+
?? tickerFile?.metadata.exchange
|
|
32
44
|
?? financials.quote?.listingExchangeName
|
|
33
45
|
?? financials.quote?.exchangeName
|
|
34
46
|
?? "";
|
|
35
47
|
try {
|
|
36
|
-
const priceHistory = await context.dataProvider.getPriceHistory(symbol, exchange, SHOT_PRICE_HISTORY_RANGE);
|
|
48
|
+
const priceHistory = await context.dataProvider.getPriceHistory(instrument.symbol, exchange, SHOT_PRICE_HISTORY_RANGE);
|
|
37
49
|
return priceHistory.length > 0 ? { ...financials, priceHistory } : financials;
|
|
38
50
|
} catch {
|
|
39
51
|
return financials;
|
|
@@ -54,13 +66,14 @@ export function isFinancialAnalysisFunction(resolved: ResolvedPaneFunction): boo
|
|
|
54
66
|
}
|
|
55
67
|
|
|
56
68
|
export function createFallbackTicker(symbol: string, financials: TickerFinancials | null, context: MarketContext): TickerRecord {
|
|
69
|
+
const instrument = parsePublicTickerKey(symbol);
|
|
57
70
|
const quote = financials?.quote;
|
|
58
71
|
return {
|
|
59
72
|
metadata: {
|
|
60
|
-
ticker: symbol,
|
|
61
|
-
exchange: quote?.listingExchangeName ?? quote?.exchangeName ?? "",
|
|
73
|
+
ticker: instrument.symbol,
|
|
74
|
+
exchange: instrument.exchange ?? quote?.listingExchangeName ?? quote?.exchangeName ?? "",
|
|
62
75
|
currency: quote?.currency ?? context.config.baseCurrency,
|
|
63
|
-
name: quote?.name ?? symbol,
|
|
76
|
+
name: quote?.name ?? instrument.symbol,
|
|
64
77
|
portfolios: [],
|
|
65
78
|
watchlists: [],
|
|
66
79
|
positions: [],
|
|
@@ -71,8 +84,37 @@ export function createFallbackTicker(symbol: string, financials: TickerFinancial
|
|
|
71
84
|
}
|
|
72
85
|
|
|
73
86
|
export function collectShotSymbols(resolved: ResolvedPaneFunction, rawArg: string): string[] {
|
|
74
|
-
|
|
87
|
+
if (resolved.pane.id === CHART_COMPOSER_PANE_ID) {
|
|
88
|
+
const spec = parseChartSpec(resolved.instance.settings?.chartSpec);
|
|
89
|
+
if (spec) {
|
|
90
|
+
return [...new Set(spec.series.flatMap((series) => (
|
|
91
|
+
series.source.kind === "security"
|
|
92
|
+
? [publicTickerKey(series.source.instrument.symbol, series.source.instrument.exchange)]
|
|
93
|
+
: []
|
|
94
|
+
)).filter(Boolean))];
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
let symbols = resolved.createOptions?.symbols?.length
|
|
75
98
|
? resolved.createOptions.symbols
|
|
76
99
|
: [resolved.createOptions?.symbol ?? normalizeTickerInput(null, cleanTickerInput(rawArg))].filter((symbol): symbol is string => !!symbol);
|
|
100
|
+
if (resolved.capability.id === "security-relationship" && symbols.length === 1) {
|
|
101
|
+
symbols = [...symbols, "SPY"];
|
|
102
|
+
}
|
|
77
103
|
return [...new Set(symbols.map(cleanTickerInput).filter(Boolean))];
|
|
78
104
|
}
|
|
105
|
+
|
|
106
|
+
export function clipPriceHistoryToRange(points: PricePoint[], range: TimeRange): PricePoint[] {
|
|
107
|
+
if (range === "ALL" || points.length === 0) return points;
|
|
108
|
+
const dated = points.flatMap((point) => {
|
|
109
|
+
const date = point.date instanceof Date ? point.date : new Date(point.date);
|
|
110
|
+
return Number.isFinite(date.getTime()) ? [{ point, date }] : [];
|
|
111
|
+
});
|
|
112
|
+
const end = dated.reduce<Date | null>((latest, entry) => (
|
|
113
|
+
!latest || entry.date.getTime() > latest.getTime() ? entry.date : latest
|
|
114
|
+
), null);
|
|
115
|
+
if (!end) return [];
|
|
116
|
+
const start = subtractTimeRange(end, range);
|
|
117
|
+
return dated
|
|
118
|
+
.filter(({ date }) => date.getTime() >= start.getTime() && date.getTime() <= end.getTime())
|
|
119
|
+
.map(({ point }) => point);
|
|
120
|
+
}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
GloomPlugin,
|
|
3
|
+
GloomPluginContext,
|
|
4
|
+
PaneDef,
|
|
5
|
+
PaneTemplateDef,
|
|
6
|
+
PluginPersistence,
|
|
7
|
+
} from "../../types/plugin";
|
|
8
|
+
import type { PersistedResourceValue } from "../../types/persistence";
|
|
2
9
|
import type { MarketContext } from "../types";
|
|
3
10
|
import type { PaneFunctionCatalog } from "./catalog";
|
|
4
11
|
|
|
@@ -6,9 +13,11 @@ export async function createPaneCatalog(context: MarketContext, plugins: GloomPl
|
|
|
6
13
|
const panes = new Map<string, PaneDef>();
|
|
7
14
|
const paneTemplates = new Map<string, PaneTemplateDef>();
|
|
8
15
|
const setupPlugins: GloomPlugin[] = [];
|
|
9
|
-
const fakePersistence =
|
|
16
|
+
const fakePersistence = createDiscoveryPluginPersistence();
|
|
10
17
|
// Collect setup-registered panes without booting the real plugin runtime or polling engines.
|
|
11
|
-
|
|
18
|
+
// Keep this object exhaustively typed so additions to GloomPluginContext fail at
|
|
19
|
+
// compile time instead of crashing `gloomberb catalog` at runtime.
|
|
20
|
+
const discoveryContext: GloomPluginContext = {
|
|
12
21
|
registerPane: (pane: PaneDef) => panes.set(pane.id, pane),
|
|
13
22
|
registerPaneTemplate: (template: PaneTemplateDef) => paneTemplates.set(template.id, template),
|
|
14
23
|
registerCommand: () => {},
|
|
@@ -19,6 +28,8 @@ export async function createPaneCatalog(context: MarketContext, plugins: GloomPl
|
|
|
19
28
|
registerShortcut: () => {},
|
|
20
29
|
registerTickerAction: () => {},
|
|
21
30
|
registerContextMenuProvider: () => {},
|
|
31
|
+
registerSyncContributor: () => () => {},
|
|
32
|
+
registerSyncTransport: () => () => {},
|
|
22
33
|
watchNewsQuery: () => () => {},
|
|
23
34
|
getData: () => null,
|
|
24
35
|
getTicker: () => null,
|
|
@@ -79,7 +90,7 @@ export async function createPaneCatalog(context: MarketContext, plugins: GloomPl
|
|
|
79
90
|
for (const template of plugin.paneTemplates ?? []) paneTemplates.set(template.id, template);
|
|
80
91
|
if (plugin.setup) {
|
|
81
92
|
setupPlugins.push(plugin);
|
|
82
|
-
await plugin.setup(
|
|
93
|
+
await plugin.setup(discoveryContext);
|
|
83
94
|
}
|
|
84
95
|
}
|
|
85
96
|
|
|
@@ -94,15 +105,31 @@ export async function createPaneCatalog(context: MarketContext, plugins: GloomPl
|
|
|
94
105
|
};
|
|
95
106
|
}
|
|
96
107
|
|
|
97
|
-
function
|
|
98
|
-
const resources = new Map<string, unknown
|
|
108
|
+
function createDiscoveryPluginPersistence(): PluginPersistence {
|
|
109
|
+
const resources = new Map<string, PersistedResourceValue<unknown>>();
|
|
99
110
|
return {
|
|
100
111
|
getState: () => null,
|
|
101
112
|
setState: () => {},
|
|
102
113
|
deleteState: () => {},
|
|
103
|
-
getResource: (kind: string, key: string) =>
|
|
104
|
-
|
|
105
|
-
|
|
114
|
+
getResource: <T = unknown>(kind: string, key: string) => (
|
|
115
|
+
resources.get(`${kind}:${key}`) as PersistedResourceValue<T> | undefined
|
|
116
|
+
) ?? null,
|
|
117
|
+
setResource: <T = unknown>(
|
|
118
|
+
kind: string,
|
|
119
|
+
key: string,
|
|
120
|
+
value: T,
|
|
121
|
+
options: Parameters<PluginPersistence["setResource"]>[3],
|
|
122
|
+
) => {
|
|
123
|
+
const fetchedAt = Date.now();
|
|
124
|
+
const entry: PersistedResourceValue<T> = {
|
|
125
|
+
value,
|
|
126
|
+
fetchedAt,
|
|
127
|
+
staleAt: fetchedAt + options.cachePolicy.staleMs,
|
|
128
|
+
expiresAt: fetchedAt + options.cachePolicy.expireMs,
|
|
129
|
+
sourceKey: options.sourceKey ?? "",
|
|
130
|
+
schemaVersion: options.schemaVersion ?? 1,
|
|
131
|
+
provenance: options.provenance ?? null,
|
|
132
|
+
};
|
|
106
133
|
resources.set(`${kind}:${key}`, entry);
|
|
107
134
|
return entry;
|
|
108
135
|
},
|
|
@@ -9,8 +9,27 @@ const {
|
|
|
9
9
|
optionPaneState,
|
|
10
10
|
filterPaneCatalogEntries,
|
|
11
11
|
renderPaneCatalogReport,
|
|
12
|
+
getPaneFunctionCapability,
|
|
13
|
+
normalizeCapabilityOptions,
|
|
14
|
+
capabilityPluginState,
|
|
12
15
|
} = paneFunctionTestInternals;
|
|
13
16
|
|
|
17
|
+
const dummyPane = {
|
|
18
|
+
id: "test-pane",
|
|
19
|
+
name: "Test",
|
|
20
|
+
component: () => null,
|
|
21
|
+
defaultPosition: "right" as const,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
function capabilityFor(templateId: string) {
|
|
25
|
+
return getPaneFunctionCapability({
|
|
26
|
+
id: templateId,
|
|
27
|
+
paneId: dummyPane.id,
|
|
28
|
+
label: "Test",
|
|
29
|
+
description: "Test",
|
|
30
|
+
}, dummyPane);
|
|
31
|
+
}
|
|
32
|
+
|
|
14
33
|
describe("pane function CLI args", () => {
|
|
15
34
|
test("parses target, argument, output, size, and pane options", () => {
|
|
16
35
|
const parsed = parsePaneFunctionArgs([
|
|
@@ -31,6 +50,7 @@ describe("pane function CLI args", () => {
|
|
|
31
50
|
expect(parsed.outputPath).toBe("/tmp/fa-nvda.png");
|
|
32
51
|
expect(parsed.width).toBe(900);
|
|
33
52
|
expect(parsed.height).toBe(700);
|
|
53
|
+
expect(parsed.requireBotSafe).toBe(false);
|
|
34
54
|
expect(parsed.options).toEqual({
|
|
35
55
|
period: "quarterly",
|
|
36
56
|
statement: "balance",
|
|
@@ -75,6 +95,12 @@ describe("pane function CLI args", () => {
|
|
|
75
95
|
expect(parsePaneCatalogArgs(["chart", "price", "--limit", "3"])).toEqual({
|
|
76
96
|
query: "chart price",
|
|
77
97
|
limit: 3,
|
|
98
|
+
botSafeOnly: false,
|
|
99
|
+
});
|
|
100
|
+
expect(parsePaneCatalogArgs(["cash", "flow", "--bot-safe"])).toEqual({
|
|
101
|
+
query: "cash flow",
|
|
102
|
+
limit: 25,
|
|
103
|
+
botSafeOnly: true,
|
|
78
104
|
});
|
|
79
105
|
});
|
|
80
106
|
|
|
@@ -92,6 +118,7 @@ describe("pane function CLI args", () => {
|
|
|
92
118
|
argPlaceholder: "ticker",
|
|
93
119
|
keywords: ["gp", "graph", "price", "chart"],
|
|
94
120
|
defaultSettings: { lockedTabId: "chart", chartRangePreset: "5Y" },
|
|
121
|
+
capability: capabilityFor("graph-price-pane"),
|
|
95
122
|
},
|
|
96
123
|
{
|
|
97
124
|
token: "FA",
|
|
@@ -105,10 +132,86 @@ describe("pane function CLI args", () => {
|
|
|
105
132
|
argPlaceholder: "ticker",
|
|
106
133
|
keywords: ["fa", "financial", "analysis", "statements"],
|
|
107
134
|
defaultSettings: { lockedTabId: "financials" },
|
|
135
|
+
capability: capabilityFor("financial-analysis-pane"),
|
|
108
136
|
},
|
|
109
137
|
], "price chart");
|
|
110
138
|
|
|
111
139
|
expect(matches.map((entry) => entry.token)).toEqual(["GP"]);
|
|
112
|
-
expect(renderPaneCatalogReport(matches, { query: "price chart", limit: 10 })).toContain("gloomberb shot GP <ticker>");
|
|
140
|
+
expect(renderPaneCatalogReport(matches, { query: "price chart", limit: 10, botSafeOnly: false })).toContain("gloomberb shot GP <ticker>");
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("finds the semantic financial comparison capability from natural wording", () => {
|
|
144
|
+
const matches = filterPaneCatalogEntries([
|
|
145
|
+
{
|
|
146
|
+
token: "GF",
|
|
147
|
+
label: "Fundamental Graph",
|
|
148
|
+
description: "Graph statement metrics for one or more tickers.",
|
|
149
|
+
paneId: "fundamental-graph",
|
|
150
|
+
paneName: "Fundamental Graph",
|
|
151
|
+
templateId: "fundamental-graph-pane",
|
|
152
|
+
shortcut: "GF",
|
|
153
|
+
argKind: "ticker-list",
|
|
154
|
+
argPlaceholder: "tickers",
|
|
155
|
+
keywords: ["fundamental", "graph", "financials", "statements"],
|
|
156
|
+
defaultSettings: {},
|
|
157
|
+
capability: capabilityFor("fundamental-graph-pane"),
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
token: "CMP",
|
|
161
|
+
label: "Comparison Chart",
|
|
162
|
+
description: "Compare stock prices.",
|
|
163
|
+
paneId: "comparison-chart",
|
|
164
|
+
paneName: "Compare",
|
|
165
|
+
templateId: "comparison-chart-pane",
|
|
166
|
+
shortcut: "CMP",
|
|
167
|
+
argKind: "ticker-list",
|
|
168
|
+
argPlaceholder: "tickers",
|
|
169
|
+
keywords: ["compare", "price"],
|
|
170
|
+
defaultSettings: {},
|
|
171
|
+
capability: capabilityFor("comparison-chart-pane"),
|
|
172
|
+
},
|
|
173
|
+
], "cash flow comparison");
|
|
174
|
+
|
|
175
|
+
expect(matches.map(({ token }) => token)).toEqual(["GF", "CMP"]);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("normalizes GF options without creating retired plugin state", () => {
|
|
179
|
+
const capability = capabilityFor("fundamental-graph-pane");
|
|
180
|
+
const options = normalizeCapabilityOptions(capability, {
|
|
181
|
+
metric: "operating cash flow",
|
|
182
|
+
period: "yearly",
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
expect(options).toEqual({
|
|
186
|
+
metric: "operatingCashFlow",
|
|
187
|
+
period: "annual",
|
|
188
|
+
});
|
|
189
|
+
expect(capabilityPluginState(capability, options)).toEqual({});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test("exposes custom G as a bot-safe mixed-series capability", () => {
|
|
193
|
+
const capability = capabilityFor("chart-composer-pane");
|
|
194
|
+
|
|
195
|
+
expect(capability).toMatchObject({
|
|
196
|
+
id: "chart-composer",
|
|
197
|
+
botSafe: true,
|
|
198
|
+
tickerCardinality: "none",
|
|
199
|
+
reportReadiness: "ready",
|
|
200
|
+
screenshotReadiness: "ready",
|
|
201
|
+
});
|
|
202
|
+
expect(normalizeCapabilityOptions(capability, {
|
|
203
|
+
range: "five years",
|
|
204
|
+
resolution: "1d",
|
|
205
|
+
})).toEqual({
|
|
206
|
+
rangePreset: "5Y",
|
|
207
|
+
chartResolution: "1d",
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test("rejects financial statement options on a price comparison", () => {
|
|
212
|
+
const capability = capabilityFor("comparison-chart-pane");
|
|
213
|
+
expect(() => normalizeCapabilityOptions(capability, {
|
|
214
|
+
tab: "cashflow",
|
|
215
|
+
})).toThrow("price-comparison does not support --tab");
|
|
113
216
|
});
|
|
114
217
|
});
|
|
@@ -21,6 +21,11 @@ import { defaultScreenshotPath, renderDesktopShot } from "./screenshot";
|
|
|
21
21
|
import {
|
|
22
22
|
buildPaneCatalogEntries,
|
|
23
23
|
} from "./catalog";
|
|
24
|
+
import {
|
|
25
|
+
capabilityPluginState,
|
|
26
|
+
getPaneFunctionCapability,
|
|
27
|
+
normalizeCapabilityOptions,
|
|
28
|
+
} from "./capabilities";
|
|
24
29
|
|
|
25
30
|
async function withPaneRuntime<T>(
|
|
26
31
|
ctx: CliCommandContext,
|
|
@@ -47,8 +52,26 @@ async function withPaneRuntime<T>(
|
|
|
47
52
|
export async function runPaneFunction(args: string[], ctx: CliCommandContext) {
|
|
48
53
|
await runPaneCliCommand(ctx, async () => {
|
|
49
54
|
await withPaneRuntime(ctx, args, async ({ parsed, context, resolved }) => {
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
if (parsed.requireBotSafe && (
|
|
56
|
+
!resolved.capability.botSafe || resolved.capability.reportReadiness !== "ready"
|
|
57
|
+
)) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
`${resolved.token} is not a verified bot-safe report capability. `
|
|
60
|
+
+ `Use "gloomberb catalog ${resolved.token}" to inspect readiness.`,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
const report = await buildFunctionReport(resolved, context, parsed.arg);
|
|
64
|
+
if (parsed.requireBotSafe && (report.data.empty || !report.data.complete)) {
|
|
65
|
+
const unavailable = report.data.unavailableSymbols.length > 0
|
|
66
|
+
? ` Missing data for ${report.data.unavailableSymbols.join(", ")}.`
|
|
67
|
+
: "";
|
|
68
|
+
throw new Error(
|
|
69
|
+
`${resolved.token} did not produce a complete bot-safe report.${unavailable}`,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
ctx.printResult({ data: report.data }, {
|
|
73
|
+
text: () => report.text,
|
|
74
|
+
});
|
|
52
75
|
});
|
|
53
76
|
});
|
|
54
77
|
}
|
|
@@ -56,10 +79,18 @@ export async function runPaneFunction(args: string[], ctx: CliCommandContext) {
|
|
|
56
79
|
export async function runPaneScreenshot(args: string[], ctx: CliCommandContext) {
|
|
57
80
|
await runPaneCliCommand(ctx, async () => {
|
|
58
81
|
await withPaneRuntime(ctx, args, async ({ parsed, context, resolved }) => {
|
|
82
|
+
if (parsed.requireBotSafe && (
|
|
83
|
+
!resolved.capability.botSafe || resolved.capability.screenshotReadiness !== "ready"
|
|
84
|
+
)) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`${resolved.token} is not a verified bot-safe screenshot capability. `
|
|
87
|
+
+ `Use "gloomberb catalog ${resolved.token}" to inspect readiness.`,
|
|
88
|
+
);
|
|
89
|
+
}
|
|
59
90
|
const outputPath = parsed.outputPath
|
|
60
91
|
? resolve(process.cwd(), ensurePngExtension(parsed.outputPath))
|
|
61
92
|
: defaultScreenshotPath(resolved, parsed.arg);
|
|
62
|
-
await renderDesktopShot({
|
|
93
|
+
const result = await renderDesktopShot({
|
|
63
94
|
resolved,
|
|
64
95
|
context,
|
|
65
96
|
rawArg: parsed.arg,
|
|
@@ -68,7 +99,29 @@ export async function runPaneScreenshot(args: string[], ctx: CliCommandContext)
|
|
|
68
99
|
height: parsed.height,
|
|
69
100
|
options: parsed.options,
|
|
70
101
|
});
|
|
71
|
-
|
|
102
|
+
if (parsed.requireBotSafe && !result.usable) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`${resolved.token} did not produce a usable bot-safe screenshot: `
|
|
105
|
+
+ `${result.empty ? "empty render" : ""}${result.empty && !result.complete ? ", " : ""}`
|
|
106
|
+
+ `${!result.complete ? `missing data for ${result.unavailableSymbols.join(", ")}` : ""}`
|
|
107
|
+
+ `${result.semanticMismatch ? `${(result.empty || !result.complete) ? ", " : ""}rendered content did not match the requested capability` : ""}`,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
ctx.printResult({ data: result }, {
|
|
111
|
+
text: (data) => [
|
|
112
|
+
`Saved screenshot to ${data.outputPath}`,
|
|
113
|
+
`Result: ${data.rowCount} semantic rows; empty=${data.empty}; complete=${data.complete}; mismatch=${data.semanticMismatch}; usable=${data.usable}`,
|
|
114
|
+
...(data.unavailableSymbols.length > 0
|
|
115
|
+
? [`Unavailable symbols: ${data.unavailableSymbols.join(", ")}`]
|
|
116
|
+
: []),
|
|
117
|
+
...(data.render.emptyStateMarkers.length > 0
|
|
118
|
+
? [`Empty markers: ${data.render.emptyStateMarkers.join(", ")}`]
|
|
119
|
+
: []),
|
|
120
|
+
...(data.render.missingExpectedText.length > 0
|
|
121
|
+
? [`Missing expected text: ${data.render.missingExpectedText.join(", ")}`]
|
|
122
|
+
: []),
|
|
123
|
+
].join("\n"),
|
|
124
|
+
});
|
|
72
125
|
});
|
|
73
126
|
});
|
|
74
127
|
}
|
|
@@ -84,7 +137,10 @@ export async function runPaneCatalog(args: string[], ctx: CliCommandContext) {
|
|
|
84
137
|
const registry = await createPaneCatalog(context, ctx.plugins);
|
|
85
138
|
try {
|
|
86
139
|
const entries = await buildPaneCatalogEntries(registry, context);
|
|
87
|
-
const
|
|
140
|
+
const botSafeEntries = effectiveParsed.botSafeOnly
|
|
141
|
+
? entries.filter((entry) => entry.capability.botSafe)
|
|
142
|
+
: entries;
|
|
143
|
+
const filtered = filterPaneCatalogEntries(botSafeEntries, parsed.query);
|
|
88
144
|
if (ctx.cliOptions.format === "text") {
|
|
89
145
|
console.log(renderPaneCatalogReport(filtered, effectiveParsed));
|
|
90
146
|
} else {
|
|
@@ -118,4 +174,7 @@ export const paneFunctionTestInternals = {
|
|
|
118
174
|
optionPaneState,
|
|
119
175
|
filterPaneCatalogEntries,
|
|
120
176
|
renderPaneCatalogReport,
|
|
177
|
+
getPaneFunctionCapability,
|
|
178
|
+
normalizeCapabilityOptions,
|
|
179
|
+
capabilityPluginState,
|
|
121
180
|
};
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
resolveFinancialPeriodOption,
|
|
7
7
|
} from "../../plugins/builtin/ticker-detail/financials/model";
|
|
8
8
|
import type { PaneRuntimeState } from "../../core/state/app/state";
|
|
9
|
+
import type { NormalizedPaneFunctionOptions } from "./capabilities";
|
|
9
10
|
|
|
10
11
|
const DEFAULT_SHOT_WIDTH = 1280;
|
|
11
12
|
const DEFAULT_SHOT_HEIGHT = 720;
|
|
@@ -22,11 +23,13 @@ export interface ParsedPaneFunctionArgs {
|
|
|
22
23
|
outputPath: string | null;
|
|
23
24
|
width: number;
|
|
24
25
|
height: number;
|
|
26
|
+
requireBotSafe: boolean;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
export interface ParsedPaneCatalogArgs {
|
|
28
30
|
query: string;
|
|
29
31
|
limit: number;
|
|
32
|
+
botSafeOnly: boolean;
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
function normalizeOptionKey(value: string): string {
|
|
@@ -59,6 +62,7 @@ export function parsePaneFunctionArgs(args: string[]): ParsedPaneFunctionArgs {
|
|
|
59
62
|
let outputPath: string | null = null;
|
|
60
63
|
let width = DEFAULT_SHOT_WIDTH;
|
|
61
64
|
let height = DEFAULT_SHOT_HEIGHT;
|
|
65
|
+
let requireBotSafe = false;
|
|
62
66
|
|
|
63
67
|
for (let index = 0; index < args.length; index += 1) {
|
|
64
68
|
const token = args[index]!;
|
|
@@ -80,7 +84,9 @@ export function parsePaneFunctionArgs(args: string[]): ParsedPaneFunctionArgs {
|
|
|
80
84
|
const nextValue = next && !next.startsWith("--") ? args[++index] : true;
|
|
81
85
|
const value: string | true = inlineValue ?? nextValue ?? true;
|
|
82
86
|
const normalizedKey = normalizeOptionKey(key);
|
|
83
|
-
if (normalizedKey === "
|
|
87
|
+
if (normalizedKey === "requireBotSafe" || normalizedKey === "botSafe") {
|
|
88
|
+
requireBotSafe = value === true || String(value).toLowerCase() === "true";
|
|
89
|
+
} else if (normalizedKey === "output" || normalizedKey === "out" || normalizedKey === "o") {
|
|
84
90
|
outputPath = value === true ? null : value;
|
|
85
91
|
} else if (normalizedKey === "width" && value !== true) {
|
|
86
92
|
const parsedWidth = Number(value);
|
|
@@ -101,12 +107,13 @@ export function parsePaneFunctionArgs(args: string[]): ParsedPaneFunctionArgs {
|
|
|
101
107
|
|
|
102
108
|
const target = positionals[0]?.trim() ?? "";
|
|
103
109
|
const arg = positionals.slice(1).join(" ").trim();
|
|
104
|
-
return { target, arg, options, outputPath, width, height };
|
|
110
|
+
return { target, arg, options, outputPath, width, height, requireBotSafe };
|
|
105
111
|
}
|
|
106
112
|
|
|
107
113
|
export function parsePaneCatalogArgs(args: string[]): ParsedPaneCatalogArgs {
|
|
108
114
|
const queryParts: string[] = [];
|
|
109
115
|
let limit = DEFAULT_CATALOG_LIMIT;
|
|
116
|
+
let botSafeOnly = false;
|
|
110
117
|
|
|
111
118
|
for (let index = 0; index < args.length; index += 1) {
|
|
112
119
|
const token = args[index]!;
|
|
@@ -120,6 +127,11 @@ export function parsePaneCatalogArgs(args: string[]): ParsedPaneCatalogArgs {
|
|
|
120
127
|
continue;
|
|
121
128
|
}
|
|
122
129
|
|
|
130
|
+
if (token === "--bot-safe" || token === "--botsafe") {
|
|
131
|
+
botSafeOnly = true;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
|
|
123
135
|
if (token === "--limit") {
|
|
124
136
|
const parsed = Number(args[++index]);
|
|
125
137
|
if (Number.isFinite(parsed) && parsed > 0) {
|
|
@@ -142,12 +154,15 @@ export function parsePaneCatalogArgs(args: string[]): ParsedPaneCatalogArgs {
|
|
|
142
154
|
return {
|
|
143
155
|
query: queryParts.join(" ").trim(),
|
|
144
156
|
limit,
|
|
157
|
+
botSafeOnly,
|
|
145
158
|
};
|
|
146
159
|
}
|
|
147
160
|
|
|
148
|
-
|
|
161
|
+
type PaneOptionValues = Record<string, string | number | boolean>;
|
|
162
|
+
|
|
163
|
+
export function optionString(options: PaneOptionValues, key: string): string | undefined {
|
|
149
164
|
const value = options[normalizeOptionKey(key)];
|
|
150
|
-
return value === true ? undefined : value;
|
|
165
|
+
return value === true || value === undefined ? undefined : String(value);
|
|
151
166
|
}
|
|
152
167
|
|
|
153
168
|
const RESERVED_OPTION_KEYS = new Set(["output", "out", "o", "width", "height", "arguments", "state"]);
|
|
@@ -211,7 +226,7 @@ function normalizeFinancialSubTabOption(value: string | undefined): string | und
|
|
|
211
226
|
))?.key;
|
|
212
227
|
}
|
|
213
228
|
|
|
214
|
-
export function optionPaneState(options:
|
|
229
|
+
export function optionPaneState(options: PaneOptionValues | NormalizedPaneFunctionOptions): PaneRuntimeState {
|
|
215
230
|
const state: PaneRuntimeState = {};
|
|
216
231
|
const rawState = optionString(options, "state");
|
|
217
232
|
if (rawState) {
|
|
@@ -222,7 +237,7 @@ export function optionPaneState(options: Record<string, string | true>): PaneRun
|
|
|
222
237
|
|
|
223
238
|
for (const [key, value] of Object.entries(options)) {
|
|
224
239
|
if (!key.startsWith("state.") || value === true) continue;
|
|
225
|
-
state[key.slice("state.".length)] = coerceSettingValue(value);
|
|
240
|
+
state[key.slice("state.".length)] = typeof value === "string" ? coerceSettingValue(value) : value;
|
|
226
241
|
}
|
|
227
242
|
|
|
228
243
|
const activeTab = optionString(options, "activeTabId")
|