@amplitude/wizard 1.0.0-beta.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/LICENSE +47 -0
- package/README.md +119 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +763 -0
- package/dist/package.json +144 -0
- package/dist/src/frameworks/android/android-wizard-agent.d.ts +6 -0
- package/dist/src/frameworks/android/android-wizard-agent.js +72 -0
- package/dist/src/frameworks/android/utils.d.ts +11 -0
- package/dist/src/frameworks/android/utils.js +32 -0
- package/dist/src/frameworks/django/django-wizard-agent.d.ts +8 -0
- package/dist/src/frameworks/django/django-wizard-agent.js +171 -0
- package/dist/src/frameworks/django/utils.d.ts +31 -0
- package/dist/src/frameworks/django/utils.js +305 -0
- package/dist/src/frameworks/fastapi/fastapi-wizard-agent.d.ts +11 -0
- package/dist/src/frameworks/fastapi/fastapi-wizard-agent.js +189 -0
- package/dist/src/frameworks/fastapi/utils.d.ts +26 -0
- package/dist/src/frameworks/fastapi/utils.js +257 -0
- package/dist/src/frameworks/flask/flask-wizard-agent.d.ts +8 -0
- package/dist/src/frameworks/flask/flask-wizard-agent.js +177 -0
- package/dist/src/frameworks/flask/utils.d.ts +28 -0
- package/dist/src/frameworks/flask/utils.js +343 -0
- package/dist/src/frameworks/flutter/flutter-wizard-agent.d.ts +4 -0
- package/dist/src/frameworks/flutter/flutter-wizard-agent.js +57 -0
- package/dist/src/frameworks/flutter/utils.d.ts +7 -0
- package/dist/src/frameworks/flutter/utils.js +64 -0
- package/dist/src/frameworks/generic/generic-wizard-agent.d.ts +2 -0
- package/dist/src/frameworks/generic/generic-wizard-agent.js +176 -0
- package/dist/src/frameworks/go/go-wizard-agent.d.ts +4 -0
- package/dist/src/frameworks/go/go-wizard-agent.js +57 -0
- package/dist/src/frameworks/go/utils.d.ts +5 -0
- package/dist/src/frameworks/go/utils.js +44 -0
- package/dist/src/frameworks/java/java-wizard-agent.d.ts +7 -0
- package/dist/src/frameworks/java/java-wizard-agent.js +73 -0
- package/dist/src/frameworks/java/utils.d.ts +15 -0
- package/dist/src/frameworks/java/utils.js +64 -0
- package/dist/src/frameworks/javascript-node/javascript-node-wizard-agent.d.ts +4 -0
- package/dist/src/frameworks/javascript-node/javascript-node-wizard-agent.js +57 -0
- package/dist/src/frameworks/javascript-web/javascript-web-wizard-agent.d.ts +3 -0
- package/dist/src/frameworks/javascript-web/javascript-web-wizard-agent.js +151 -0
- package/dist/src/frameworks/javascript-web/utils.d.ts +28 -0
- package/dist/src/frameworks/javascript-web/utils.js +153 -0
- package/dist/src/frameworks/nextjs/nextjs-wizard-agent.d.ts +7 -0
- package/dist/src/frameworks/nextjs/nextjs-wizard-agent.js +98 -0
- package/dist/src/frameworks/nextjs/utils.d.ts +12 -0
- package/dist/src/frameworks/nextjs/utils.js +51 -0
- package/dist/src/frameworks/python/python-wizard-agent.d.ts +7 -0
- package/dist/src/frameworks/python/python-wizard-agent.js +193 -0
- package/dist/src/frameworks/python/utils.d.ts +28 -0
- package/dist/src/frameworks/python/utils.js +146 -0
- package/dist/src/frameworks/react-native/react-native-wizard-agent.d.ts +6 -0
- package/dist/src/frameworks/react-native/react-native-wizard-agent.js +84 -0
- package/dist/src/frameworks/react-native/utils.d.ts +21 -0
- package/dist/src/frameworks/react-native/utils.js +82 -0
- package/dist/src/frameworks/react-router/react-router-wizard-agent.d.ts +7 -0
- package/dist/src/frameworks/react-router/react-router-wizard-agent.js +98 -0
- package/dist/src/frameworks/react-router/utils.d.ts +13 -0
- package/dist/src/frameworks/react-router/utils.js +160 -0
- package/dist/src/frameworks/swift/swift-wizard-agent.d.ts +7 -0
- package/dist/src/frameworks/swift/swift-wizard-agent.js +72 -0
- package/dist/src/frameworks/swift/utils.d.ts +12 -0
- package/dist/src/frameworks/swift/utils.js +82 -0
- package/dist/src/frameworks/unity/unity-wizard-agent.d.ts +6 -0
- package/dist/src/frameworks/unity/unity-wizard-agent.js +79 -0
- package/dist/src/frameworks/unity/utils.d.ts +12 -0
- package/dist/src/frameworks/unity/utils.js +66 -0
- package/dist/src/frameworks/unreal/unreal-wizard-agent.d.ts +6 -0
- package/dist/src/frameworks/unreal/unreal-wizard-agent.js +77 -0
- package/dist/src/frameworks/unreal/utils.d.ts +10 -0
- package/dist/src/frameworks/unreal/utils.js +29 -0
- package/dist/src/frameworks/vue/vue-wizard-agent.d.ts +4 -0
- package/dist/src/frameworks/vue/vue-wizard-agent.js +64 -0
- package/dist/src/lib/agent-hooks.d.ts +26 -0
- package/dist/src/lib/agent-hooks.js +118 -0
- package/dist/src/lib/agent-interface.d.ts +175 -0
- package/dist/src/lib/agent-interface.js +1217 -0
- package/dist/src/lib/agent-runner.d.ts +9 -0
- package/dist/src/lib/agent-runner.js +415 -0
- package/dist/src/lib/ampli-config.d.ts +105 -0
- package/dist/src/lib/ampli-config.js +178 -0
- package/dist/src/lib/api.d.ts +107 -0
- package/dist/src/lib/api.js +442 -0
- package/dist/src/lib/commandments.d.ts +1 -0
- package/dist/src/lib/commandments.js +24 -0
- package/dist/src/lib/console-query.d.ts +27 -0
- package/dist/src/lib/console-query.js +121 -0
- package/dist/src/lib/constants.d.ts +124 -0
- package/dist/src/lib/constants.js +170 -0
- package/dist/src/lib/detect-amplitude.d.ts +31 -0
- package/dist/src/lib/detect-amplitude.js +407 -0
- package/dist/src/lib/framework-config.d.ts +188 -0
- package/dist/src/lib/framework-config.js +21 -0
- package/dist/src/lib/health-checks/endpoints.d.ts +3 -0
- package/dist/src/lib/health-checks/endpoints.js +45 -0
- package/dist/src/lib/health-checks/index.d.ts +4 -0
- package/dist/src/lib/health-checks/index.js +22 -0
- package/dist/src/lib/health-checks/readiness.d.ts +24 -0
- package/dist/src/lib/health-checks/readiness.js +118 -0
- package/dist/src/lib/health-checks/statuspage.d.ts +9 -0
- package/dist/src/lib/health-checks/statuspage.js +104 -0
- package/dist/src/lib/health-checks/types.d.ts +31 -0
- package/dist/src/lib/health-checks/types.js +9 -0
- package/dist/src/lib/helper-functions.d.ts +1 -0
- package/dist/src/lib/helper-functions.js +5 -0
- package/dist/src/lib/middleware/benchmark.d.ts +54 -0
- package/dist/src/lib/middleware/benchmark.js +48 -0
- package/dist/src/lib/middleware/benchmarks/cache-tracker.d.ts +44 -0
- package/dist/src/lib/middleware/benchmarks/cache-tracker.js +80 -0
- package/dist/src/lib/middleware/benchmarks/compaction-tracker.d.ts +29 -0
- package/dist/src/lib/middleware/benchmarks/compaction-tracker.js +59 -0
- package/dist/src/lib/middleware/benchmarks/context-size-tracker.d.ts +26 -0
- package/dist/src/lib/middleware/benchmarks/context-size-tracker.js +55 -0
- package/dist/src/lib/middleware/benchmarks/cost-tracker.d.ts +16 -0
- package/dist/src/lib/middleware/benchmarks/cost-tracker.js +75 -0
- package/dist/src/lib/middleware/benchmarks/duration-tracker.d.ts +20 -0
- package/dist/src/lib/middleware/benchmarks/duration-tracker.js +39 -0
- package/dist/src/lib/middleware/benchmarks/index.d.ts +9 -0
- package/dist/src/lib/middleware/benchmarks/index.js +67 -0
- package/dist/src/lib/middleware/benchmarks/json-writer.d.ts +15 -0
- package/dist/src/lib/middleware/benchmarks/json-writer.js +144 -0
- package/dist/src/lib/middleware/benchmarks/summary.d.ts +9 -0
- package/dist/src/lib/middleware/benchmarks/summary.js +105 -0
- package/dist/src/lib/middleware/benchmarks/token-tracker.d.ts +40 -0
- package/dist/src/lib/middleware/benchmarks/token-tracker.js +76 -0
- package/dist/src/lib/middleware/benchmarks/turn-counter.d.ts +34 -0
- package/dist/src/lib/middleware/benchmarks/turn-counter.js +58 -0
- package/dist/src/lib/middleware/config.d.ts +24 -0
- package/dist/src/lib/middleware/config.js +96 -0
- package/dist/src/lib/middleware/index.d.ts +11 -0
- package/dist/src/lib/middleware/index.js +17 -0
- package/dist/src/lib/middleware/phase-detector.d.ts +8 -0
- package/dist/src/lib/middleware/phase-detector.js +63 -0
- package/dist/src/lib/middleware/pipeline.d.ts +29 -0
- package/dist/src/lib/middleware/pipeline.js +81 -0
- package/dist/src/lib/middleware/schemas.d.ts +27 -0
- package/dist/src/lib/middleware/schemas.js +84 -0
- package/dist/src/lib/middleware/types.d.ts +94 -0
- package/dist/src/lib/middleware/types.js +8 -0
- package/dist/src/lib/package-manager-detection.d.ts +42 -0
- package/dist/src/lib/package-manager-detection.js +292 -0
- package/dist/src/lib/registry.d.ts +3 -0
- package/dist/src/lib/registry.js +42 -0
- package/dist/src/lib/safe-tools.d.ts +2 -0
- package/dist/src/lib/safe-tools.js +214 -0
- package/dist/src/lib/wizard-session.d.ts +220 -0
- package/dist/src/lib/wizard-session.js +127 -0
- package/dist/src/lib/wizard-tools.d.ts +82 -0
- package/dist/src/lib/wizard-tools.js +499 -0
- package/dist/src/run.d.ts +19 -0
- package/dist/src/run.js +151 -0
- package/dist/src/steps/add-mcp-server-to-clients/MCPClient.d.ts +30 -0
- package/dist/src/steps/add-mcp-server-to-clients/MCPClient.js +141 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/claude-code.d.ts +29 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/claude-code.js +180 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/claude.d.ts +20 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/claude.js +63 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/codex.d.ts +28 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/codex.js +77 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/cursor.d.ts +24 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/cursor.js +60 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/visual-studio-code.d.ts +27 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/visual-studio-code.js +101 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/zed.d.ts +26 -0
- package/dist/src/steps/add-mcp-server-to-clients/clients/zed.js +102 -0
- package/dist/src/steps/add-mcp-server-to-clients/defaults.d.ts +44 -0
- package/dist/src/steps/add-mcp-server-to-clients/defaults.js +123 -0
- package/dist/src/steps/add-mcp-server-to-clients/index.d.ts +19 -0
- package/dist/src/steps/add-mcp-server-to-clients/index.js +110 -0
- package/dist/src/steps/add-or-update-environment-variables.d.ts +10 -0
- package/dist/src/steps/add-or-update-environment-variables.js +188 -0
- package/dist/src/steps/index.d.ts +4 -0
- package/dist/src/steps/index.js +20 -0
- package/dist/src/steps/run-prettier.d.ts +5 -0
- package/dist/src/steps/run-prettier.js +90 -0
- package/dist/src/steps/upload-environment-variables/EnvironmentProvider.d.ts +11 -0
- package/dist/src/steps/upload-environment-variables/EnvironmentProvider.js +11 -0
- package/dist/src/steps/upload-environment-variables/index.d.ts +6 -0
- package/dist/src/steps/upload-environment-variables/index.js +37 -0
- package/dist/src/steps/upload-environment-variables/providers/vercel.d.ts +15 -0
- package/dist/src/steps/upload-environment-variables/providers/vercel.js +145 -0
- package/dist/src/telemetry.d.ts +2 -0
- package/dist/src/telemetry.js +12 -0
- package/dist/src/ui/index.d.ts +8 -0
- package/dist/src/ui/index.js +16 -0
- package/dist/src/ui/logging-ui.d.ts +56 -0
- package/dist/src/ui/logging-ui.js +157 -0
- package/dist/src/ui/tui/App.d.ts +6 -0
- package/dist/src/ui/tui/App.js +34 -0
- package/dist/src/ui/tui/components/AmplitudeLogo.d.ts +5 -0
- package/dist/src/ui/tui/components/AmplitudeLogo.js +81 -0
- package/dist/src/ui/tui/components/AmplitudeTextLogo.d.ts +3 -0
- package/dist/src/ui/tui/components/AmplitudeTextLogo.js +31 -0
- package/dist/src/ui/tui/components/ConsoleView.d.ts +23 -0
- package/dist/src/ui/tui/components/ConsoleView.js +220 -0
- package/dist/src/ui/tui/components/TitleBar.d.ts +6 -0
- package/dist/src/ui/tui/components/TitleBar.js +16 -0
- package/dist/src/ui/tui/console-commands.d.ts +16 -0
- package/dist/src/ui/tui/console-commands.js +31 -0
- package/dist/src/ui/tui/context/CommandModeContext.d.ts +2 -0
- package/dist/src/ui/tui/context/CommandModeContext.js +3 -0
- package/dist/src/ui/tui/flows.d.ts +48 -0
- package/dist/src/ui/tui/flows.js +154 -0
- package/dist/src/ui/tui/hooks/useScreenInput.d.ts +13 -0
- package/dist/src/ui/tui/hooks/useScreenInput.js +18 -0
- package/dist/src/ui/tui/hooks/useStdoutDimensions.d.ts +9 -0
- package/dist/src/ui/tui/hooks/useStdoutDimensions.js +29 -0
- package/dist/src/ui/tui/ink-ui.d.ts +62 -0
- package/dist/src/ui/tui/ink-ui.js +142 -0
- package/dist/src/ui/tui/primitives/CardLayout.d.ts +12 -0
- package/dist/src/ui/tui/primitives/CardLayout.js +9 -0
- package/dist/src/ui/tui/primitives/ConfirmationInput.d.ts +13 -0
- package/dist/src/ui/tui/primitives/ConfirmationInput.js +35 -0
- package/dist/src/ui/tui/primitives/DissolveTransition.d.ts +21 -0
- package/dist/src/ui/tui/primitives/DissolveTransition.js +143 -0
- package/dist/src/ui/tui/primitives/EventPlanViewer.d.ts +9 -0
- package/dist/src/ui/tui/primitives/EventPlanViewer.js +9 -0
- package/dist/src/ui/tui/primitives/KagiSmallWebViewer.d.ts +7 -0
- package/dist/src/ui/tui/primitives/KagiSmallWebViewer.js +101 -0
- package/dist/src/ui/tui/primitives/LoadingBox.d.ts +8 -0
- package/dist/src/ui/tui/primitives/LoadingBox.js +9 -0
- package/dist/src/ui/tui/primitives/LogViewer.d.ts +11 -0
- package/dist/src/ui/tui/primitives/LogViewer.js +55 -0
- package/dist/src/ui/tui/primitives/PickerMenu.d.ts +20 -0
- package/dist/src/ui/tui/primitives/PickerMenu.js +212 -0
- package/dist/src/ui/tui/primitives/ProgressList.d.ts +15 -0
- package/dist/src/ui/tui/primitives/ProgressList.js +29 -0
- package/dist/src/ui/tui/primitives/PromptLabel.d.ts +11 -0
- package/dist/src/ui/tui/primitives/PromptLabel.js +12 -0
- package/dist/src/ui/tui/primitives/ReportViewer.d.ts +12 -0
- package/dist/src/ui/tui/primitives/ReportViewer.js +99 -0
- package/dist/src/ui/tui/primitives/ScreenErrorBoundary.d.ts +26 -0
- package/dist/src/ui/tui/primitives/ScreenErrorBoundary.js +29 -0
- package/dist/src/ui/tui/primitives/SlashCommandInput.d.ts +21 -0
- package/dist/src/ui/tui/primitives/SlashCommandInput.js +85 -0
- package/dist/src/ui/tui/primitives/SnakeGame.d.ts +1 -0
- package/dist/src/ui/tui/primitives/SnakeGame.js +1 -0
- package/dist/src/ui/tui/primitives/SplitView.d.ts +11 -0
- package/dist/src/ui/tui/primitives/SplitView.js +8 -0
- package/dist/src/ui/tui/primitives/TabContainer.d.ts +18 -0
- package/dist/src/ui/tui/primitives/TabContainer.js +30 -0
- package/dist/src/ui/tui/primitives/index.d.ts +23 -0
- package/dist/src/ui/tui/primitives/index.js +19 -0
- package/dist/src/ui/tui/router.d.ts +61 -0
- package/dist/src/ui/tui/router.js +104 -0
- package/dist/src/ui/tui/screen-registry.d.ts +19 -0
- package/dist/src/ui/tui/screen-registry.js +56 -0
- package/dist/src/ui/tui/screens/ActivationOptionsScreen.d.ts +12 -0
- package/dist/src/ui/tui/screens/ActivationOptionsScreen.js +57 -0
- package/dist/src/ui/tui/screens/AuthScreen.d.ts +18 -0
- package/dist/src/ui/tui/screens/AuthScreen.js +107 -0
- package/dist/src/ui/tui/screens/ChecklistScreen.d.ts +22 -0
- package/dist/src/ui/tui/screens/ChecklistScreen.js +122 -0
- package/dist/src/ui/tui/screens/DataIngestionCheckScreen.d.ts +24 -0
- package/dist/src/ui/tui/screens/DataIngestionCheckScreen.js +113 -0
- package/dist/src/ui/tui/screens/DataSetupScreen.d.ts +17 -0
- package/dist/src/ui/tui/screens/DataSetupScreen.js +73 -0
- package/dist/src/ui/tui/screens/IntroScreen.d.ts +16 -0
- package/dist/src/ui/tui/screens/IntroScreen.js +86 -0
- package/dist/src/ui/tui/screens/LoginScreen.d.ts +15 -0
- package/dist/src/ui/tui/screens/LoginScreen.js +65 -0
- package/dist/src/ui/tui/screens/LogoutScreen.d.ts +12 -0
- package/dist/src/ui/tui/screens/LogoutScreen.js +28 -0
- package/dist/src/ui/tui/screens/McpScreen.d.ts +26 -0
- package/dist/src/ui/tui/screens/McpScreen.js +148 -0
- package/dist/src/ui/tui/screens/OutageScreen.d.ts +10 -0
- package/dist/src/ui/tui/screens/OutageScreen.js +17 -0
- package/dist/src/ui/tui/screens/OutroScreen.d.ts +11 -0
- package/dist/src/ui/tui/screens/OutroScreen.js +69 -0
- package/dist/src/ui/tui/screens/RegionSelectScreen.d.ts +17 -0
- package/dist/src/ui/tui/screens/RegionSelectScreen.js +40 -0
- package/dist/src/ui/tui/screens/RunScreen.d.ts +16 -0
- package/dist/src/ui/tui/screens/RunScreen.js +212 -0
- package/dist/src/ui/tui/screens/SettingsOverrideScreen.d.ts +10 -0
- package/dist/src/ui/tui/screens/SettingsOverrideScreen.js +23 -0
- package/dist/src/ui/tui/screens/SetupScreen.d.ts +13 -0
- package/dist/src/ui/tui/screens/SetupScreen.js +73 -0
- package/dist/src/ui/tui/screens/SlackScreen.d.ts +25 -0
- package/dist/src/ui/tui/screens/SlackScreen.js +97 -0
- package/dist/src/ui/tui/services/mcp-installer.d.ts +25 -0
- package/dist/src/ui/tui/services/mcp-installer.js +82 -0
- package/dist/src/ui/tui/start-tui.d.ts +10 -0
- package/dist/src/ui/tui/start-tui.js +50 -0
- package/dist/src/ui/tui/store.d.ts +231 -0
- package/dist/src/ui/tui/store.js +568 -0
- package/dist/src/ui/tui/styles.d.ts +31 -0
- package/dist/src/ui/tui/styles.js +33 -0
- package/dist/src/ui/wizard-ui.d.ts +110 -0
- package/dist/src/ui/wizard-ui.js +18 -0
- package/dist/src/utils/ampli-settings.d.ts +37 -0
- package/dist/src/utils/ampli-settings.js +182 -0
- package/dist/src/utils/analytics.d.ts +35 -0
- package/dist/src/utils/analytics.js +133 -0
- package/dist/src/utils/anthropic-status.d.ts +17 -0
- package/dist/src/utils/anthropic-status.js +51 -0
- package/dist/src/utils/api-key-store.d.ts +35 -0
- package/dist/src/utils/api-key-store.js +176 -0
- package/dist/src/utils/bash.d.ts +2 -0
- package/dist/src/utils/bash.js +53 -0
- package/dist/src/utils/custom-headers.d.ts +9 -0
- package/dist/src/utils/custom-headers.js +23 -0
- package/dist/src/utils/debug.d.ts +23 -0
- package/dist/src/utils/debug.js +86 -0
- package/dist/src/utils/environment.d.ts +4 -0
- package/dist/src/utils/environment.js +76 -0
- package/dist/src/utils/file-utils.d.ts +2 -0
- package/dist/src/utils/file-utils.js +16 -0
- package/dist/src/utils/get-api-key.d.ts +17 -0
- package/dist/src/utils/get-api-key.js +50 -0
- package/dist/src/utils/logging.d.ts +9 -0
- package/dist/src/utils/logging.js +48 -0
- package/dist/src/utils/oauth.d.ts +53 -0
- package/dist/src/utils/oauth.js +354 -0
- package/dist/src/utils/package-json.d.ts +25 -0
- package/dist/src/utils/package-json.js +26 -0
- package/dist/src/utils/package-manager.d.ts +21 -0
- package/dist/src/utils/package-manager.js +208 -0
- package/dist/src/utils/semver.d.ts +21 -0
- package/dist/src/utils/semver.js +61 -0
- package/dist/src/utils/setup-utils.d.ts +82 -0
- package/dist/src/utils/setup-utils.js +467 -0
- package/dist/src/utils/shell-completions.d.ts +10 -0
- package/dist/src/utils/shell-completions.js +199 -0
- package/dist/src/utils/string.d.ts +1 -0
- package/dist/src/utils/string.js +8 -0
- package/dist/src/utils/types.d.ts +72 -0
- package/dist/src/utils/types.js +2 -0
- package/dist/src/utils/urls.d.ts +14 -0
- package/dist/src/utils/urls.js +69 -0
- package/dist/src/utils/vendor/is-unicorn-supported.d.ts +1 -0
- package/dist/src/utils/vendor/is-unicorn-supported.js +23 -0
- package/dist/src/utils/wizard-abort.d.ts +13 -0
- package/dist/src/utils/wizard-abort.js +56 -0
- package/man/amplitude-wizard.1 +170 -0
- package/package.json +144 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* RunScreen — Tabbed observational view of the agent run.
|
|
4
|
+
*
|
|
5
|
+
* Two tabs:
|
|
6
|
+
* - Status: SplitView with TipsCard (left) + ProgressList (right)
|
|
7
|
+
* - Logs: LogViewer tailing the wizard log file
|
|
8
|
+
*
|
|
9
|
+
* No prompts — the agent runs headlessly.
|
|
10
|
+
* TipsCard reactively shows tips based on discovered features.
|
|
11
|
+
*/
|
|
12
|
+
import { Box, Text } from 'ink';
|
|
13
|
+
import { useState, useEffect } from 'react';
|
|
14
|
+
import { useScreenInput } from '../hooks/useScreenInput.js';
|
|
15
|
+
import { useStdoutDimensions } from '../hooks/useStdoutDimensions.js';
|
|
16
|
+
import { useSyncExternalStore } from 'react';
|
|
17
|
+
import { TabContainer, SplitView, ProgressList, LogViewer, EventPlanViewer, KagiSmallWebViewer, SnakeGame, } from '../primitives/index.js';
|
|
18
|
+
import { Colors, Icons } from '../styles.js';
|
|
19
|
+
import { AnimatedAmplitudeLogo } from '../components/AmplitudeLogo.js';
|
|
20
|
+
import { DiscoveredFeature, AdditionalFeature, ADDITIONAL_FEATURE_LABELS, } from '../../../lib/wizard-session.js';
|
|
21
|
+
import { OUTBOUND_URLS } from '../../../lib/constants.js';
|
|
22
|
+
const LOG_FILE = '/tmp/amplitude-wizard.log';
|
|
23
|
+
/** Tips that rotate on a timer — each inner array is one "page". */
|
|
24
|
+
const TIP_PAGES = [
|
|
25
|
+
[
|
|
26
|
+
{
|
|
27
|
+
id: 'events',
|
|
28
|
+
title: 'Events are the bedrock of your Amplitude data',
|
|
29
|
+
description: 'As people use your product, events build a picture of their behavior and satisfaction. Good events make great data.',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: 'persons',
|
|
33
|
+
title: 'You can also track people and groups with Amplitude',
|
|
34
|
+
description: 'Events can be associated with the humans who generate them, letting you understand a specific customer problem if they email about it.',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: 'properties',
|
|
38
|
+
title: 'Get way more detail using properties',
|
|
39
|
+
description: 'Events and person records can have any properties you want. Track things like how they found your website, what subscription tier they choose, and much more.',
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
[
|
|
43
|
+
{
|
|
44
|
+
id: 'session-replay',
|
|
45
|
+
title: 'Watch real user sessions with Session Replay',
|
|
46
|
+
description: 'See exactly what users see — clicks, scrolls, rage clicks, and dead ends. Debug issues faster and build empathy for your users without scheduling a single call.',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: 'experimentation',
|
|
50
|
+
title: 'Run experiments with confidence',
|
|
51
|
+
description: 'Amplitude supports both feature experiments and web experiments. Test hypotheses, roll out changes safely, and let data decide what ships.',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: 'feature-flags',
|
|
55
|
+
title: 'Ship fearlessly with feature flags',
|
|
56
|
+
description: 'Control who sees what, when. Roll out features gradually, kill switches instantly, and decouple deployment from release.',
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
[
|
|
60
|
+
{
|
|
61
|
+
id: 'guides-surveys',
|
|
62
|
+
title: 'Reach users in-product with Guides & Surveys',
|
|
63
|
+
description: 'Onboard new users, announce features, and collect feedback — all without a code deploy. Target the right audience using your Amplitude data.',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: 'activation',
|
|
67
|
+
title: 'Unify your data with Amplitude Activation',
|
|
68
|
+
description: 'Collect, clean, and route data to every tool in your stack. One SDK, one source of truth, zero data silos.',
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: 'ai',
|
|
72
|
+
title: 'Ask questions in plain English',
|
|
73
|
+
description: 'Amplitude AI lets anyone on your team ask data questions in natural language and get instant charts and insights — no SQL required.',
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
[
|
|
77
|
+
{
|
|
78
|
+
id: 'mcp',
|
|
79
|
+
title: 'Give your AI agents analytics superpowers with Amplitude MCP',
|
|
80
|
+
description: 'Connect any AI agent to your Amplitude data via MCP. Your agents can query metrics, build charts, and act on insights — no dashboard required.',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: 'skills-marketplace',
|
|
84
|
+
title: 'Extend your agents with the Skills Marketplace',
|
|
85
|
+
description: 'Browse and install pre-built skills that teach your agents new tricks — from anomaly detection to automated reporting. Build once, share across your org.',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
id: 'global-agent',
|
|
89
|
+
title: 'Meet your always-on analytics agent',
|
|
90
|
+
description: 'Ask questions in Amplitude or in Slack and get instant answers backed by your data. One agent that works wherever your team already lives.',
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
];
|
|
94
|
+
/** How often (ms) to rotate to the next tip page. */
|
|
95
|
+
const TIP_ROTATION_INTERVAL = 30_000;
|
|
96
|
+
/** Conditional tips shown regardless of the current page. */
|
|
97
|
+
const CONDITIONAL_TIPS = [
|
|
98
|
+
{
|
|
99
|
+
id: 'stripe',
|
|
100
|
+
title: 'You can track Stripe revenue with Amplitude',
|
|
101
|
+
description: 'Add Stripe as a data source while you wait:',
|
|
102
|
+
url: OUTBOUND_URLS.stripeDataSource,
|
|
103
|
+
visible: (store) => store.session.discoveredFeatures.includes(DiscoveredFeature.Stripe),
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
id: 'llm',
|
|
107
|
+
title: 'Amplitude can also help you track your LLM costs',
|
|
108
|
+
description: '',
|
|
109
|
+
visible: (store) => store.session.discoveredFeatures.includes(DiscoveredFeature.LLM),
|
|
110
|
+
toggle: {
|
|
111
|
+
key: 'l',
|
|
112
|
+
feature: AdditionalFeature.LLM,
|
|
113
|
+
enabledLabel: 'LLM analytics setup queued next',
|
|
114
|
+
prompt: 'We detected LLM dependencies in your project.',
|
|
115
|
+
isEnabled: (store) => store.session.llmOptIn,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
];
|
|
119
|
+
/** Min terminal width to show the logo in the TipsCard. */
|
|
120
|
+
const LOGO_MIN_COLS = 100;
|
|
121
|
+
/** Delay (ms) between each tip appearing during a page transition. */
|
|
122
|
+
const TIP_REVEAL_DELAY = 400;
|
|
123
|
+
const TipsCard = ({ store }) => {
|
|
124
|
+
const [columns] = useStdoutDimensions();
|
|
125
|
+
const [pageIndex, setPageIndex] = useState(0);
|
|
126
|
+
/** Number of page tips currently visible (for staggered reveal). */
|
|
127
|
+
const [visibleCount, setVisibleCount] = useState(TIP_PAGES[0].length);
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
const timer = setInterval(() => {
|
|
130
|
+
setPageIndex((prev) => (prev + 1) % TIP_PAGES.length);
|
|
131
|
+
setVisibleCount(0);
|
|
132
|
+
}, TIP_ROTATION_INTERVAL);
|
|
133
|
+
return () => clearInterval(timer);
|
|
134
|
+
}, []);
|
|
135
|
+
// Stagger reveal: increment visibleCount one at a time after each page change
|
|
136
|
+
useEffect(() => {
|
|
137
|
+
const pageLen = TIP_PAGES[pageIndex].length;
|
|
138
|
+
if (visibleCount >= pageLen)
|
|
139
|
+
return;
|
|
140
|
+
const timer = setTimeout(() => setVisibleCount((c) => c + 1), visibleCount === 0 ? 100 : TIP_REVEAL_DELAY);
|
|
141
|
+
return () => clearTimeout(timer);
|
|
142
|
+
}, [pageIndex, visibleCount]);
|
|
143
|
+
useScreenInput((input) => {
|
|
144
|
+
for (const tip of CONDITIONAL_TIPS) {
|
|
145
|
+
if (tip.toggle &&
|
|
146
|
+
input.toLowerCase() === tip.toggle.key &&
|
|
147
|
+
(!tip.visible || tip.visible(store)) &&
|
|
148
|
+
!tip.toggle.isEnabled(store)) {
|
|
149
|
+
store.enableFeature(tip.toggle.feature);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
const pageTips = TIP_PAGES[pageIndex].slice(0, visibleCount);
|
|
154
|
+
const visibleConditional = CONDITIONAL_TIPS.filter((tip) => !tip.visible || tip.visible(store));
|
|
155
|
+
const allTips = [...pageTips, ...visibleConditional];
|
|
156
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [columns >= LOGO_MIN_COLS && _jsx(AnimatedAmplitudeLogo, {}), _jsx(Text, { bold: true, color: Colors.accent, children: "Learn about Amplitude" }), _jsxs(Text, { color: Colors.muted, children: [Icons.diamond, " ", pageIndex + 1, "/", TIP_PAGES.length] }), _jsx(Box, { height: 1 }), allTips.map((tip) => (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Text, { children: [_jsxs(Text, { color: Colors.accent, children: [Icons.diamond, " "] }), _jsx(Text, { bold: true, children: tip.title })] }), tip.toggle ? (tip.toggle.isEnabled(store) ? (_jsxs(Text, { color: Colors.success, children: [Icons.check, " ", tip.toggle.enabledLabel] })) : (_jsxs(Text, { color: Colors.muted, children: [tip.toggle.prompt, " Press", ' ', _jsx(Text, { bold: true, color: Colors.accent, children: tip.toggle.key.toUpperCase() }), ' ', "to enable."] }))) : (_jsxs(Text, { color: Colors.muted, children: [tip.description, tip.url && (_jsxs(_Fragment, { children: [' ', _jsx(Text, { color: "cyan", children: tip.url })] }))] }))] }, tip.id)))] }));
|
|
157
|
+
};
|
|
158
|
+
export const RunScreen = ({ store }) => {
|
|
159
|
+
useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
|
|
160
|
+
const progressItems = store.tasks.map((t) => ({
|
|
161
|
+
label: t.label,
|
|
162
|
+
activeForm: t.activeForm,
|
|
163
|
+
status: t.status,
|
|
164
|
+
}));
|
|
165
|
+
// When all tasks are done but the queue has features, show a transitional item
|
|
166
|
+
const queue = store.session.additionalFeatureQueue;
|
|
167
|
+
const allDone = progressItems.length > 0 &&
|
|
168
|
+
progressItems.every((t) => t.status === 'completed');
|
|
169
|
+
if (allDone && queue.length > 0) {
|
|
170
|
+
const nextLabel = ADDITIONAL_FEATURE_LABELS[queue[0]];
|
|
171
|
+
progressItems.push({
|
|
172
|
+
label: `Set up ${nextLabel}`,
|
|
173
|
+
activeForm: `Setting up ${nextLabel}...`,
|
|
174
|
+
status: 'in_progress',
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
const lastStatus = store.statusMessages.length > 0
|
|
178
|
+
? store.statusMessages[store.statusMessages.length - 1]
|
|
179
|
+
: undefined;
|
|
180
|
+
const tabs = [
|
|
181
|
+
{
|
|
182
|
+
id: 'status',
|
|
183
|
+
label: 'Status',
|
|
184
|
+
component: (_jsx(SplitView, { left: _jsx(TipsCard, { store: store }), right: _jsx(ProgressList, { items: progressItems, title: "Tasks" }) })),
|
|
185
|
+
},
|
|
186
|
+
...(store.eventPlan.length > 0
|
|
187
|
+
? [
|
|
188
|
+
{
|
|
189
|
+
id: 'events',
|
|
190
|
+
label: 'Event plan',
|
|
191
|
+
component: _jsx(EventPlanViewer, { events: store.eventPlan }),
|
|
192
|
+
},
|
|
193
|
+
]
|
|
194
|
+
: []),
|
|
195
|
+
{
|
|
196
|
+
id: 'logs',
|
|
197
|
+
label: 'All logs',
|
|
198
|
+
component: _jsx(LogViewer, { filePath: LOG_FILE }),
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
id: 'smallweb',
|
|
202
|
+
label: 'Small Web',
|
|
203
|
+
component: _jsx(KagiSmallWebViewer, {}),
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
id: 'snake',
|
|
207
|
+
label: 'Snake',
|
|
208
|
+
component: _jsx(SnakeGame, {}),
|
|
209
|
+
},
|
|
210
|
+
];
|
|
211
|
+
return (_jsx(TabContainer, { tabs: tabs, statusMessage: lastStatus, requestedTab: store.requestedTab, onTabConsumed: () => store.clearRequestedTab() }));
|
|
212
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SettingsOverrideScreen — Modal when .claude/settings.json contains env overrides
|
|
3
|
+
* that block the Wizard from reaching the Amplitude LLM Gateway.
|
|
4
|
+
*/
|
|
5
|
+
import type { WizardStore } from '../store.js';
|
|
6
|
+
interface SettingsOverrideScreenProps {
|
|
7
|
+
store: WizardStore;
|
|
8
|
+
}
|
|
9
|
+
export declare const SettingsOverrideScreen: ({ store, }: SettingsOverrideScreenProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* SettingsOverrideScreen — Modal when .claude/settings.json contains env overrides
|
|
4
|
+
* that block the Wizard from reaching the Amplitude LLM Gateway.
|
|
5
|
+
*/
|
|
6
|
+
import { Box, Text } from 'ink';
|
|
7
|
+
import { useState, useSyncExternalStore } from 'react';
|
|
8
|
+
import { ConfirmationInput } from '../primitives/index.js';
|
|
9
|
+
import { Colors, Icons } from '../styles.js';
|
|
10
|
+
export const SettingsOverrideScreen = ({ store, }) => {
|
|
11
|
+
useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
|
|
12
|
+
const [feedback, setFeedback] = useState(null);
|
|
13
|
+
const keys = store.session.settingsOverrideKeys;
|
|
14
|
+
if (!keys || keys.length === 0) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
return (_jsx(Box, { flexDirection: "column", flexGrow: 1, alignItems: "center", justifyContent: "center", children: _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 3, paddingY: 1, width: 64, children: [_jsx(Box, { justifyContent: "center", marginBottom: 1, children: _jsxs(Text, { color: "red", bold: true, children: [Icons.warning, " Settings Conflict"] }) }), _jsxs(Text, { children: ["Your project's ", _jsx(Text, { bold: true, children: ".claude/settings.json" }), " sets:"] }), _jsx(Box, { flexDirection: "column", marginY: 1, paddingLeft: 2, children: keys.map((key) => (_jsxs(Text, { children: [Icons.bullet, ' ', _jsx(Text, { color: "yellow", bold: true, children: key })] }, key))) }), _jsx(Text, { color: Colors.muted, children: "These overrides prevent the Wizard from reaching the Amplitude LLM Gateway. We can back up the file and continue." }), feedback && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", children: [Icons.warning, " ", feedback] }) })), _jsx(Box, { marginY: 1, children: _jsx(Text, { color: Colors.muted, children: '─'.repeat(56) }) }), _jsx(ConfirmationInput, { message: "Back up to .wizard-backup and continue?", confirmLabel: "Backup & continue [Enter]", cancelLabel: "Exit [Esc]", onConfirm: () => {
|
|
18
|
+
const ok = store.backupAndFixSettingsOverride();
|
|
19
|
+
if (!ok) {
|
|
20
|
+
setFeedback('Could not back up the settings file.');
|
|
21
|
+
}
|
|
22
|
+
}, onCancel: () => process.exit(1) })] }) }));
|
|
23
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SetupScreen — Generic framework disambiguation.
|
|
3
|
+
*
|
|
4
|
+
* Iterates unresolved setup questions from the FrameworkConfig
|
|
5
|
+
* and renders a PickerMenu for each. If all questions are auto-resolved,
|
|
6
|
+
* this screen is skipped entirely (the router skips it via its show() predicate).
|
|
7
|
+
*/
|
|
8
|
+
import type { WizardStore } from '../store.js';
|
|
9
|
+
interface SetupScreenProps {
|
|
10
|
+
store: WizardStore;
|
|
11
|
+
}
|
|
12
|
+
export declare const SetupScreen: ({ store }: SetupScreenProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* SetupScreen — Generic framework disambiguation.
|
|
4
|
+
*
|
|
5
|
+
* Iterates unresolved setup questions from the FrameworkConfig
|
|
6
|
+
* and renders a PickerMenu for each. If all questions are auto-resolved,
|
|
7
|
+
* this screen is skipped entirely (the router skips it via its show() predicate).
|
|
8
|
+
*/
|
|
9
|
+
import { Box, Text } from 'ink';
|
|
10
|
+
import { useState, useEffect } from 'react';
|
|
11
|
+
import { useSyncExternalStore } from 'react';
|
|
12
|
+
import { PickerMenu } from '../primitives/index.js';
|
|
13
|
+
import { Colors } from '../styles.js';
|
|
14
|
+
export const SetupScreen = ({ store }) => {
|
|
15
|
+
useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
|
|
16
|
+
const config = store.session.frameworkConfig;
|
|
17
|
+
const questions = config?.metadata.setup?.questions ?? [];
|
|
18
|
+
// Track which question index we're currently showing
|
|
19
|
+
const [currentIndex, setCurrentIndex] = useState(0);
|
|
20
|
+
const [resolving, setResolving] = useState(true);
|
|
21
|
+
// On mount, run auto-detection for all questions
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
void (async () => {
|
|
24
|
+
for (const q of questions) {
|
|
25
|
+
// Skip if already resolved (e.g. by CLI arg)
|
|
26
|
+
if (q.key in store.session.frameworkContext)
|
|
27
|
+
continue;
|
|
28
|
+
try {
|
|
29
|
+
const detected = await q.detect({
|
|
30
|
+
installDir: store.session.installDir,
|
|
31
|
+
});
|
|
32
|
+
if (detected !== null) {
|
|
33
|
+
store.setFrameworkContext(q.key, detected);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Detection failed — will ask the user
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
setResolving(false);
|
|
41
|
+
// If all resolved, the router's isComplete predicate will
|
|
42
|
+
// resolve past this screen on the next render cycle.
|
|
43
|
+
})();
|
|
44
|
+
}, []);
|
|
45
|
+
if (resolving) {
|
|
46
|
+
return (_jsx(Box, { flexDirection: "column", flexGrow: 1, children: _jsx(Text, { color: Colors.muted, children: "Detecting project configuration..." }) }));
|
|
47
|
+
}
|
|
48
|
+
// Get unresolved questions
|
|
49
|
+
const unresolved = questions.filter((q) => !(q.key in store.session.frameworkContext));
|
|
50
|
+
if (unresolved.length === 0) {
|
|
51
|
+
// All resolved — should have already advanced
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
const question = unresolved[currentIndex] ?? unresolved[0];
|
|
55
|
+
if (!question)
|
|
56
|
+
return null;
|
|
57
|
+
return (_jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { bold: true, color: Colors.accent, children: "Project Setup" }), config && (_jsxs(Text, { color: Colors.muted, children: ["Configuring ", config.metadata.name, " integration"] }))] }), _jsx(PickerMenu, { message: question.message, options: question.options.map((o) => ({
|
|
58
|
+
label: o.label,
|
|
59
|
+
value: o.value,
|
|
60
|
+
hint: o.hint,
|
|
61
|
+
})), onSelect: (value) => {
|
|
62
|
+
const selected = Array.isArray(value) ? value[0] : value;
|
|
63
|
+
store.setFrameworkContext(question.key, selected);
|
|
64
|
+
// Check if more unresolved questions remain
|
|
65
|
+
const remaining = unresolved.filter((q) => q.key !== question.key &&
|
|
66
|
+
!(q.key in store.session.frameworkContext));
|
|
67
|
+
if (remaining.length > 0) {
|
|
68
|
+
setCurrentIndex((i) => i + 1);
|
|
69
|
+
}
|
|
70
|
+
// When no remaining questions, setFrameworkContext already
|
|
71
|
+
// triggered emitChange — router resolves past this screen.
|
|
72
|
+
} })] }));
|
|
73
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SlackScreen — Amplitude Slack integration setup.
|
|
3
|
+
*
|
|
4
|
+
* Guides the user to connect their Slack workspace to Amplitude.
|
|
5
|
+
* Since the OAuth handshake happens in the browser (Amplitude Settings),
|
|
6
|
+
* this screen opens the right settings URL and lets the user confirm
|
|
7
|
+
* once connected or skip.
|
|
8
|
+
*
|
|
9
|
+
* Region-aware: EU users need the "Amplitude - EU" Slack app.
|
|
10
|
+
*/
|
|
11
|
+
import { type WizardStore } from '../store.js';
|
|
12
|
+
interface SlackScreenProps {
|
|
13
|
+
store: WizardStore;
|
|
14
|
+
/** When true, exit the process after completion instead of routing to outro. */
|
|
15
|
+
standalone?: boolean;
|
|
16
|
+
/** When provided, called on completion instead of setSlackComplete (overlay mode). */
|
|
17
|
+
onComplete?: () => void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Build the Amplitude settings URL for Slack connection.
|
|
21
|
+
* Uses the org name from the API; falls back to base URL.
|
|
22
|
+
*/
|
|
23
|
+
export declare function slackSettingsUrl(baseUrl: string, orgName: string | null): string;
|
|
24
|
+
export declare const SlackScreen: ({ store, standalone, onComplete, }: SlackScreenProps) => import("react/jsx-runtime").JSX.Element;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* SlackScreen — Amplitude Slack integration setup.
|
|
4
|
+
*
|
|
5
|
+
* Guides the user to connect their Slack workspace to Amplitude.
|
|
6
|
+
* Since the OAuth handshake happens in the browser (Amplitude Settings),
|
|
7
|
+
* this screen opens the right settings URL and lets the user confirm
|
|
8
|
+
* once connected or skip.
|
|
9
|
+
*
|
|
10
|
+
* Region-aware: EU users need the "Amplitude - EU" Slack app.
|
|
11
|
+
*/
|
|
12
|
+
import { Box, Text } from 'ink';
|
|
13
|
+
import { useState, useEffect } from 'react';
|
|
14
|
+
import { useSyncExternalStore } from 'react';
|
|
15
|
+
import { SlackOutcome } from '../store.js';
|
|
16
|
+
import { ConfirmationInput } from '../primitives/index.js';
|
|
17
|
+
import { Colors } from '../styles.js';
|
|
18
|
+
import { fetchAmplitudeUser } from '../../../lib/api.js';
|
|
19
|
+
import { OUTBOUND_URLS } from '../../../lib/constants.js';
|
|
20
|
+
import { logToFile } from '../../../utils/debug.js';
|
|
21
|
+
import opn from 'opn';
|
|
22
|
+
var Phase;
|
|
23
|
+
(function (Phase) {
|
|
24
|
+
Phase["Prompt"] = "prompt";
|
|
25
|
+
Phase["Opening"] = "opening";
|
|
26
|
+
Phase["Waiting"] = "waiting";
|
|
27
|
+
Phase["Done"] = "done";
|
|
28
|
+
})(Phase || (Phase = {}));
|
|
29
|
+
/**
|
|
30
|
+
* Build the Amplitude settings URL for Slack connection.
|
|
31
|
+
* Uses the org name from the API; falls back to base URL.
|
|
32
|
+
*/
|
|
33
|
+
export function slackSettingsUrl(baseUrl, orgName) {
|
|
34
|
+
if (orgName) {
|
|
35
|
+
return `${baseUrl}/analytics/${encodeURIComponent(orgName)}/settings/profile`;
|
|
36
|
+
}
|
|
37
|
+
return `${baseUrl}/settings/profile`;
|
|
38
|
+
}
|
|
39
|
+
const markDone = (store, outcome, standalone, onComplete) => {
|
|
40
|
+
if (onComplete) {
|
|
41
|
+
onComplete();
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
store.setSlackComplete(outcome);
|
|
45
|
+
if (standalone) {
|
|
46
|
+
process.exit(0);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
export const SlackScreen = ({ store, standalone = false, onComplete, }) => {
|
|
51
|
+
useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
|
|
52
|
+
const [phase, setPhase] = useState(Phase.Prompt);
|
|
53
|
+
const [resolvedOrgName, setResolvedOrgName] = useState(store.session.selectedOrgName);
|
|
54
|
+
const region = store.session.region ?? 'us';
|
|
55
|
+
const isEu = region === 'eu';
|
|
56
|
+
const appName = isEu ? 'Amplitude - EU' : 'Amplitude';
|
|
57
|
+
// Fetch org name from the API if it wasn't populated during the SUSI flow
|
|
58
|
+
// (e.g. returning users, or the standalone `slack` command).
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
logToFile(`[SlackScreen] selectedOrgName=${store.session.selectedOrgName ?? ''} credentials=${store.session.credentials ? 'present' : 'null'} region=${region}`);
|
|
61
|
+
if (resolvedOrgName) {
|
|
62
|
+
logToFile(`[SlackScreen] using existing orgName=${resolvedOrgName}`);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const credentials = store.session.credentials;
|
|
66
|
+
if (!credentials) {
|
|
67
|
+
logToFile(`[SlackScreen] no credentials — falling back to base URL`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
logToFile(`[SlackScreen] fetching org name via API`);
|
|
71
|
+
void fetchAmplitudeUser(credentials.idToken ?? credentials.accessToken, region)
|
|
72
|
+
.then((info) => {
|
|
73
|
+
const name = info.orgs[0]?.name ?? null;
|
|
74
|
+
logToFile(`[SlackScreen] API returned orgs=${JSON.stringify(info.orgs.map((o) => o.name))} using=${name}`);
|
|
75
|
+
setResolvedOrgName(name);
|
|
76
|
+
})
|
|
77
|
+
.catch((err) => {
|
|
78
|
+
logToFile(`[SlackScreen] API fetch failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
79
|
+
});
|
|
80
|
+
}, []);
|
|
81
|
+
const settingsUrl = slackSettingsUrl(OUTBOUND_URLS.overview[(region ?? 'us')], resolvedOrgName);
|
|
82
|
+
const handleConnect = () => {
|
|
83
|
+
setPhase(Phase.Opening);
|
|
84
|
+
opn(settingsUrl, { wait: false }).catch(() => {
|
|
85
|
+
/* fire-and-forget */
|
|
86
|
+
});
|
|
87
|
+
setTimeout(() => setPhase(Phase.Waiting), 800);
|
|
88
|
+
};
|
|
89
|
+
const handleSkip = () => {
|
|
90
|
+
markDone(store, SlackOutcome.Skipped, standalone, onComplete);
|
|
91
|
+
};
|
|
92
|
+
const handleDone = () => {
|
|
93
|
+
setPhase(Phase.Done);
|
|
94
|
+
setTimeout(() => markDone(store, SlackOutcome.Configured, standalone, onComplete), 1500);
|
|
95
|
+
};
|
|
96
|
+
return (_jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [_jsx(Text, { bold: true, color: Colors.accent, children: "Slack Integration" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: Colors.muted, children: "Connect Amplitude to Slack for chart previews, dashboard sharing," }), _jsx(Text, { color: Colors.muted, children: "and real-time tracking plan notifications." }), isEu && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "yellow", children: "EU region: install the \"Amplitude - EU\" app from the Slack App Directory." }) })), phase === Phase.Prompt && (_jsx(Box, { marginTop: 1, children: _jsx(ConfirmationInput, { message: `Open Amplitude Settings to connect the "${appName}" Slack app?`, confirmLabel: "Open settings", cancelLabel: "Skip for now", onConfirm: handleConnect, onCancel: handleSkip }) })), phase === Phase.Opening && (_jsx(Text, { color: Colors.muted, children: "Opening browser..." })), phase === Phase.Waiting && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { children: ["Browser opened to ", _jsx(Text, { color: "cyan", children: settingsUrl })] }), _jsx(Text, { color: Colors.muted, children: "Go to Settings > Personal Settings > Profile and click \"Connect to Slack\"." }), _jsx(Box, { marginTop: 1, children: _jsx(ConfirmationInput, { message: "Connected to Slack?", confirmLabel: "Yes, connected", cancelLabel: "Skip for now", onConfirm: handleDone, onCancel: handleSkip }) })] })), phase === Phase.Done && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsxs(Text, { color: "green", bold: true, children: ['\u2714', " Slack connected! You'll get chart previews and notifications in Slack."] }) }))] })] }));
|
|
97
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* McpInstaller — service layer between McpScreen and MCP business logic.
|
|
3
|
+
*
|
|
4
|
+
* Decouples the screen from step internals. Testable, swappable,
|
|
5
|
+
* no dynamic imports in React components.
|
|
6
|
+
*/
|
|
7
|
+
export interface McpClientInfo {
|
|
8
|
+
name: string;
|
|
9
|
+
}
|
|
10
|
+
export interface McpInstaller {
|
|
11
|
+
/** Detect which MCP-capable editors are available on this machine. */
|
|
12
|
+
detectClients(): Promise<McpClientInfo[]>;
|
|
13
|
+
/** Install the Amplitude MCP server to the given clients. Returns names of successfully installed clients. */
|
|
14
|
+
install(clientNames: string[]): Promise<string[]>;
|
|
15
|
+
/** Remove the Amplitude MCP server from all installed clients. Returns names of removed clients. */
|
|
16
|
+
remove(): Promise<string[]>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Production McpInstaller backed by real MCP client detection and installation.
|
|
20
|
+
*
|
|
21
|
+
* @param local - When true, installs/removes the local development server
|
|
22
|
+
* (http://localhost:8787) instead of the production server. Mirrors the
|
|
23
|
+
* --local-mcp CLI flag and session.localMcp.
|
|
24
|
+
*/
|
|
25
|
+
export declare function createMcpInstaller(local?: boolean): McpInstaller;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* McpInstaller — service layer between McpScreen and MCP business logic.
|
|
3
|
+
*
|
|
4
|
+
* Decouples the screen from step internals. Testable, swappable,
|
|
5
|
+
* no dynamic imports in React components.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { getSupportedClients, removeMCPServer, getInstalledClients, } from '../../../steps/add-mcp-server-to-clients/index.js';
|
|
9
|
+
import { ALL_FEATURE_VALUES } from '../../../steps/add-mcp-server-to-clients/defaults.js';
|
|
10
|
+
import { logToFile } from '../../../utils/debug.js';
|
|
11
|
+
const RawMCPClientSchema = z
|
|
12
|
+
.object({
|
|
13
|
+
name: z.string(),
|
|
14
|
+
addServer: z.unknown(),
|
|
15
|
+
})
|
|
16
|
+
.refine((obj) => typeof obj.addServer === 'function', {
|
|
17
|
+
message: 'addServer must be a function',
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* Production McpInstaller backed by real MCP client detection and installation.
|
|
21
|
+
*
|
|
22
|
+
* @param local - When true, installs/removes the local development server
|
|
23
|
+
* (http://localhost:8787) instead of the production server. Mirrors the
|
|
24
|
+
* --local-mcp CLI flag and session.localMcp.
|
|
25
|
+
*/
|
|
26
|
+
export function createMcpInstaller(local = false) {
|
|
27
|
+
// Cache the raw MCPClient objects so install() can reference them by name
|
|
28
|
+
let cachedClients = [];
|
|
29
|
+
return {
|
|
30
|
+
async detectClients() {
|
|
31
|
+
const supported = await getSupportedClients();
|
|
32
|
+
cachedClients = supported.map((c) => ({ name: c.name, raw: c }));
|
|
33
|
+
return supported.map((c) => ({ name: c.name }));
|
|
34
|
+
},
|
|
35
|
+
async install(clientNames) {
|
|
36
|
+
const features = [...ALL_FEATURE_VALUES];
|
|
37
|
+
// No access token — write URL only and let each editor handle OAuth on
|
|
38
|
+
// first use. Pre-populating a token would break after 24 hours.
|
|
39
|
+
const accessToken = undefined;
|
|
40
|
+
const toInstall = [];
|
|
41
|
+
for (const c of cachedClients) {
|
|
42
|
+
if (!clientNames.includes(c.name))
|
|
43
|
+
continue;
|
|
44
|
+
const parsed = RawMCPClientSchema.safeParse(c.raw);
|
|
45
|
+
if (!parsed.success) {
|
|
46
|
+
logToFile(`[McpInstaller] Skipping invalid client ${c.name}: ${parsed.error.message}`);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
// Use the original instance, not parsed.data — Zod creates a plain-object
|
|
50
|
+
// copy which strips the prototype chain and breaks `this` inside class methods.
|
|
51
|
+
toInstall.push(c.raw);
|
|
52
|
+
}
|
|
53
|
+
if (toInstall.length === 0) {
|
|
54
|
+
logToFile(`[McpInstaller] No clients matched. clientNames=${JSON.stringify(clientNames)}, cached=${JSON.stringify(cachedClients.map((c) => c.name))}`);
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
const installed = [];
|
|
58
|
+
for (const client of toInstall) {
|
|
59
|
+
try {
|
|
60
|
+
const result = await client.addServer(accessToken, features, local);
|
|
61
|
+
if (result?.success) {
|
|
62
|
+
installed.push(client.name);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
logToFile(`[McpInstaller] addServer returned success=false for ${client.name}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
logToFile(`[McpInstaller] addServer threw for ${client.name}: ${err instanceof Error ? err.message : String(err)}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return installed;
|
|
73
|
+
},
|
|
74
|
+
async remove() {
|
|
75
|
+
const installed = await getInstalledClients(local);
|
|
76
|
+
if (installed.length === 0)
|
|
77
|
+
return [];
|
|
78
|
+
await removeMCPServer(installed, local);
|
|
79
|
+
return installed.map((c) => c.name);
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* start-tui.ts — Sets up the Ink TUI renderer and InkUI.
|
|
3
|
+
*/
|
|
4
|
+
import { WizardStore, Flow } from './store.js';
|
|
5
|
+
import type { WizardSession } from '../../lib/wizard-session.js';
|
|
6
|
+
export declare function startTUI(version: string, flow?: Flow, initialSession?: WizardSession): {
|
|
7
|
+
unmount: () => void;
|
|
8
|
+
store: WizardStore;
|
|
9
|
+
waitForSetup: () => Promise<void>;
|
|
10
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* start-tui.ts — Sets up the Ink TUI renderer and InkUI.
|
|
3
|
+
*/
|
|
4
|
+
import { render } from 'ink';
|
|
5
|
+
import { createElement } from 'react';
|
|
6
|
+
import { WizardStore, Flow } from './store.js';
|
|
7
|
+
import { InkUI } from './ink-ui.js';
|
|
8
|
+
import { setUI } from '../index.js';
|
|
9
|
+
import { App } from './App.js';
|
|
10
|
+
// ANSI escape sequences
|
|
11
|
+
const RESET_ATTRS = '\x1b[0m';
|
|
12
|
+
const CLEAR_SCREEN = '\x1b[2J';
|
|
13
|
+
const CURSOR_HOME = '\x1b[H';
|
|
14
|
+
const BG_BLACK = '\x1b[48;2;0;0;0m';
|
|
15
|
+
// OSC 10/11: set terminal foreground/background colors (ignored by unsupporting terminals)
|
|
16
|
+
const OSC_FG_BRIGHT = '\x1b]10;#f4f4ff\x07';
|
|
17
|
+
const OSC_BG_DARK = '\x1b]11;#0d0d16\x07';
|
|
18
|
+
// OSC 110/111: reset to user defaults
|
|
19
|
+
const OSC_FG_RESET = '\x1b]110;\x07';
|
|
20
|
+
const OSC_BG_RESET = '\x1b]111;\x07';
|
|
21
|
+
/** Set foreground bright + background near-black, clear screen, cursor to top-left. */
|
|
22
|
+
const FORCE_DARK = OSC_FG_BRIGHT + OSC_BG_DARK + BG_BLACK + CLEAR_SCREEN + CURSOR_HOME;
|
|
23
|
+
export function startTUI(version, flow = Flow.Wizard, initialSession) {
|
|
24
|
+
// Force dark background regardless of terminal theme.
|
|
25
|
+
// The UI adapts to whatever size the terminal already is.
|
|
26
|
+
process.stdout.write(FORCE_DARK);
|
|
27
|
+
const store = new WizardStore(flow);
|
|
28
|
+
store.version = version;
|
|
29
|
+
if (initialSession) {
|
|
30
|
+
store.session = initialSession;
|
|
31
|
+
}
|
|
32
|
+
// Swap in the InkUI
|
|
33
|
+
const inkUI = new InkUI(store);
|
|
34
|
+
setUI(inkUI);
|
|
35
|
+
// Render the Ink app
|
|
36
|
+
const { unmount: inkUnmount } = render(createElement(App, { store }));
|
|
37
|
+
// Reset terminal colors on exit
|
|
38
|
+
const cleanup = () => {
|
|
39
|
+
process.stdout.write(OSC_FG_RESET + OSC_BG_RESET + RESET_ATTRS + CLEAR_SCREEN + CURSOR_HOME);
|
|
40
|
+
};
|
|
41
|
+
process.on('exit', cleanup);
|
|
42
|
+
return {
|
|
43
|
+
unmount: () => {
|
|
44
|
+
inkUnmount();
|
|
45
|
+
cleanup();
|
|
46
|
+
},
|
|
47
|
+
store,
|
|
48
|
+
waitForSetup: () => store.setupComplete,
|
|
49
|
+
};
|
|
50
|
+
}
|