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,7 +1,8 @@
|
|
|
1
1
|
import { useCallback, useRef, useState } from "react";
|
|
2
|
-
import type { TextareaRenderable } from "../../../../ui";
|
|
2
|
+
import type { InputRenderable, TextareaRenderable } from "../../../../ui";
|
|
3
3
|
import type { AiProvider } from "../providers";
|
|
4
4
|
import { resolveDefaultAiProviderId } from "../providers";
|
|
5
|
+
import { modelIdAfterAiProviderChange, normalizeAiModelId } from "../runner-selection";
|
|
5
6
|
import {
|
|
6
7
|
createScreenerTab,
|
|
7
8
|
generateScreenerEditorKey,
|
|
@@ -10,6 +11,8 @@ import {
|
|
|
10
11
|
} from "./model";
|
|
11
12
|
|
|
12
13
|
export function useAiScreenerEditorRuntime({
|
|
14
|
+
defaultModelId,
|
|
15
|
+
defaultProviderId,
|
|
13
16
|
providers,
|
|
14
17
|
queueInitialRun,
|
|
15
18
|
selectableProviders,
|
|
@@ -18,6 +21,8 @@ export function useAiScreenerEditorRuntime({
|
|
|
18
21
|
updateTabs,
|
|
19
22
|
upsertTab,
|
|
20
23
|
}: {
|
|
24
|
+
defaultModelId: string | null;
|
|
25
|
+
defaultProviderId: string;
|
|
21
26
|
providers: AiProvider[];
|
|
22
27
|
queueInitialRun: (tabId: string) => void;
|
|
23
28
|
selectableProviders: AiProvider[];
|
|
@@ -27,25 +32,43 @@ export function useAiScreenerEditorRuntime({
|
|
|
27
32
|
upsertTab: (tabId: string, updater: (tab: AiScreenerTab) => AiScreenerTab) => void;
|
|
28
33
|
}) {
|
|
29
34
|
const [editorState, setEditorState] = useState<ScreenerEditorState | null>(null);
|
|
35
|
+
const [editorFocusTarget, setEditorFocusTarget] = useState<"prompt" | "model">("prompt");
|
|
36
|
+
const editorModelInputRef = useRef<InputRenderable | null>(null);
|
|
30
37
|
const editorTextareaRef = useRef<TextareaRenderable | null>(null);
|
|
31
38
|
|
|
39
|
+
const focusEditorPrompt = useCallback(() => {
|
|
40
|
+
setEditorFocusTarget("prompt");
|
|
41
|
+
queueMicrotask(() => editorTextareaRef.current?.focus?.());
|
|
42
|
+
}, []);
|
|
43
|
+
|
|
44
|
+
const focusEditorModel = useCallback(() => {
|
|
45
|
+
setEditorFocusTarget("model");
|
|
46
|
+
queueMicrotask(() => editorModelInputRef.current?.focus?.());
|
|
47
|
+
}, []);
|
|
48
|
+
|
|
32
49
|
const openCreateEditor = useCallback(() => {
|
|
50
|
+
setEditorFocusTarget("prompt");
|
|
33
51
|
setEditorState({
|
|
34
52
|
mode: "create",
|
|
35
53
|
tabId: null,
|
|
36
|
-
providerId:
|
|
54
|
+
providerId: selectableProviders.some((provider) => provider.id === defaultProviderId)
|
|
55
|
+
? defaultProviderId
|
|
56
|
+
: resolveDefaultAiProviderId(providers),
|
|
57
|
+
modelId: defaultModelId ?? "",
|
|
37
58
|
prompt: "",
|
|
38
59
|
key: generateScreenerEditorKey(),
|
|
39
60
|
error: null,
|
|
40
61
|
});
|
|
41
|
-
}, [providers]);
|
|
62
|
+
}, [defaultModelId, defaultProviderId, providers, selectableProviders]);
|
|
42
63
|
|
|
43
64
|
const openEditEditor = useCallback((tab: AiScreenerTab | null) => {
|
|
44
65
|
if (!tab) return;
|
|
66
|
+
setEditorFocusTarget("prompt");
|
|
45
67
|
setEditorState({
|
|
46
68
|
mode: "edit",
|
|
47
69
|
tabId: tab.id,
|
|
48
70
|
providerId: tab.providerId,
|
|
71
|
+
modelId: tab.modelId ?? "",
|
|
49
72
|
prompt: tab.prompt,
|
|
50
73
|
key: generateScreenerEditorKey(),
|
|
51
74
|
error: null,
|
|
@@ -53,10 +76,24 @@ export function useAiScreenerEditorRuntime({
|
|
|
53
76
|
}, []);
|
|
54
77
|
|
|
55
78
|
const closeEditor = useCallback(() => {
|
|
79
|
+
editorModelInputRef.current = null;
|
|
56
80
|
editorTextareaRef.current = null;
|
|
81
|
+
setEditorFocusTarget("prompt");
|
|
57
82
|
setEditorState(null);
|
|
58
83
|
}, []);
|
|
59
84
|
|
|
85
|
+
const selectEditorProvider = useCallback((providerId: string) => {
|
|
86
|
+
setEditorState((current) => {
|
|
87
|
+
if (!current || current.providerId === providerId) return current;
|
|
88
|
+
return {
|
|
89
|
+
...current,
|
|
90
|
+
providerId,
|
|
91
|
+
modelId: modelIdAfterAiProviderChange(providerId, defaultProviderId, defaultModelId),
|
|
92
|
+
error: null,
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
}, [defaultModelId, defaultProviderId]);
|
|
96
|
+
|
|
60
97
|
const cycleEditorProvider = useCallback((direction: -1 | 1) => {
|
|
61
98
|
setEditorState((current) => {
|
|
62
99
|
if (!current || selectableProviders.length === 0) return current;
|
|
@@ -65,10 +102,15 @@ export function useAiScreenerEditorRuntime({
|
|
|
65
102
|
return {
|
|
66
103
|
...current,
|
|
67
104
|
providerId: selectableProviders[nextIndex]!.id,
|
|
105
|
+
modelId: modelIdAfterAiProviderChange(
|
|
106
|
+
selectableProviders[nextIndex]!.id,
|
|
107
|
+
defaultProviderId,
|
|
108
|
+
defaultModelId,
|
|
109
|
+
),
|
|
68
110
|
error: null,
|
|
69
111
|
};
|
|
70
112
|
});
|
|
71
|
-
}, [selectableProviders]);
|
|
113
|
+
}, [defaultModelId, defaultProviderId, selectableProviders]);
|
|
72
114
|
|
|
73
115
|
const saveEditor = useCallback(() => {
|
|
74
116
|
if (!editorState) return;
|
|
@@ -79,7 +121,7 @@ export function useAiScreenerEditorRuntime({
|
|
|
79
121
|
}
|
|
80
122
|
|
|
81
123
|
if (editorState.mode === "create") {
|
|
82
|
-
const tab = createScreenerTab(prompt, editorState.providerId);
|
|
124
|
+
const tab = createScreenerTab(prompt, editorState.providerId, normalizeAiModelId(editorState.modelId));
|
|
83
125
|
queueInitialRun(tab.id);
|
|
84
126
|
updateTabs((current) => [...current, tab]);
|
|
85
127
|
setActiveTabId(tab.id);
|
|
@@ -89,22 +131,30 @@ export function useAiScreenerEditorRuntime({
|
|
|
89
131
|
...current,
|
|
90
132
|
prompt,
|
|
91
133
|
providerId: editorState.providerId,
|
|
134
|
+
modelId: normalizeAiModelId(editorState.modelId),
|
|
92
135
|
lastError: null,
|
|
93
136
|
}));
|
|
94
137
|
}
|
|
95
138
|
|
|
96
139
|
editorTextareaRef.current = null;
|
|
140
|
+
editorModelInputRef.current = null;
|
|
141
|
+
setEditorFocusTarget("prompt");
|
|
97
142
|
setEditorState(null);
|
|
98
143
|
}, [editorState, queueInitialRun, setActiveTabId, setCursorSymbol, updateTabs, upsertTab]);
|
|
99
144
|
|
|
100
145
|
return {
|
|
101
146
|
closeEditor,
|
|
102
147
|
cycleEditorProvider,
|
|
148
|
+
editorFocusTarget,
|
|
149
|
+
editorModelInputRef,
|
|
103
150
|
editorState,
|
|
104
151
|
editorTextareaRef,
|
|
152
|
+
focusEditorModel,
|
|
153
|
+
focusEditorPrompt,
|
|
105
154
|
openCreateEditor,
|
|
106
155
|
openEditEditor,
|
|
107
156
|
saveEditor,
|
|
157
|
+
selectEditorProvider,
|
|
108
158
|
setEditorState,
|
|
109
159
|
};
|
|
110
160
|
}
|
|
@@ -1,21 +1,28 @@
|
|
|
1
1
|
import type { RefObject } from "react";
|
|
2
2
|
import { useEffect } from "react";
|
|
3
|
-
import { Box, Text, Textarea, type TextareaRenderable } from "../../../../ui";
|
|
4
|
-
import { Button, SegmentedControl } from "../../../../components";
|
|
3
|
+
import { Box, Text, Textarea, type InputRenderable, type TextareaRenderable } from "../../../../ui";
|
|
5
4
|
import { colors } from "../../../../theme/colors";
|
|
6
|
-
import
|
|
5
|
+
import { t } from "../../../../i18n";
|
|
6
|
+
import {
|
|
7
|
+
getAiProviderUnavailableReason,
|
|
8
|
+
type AiProvider,
|
|
9
|
+
} from "../providers";
|
|
7
10
|
import type { ScreenerEditorState } from "./model";
|
|
11
|
+
import { AiRunnerSelector } from "../runner-selector";
|
|
12
|
+
import { isAiProviderReady } from "../runner-selection";
|
|
8
13
|
|
|
9
14
|
function ScreenerPromptEditor({
|
|
10
15
|
editorKey,
|
|
11
16
|
initialValue,
|
|
12
17
|
focused,
|
|
13
18
|
textareaRef,
|
|
19
|
+
onFocusRequest,
|
|
14
20
|
}: {
|
|
15
21
|
editorKey: string;
|
|
16
22
|
initialValue: string;
|
|
17
23
|
focused: boolean;
|
|
18
24
|
textareaRef: RefObject<TextareaRenderable | null>;
|
|
25
|
+
onFocusRequest: () => void;
|
|
19
26
|
}) {
|
|
20
27
|
useEffect(() => {
|
|
21
28
|
if (focused) {
|
|
@@ -26,16 +33,17 @@ function ScreenerPromptEditor({
|
|
|
26
33
|
return (
|
|
27
34
|
<Box
|
|
28
35
|
flexGrow={1}
|
|
29
|
-
minHeight={
|
|
36
|
+
minHeight={3}
|
|
30
37
|
border
|
|
31
38
|
borderColor={colors.border}
|
|
32
39
|
backgroundColor={colors.panel}
|
|
40
|
+
onMouseDown={onFocusRequest}
|
|
33
41
|
>
|
|
34
42
|
<Textarea
|
|
35
43
|
key={editorKey}
|
|
36
44
|
ref={textareaRef}
|
|
37
45
|
initialValue={initialValue}
|
|
38
|
-
placeholder="Examples: humanoid robot suppliers, defense software compounders, EM payment rails, obesity-drug picks-and-shovels..."
|
|
46
|
+
placeholder={t("Examples: humanoid robot suppliers, defense software compounders, EM payment rails, obesity-drug picks-and-shovels...")}
|
|
39
47
|
focused={focused}
|
|
40
48
|
textColor={colors.text}
|
|
41
49
|
placeholderColor={colors.textDim}
|
|
@@ -48,48 +56,49 @@ function ScreenerPromptEditor({
|
|
|
48
56
|
}
|
|
49
57
|
|
|
50
58
|
export function AiScreenerEditorView({
|
|
51
|
-
contentHeight,
|
|
52
59
|
editorProvider,
|
|
60
|
+
editorFocusTarget,
|
|
53
61
|
editorState,
|
|
54
62
|
focused,
|
|
63
|
+
modelInputRef,
|
|
55
64
|
selectableProviders,
|
|
56
65
|
textareaRef,
|
|
57
|
-
|
|
58
|
-
onCancel,
|
|
66
|
+
onModelFocusRequest,
|
|
59
67
|
onProviderChange,
|
|
60
|
-
|
|
68
|
+
onModelChange,
|
|
69
|
+
onPromptFocusRequest,
|
|
61
70
|
}: {
|
|
62
|
-
contentHeight: number;
|
|
63
71
|
editorProvider: AiProvider | null;
|
|
72
|
+
editorFocusTarget: "prompt" | "model";
|
|
64
73
|
editorState: ScreenerEditorState;
|
|
65
74
|
focused: boolean;
|
|
75
|
+
modelInputRef: RefObject<InputRenderable | null>;
|
|
66
76
|
selectableProviders: AiProvider[];
|
|
67
77
|
textareaRef: RefObject<TextareaRenderable | null>;
|
|
68
|
-
|
|
69
|
-
onCancel: () => void;
|
|
78
|
+
onModelFocusRequest: () => void;
|
|
70
79
|
onProviderChange: (providerId: string) => void;
|
|
71
|
-
|
|
80
|
+
onModelChange: (modelId: string) => void;
|
|
81
|
+
onPromptFocusRequest: () => void;
|
|
72
82
|
}) {
|
|
73
83
|
return (
|
|
74
84
|
<>
|
|
75
|
-
<Box flexDirection="row" height={1} gap={1}>
|
|
76
|
-
<Button label="Save" variant="primary" onPress={onSave} />
|
|
77
|
-
<Button label="Cancel" variant="ghost" onPress={onCancel} />
|
|
78
|
-
</Box>
|
|
79
|
-
|
|
80
85
|
<Box flexDirection="column" paddingX={1} paddingTop={1} gap={1}>
|
|
81
86
|
<Text fg={colors.textDim}>
|
|
82
87
|
{editorState.mode === "create"
|
|
83
|
-
? "Describe the companies or setups you want this screener to discover."
|
|
84
|
-
: "Update the screener prompt or provider. Saving does not rerun it automatically."}
|
|
88
|
+
? t("Describe the companies or setups you want this screener to discover.")
|
|
89
|
+
: t("Update the screener prompt or provider. Saving does not rerun it automatically.")}
|
|
85
90
|
</Text>
|
|
86
|
-
<
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
91
|
+
<AiRunnerSelector
|
|
92
|
+
providers={selectableProviders}
|
|
93
|
+
providerId={editorState.providerId}
|
|
94
|
+
modelId={editorState.modelId}
|
|
95
|
+
modelInputRef={modelInputRef}
|
|
96
|
+
modelFocused={focused && editorFocusTarget === "model"}
|
|
97
|
+
onProviderChange={onProviderChange}
|
|
98
|
+
onModelChange={onModelChange}
|
|
99
|
+
onModelFocusRequest={onModelFocusRequest}
|
|
100
|
+
onModelBlur={onPromptFocusRequest}
|
|
101
|
+
modelHint="Ctrl+O opens the Pi model catalog."
|
|
93
102
|
/>
|
|
94
103
|
{editorState.error ? (
|
|
95
104
|
<Text fg={colors.negative}>{editorState.error}</Text>
|
|
@@ -100,24 +109,21 @@ export function AiScreenerEditorView({
|
|
|
100
109
|
)}
|
|
101
110
|
</Box>
|
|
102
111
|
|
|
103
|
-
<Box flexGrow={1} minHeight={
|
|
112
|
+
<Box flexGrow={1} minHeight={4} padding={1}>
|
|
104
113
|
<ScreenerPromptEditor
|
|
105
114
|
editorKey={editorState.key}
|
|
106
115
|
initialValue={editorState.prompt}
|
|
107
|
-
focused={focused}
|
|
116
|
+
focused={focused && editorFocusTarget === "prompt"}
|
|
108
117
|
textareaRef={textareaRef}
|
|
118
|
+
onFocusRequest={onPromptFocusRequest}
|
|
109
119
|
/>
|
|
110
120
|
</Box>
|
|
111
121
|
|
|
112
|
-
<Box height={1} paddingX={1}>
|
|
113
|
-
<Text fg={colors.textDim}>{"\u2500".repeat(Math.max(width - 2, 0))}</Text>
|
|
114
|
-
</Box>
|
|
115
|
-
|
|
116
122
|
<Box flexDirection="column" paddingX={1}>
|
|
117
123
|
<Text fg={colors.textDim}>
|
|
118
|
-
{editorProvider
|
|
119
|
-
? `${editorProvider
|
|
120
|
-
: "Click a provider
|
|
124
|
+
{editorProvider && !isAiProviderReady(editorProvider)
|
|
125
|
+
? `${getAiProviderUnavailableReason(editorProvider)} Save and switch later.`
|
|
126
|
+
: "Click a provider to switch. Save to keep the draft."}
|
|
121
127
|
</Text>
|
|
122
128
|
</Box>
|
|
123
129
|
</>
|
|
@@ -1,93 +1,108 @@
|
|
|
1
1
|
import { usePaneFooter } from "../../../../components";
|
|
2
|
-
import {
|
|
3
|
-
import { getAiProvider, type AiProvider } from "../providers";
|
|
2
|
+
import { t } from "../../../../i18n";
|
|
4
3
|
import type { AiScreenerTab, RunState, ScreenerEditorState } from "./model";
|
|
5
4
|
|
|
6
5
|
interface UseAiScreenerFooterOptions {
|
|
7
6
|
activeTab: AiScreenerTab | null;
|
|
8
|
-
addTab: () => void;
|
|
9
|
-
cycleEditorProvider: (direction: -1 | 1) => void;
|
|
10
|
-
editActiveTab: () => void;
|
|
11
|
-
editorProvider: AiProvider | null;
|
|
12
7
|
editorState: ScreenerEditorState | null;
|
|
13
|
-
forceRefreshActiveTab: () => void;
|
|
14
|
-
forceRunArmed: boolean;
|
|
15
8
|
isRunningActiveTab: boolean;
|
|
16
|
-
providers: AiProvider[];
|
|
17
|
-
refreshActiveTab: () => void;
|
|
18
|
-
removeTab: (tabId: string) => void;
|
|
19
9
|
runState: RunState | null;
|
|
20
|
-
|
|
21
|
-
|
|
10
|
+
onAddTab: () => void;
|
|
11
|
+
onCancelRun: () => void;
|
|
12
|
+
onCloseEditor: () => void;
|
|
13
|
+
onEdit: () => void;
|
|
14
|
+
onRefresh: () => void;
|
|
15
|
+
onSaveEditor: () => void;
|
|
22
16
|
}
|
|
23
17
|
|
|
24
18
|
export function useAiScreenerFooter({
|
|
25
19
|
activeTab,
|
|
26
|
-
addTab,
|
|
27
|
-
cycleEditorProvider,
|
|
28
|
-
editActiveTab,
|
|
29
|
-
editorProvider,
|
|
30
20
|
editorState,
|
|
31
|
-
forceRefreshActiveTab,
|
|
32
|
-
forceRunArmed,
|
|
33
21
|
isRunningActiveTab,
|
|
34
|
-
providers,
|
|
35
|
-
refreshActiveTab,
|
|
36
|
-
removeTab,
|
|
37
22
|
runState,
|
|
38
|
-
|
|
39
|
-
|
|
23
|
+
onAddTab,
|
|
24
|
+
onCancelRun,
|
|
25
|
+
onCloseEditor,
|
|
26
|
+
onEdit,
|
|
27
|
+
onRefresh,
|
|
28
|
+
onSaveEditor,
|
|
40
29
|
}: UseAiScreenerFooterOptions) {
|
|
41
|
-
const activeProvider = activeTab ? getAiProvider(activeTab.providerId, providers) : null;
|
|
42
|
-
const statusText = activeTab
|
|
43
|
-
? isRunningActiveTab && runState
|
|
44
|
-
? `${runState.mode === "force" ? "Force refreshing" : "Refreshing"} with ${activeProvider?.name ?? "AI"}...`
|
|
45
|
-
: activeTab.lastSuccessAt
|
|
46
|
-
? `Last ran ${formatTimeAgo(new Date(activeTab.lastSuccessAt))}`
|
|
47
|
-
: "Never run"
|
|
48
|
-
: "No screener selected";
|
|
49
|
-
|
|
50
30
|
usePaneFooter("ai-screener", () => ({
|
|
51
|
-
info:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
31
|
+
info: isRunningActiveTab && runState
|
|
32
|
+
? [{
|
|
33
|
+
id: "running",
|
|
34
|
+
parts: [{
|
|
35
|
+
text: t("Refreshing…"),
|
|
36
|
+
tone: "muted" as const,
|
|
37
|
+
}],
|
|
38
|
+
}]
|
|
39
|
+
: activeTab?.lastError
|
|
40
|
+
? [{
|
|
41
|
+
id: "error",
|
|
42
|
+
parts: [{ text: activeTab.lastError, tone: "warning" as const }],
|
|
43
|
+
}]
|
|
44
|
+
: activeTab?.lastWarning
|
|
45
|
+
? [{
|
|
46
|
+
id: "warning",
|
|
47
|
+
parts: [{ text: activeTab.lastWarning, tone: "warning" as const }],
|
|
48
|
+
}]
|
|
49
|
+
: [],
|
|
62
50
|
hints: editorState
|
|
63
51
|
? [
|
|
64
|
-
{
|
|
65
|
-
|
|
52
|
+
{
|
|
53
|
+
id: "save",
|
|
54
|
+
key: "Ctrl+S",
|
|
55
|
+
label: t("save"),
|
|
56
|
+
onPress: onSaveEditor,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: "cancel-edit",
|
|
60
|
+
key: "Esc",
|
|
61
|
+
label: t("cancel"),
|
|
62
|
+
onPress: onCloseEditor,
|
|
63
|
+
},
|
|
66
64
|
]
|
|
67
|
-
:
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
65
|
+
: isRunningActiveTab
|
|
66
|
+
? [
|
|
67
|
+
{
|
|
68
|
+
id: "stop",
|
|
69
|
+
key: "Esc",
|
|
70
|
+
label: t("stop"),
|
|
71
|
+
onPress: onCancelRun,
|
|
72
|
+
},
|
|
73
|
+
]
|
|
74
|
+
: [
|
|
75
|
+
{
|
|
76
|
+
id: "new",
|
|
77
|
+
key: "t",
|
|
78
|
+
label: t("ab"),
|
|
79
|
+
onPress: onAddTab,
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
id: "refresh",
|
|
83
|
+
key: "r",
|
|
84
|
+
label: t("efresh"),
|
|
85
|
+
onPress: onRefresh,
|
|
86
|
+
disabled: !activeTab,
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: "edit",
|
|
90
|
+
key: "e",
|
|
91
|
+
label: t("dit"),
|
|
92
|
+
onPress: onEdit,
|
|
93
|
+
disabled: !activeTab,
|
|
94
|
+
},
|
|
95
|
+
],
|
|
74
96
|
}), [
|
|
75
|
-
activeProvider?.available,
|
|
76
|
-
activeProvider?.name,
|
|
77
97
|
activeTab,
|
|
78
|
-
addTab,
|
|
79
|
-
cycleEditorProvider,
|
|
80
|
-
editActiveTab,
|
|
81
|
-
editorProvider?.available,
|
|
82
|
-
editorProvider?.name,
|
|
83
98
|
editorState,
|
|
84
|
-
forceRefreshActiveTab,
|
|
85
|
-
forceRunArmed,
|
|
86
99
|
isRunningActiveTab,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
100
|
+
onAddTab,
|
|
101
|
+
onCancelRun,
|
|
102
|
+
onCloseEditor,
|
|
103
|
+
onEdit,
|
|
104
|
+
onRefresh,
|
|
105
|
+
onSaveEditor,
|
|
106
|
+
runState,
|
|
92
107
|
]);
|
|
93
108
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useShortcut } from "../../../../react/input";
|
|
2
|
-
import type { AiScreenerTab,
|
|
2
|
+
import type { AiScreenerTab, ScreenerEditorState } from "./model";
|
|
3
3
|
|
|
4
4
|
export function useAiScreenerKeyboard({
|
|
5
5
|
activeTab,
|
|
@@ -9,11 +9,14 @@ export function useAiScreenerKeyboard({
|
|
|
9
9
|
cycleEditorProvider,
|
|
10
10
|
cycleTabs,
|
|
11
11
|
editActiveTab,
|
|
12
|
+
editorFocusTarget,
|
|
12
13
|
editorState,
|
|
13
14
|
focused,
|
|
15
|
+
focusEditorModel,
|
|
16
|
+
focusEditorPrompt,
|
|
14
17
|
isRunningActiveTab,
|
|
18
|
+
refreshActiveTab,
|
|
15
19
|
removeTab,
|
|
16
|
-
runTab,
|
|
17
20
|
saveEditor,
|
|
18
21
|
}: {
|
|
19
22
|
activeTab: AiScreenerTab | null;
|
|
@@ -23,27 +26,44 @@ export function useAiScreenerKeyboard({
|
|
|
23
26
|
cycleEditorProvider: (direction: -1 | 1) => void;
|
|
24
27
|
cycleTabs: (direction: -1 | 1) => void;
|
|
25
28
|
editActiveTab: () => void;
|
|
29
|
+
editorFocusTarget: "prompt" | "model";
|
|
26
30
|
editorState: ScreenerEditorState | null;
|
|
27
31
|
focused: boolean;
|
|
32
|
+
focusEditorModel: () => void;
|
|
33
|
+
focusEditorPrompt: () => void;
|
|
28
34
|
isRunningActiveTab: boolean;
|
|
35
|
+
refreshActiveTab: () => void;
|
|
29
36
|
removeTab: (tabId: string) => void;
|
|
30
|
-
runTab: (tabId: string, mode: RunState["mode"]) => void;
|
|
31
37
|
saveEditor: () => void;
|
|
32
38
|
}) {
|
|
33
39
|
useShortcut((event) => {
|
|
34
40
|
if (!focused) return;
|
|
35
41
|
|
|
36
42
|
if (editorState) {
|
|
43
|
+
if (event.ctrl && event.name === "s") {
|
|
44
|
+
event.stopPropagation?.();
|
|
45
|
+
event.preventDefault?.();
|
|
46
|
+
saveEditor();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (editorFocusTarget === "model") {
|
|
50
|
+
if (event.name === "escape" || event.name === "tab") {
|
|
51
|
+
event.stopPropagation?.();
|
|
52
|
+
event.preventDefault?.();
|
|
53
|
+
focusEditorPrompt();
|
|
54
|
+
}
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
37
57
|
if (event.name === "escape") {
|
|
38
58
|
event.stopPropagation?.();
|
|
39
59
|
event.preventDefault?.();
|
|
40
60
|
closeEditor();
|
|
41
61
|
return;
|
|
42
62
|
}
|
|
43
|
-
if (event.ctrl && event.name === "
|
|
63
|
+
if (event.ctrl && event.name === "o") {
|
|
44
64
|
event.stopPropagation?.();
|
|
45
65
|
event.preventDefault?.();
|
|
46
|
-
|
|
66
|
+
focusEditorModel();
|
|
47
67
|
return;
|
|
48
68
|
}
|
|
49
69
|
if (event.ctrl && event.name === "p") {
|
|
@@ -75,12 +95,8 @@ export function useAiScreenerKeyboard({
|
|
|
75
95
|
cancelRun();
|
|
76
96
|
return;
|
|
77
97
|
}
|
|
78
|
-
if (event.shift && event.name === "r" && activeTab && !isRunningActiveTab) {
|
|
79
|
-
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
if (event.name === "r" && activeTab && !isRunningActiveTab) {
|
|
83
|
-
void runTab(activeTab.id, "refresh");
|
|
98
|
+
if (!event.shift && event.name === "r" && activeTab && !isRunningActiveTab) {
|
|
99
|
+
refreshActiveTab();
|
|
84
100
|
return;
|
|
85
101
|
}
|
|
86
102
|
if (event.name === "e") {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { normalizeTabs } from "./model";
|
|
3
|
+
|
|
4
|
+
describe("AI screener model", () => {
|
|
5
|
+
test("migrates persisted provider aliases and defaults missing providers", () => {
|
|
6
|
+
const tabs = normalizeTabs({
|
|
7
|
+
tabs: [
|
|
8
|
+
{ id: "claude", providerId: "claude" },
|
|
9
|
+
{ id: "codex", providerId: "codex" },
|
|
10
|
+
{ id: "gemini", providerId: "gemini" },
|
|
11
|
+
{ id: "unsupported", providerId: "opencode" },
|
|
12
|
+
{ id: "missing" },
|
|
13
|
+
],
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
expect(tabs.map((tab) => tab.providerId)).toEqual([
|
|
17
|
+
"anthropic",
|
|
18
|
+
"openai-codex",
|
|
19
|
+
"google",
|
|
20
|
+
"opencode",
|
|
21
|
+
"anthropic",
|
|
22
|
+
]);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { migrateLegacyAiProviderId } from "../providers";
|
|
1
2
|
import { deriveScreenerTitle, type ValidatedScreenerResult } from "./contract";
|
|
2
3
|
|
|
3
4
|
export interface AiScreenerTab {
|
|
@@ -5,6 +6,7 @@ export interface AiScreenerTab {
|
|
|
5
6
|
title: string;
|
|
6
7
|
prompt: string;
|
|
7
8
|
providerId: string;
|
|
9
|
+
modelId: string | null;
|
|
8
10
|
createdAt: number;
|
|
9
11
|
lastRunAt: number | null;
|
|
10
12
|
lastSuccessAt: number | null;
|
|
@@ -27,7 +29,6 @@ export interface ScreenerSortPreference {
|
|
|
27
29
|
|
|
28
30
|
export interface RunState {
|
|
29
31
|
tabId: string;
|
|
30
|
-
mode: "refresh" | "force";
|
|
31
32
|
output: string;
|
|
32
33
|
}
|
|
33
34
|
|
|
@@ -35,6 +36,7 @@ export interface ScreenerEditorState {
|
|
|
35
36
|
mode: "create" | "edit";
|
|
36
37
|
tabId: string | null;
|
|
37
38
|
providerId: string;
|
|
39
|
+
modelId: string;
|
|
38
40
|
prompt: string;
|
|
39
41
|
key: string;
|
|
40
42
|
error: string | null;
|
|
@@ -54,12 +56,13 @@ export function generateScreenerEditorKey(): string {
|
|
|
54
56
|
return `editor-${Date.now()}-${nextScreenerEditorId++}`;
|
|
55
57
|
}
|
|
56
58
|
|
|
57
|
-
export function createScreenerTab(prompt: string, providerId: string): AiScreenerTab {
|
|
59
|
+
export function createScreenerTab(prompt: string, providerId: string, modelId: string | null = null): AiScreenerTab {
|
|
58
60
|
return {
|
|
59
61
|
id: generateScreenerTabId(),
|
|
60
62
|
title: deriveScreenerTitle(prompt),
|
|
61
63
|
prompt,
|
|
62
64
|
providerId,
|
|
65
|
+
modelId: modelId?.trim() || null,
|
|
63
66
|
createdAt: Date.now(),
|
|
64
67
|
lastRunAt: null,
|
|
65
68
|
lastSuccessAt: null,
|
|
@@ -80,7 +83,10 @@ export function normalizeTabs(value: unknown): AiScreenerTab[] {
|
|
|
80
83
|
...entry,
|
|
81
84
|
title: typeof entry.title === "string" ? entry.title : "New Screener",
|
|
82
85
|
prompt: typeof entry.prompt === "string" ? entry.prompt : "",
|
|
83
|
-
providerId: typeof entry.providerId === "string"
|
|
86
|
+
providerId: typeof entry.providerId === "string" && entry.providerId.trim()
|
|
87
|
+
? migrateLegacyAiProviderId(entry.providerId.trim())
|
|
88
|
+
: "anthropic",
|
|
89
|
+
modelId: typeof entry.modelId === "string" && entry.modelId.trim() ? entry.modelId.trim() : null,
|
|
84
90
|
createdAt: typeof entry.createdAt === "number" ? entry.createdAt : Date.now(),
|
|
85
91
|
lastRunAt: typeof entry.lastRunAt === "number" ? entry.lastRunAt : null,
|
|
86
92
|
lastSuccessAt: typeof entry.lastSuccessAt === "number" ? entry.lastSuccessAt : null,
|