@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,1217 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared agent interface for Amplitude wizards
|
|
4
|
+
* Uses Claude Agent SDK directly with Amplitude LLM gateway
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
40
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
41
|
+
};
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.AgentErrorType = exports.AgentSignals = void 0;
|
|
44
|
+
exports.checkClaudeSettingsOverrides = checkClaudeSettingsOverrides;
|
|
45
|
+
exports.backupAndFixClaudeSettings = backupAndFixClaudeSettings;
|
|
46
|
+
exports.restoreClaudeSettings = restoreClaudeSettings;
|
|
47
|
+
exports.createStopHook = createStopHook;
|
|
48
|
+
exports.buildWizardMetadata = buildWizardMetadata;
|
|
49
|
+
exports.isSkillInstallCommand = isSkillInstallCommand;
|
|
50
|
+
exports.matchesAllowedPrefix = matchesAllowedPrefix;
|
|
51
|
+
exports.wizardCanUseTool = wizardCanUseTool;
|
|
52
|
+
exports.initializeAgent = initializeAgent;
|
|
53
|
+
exports.getAgent = getAgent;
|
|
54
|
+
exports.runAgentLocally = runAgentLocally;
|
|
55
|
+
exports.runAgent = runAgent;
|
|
56
|
+
const path_1 = __importDefault(require("path"));
|
|
57
|
+
const fs = __importStar(require("fs"));
|
|
58
|
+
const ui_1 = require("../ui");
|
|
59
|
+
const debug_1 = require("../utils/debug");
|
|
60
|
+
const analytics_1 = require("../utils/analytics");
|
|
61
|
+
const constants_1 = require("./constants");
|
|
62
|
+
const wizard_session_1 = require("./wizard-session");
|
|
63
|
+
const wizard_abort_1 = require("../utils/wizard-abort");
|
|
64
|
+
const custom_headers_1 = require("../utils/custom-headers");
|
|
65
|
+
const urls_1 = require("../utils/urls");
|
|
66
|
+
const ampli_settings_1 = require("../utils/ampli-settings");
|
|
67
|
+
const safe_tools_1 = require("./safe-tools");
|
|
68
|
+
const wizard_tools_1 = require("./wizard-tools");
|
|
69
|
+
const commandments_1 = require("./commandments");
|
|
70
|
+
const zod_1 = require("zod");
|
|
71
|
+
const schemas_1 = require("./middleware/schemas");
|
|
72
|
+
const agent_hooks_1 = require("./agent-hooks");
|
|
73
|
+
// Dynamic import cache for ESM module
|
|
74
|
+
let _sdkModule = null;
|
|
75
|
+
async function getSDKModule() {
|
|
76
|
+
if (!_sdkModule) {
|
|
77
|
+
const mod = await import('@anthropic-ai/claude-agent-sdk');
|
|
78
|
+
_sdkModule = { query: mod.query };
|
|
79
|
+
}
|
|
80
|
+
return _sdkModule;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get the path to the bundled Claude Code CLI from the SDK package.
|
|
84
|
+
* This ensures we use the SDK's bundled version rather than the user's installed Claude Code.
|
|
85
|
+
*/
|
|
86
|
+
function getClaudeCodeExecutablePath() {
|
|
87
|
+
// require.resolve finds the package's main entry, then we get cli.js from same dir
|
|
88
|
+
const sdkPackagePath = require.resolve('@anthropic-ai/claude-agent-sdk');
|
|
89
|
+
return path_1.default.join(path_1.default.dirname(sdkPackagePath), 'cli.js');
|
|
90
|
+
}
|
|
91
|
+
exports.AgentSignals = {
|
|
92
|
+
/** Signal emitted when the agent reports progress to the user */
|
|
93
|
+
STATUS: '[STATUS]',
|
|
94
|
+
/** Signal emitted when the agent cannot access the Amplitude MCP server */
|
|
95
|
+
ERROR_MCP_MISSING: '[ERROR-MCP-MISSING]',
|
|
96
|
+
/** Signal emitted when the agent cannot access the setup resource */
|
|
97
|
+
ERROR_RESOURCE_MISSING: '[ERROR-RESOURCE-MISSING]',
|
|
98
|
+
/** Signal emitted when the agent provides a remark about its run */
|
|
99
|
+
WIZARD_REMARK: '[WIZARD-REMARK]',
|
|
100
|
+
/** Signal prefix for benchmark logging */
|
|
101
|
+
BENCHMARK: '[BENCHMARK]',
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Error types that can be returned from agent execution.
|
|
105
|
+
* These correspond to the error signals that the agent emits.
|
|
106
|
+
*/
|
|
107
|
+
var AgentErrorType;
|
|
108
|
+
(function (AgentErrorType) {
|
|
109
|
+
/** Agent could not access the Amplitude MCP server */
|
|
110
|
+
AgentErrorType["MCP_MISSING"] = "WIZARD_MCP_MISSING";
|
|
111
|
+
/** Agent could not access the setup resource */
|
|
112
|
+
AgentErrorType["RESOURCE_MISSING"] = "WIZARD_RESOURCE_MISSING";
|
|
113
|
+
/** API rate limit exceeded */
|
|
114
|
+
AgentErrorType["RATE_LIMIT"] = "WIZARD_RATE_LIMIT";
|
|
115
|
+
/** Generic API error */
|
|
116
|
+
AgentErrorType["API_ERROR"] = "WIZARD_API_ERROR";
|
|
117
|
+
/** Authentication failed — bearer token invalid or expired */
|
|
118
|
+
AgentErrorType["AUTH_ERROR"] = "WIZARD_AUTH_ERROR";
|
|
119
|
+
})(AgentErrorType || (exports.AgentErrorType = AgentErrorType = {}));
|
|
120
|
+
const BLOCKING_ENV_KEYS = ['ANTHROPIC_BASE_URL', 'ANTHROPIC_AUTH_TOKEN'];
|
|
121
|
+
/**
|
|
122
|
+
* Check if .claude/settings.json in the project directory contains env
|
|
123
|
+
* overrides for blocking keys that block the Wizard from accessing the Amplitude LLM Gateway.
|
|
124
|
+
* Returns the list of matched key names, or an empty array if none found.
|
|
125
|
+
*/
|
|
126
|
+
function checkClaudeSettingsOverrides(workingDirectory) {
|
|
127
|
+
const candidates = [
|
|
128
|
+
path_1.default.join(workingDirectory, '.claude', 'settings.json'),
|
|
129
|
+
path_1.default.join(workingDirectory, '.claude', 'settings'),
|
|
130
|
+
];
|
|
131
|
+
const claudeSettingsSchema = zod_1.z.object({
|
|
132
|
+
env: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()),
|
|
133
|
+
});
|
|
134
|
+
for (const filePath of candidates) {
|
|
135
|
+
try {
|
|
136
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
137
|
+
const result = claudeSettingsSchema.safeParse(JSON.parse(raw));
|
|
138
|
+
if (result.success) {
|
|
139
|
+
return BLOCKING_ENV_KEYS.filter((key) => key in result.data.env);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// File doesn't exist or isn't valid JSON — skip
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Copy .claude/settings.json to .wizard-backup (overwriting if it exists),
|
|
150
|
+
* then remove the original so the SDK doesn't load the blocking overrides.
|
|
151
|
+
*/
|
|
152
|
+
function backupAndFixClaudeSettings(workingDirectory) {
|
|
153
|
+
for (const name of ['settings.json', 'settings']) {
|
|
154
|
+
const filePath = path_1.default.join(workingDirectory, '.claude', name);
|
|
155
|
+
const backupPath = `${filePath}.wizard-backup`;
|
|
156
|
+
analytics_1.analytics.wizardCapture('backedup-claude-settings');
|
|
157
|
+
try {
|
|
158
|
+
fs.copyFileSync(filePath, backupPath);
|
|
159
|
+
fs.unlinkSync(filePath);
|
|
160
|
+
(0, wizard_abort_1.registerCleanup)(() => {
|
|
161
|
+
try {
|
|
162
|
+
restoreClaudeSettings(workingDirectory);
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
analytics_1.analytics.captureException(error instanceof Error ? error : new Error(String(error)));
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
// File doesn't exist — try next candidate
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Restore .claude/settings.json from .wizard-backup.
|
|
178
|
+
* Copies (not moves) so the backup is preserved.
|
|
179
|
+
*/
|
|
180
|
+
function restoreClaudeSettings(workingDirectory) {
|
|
181
|
+
for (const name of ['settings.json', 'settings']) {
|
|
182
|
+
const backup = path_1.default.join(workingDirectory, '.claude', `${name}.wizard-backup`);
|
|
183
|
+
try {
|
|
184
|
+
fs.copyFileSync(backup, path_1.default.join(workingDirectory, '.claude', name));
|
|
185
|
+
analytics_1.analytics.wizardCapture('restored-claude-settings');
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
analytics_1.analytics.captureException(error instanceof Error ? error : new Error(String(error)));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Create a stop hook callback that drains the additional feature queue,
|
|
195
|
+
* then collects a remark, then allows stop.
|
|
196
|
+
*
|
|
197
|
+
* Three-phase logic using closure state:
|
|
198
|
+
* Phase 1 — drain queue: block with each feature prompt in order
|
|
199
|
+
* Phase 2 — collect remark (once): block with remark prompt
|
|
200
|
+
* Phase 3 — allow stop: return {}
|
|
201
|
+
*
|
|
202
|
+
* If `isAuthError()` returns true, all phases are skipped and stop is
|
|
203
|
+
* allowed immediately — the agent cannot respond when auth has failed.
|
|
204
|
+
*/
|
|
205
|
+
function createStopHook(featureQueue, isAuthError = () => false) {
|
|
206
|
+
let featureIndex = 0;
|
|
207
|
+
let remarkRequested = false;
|
|
208
|
+
return (input) => {
|
|
209
|
+
const stop_hook_active = input.stop_hook_active;
|
|
210
|
+
(0, debug_1.logToFile)('Stop hook triggered', {
|
|
211
|
+
stop_hook_active,
|
|
212
|
+
featureIndex,
|
|
213
|
+
remarkRequested,
|
|
214
|
+
queueLength: featureQueue.length,
|
|
215
|
+
});
|
|
216
|
+
// If an auth error occurred, allow stop immediately — the agent cannot
|
|
217
|
+
// make further API calls to process feature prompts or reflection requests.
|
|
218
|
+
if (isAuthError()) {
|
|
219
|
+
(0, debug_1.logToFile)('Stop hook: allowing stop (auth error detected)');
|
|
220
|
+
return Promise.resolve({});
|
|
221
|
+
}
|
|
222
|
+
// Phase 1: drain feature queue
|
|
223
|
+
if (featureIndex < featureQueue.length) {
|
|
224
|
+
const feature = featureQueue[featureIndex++];
|
|
225
|
+
const prompt = wizard_session_1.ADDITIONAL_FEATURE_PROMPTS[feature];
|
|
226
|
+
(0, debug_1.logToFile)(`Stop hook: injecting feature prompt for ${feature}`);
|
|
227
|
+
return Promise.resolve({ decision: 'block', reason: prompt });
|
|
228
|
+
}
|
|
229
|
+
// Phase 2: collect remark (once)
|
|
230
|
+
if (!remarkRequested) {
|
|
231
|
+
remarkRequested = true;
|
|
232
|
+
(0, debug_1.logToFile)('Stop hook: requesting reflection');
|
|
233
|
+
return Promise.resolve({
|
|
234
|
+
decision: 'block',
|
|
235
|
+
reason: `Before concluding, provide a brief remark about what information or guidance would have been useful to have in the integration prompt or documentation for this run. Specifically cite anything that would have prevented tool failures, erroneous edits, or other wasted turns. Format your response exactly as: ${exports.AgentSignals.WIZARD_REMARK} Your remark here`,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
// Phase 3: allow stop
|
|
239
|
+
(0, debug_1.logToFile)('Stop hook: allowing stop');
|
|
240
|
+
return Promise.resolve({});
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
const GATEWAY_LIVENESS_TIMEOUT_MS = 8_000;
|
|
244
|
+
/**
|
|
245
|
+
* Ping the gateway URL with a short timeout.
|
|
246
|
+
* Any HTTP response (even 4xx/5xx) means the gateway is reachable.
|
|
247
|
+
* A timeout or connection error means it's down.
|
|
248
|
+
*/
|
|
249
|
+
async function checkGatewayLiveness(gatewayUrl) {
|
|
250
|
+
const controller = new AbortController();
|
|
251
|
+
const id = setTimeout(() => controller.abort(), GATEWAY_LIVENESS_TIMEOUT_MS);
|
|
252
|
+
try {
|
|
253
|
+
await fetch(gatewayUrl, { method: 'HEAD', signal: controller.signal });
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
finally {
|
|
260
|
+
clearTimeout(id);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Select wizard metadata from WIZARD_VARIANTS using the variant feature flag.
|
|
265
|
+
* If the flag is missing or the value is not in config, returns the "base" variant (VARIANT: "base").
|
|
266
|
+
*/
|
|
267
|
+
function buildWizardMetadata(flags = {}) {
|
|
268
|
+
const variantKey = flags[constants_1.WIZARD_VARIANT_FLAG_KEY];
|
|
269
|
+
const variant = (variantKey && constants_1.WIZARD_VARIANTS[variantKey]) ?? constants_1.WIZARD_VARIANTS['base'];
|
|
270
|
+
return { ...variant };
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Build env for the SDK subprocess: process.env plus ANTHROPIC_CUSTOM_HEADERS from wizard metadata/flags.
|
|
274
|
+
*/
|
|
275
|
+
function buildAgentEnv(wizardMetadata, wizardFlags) {
|
|
276
|
+
const headers = (0, custom_headers_1.createCustomHeaders)();
|
|
277
|
+
for (const [key, value] of Object.entries(wizardMetadata)) {
|
|
278
|
+
headers.add(key.startsWith(constants_1.AMPLITUDE_PROPERTY_HEADER_PREFIX)
|
|
279
|
+
? key
|
|
280
|
+
: `${constants_1.AMPLITUDE_PROPERTY_HEADER_PREFIX}${key}`, value);
|
|
281
|
+
}
|
|
282
|
+
for (const [flagKey, variant] of Object.entries(wizardFlags)) {
|
|
283
|
+
if (!flagKey.toLowerCase().startsWith('wizard'))
|
|
284
|
+
continue;
|
|
285
|
+
headers.addFlag(flagKey, variant);
|
|
286
|
+
}
|
|
287
|
+
const encoded = headers.encode();
|
|
288
|
+
(0, debug_1.logToFile)('ANTHROPIC_CUSTOM_HEADERS', encoded);
|
|
289
|
+
return encoded;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Executables that can be used to run build commands.
|
|
293
|
+
* Includes package managers, language build tools, and static site generators.
|
|
294
|
+
*/
|
|
295
|
+
const PACKAGE_MANAGERS = [
|
|
296
|
+
// JavaScript / Node
|
|
297
|
+
'npm',
|
|
298
|
+
'pnpm',
|
|
299
|
+
'yarn',
|
|
300
|
+
'bun',
|
|
301
|
+
'npx',
|
|
302
|
+
'deno',
|
|
303
|
+
// Python
|
|
304
|
+
'pip',
|
|
305
|
+
'pip3',
|
|
306
|
+
'poetry',
|
|
307
|
+
'pipenv',
|
|
308
|
+
'uv',
|
|
309
|
+
// Ruby
|
|
310
|
+
'gem',
|
|
311
|
+
'bundle',
|
|
312
|
+
'bundler',
|
|
313
|
+
'rake',
|
|
314
|
+
// PHP
|
|
315
|
+
'composer',
|
|
316
|
+
// Go
|
|
317
|
+
'go',
|
|
318
|
+
// Rust
|
|
319
|
+
'cargo',
|
|
320
|
+
// Java / Kotlin / Android
|
|
321
|
+
'gradle',
|
|
322
|
+
'./gradlew',
|
|
323
|
+
'mvn',
|
|
324
|
+
'./mvnw',
|
|
325
|
+
// .NET
|
|
326
|
+
'dotnet',
|
|
327
|
+
// Swift
|
|
328
|
+
'swift',
|
|
329
|
+
// Haskell
|
|
330
|
+
'stack',
|
|
331
|
+
'cabal',
|
|
332
|
+
// Elixir
|
|
333
|
+
'mix',
|
|
334
|
+
// Flutter / Dart
|
|
335
|
+
'flutter',
|
|
336
|
+
'dart',
|
|
337
|
+
// Make
|
|
338
|
+
'make',
|
|
339
|
+
// Static site generators
|
|
340
|
+
'zola',
|
|
341
|
+
'hugo',
|
|
342
|
+
'jekyll',
|
|
343
|
+
'eleventy',
|
|
344
|
+
'hexo',
|
|
345
|
+
'pelican',
|
|
346
|
+
'mkdocs',
|
|
347
|
+
];
|
|
348
|
+
/**
|
|
349
|
+
* Commands that are safe to run with no sub-command (the executable alone builds the project).
|
|
350
|
+
*/
|
|
351
|
+
const STANDALONE_BUILD_COMMANDS = ['hugo', 'make', 'eleventy'];
|
|
352
|
+
/**
|
|
353
|
+
* Safe sub-commands/scripts that can be run with any executable in PACKAGE_MANAGERS.
|
|
354
|
+
* Uses startsWith matching, so 'build' matches 'build', 'build:prod', etc.
|
|
355
|
+
* Note: Linting tools are in LINTING_TOOLS and checked separately.
|
|
356
|
+
*/
|
|
357
|
+
const SAFE_SCRIPTS = [
|
|
358
|
+
// Package / dependency installation
|
|
359
|
+
'install',
|
|
360
|
+
'add',
|
|
361
|
+
'ci',
|
|
362
|
+
'get',
|
|
363
|
+
'restore',
|
|
364
|
+
'fetch',
|
|
365
|
+
'deps',
|
|
366
|
+
'update',
|
|
367
|
+
// Build / compile / generate
|
|
368
|
+
'build',
|
|
369
|
+
'compile',
|
|
370
|
+
'assemble',
|
|
371
|
+
'package',
|
|
372
|
+
'generate',
|
|
373
|
+
'bundle',
|
|
374
|
+
// Type checking (various naming conventions)
|
|
375
|
+
'tsc',
|
|
376
|
+
'typecheck',
|
|
377
|
+
'type-check',
|
|
378
|
+
'check-types',
|
|
379
|
+
'types',
|
|
380
|
+
// Check / verify
|
|
381
|
+
'check',
|
|
382
|
+
// Test
|
|
383
|
+
'test',
|
|
384
|
+
// Serve (for build verification with static site tools)
|
|
385
|
+
'serve',
|
|
386
|
+
// Module / dependency management sub-commands
|
|
387
|
+
'mod',
|
|
388
|
+
'pub',
|
|
389
|
+
// Make targets
|
|
390
|
+
'all',
|
|
391
|
+
// Linting/formatting script names (actual tools are in LINTING_TOOLS)
|
|
392
|
+
'lint',
|
|
393
|
+
'format',
|
|
394
|
+
];
|
|
395
|
+
/**
|
|
396
|
+
* Dangerous shell operators that could allow command injection.
|
|
397
|
+
* Note: We handle `2>&1` and `| tail/head` separately as safe patterns.
|
|
398
|
+
* Note: `&&` is allowed for specific safe patterns like skill installation.
|
|
399
|
+
*/
|
|
400
|
+
const DANGEROUS_OPERATORS = /[;`$()]/;
|
|
401
|
+
/**
|
|
402
|
+
* Check if command is a Amplitude skill installation from MCP.
|
|
403
|
+
* We control the MCP server, so we only need to verify:
|
|
404
|
+
* 1. It installs to .claude/skills/
|
|
405
|
+
* 2. It downloads from our GitHub releases or localhost (dev)
|
|
406
|
+
*/
|
|
407
|
+
function isSkillInstallCommand(command) {
|
|
408
|
+
if (!command.startsWith('mkdir -p .claude/skills/'))
|
|
409
|
+
return false;
|
|
410
|
+
const urlMatch = command.match(/curl -sL ['"]([^'"]+)['"]/);
|
|
411
|
+
if (!urlMatch)
|
|
412
|
+
return false;
|
|
413
|
+
const url = urlMatch[1];
|
|
414
|
+
return (url.startsWith('https://github.com/Amplitude/context-mill/releases/') ||
|
|
415
|
+
/^http:\/\/localhost:\d+\//.test(url));
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Check if command is an allowed package manager command.
|
|
419
|
+
* Matches: <pkg-manager> [run|exec] <safe-script> [args...]
|
|
420
|
+
*/
|
|
421
|
+
function matchesAllowedPrefix(command) {
|
|
422
|
+
const parts = command.split(/\s+/);
|
|
423
|
+
if (parts.length === 0 || !PACKAGE_MANAGERS.includes(parts[0])) {
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
// Allow tools that are safe to invoke with no sub-command (e.g. `hugo`, `make`)
|
|
427
|
+
if (parts.length === 1 && STANDALONE_BUILD_COMMANDS.includes(parts[0])) {
|
|
428
|
+
return true;
|
|
429
|
+
}
|
|
430
|
+
// Skip 'run' or 'exec' if present
|
|
431
|
+
let scriptIndex = 1;
|
|
432
|
+
if (parts[scriptIndex] === 'run' || parts[scriptIndex] === 'exec') {
|
|
433
|
+
scriptIndex++;
|
|
434
|
+
}
|
|
435
|
+
// Get the script/command portion (may include args)
|
|
436
|
+
const scriptPart = parts.slice(scriptIndex).join(' ');
|
|
437
|
+
// Check if script starts with any safe script name or linting tool
|
|
438
|
+
return (SAFE_SCRIPTS.some((safe) => scriptPart.startsWith(safe)) ||
|
|
439
|
+
safe_tools_1.LINTING_TOOLS.some((tool) => scriptPart.startsWith(tool)));
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Permission hook that allows only safe commands.
|
|
443
|
+
* - Package manager install commands
|
|
444
|
+
* - Build/typecheck/lint commands for verification
|
|
445
|
+
* - Piping to tail/head for output limiting is allowed
|
|
446
|
+
* - Stderr redirection (2>&1) is allowed
|
|
447
|
+
* - Amplitude skill installation commands from MCP
|
|
448
|
+
*/
|
|
449
|
+
function wizardCanUseTool(toolName, input) {
|
|
450
|
+
// Block direct reads/writes of .env files — use wizard-tools MCP instead
|
|
451
|
+
if (toolName === 'Read' || toolName === 'Write' || toolName === 'Edit') {
|
|
452
|
+
const filePath = typeof input.file_path === 'string' ? input.file_path : '';
|
|
453
|
+
const basename = path_1.default.basename(filePath);
|
|
454
|
+
if (basename.startsWith('.env')) {
|
|
455
|
+
(0, debug_1.logToFile)(`Denying ${toolName} on env file: ${filePath}`);
|
|
456
|
+
return {
|
|
457
|
+
behavior: 'deny',
|
|
458
|
+
message: `Direct ${toolName} of ${basename} is not allowed. Use the wizard-tools MCP server (check_env_keys / set_env_values) to read or modify environment variables.`,
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
return { behavior: 'allow', updatedInput: input };
|
|
462
|
+
}
|
|
463
|
+
// Block Grep when it directly targets a .env file.
|
|
464
|
+
// Note: ripgrep skips dotfiles (like .env*) by default during directory traversal,
|
|
465
|
+
// so broad searches like `Grep { path: "." }` are already safe.
|
|
466
|
+
if (toolName === 'Grep') {
|
|
467
|
+
const grepPath = typeof input.path === 'string' ? input.path : '';
|
|
468
|
+
if (grepPath && path_1.default.basename(grepPath).startsWith('.env')) {
|
|
469
|
+
(0, debug_1.logToFile)(`Denying Grep on env file: ${grepPath}`);
|
|
470
|
+
return {
|
|
471
|
+
behavior: 'deny',
|
|
472
|
+
message: `Grep on ${path_1.default.basename(grepPath)} is not allowed. Use the wizard-tools MCP server (check_env_keys) to check environment variables.`,
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
return { behavior: 'allow', updatedInput: input };
|
|
476
|
+
}
|
|
477
|
+
// Allow all other non-Bash tools
|
|
478
|
+
if (toolName !== 'Bash') {
|
|
479
|
+
return { behavior: 'allow', updatedInput: input };
|
|
480
|
+
}
|
|
481
|
+
const command = (typeof input.command === 'string' ? input.command : '').trim();
|
|
482
|
+
// Check for Amplitude skill installation command (before dangerous operator check)
|
|
483
|
+
// These commands use && chaining but are generated by MCP with a strict format
|
|
484
|
+
if (isSkillInstallCommand(command)) {
|
|
485
|
+
(0, debug_1.logToFile)(`Allowing skill installation command: ${command}`);
|
|
486
|
+
(0, debug_1.debug)(`Allowing skill installation command: ${command}`);
|
|
487
|
+
return { behavior: 'allow', updatedInput: input };
|
|
488
|
+
}
|
|
489
|
+
// Block definitely dangerous operators: ; ` $ ( )
|
|
490
|
+
if (DANGEROUS_OPERATORS.test(command)) {
|
|
491
|
+
(0, debug_1.logToFile)(`Denying bash command with dangerous operators: ${command}`);
|
|
492
|
+
(0, debug_1.debug)(`Denying bash command with dangerous operators: ${command}`);
|
|
493
|
+
analytics_1.analytics.wizardCapture('bash denied', {
|
|
494
|
+
reason: 'dangerous operators',
|
|
495
|
+
command,
|
|
496
|
+
});
|
|
497
|
+
return {
|
|
498
|
+
behavior: 'deny',
|
|
499
|
+
message: `Bash command not allowed. Shell operators like ; \` $ ( ) are not permitted.`,
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
// Normalize: remove safe stderr redirection (2>&1, 2>&2, etc.)
|
|
503
|
+
const normalized = command.replace(/\s*\d*>&\d+\s*/g, ' ').trim();
|
|
504
|
+
// Check for pipe to tail/head (safe output limiting)
|
|
505
|
+
const pipeMatch = normalized.match(/^(.+?)\s*\|\s*(tail|head)(\s+\S+)*\s*$/);
|
|
506
|
+
if (pipeMatch) {
|
|
507
|
+
const baseCommand = pipeMatch[1].trim();
|
|
508
|
+
// Block if base command has pipes or & (multiple chaining)
|
|
509
|
+
if (/[|&]/.test(baseCommand)) {
|
|
510
|
+
(0, debug_1.logToFile)(`Denying bash command with multiple pipes: ${command}`);
|
|
511
|
+
(0, debug_1.debug)(`Denying bash command with multiple pipes: ${command}`);
|
|
512
|
+
analytics_1.analytics.wizardCapture('bash denied', {
|
|
513
|
+
reason: 'multiple pipes',
|
|
514
|
+
command,
|
|
515
|
+
});
|
|
516
|
+
return {
|
|
517
|
+
behavior: 'deny',
|
|
518
|
+
message: `Bash command not allowed. Only single pipe to tail/head is permitted.`,
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
if (matchesAllowedPrefix(baseCommand)) {
|
|
522
|
+
(0, debug_1.logToFile)(`Allowing bash command with output limiter: ${command}`);
|
|
523
|
+
(0, debug_1.debug)(`Allowing bash command with output limiter: ${command}`);
|
|
524
|
+
return { behavior: 'allow', updatedInput: input };
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
// Block remaining pipes and & (not covered by tail/head case above)
|
|
528
|
+
if (/[|&]/.test(normalized)) {
|
|
529
|
+
(0, debug_1.logToFile)(`Denying bash command with pipe/&: ${command}`);
|
|
530
|
+
(0, debug_1.debug)(`Denying bash command with pipe/&: ${command}`);
|
|
531
|
+
analytics_1.analytics.wizardCapture('bash denied', {
|
|
532
|
+
reason: 'disallowed pipe',
|
|
533
|
+
command,
|
|
534
|
+
});
|
|
535
|
+
return {
|
|
536
|
+
behavior: 'deny',
|
|
537
|
+
message: `Bash command not allowed. Pipes are only permitted with tail/head for output limiting.`,
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
// Check if command starts with any allowed prefix (package manager commands)
|
|
541
|
+
if (matchesAllowedPrefix(normalized)) {
|
|
542
|
+
(0, debug_1.logToFile)(`Allowing bash command: ${command}`);
|
|
543
|
+
(0, debug_1.debug)(`Allowing bash command: ${command}`);
|
|
544
|
+
return { behavior: 'allow', updatedInput: input };
|
|
545
|
+
}
|
|
546
|
+
(0, debug_1.logToFile)(`Denying bash command: ${command}`);
|
|
547
|
+
(0, debug_1.debug)(`Denying bash command: ${command}`);
|
|
548
|
+
analytics_1.analytics.wizardCapture('bash denied', {
|
|
549
|
+
reason: 'not in allowlist',
|
|
550
|
+
command,
|
|
551
|
+
});
|
|
552
|
+
return {
|
|
553
|
+
behavior: 'deny',
|
|
554
|
+
message: `Bash command not allowed. Only install, build, typecheck, lint, and formatting commands are permitted.`,
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Initialize agent configuration for the LLM gateway
|
|
559
|
+
*/
|
|
560
|
+
async function initializeAgent(config, options) {
|
|
561
|
+
// Initialize log file for this run
|
|
562
|
+
(0, debug_1.initLogFile)();
|
|
563
|
+
(0, debug_1.logToFile)('Agent initialization starting');
|
|
564
|
+
(0, debug_1.logToFile)('Install directory:', options.installDir);
|
|
565
|
+
(0, ui_1.getUI)().log.step('Initializing Claude agent...');
|
|
566
|
+
try {
|
|
567
|
+
const useDirectApiKey = !!process.env.ANTHROPIC_API_KEY;
|
|
568
|
+
const useLocalClaude = !config.amplitudeBearerToken && !useDirectApiKey;
|
|
569
|
+
if (useDirectApiKey) {
|
|
570
|
+
(0, debug_1.logToFile)('ANTHROPIC_API_KEY found — bypassing Amplitude gateway');
|
|
571
|
+
}
|
|
572
|
+
else if (useLocalClaude) {
|
|
573
|
+
(0, debug_1.logToFile)('No Amplitude API key — using local claude CLI');
|
|
574
|
+
}
|
|
575
|
+
else {
|
|
576
|
+
// Configure LLM gateway environment variables (inherited by SDK subprocess)
|
|
577
|
+
const gatewayUrl = (0, urls_1.getLlmGatewayUrlFromHost)(config.amplitudeApiHost);
|
|
578
|
+
// Fail fast if the gateway isn't responding rather than hanging indefinitely
|
|
579
|
+
const alive = await checkGatewayLiveness(gatewayUrl);
|
|
580
|
+
if (!alive) {
|
|
581
|
+
throw new Error(`Could not reach the Amplitude LLM gateway (${gatewayUrl}). ` +
|
|
582
|
+
`Check your network connection, or set ANTHROPIC_API_KEY to use the Anthropic API directly.`);
|
|
583
|
+
}
|
|
584
|
+
process.env.ANTHROPIC_BASE_URL = gatewayUrl;
|
|
585
|
+
process.env.ANTHROPIC_AUTH_TOKEN = config.amplitudeBearerToken;
|
|
586
|
+
// Use CLAUDE_CODE_OAUTH_TOKEN to override any stored /login credentials
|
|
587
|
+
process.env.CLAUDE_CODE_OAUTH_TOKEN = config.amplitudeBearerToken;
|
|
588
|
+
// Disable experimental betas (like input_examples) that the LLM gateway doesn't support
|
|
589
|
+
process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS = 'true';
|
|
590
|
+
(0, debug_1.logToFile)('Configured LLM gateway:', gatewayUrl);
|
|
591
|
+
}
|
|
592
|
+
// Configure MCP servers
|
|
593
|
+
const mcpServers = {};
|
|
594
|
+
if (!config.skipAmplitudeMcp) {
|
|
595
|
+
mcpServers['amplitude-wizard'] = {
|
|
596
|
+
type: 'http',
|
|
597
|
+
url: config.amplitudeMcpUrl,
|
|
598
|
+
headers: {
|
|
599
|
+
Authorization: `Bearer ${config.amplitudeBearerToken}`,
|
|
600
|
+
'User-Agent': constants_1.WIZARD_USER_AGENT,
|
|
601
|
+
},
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
for (const [name, { url }] of Object.entries(config.additionalMcpServers ?? {})) {
|
|
605
|
+
mcpServers[name] = { type: 'http', url };
|
|
606
|
+
}
|
|
607
|
+
// Add in-process wizard tools (env files, package manager detection)
|
|
608
|
+
const wizardToolsServer = await (0, wizard_tools_1.createWizardToolsServer)({
|
|
609
|
+
workingDirectory: config.workingDirectory,
|
|
610
|
+
detectPackageManager: config.detectPackageManager,
|
|
611
|
+
skillsBaseUrl: config.skillsBaseUrl,
|
|
612
|
+
});
|
|
613
|
+
mcpServers['wizard-tools'] = wizardToolsServer;
|
|
614
|
+
const agentRunConfig = {
|
|
615
|
+
workingDirectory: config.workingDirectory,
|
|
616
|
+
mcpServers,
|
|
617
|
+
// Gateway expects 'anthropic/claude-sonnet-4-6'; direct Anthropic API expects 'claude-sonnet-4-6'
|
|
618
|
+
model: useDirectApiKey
|
|
619
|
+
? 'claude-sonnet-4-6'
|
|
620
|
+
: 'anthropic/claude-sonnet-4-6',
|
|
621
|
+
wizardFlags: config.wizardFlags,
|
|
622
|
+
wizardMetadata: config.wizardMetadata,
|
|
623
|
+
useLocalClaude,
|
|
624
|
+
useDirectApiKey,
|
|
625
|
+
};
|
|
626
|
+
(0, debug_1.logToFile)('Agent config:', {
|
|
627
|
+
workingDirectory: agentRunConfig.workingDirectory,
|
|
628
|
+
amplitudeMcpUrl: config.amplitudeMcpUrl,
|
|
629
|
+
useLocalClaude,
|
|
630
|
+
useDirectApiKey,
|
|
631
|
+
bearerTokenPresent: !!config.amplitudeBearerToken,
|
|
632
|
+
});
|
|
633
|
+
if (options.debug) {
|
|
634
|
+
(0, debug_1.debug)('Agent config:', {
|
|
635
|
+
workingDirectory: agentRunConfig.workingDirectory,
|
|
636
|
+
amplitudeMcpUrl: config.amplitudeMcpUrl,
|
|
637
|
+
useLocalClaude,
|
|
638
|
+
useDirectApiKey,
|
|
639
|
+
bearerTokenPresent: !!config.amplitudeBearerToken,
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
(0, ui_1.getUI)().log.step(`Verbose logs: ${(0, debug_1.getLogFilePath)()}`);
|
|
643
|
+
(0, ui_1.getUI)().log.success("Agent initialized. Let's get cooking!");
|
|
644
|
+
return agentRunConfig;
|
|
645
|
+
}
|
|
646
|
+
catch (error) {
|
|
647
|
+
(0, debug_1.logToFile)('Agent initialization error:', error);
|
|
648
|
+
(0, debug_1.debug)('Agent initialization error:', error);
|
|
649
|
+
throw error;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
let _agentPromise = null;
|
|
653
|
+
function buildDefaultAgentConfig() {
|
|
654
|
+
const storedToken = (0, ampli_settings_1.getStoredToken)()?.accessToken ?? '';
|
|
655
|
+
const host = (0, urls_1.getHostFromRegion)('us');
|
|
656
|
+
const mcpUrl = process.env.MCP_URL ?? 'https://mcp.amplitude.com/mcp';
|
|
657
|
+
return {
|
|
658
|
+
workingDirectory: process.cwd(),
|
|
659
|
+
amplitudeMcpUrl: mcpUrl,
|
|
660
|
+
amplitudeApiKey: storedToken,
|
|
661
|
+
amplitudeBearerToken: storedToken,
|
|
662
|
+
amplitudeApiHost: host,
|
|
663
|
+
skipAmplitudeMcp: !storedToken,
|
|
664
|
+
detectPackageManager: () => Promise.resolve({ detected: [], primary: null, recommendation: '' }),
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
const DEFAULT_WIZARD_OPTIONS = {
|
|
668
|
+
debug: false,
|
|
669
|
+
forceInstall: false,
|
|
670
|
+
installDir: process.cwd(),
|
|
671
|
+
default: false,
|
|
672
|
+
signup: false,
|
|
673
|
+
localMcp: false,
|
|
674
|
+
ci: false,
|
|
675
|
+
menu: false,
|
|
676
|
+
benchmark: false,
|
|
677
|
+
};
|
|
678
|
+
/**
|
|
679
|
+
* Return the already-initialized agent config, or call initializeAgent to create it.
|
|
680
|
+
* Concurrent calls during initialization share the same Promise.
|
|
681
|
+
* On error the cached Promise is cleared so the next call retries.
|
|
682
|
+
*
|
|
683
|
+
* Omitting config/options reads the bearer token from ~/.ampli.json and uses production
|
|
684
|
+
* defaults (MCP disabled if no token found, cwd as working directory).
|
|
685
|
+
*/
|
|
686
|
+
async function getAgent(config = buildDefaultAgentConfig(), options = DEFAULT_WIZARD_OPTIONS) {
|
|
687
|
+
if (!_agentPromise) {
|
|
688
|
+
_agentPromise = initializeAgent(config, options).catch((err) => {
|
|
689
|
+
_agentPromise = null;
|
|
690
|
+
throw err;
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
return _agentPromise;
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Run the agent by spawning the user's local `claude` CLI with --continue.
|
|
697
|
+
* Used when no Amplitude API key is present (local development).
|
|
698
|
+
* Streams stdout line-by-line and forwards text to the spinner.
|
|
699
|
+
*/
|
|
700
|
+
async function runAgentLocally(prompt, workingDirectory, spinner, successMessage, errorMessage) {
|
|
701
|
+
const { spawn } = await import('child_process');
|
|
702
|
+
(0, debug_1.logToFile)('Running agent via local claude CLI');
|
|
703
|
+
return new Promise((resolve, reject) => {
|
|
704
|
+
const proc = spawn('claude', ['--continue', prompt], {
|
|
705
|
+
cwd: workingDirectory,
|
|
706
|
+
env: process.env,
|
|
707
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
708
|
+
});
|
|
709
|
+
proc.stdout.setEncoding('utf8');
|
|
710
|
+
proc.stderr.setEncoding('utf8');
|
|
711
|
+
proc.stdout.on('data', (chunk) => {
|
|
712
|
+
const lines = chunk.split('\n').filter((l) => l.trim());
|
|
713
|
+
for (const line of lines) {
|
|
714
|
+
(0, debug_1.logToFile)('claude stdout:', line);
|
|
715
|
+
spinner.message(line.slice(0, 80));
|
|
716
|
+
(0, ui_1.getUI)().pushStatus(line.slice(0, 80));
|
|
717
|
+
}
|
|
718
|
+
});
|
|
719
|
+
proc.stderr.on('data', (chunk) => {
|
|
720
|
+
(0, debug_1.logToFile)('claude stderr:', chunk);
|
|
721
|
+
});
|
|
722
|
+
proc.on('close', (code) => {
|
|
723
|
+
if (code === 0) {
|
|
724
|
+
spinner.stop(successMessage);
|
|
725
|
+
resolve({});
|
|
726
|
+
}
|
|
727
|
+
else {
|
|
728
|
+
spinner.stop(errorMessage);
|
|
729
|
+
reject(new Error(`claude exited with code ${code ?? 'unknown'}`));
|
|
730
|
+
}
|
|
731
|
+
});
|
|
732
|
+
proc.on('error', (err) => {
|
|
733
|
+
spinner.stop(errorMessage);
|
|
734
|
+
reject(err);
|
|
735
|
+
});
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Execute an agent with the provided prompt and options
|
|
740
|
+
* Handles the full lifecycle: spinner, execution, error handling
|
|
741
|
+
*
|
|
742
|
+
* @returns An object containing any error detected in the agent's output
|
|
743
|
+
*/
|
|
744
|
+
async function runAgent(agentConfig, prompt, options, spinner, config, middleware) {
|
|
745
|
+
const { spinnerMessage = 'Customizing your Amplitude setup...', successMessage = 'Amplitude integration complete', errorMessage = 'Integration failed', } = config ?? {};
|
|
746
|
+
spinner.start(spinnerMessage);
|
|
747
|
+
if (agentConfig.useLocalClaude) {
|
|
748
|
+
return runAgentLocally(prompt, agentConfig.workingDirectory, spinner, successMessage, errorMessage);
|
|
749
|
+
}
|
|
750
|
+
const { query } = await getSDKModule();
|
|
751
|
+
const cliPath = getClaudeCodeExecutablePath();
|
|
752
|
+
(0, debug_1.logToFile)('Starting agent run');
|
|
753
|
+
(0, debug_1.logToFile)('Claude Code executable:', cliPath);
|
|
754
|
+
(0, debug_1.logToFile)('Prompt:', prompt);
|
|
755
|
+
const startTime = Date.now();
|
|
756
|
+
const collectedText = [];
|
|
757
|
+
const recentStatuses = []; // rolling last-3 STATUS messages for heartbeat
|
|
758
|
+
// Track if we received a successful result (before any cleanup errors)
|
|
759
|
+
let receivedSuccessResult = false;
|
|
760
|
+
let lastResultMessage = null;
|
|
761
|
+
// Workaround for SDK bug: stdin closes before canUseTool responses can be sent.
|
|
762
|
+
// The fix is to use an async generator for the prompt that stays open until
|
|
763
|
+
// the result is received, keeping the stdin stream alive for permission responses.
|
|
764
|
+
// signalDone is reassigned each retry attempt — the outer catch always has the latest.
|
|
765
|
+
// See: https://github.com/anthropics/claude-code/issues/4775
|
|
766
|
+
// See: https://github.com/anthropics/claude-agent-sdk-typescript/issues/41
|
|
767
|
+
let signalDone = Function.prototype;
|
|
768
|
+
// Helper to handle successful completion (used in normal path and race condition recovery)
|
|
769
|
+
const completeWithSuccess = (suppressedError) => {
|
|
770
|
+
const durationMs = Date.now() - startTime;
|
|
771
|
+
const durationSeconds = Math.round(durationMs / 1000);
|
|
772
|
+
if (suppressedError) {
|
|
773
|
+
(0, debug_1.logToFile)(`Ignoring post-completion error, agent completed successfully in ${durationSeconds}s`);
|
|
774
|
+
(0, debug_1.logToFile)('Suppressed error:', suppressedError.message);
|
|
775
|
+
}
|
|
776
|
+
else {
|
|
777
|
+
(0, debug_1.logToFile)(`Agent run completed in ${durationSeconds}s`);
|
|
778
|
+
}
|
|
779
|
+
// Extract and capture the agent's reflection on the run
|
|
780
|
+
const outputText = collectedText.join('\n');
|
|
781
|
+
const remarkRegex = new RegExp(`${exports.AgentSignals.WIZARD_REMARK.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*(.+?)(?:\\n|$)`, 's');
|
|
782
|
+
const remarkMatch = outputText.match(remarkRegex);
|
|
783
|
+
if (remarkMatch && remarkMatch[1]) {
|
|
784
|
+
const remark = remarkMatch[1].trim();
|
|
785
|
+
if (remark) {
|
|
786
|
+
analytics_1.analytics.capture(constants_1.WIZARD_REMARK_EVENT_NAME, { remark });
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
analytics_1.analytics.wizardCapture('agent completed', {
|
|
790
|
+
duration_ms: durationMs,
|
|
791
|
+
duration_seconds: durationSeconds,
|
|
792
|
+
});
|
|
793
|
+
try {
|
|
794
|
+
if (lastResultMessage) {
|
|
795
|
+
middleware?.finalize(lastResultMessage, durationMs);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
catch (e) {
|
|
799
|
+
(0, debug_1.logToFile)(`${exports.AgentSignals.BENCHMARK} Middleware finalize error:`, e);
|
|
800
|
+
}
|
|
801
|
+
spinner.stop(successMessage);
|
|
802
|
+
return {};
|
|
803
|
+
};
|
|
804
|
+
// Heartbeat interval — every 10s print the last 3 STATUS messages so the
|
|
805
|
+
// user can see progress in the CLI without waiting for the next update.
|
|
806
|
+
const heartbeatInterval = setInterval(() => {
|
|
807
|
+
if (recentStatuses.length > 0) {
|
|
808
|
+
(0, ui_1.getUI)().heartbeat([...recentStatuses]);
|
|
809
|
+
}
|
|
810
|
+
}, 10_000);
|
|
811
|
+
// Event plan file watcher — cleaned up in finally block
|
|
812
|
+
let eventPlanWatcher;
|
|
813
|
+
let eventPlanInterval;
|
|
814
|
+
try {
|
|
815
|
+
// Tools needed for the wizard:
|
|
816
|
+
// - File operations: Read, Write, Edit
|
|
817
|
+
// - Search: Glob, Grep
|
|
818
|
+
// - Commands: Bash (with restrictions via canUseTool)
|
|
819
|
+
// - MCP discovery: ListMcpResourcesTool (to find available skills)
|
|
820
|
+
// - Skills: Skill (to load installed Amplitude skills)
|
|
821
|
+
// MCP tools (Amplitude) come from mcpServers, not allowedTools
|
|
822
|
+
const allowedTools = [
|
|
823
|
+
'Read',
|
|
824
|
+
'Write',
|
|
825
|
+
'Edit',
|
|
826
|
+
'Glob',
|
|
827
|
+
'Grep',
|
|
828
|
+
'Bash',
|
|
829
|
+
'ListMcpResourcesTool',
|
|
830
|
+
'Skill',
|
|
831
|
+
...wizard_tools_1.WIZARD_TOOL_NAMES,
|
|
832
|
+
];
|
|
833
|
+
// Watch for .amplitude-events.json and feed into the store (set up once, before retries)
|
|
834
|
+
const eventPlanPath = path_1.default.join(agentConfig.workingDirectory, '.amplitude-events.json');
|
|
835
|
+
const eventPlanSchema = zod_1.z.array(zod_1.z.looseObject({
|
|
836
|
+
name: zod_1.z.string().optional(),
|
|
837
|
+
event: zod_1.z.string().optional(),
|
|
838
|
+
eventName: zod_1.z.string().optional(),
|
|
839
|
+
description: zod_1.z.string().optional(),
|
|
840
|
+
eventDescriptionAndReasoning: zod_1.z.string().optional(),
|
|
841
|
+
}));
|
|
842
|
+
const readEventPlan = () => {
|
|
843
|
+
try {
|
|
844
|
+
const content = fs.readFileSync(eventPlanPath, 'utf-8');
|
|
845
|
+
const result = eventPlanSchema.safeParse(JSON.parse(content));
|
|
846
|
+
if (result.success) {
|
|
847
|
+
(0, ui_1.getUI)().setEventPlan(result.data.map((e) => ({
|
|
848
|
+
name: e.name ?? e.event ?? e.eventName ?? '',
|
|
849
|
+
description: e.description ?? e.eventDescriptionAndReasoning ?? '',
|
|
850
|
+
})));
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
catch {
|
|
854
|
+
// File doesn't exist or isn't valid JSON yet
|
|
855
|
+
}
|
|
856
|
+
};
|
|
857
|
+
try {
|
|
858
|
+
eventPlanWatcher = fs.watch(eventPlanPath, () => readEventPlan());
|
|
859
|
+
readEventPlan();
|
|
860
|
+
}
|
|
861
|
+
catch {
|
|
862
|
+
// File doesn't exist yet — poll until it appears
|
|
863
|
+
eventPlanInterval = setInterval(() => {
|
|
864
|
+
try {
|
|
865
|
+
fs.accessSync(eventPlanPath);
|
|
866
|
+
readEventPlan();
|
|
867
|
+
clearInterval(eventPlanInterval);
|
|
868
|
+
eventPlanInterval = undefined;
|
|
869
|
+
eventPlanWatcher = fs.watch(eventPlanPath, () => readEventPlan());
|
|
870
|
+
}
|
|
871
|
+
catch {
|
|
872
|
+
// Still waiting
|
|
873
|
+
}
|
|
874
|
+
}, 1000);
|
|
875
|
+
}
|
|
876
|
+
// Retry loop: if the agent stalls (no message for STALL_TIMEOUT_MS), abort and
|
|
877
|
+
// re-run with a fresh AbortController and prompt stream. Up to MAX_RETRIES retries.
|
|
878
|
+
const MAX_RETRIES = 2;
|
|
879
|
+
const STALL_TIMEOUT_MS = 20_000;
|
|
880
|
+
// Tracks whether an authentication failure was detected in the current attempt.
|
|
881
|
+
// Passed to createStopHook so it can skip reflection when auth is broken.
|
|
882
|
+
let authErrorDetected = false;
|
|
883
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
884
|
+
if (attempt > 0) {
|
|
885
|
+
(0, debug_1.logToFile)(`Agent stall retry: attempt ${attempt + 1} of ${MAX_RETRIES + 1}`);
|
|
886
|
+
analytics_1.analytics.wizardCapture('agent stall retry', { attempt });
|
|
887
|
+
// Clear per-attempt output so stale error markers don't affect the fresh run
|
|
888
|
+
collectedText.length = 0;
|
|
889
|
+
recentStatuses.length = 0;
|
|
890
|
+
authErrorDetected = false;
|
|
891
|
+
}
|
|
892
|
+
// Fresh prompt stream per attempt — stdin stays open until result received
|
|
893
|
+
const resultReceived = new Promise((resolve) => {
|
|
894
|
+
signalDone = resolve;
|
|
895
|
+
});
|
|
896
|
+
const createPromptStream = async function* () {
|
|
897
|
+
yield {
|
|
898
|
+
type: 'user',
|
|
899
|
+
session_id: '',
|
|
900
|
+
message: { role: 'user', content: prompt },
|
|
901
|
+
parent_tool_use_id: null,
|
|
902
|
+
};
|
|
903
|
+
await resultReceived;
|
|
904
|
+
};
|
|
905
|
+
// AbortController lets us cancel a stalled query so we can retry
|
|
906
|
+
const controller = new AbortController();
|
|
907
|
+
let staleTimer;
|
|
908
|
+
const resetStaleTimer = () => {
|
|
909
|
+
if (staleTimer)
|
|
910
|
+
clearTimeout(staleTimer);
|
|
911
|
+
staleTimer = setTimeout(() => {
|
|
912
|
+
(0, debug_1.logToFile)(`Agent stalled — no message for ${STALL_TIMEOUT_MS / 1000}s (attempt ${attempt + 1})`);
|
|
913
|
+
analytics_1.analytics.wizardCapture('agent stall detected', {
|
|
914
|
+
attempt: attempt + 1,
|
|
915
|
+
stall_timeout_ms: STALL_TIMEOUT_MS,
|
|
916
|
+
});
|
|
917
|
+
controller.abort('stall');
|
|
918
|
+
}, STALL_TIMEOUT_MS);
|
|
919
|
+
};
|
|
920
|
+
try {
|
|
921
|
+
const response = query({
|
|
922
|
+
prompt: createPromptStream(),
|
|
923
|
+
options: {
|
|
924
|
+
model: agentConfig.model,
|
|
925
|
+
cwd: agentConfig.workingDirectory,
|
|
926
|
+
permissionMode: 'acceptEdits',
|
|
927
|
+
mcpServers: agentConfig.mcpServers,
|
|
928
|
+
// Load skills from project's .claude/skills/ directory
|
|
929
|
+
settingSources: ['project'],
|
|
930
|
+
// Explicitly enable required tools including Skill
|
|
931
|
+
allowedTools,
|
|
932
|
+
systemPrompt: {
|
|
933
|
+
type: 'preset',
|
|
934
|
+
preset: 'claude_code',
|
|
935
|
+
// Append wizard-wide commandments (from YAML) rather than replacing
|
|
936
|
+
// the preset so we keep default Claude Code behaviors.
|
|
937
|
+
append: (0, commandments_1.getWizardCommandments)(),
|
|
938
|
+
},
|
|
939
|
+
env: {
|
|
940
|
+
...process.env,
|
|
941
|
+
// When using the Amplitude gateway, block ANTHROPIC_API_KEY so it doesn't
|
|
942
|
+
// override the gateway's OAuth token. When using a direct API key, pass it through.
|
|
943
|
+
...(agentConfig.useDirectApiKey
|
|
944
|
+
? {}
|
|
945
|
+
: { ANTHROPIC_API_KEY: undefined }),
|
|
946
|
+
ANTHROPIC_CUSTOM_HEADERS: buildAgentEnv(agentConfig.wizardMetadata ?? {}, agentConfig.wizardFlags ?? {}),
|
|
947
|
+
},
|
|
948
|
+
canUseTool: (toolName, input) => {
|
|
949
|
+
(0, debug_1.logToFile)('canUseTool called:', { toolName, input });
|
|
950
|
+
const result = wizardCanUseTool(toolName, input);
|
|
951
|
+
(0, debug_1.logToFile)('canUseTool result:', result);
|
|
952
|
+
return Promise.resolve(result);
|
|
953
|
+
},
|
|
954
|
+
tools: { type: 'preset', preset: 'claude_code' },
|
|
955
|
+
// Capture stderr from CLI subprocess for debugging
|
|
956
|
+
stderr: (data) => {
|
|
957
|
+
(0, debug_1.logToFile)('CLI stderr:', data);
|
|
958
|
+
if (options.debug) {
|
|
959
|
+
(0, debug_1.debug)('CLI stderr:', data);
|
|
960
|
+
}
|
|
961
|
+
},
|
|
962
|
+
hooks: (0, agent_hooks_1.buildHooksConfig)({
|
|
963
|
+
Stop: createStopHook(config?.additionalFeatureQueue ?? [], () => authErrorDetected),
|
|
964
|
+
}),
|
|
965
|
+
// Allow aborting a stalled query so we can retry cleanly
|
|
966
|
+
abortSignal: controller.signal,
|
|
967
|
+
},
|
|
968
|
+
});
|
|
969
|
+
// Start stale timer — reset on each received message
|
|
970
|
+
resetStaleTimer();
|
|
971
|
+
// Process the async generator — validate each message at the boundary
|
|
972
|
+
for await (const rawMessage of response) {
|
|
973
|
+
resetStaleTimer();
|
|
974
|
+
const parsed = (0, schemas_1.safeParseSDKMessage)(rawMessage);
|
|
975
|
+
if (!parsed.ok) {
|
|
976
|
+
(0, debug_1.logToFile)('Skipping malformed SDK message:', parsed.error.issues.map((i) => `${i.path.join('.')}: ${i.message}`));
|
|
977
|
+
continue;
|
|
978
|
+
}
|
|
979
|
+
const message = parsed.message;
|
|
980
|
+
// Pass receivedSuccessResult so handleSDKMessage can suppress user-facing error
|
|
981
|
+
// output for post-success cleanup errors while still logging them to file
|
|
982
|
+
handleSDKMessage(message, options, spinner, collectedText, receivedSuccessResult, recentStatuses);
|
|
983
|
+
try {
|
|
984
|
+
middleware?.onMessage(message);
|
|
985
|
+
}
|
|
986
|
+
catch (e) {
|
|
987
|
+
(0, debug_1.logToFile)(`${exports.AgentSignals.BENCHMARK} Middleware onMessage error:`, e);
|
|
988
|
+
}
|
|
989
|
+
// Detect authentication failures so the stop hook can skip reflection
|
|
990
|
+
if (message.type === 'result' &&
|
|
991
|
+
message.is_error &&
|
|
992
|
+
JSON.stringify(message).includes('authentication_failed')) {
|
|
993
|
+
authErrorDetected = true;
|
|
994
|
+
(0, debug_1.logToFile)('Auth error detected: authentication_failed in result');
|
|
995
|
+
}
|
|
996
|
+
if (message.type === 'system' && message.subtype === 'init') {
|
|
997
|
+
for (const server of message.mcp_servers ?? []) {
|
|
998
|
+
if (server.name === 'amplitude-wizard' &&
|
|
999
|
+
server.status === 'needs-auth') {
|
|
1000
|
+
authErrorDetected = true;
|
|
1001
|
+
(0, debug_1.logToFile)('Auth error detected: amplitude-wizard MCP needs-auth');
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
// Signal completion when result received
|
|
1006
|
+
if (message.type === 'result') {
|
|
1007
|
+
// Track successful results before any potential cleanup errors
|
|
1008
|
+
// The SDK may emit a second error result during cleanup due to a race condition
|
|
1009
|
+
if (message.subtype === 'success' && !message.is_error) {
|
|
1010
|
+
receivedSuccessResult = true;
|
|
1011
|
+
lastResultMessage = message;
|
|
1012
|
+
}
|
|
1013
|
+
signalDone();
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
// Clean completion — exit the retry loop
|
|
1017
|
+
clearTimeout(staleTimer);
|
|
1018
|
+
break;
|
|
1019
|
+
}
|
|
1020
|
+
catch (innerError) {
|
|
1021
|
+
clearTimeout(staleTimer);
|
|
1022
|
+
signalDone(); // unblock the prompt stream for this attempt
|
|
1023
|
+
// Stall-aborted with retries remaining — try again
|
|
1024
|
+
if (controller.signal.aborted && attempt < MAX_RETRIES) {
|
|
1025
|
+
(0, debug_1.logToFile)(`Retrying after stall (next attempt: ${attempt + 2} of ${MAX_RETRIES + 1})`);
|
|
1026
|
+
continue;
|
|
1027
|
+
}
|
|
1028
|
+
// Already received a successful result — this is an SDK cleanup race condition
|
|
1029
|
+
if (receivedSuccessResult) {
|
|
1030
|
+
return completeWithSuccess(innerError);
|
|
1031
|
+
}
|
|
1032
|
+
// Re-throw to the outer catch for API error handling / spinner cleanup
|
|
1033
|
+
throw innerError;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
const outputText = collectedText.join('\n');
|
|
1037
|
+
// Auth error takes priority — the agent cannot recover without re-authentication
|
|
1038
|
+
if (authErrorDetected) {
|
|
1039
|
+
(0, debug_1.logToFile)('Agent error: AUTH_ERROR');
|
|
1040
|
+
spinner.stop('Authentication failed');
|
|
1041
|
+
return { error: AgentErrorType.AUTH_ERROR };
|
|
1042
|
+
}
|
|
1043
|
+
// Check for error markers in the agent's output
|
|
1044
|
+
if (outputText.includes(exports.AgentSignals.ERROR_MCP_MISSING)) {
|
|
1045
|
+
(0, debug_1.logToFile)('Agent error: MCP_MISSING');
|
|
1046
|
+
spinner.stop('Agent could not access Amplitude MCP');
|
|
1047
|
+
return { error: AgentErrorType.MCP_MISSING };
|
|
1048
|
+
}
|
|
1049
|
+
if (outputText.includes(exports.AgentSignals.ERROR_RESOURCE_MISSING)) {
|
|
1050
|
+
(0, debug_1.logToFile)('Agent error: RESOURCE_MISSING');
|
|
1051
|
+
spinner.stop('Agent could not access setup resource');
|
|
1052
|
+
return { error: AgentErrorType.RESOURCE_MISSING };
|
|
1053
|
+
}
|
|
1054
|
+
// Check for API errors (rate limits, etc.)
|
|
1055
|
+
// Extract just the API error line(s), not the entire output
|
|
1056
|
+
const apiErrorMatch = outputText.match(/API Error: [^\n]+/g);
|
|
1057
|
+
const apiErrorMessage = apiErrorMatch
|
|
1058
|
+
? apiErrorMatch.join('\n')
|
|
1059
|
+
: 'Unknown API error';
|
|
1060
|
+
if (outputText.includes('API Error: 429')) {
|
|
1061
|
+
(0, debug_1.logToFile)('Agent error: RATE_LIMIT');
|
|
1062
|
+
spinner.stop('Rate limit exceeded');
|
|
1063
|
+
return { error: AgentErrorType.RATE_LIMIT, message: apiErrorMessage };
|
|
1064
|
+
}
|
|
1065
|
+
if (outputText.includes('API Error:')) {
|
|
1066
|
+
(0, debug_1.logToFile)('Agent error: API_ERROR');
|
|
1067
|
+
spinner.stop('API error occurred');
|
|
1068
|
+
return { error: AgentErrorType.API_ERROR, message: apiErrorMessage };
|
|
1069
|
+
}
|
|
1070
|
+
return completeWithSuccess();
|
|
1071
|
+
}
|
|
1072
|
+
catch (error) {
|
|
1073
|
+
// Signal done to unblock the async generator
|
|
1074
|
+
signalDone();
|
|
1075
|
+
// If we already received a successful result, the error is from SDK cleanup
|
|
1076
|
+
// This happens due to a race condition: the SDK tries to send a cleanup command
|
|
1077
|
+
// after the prompt stream closes, but streaming mode is still active.
|
|
1078
|
+
// See: https://github.com/anthropics/claude-agent-sdk-typescript/issues/41
|
|
1079
|
+
if (receivedSuccessResult) {
|
|
1080
|
+
return completeWithSuccess(error);
|
|
1081
|
+
}
|
|
1082
|
+
// Check if we collected an API error before the exception was thrown
|
|
1083
|
+
const outputText = collectedText.join('\n');
|
|
1084
|
+
// Extract just the API error line(s), not the entire output
|
|
1085
|
+
const apiErrorMatch = outputText.match(/API Error: [^\n]+/g);
|
|
1086
|
+
const apiErrorMessage = apiErrorMatch
|
|
1087
|
+
? apiErrorMatch.join('\n')
|
|
1088
|
+
: 'Unknown API error';
|
|
1089
|
+
if (outputText.includes('API Error: 429')) {
|
|
1090
|
+
(0, debug_1.logToFile)('Agent error (caught): RATE_LIMIT');
|
|
1091
|
+
spinner.stop('Rate limit exceeded');
|
|
1092
|
+
return { error: AgentErrorType.RATE_LIMIT, message: apiErrorMessage };
|
|
1093
|
+
}
|
|
1094
|
+
if (outputText.includes('API Error:')) {
|
|
1095
|
+
(0, debug_1.logToFile)('Agent error (caught): API_ERROR');
|
|
1096
|
+
spinner.stop('API error occurred');
|
|
1097
|
+
return { error: AgentErrorType.API_ERROR, message: apiErrorMessage };
|
|
1098
|
+
}
|
|
1099
|
+
// No API error found, re-throw the original exception
|
|
1100
|
+
spinner.stop(errorMessage);
|
|
1101
|
+
(0, ui_1.getUI)().log.error(`Error: ${error.message}`);
|
|
1102
|
+
(0, debug_1.logToFile)('Agent run failed:', error);
|
|
1103
|
+
(0, debug_1.debug)('Full error:', error);
|
|
1104
|
+
throw error;
|
|
1105
|
+
}
|
|
1106
|
+
finally {
|
|
1107
|
+
clearInterval(heartbeatInterval);
|
|
1108
|
+
eventPlanWatcher?.close();
|
|
1109
|
+
if (eventPlanInterval)
|
|
1110
|
+
clearInterval(eventPlanInterval);
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
/**
|
|
1114
|
+
* Handle SDK messages and provide user feedback
|
|
1115
|
+
*
|
|
1116
|
+
* @param receivedSuccessResult - If true, suppress user-facing error output for cleanup errors
|
|
1117
|
+
* while still logging to file. The SDK may emit a second error
|
|
1118
|
+
* result after success due to cleanup race conditions.
|
|
1119
|
+
*/
|
|
1120
|
+
function handleSDKMessage(message, options, spinner, collectedText, receivedSuccessResult = false, recentStatuses) {
|
|
1121
|
+
(0, debug_1.logToFile)(`SDK Message: ${message.type}`, JSON.stringify(message, null, 2));
|
|
1122
|
+
if (options.debug) {
|
|
1123
|
+
(0, debug_1.debug)(`SDK Message type: ${message.type}`);
|
|
1124
|
+
}
|
|
1125
|
+
switch (message.type) {
|
|
1126
|
+
case 'assistant': {
|
|
1127
|
+
// Extract text content from assistant messages
|
|
1128
|
+
const content = message.message?.content;
|
|
1129
|
+
if (Array.isArray(content)) {
|
|
1130
|
+
for (const block of content) {
|
|
1131
|
+
if (block.type === 'text' && typeof block.text === 'string') {
|
|
1132
|
+
collectedText.push(block.text);
|
|
1133
|
+
// Check for [STATUS] markers
|
|
1134
|
+
const statusRegex = new RegExp(`^.*${exports.AgentSignals.STATUS.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*(.+?)$`, 'm');
|
|
1135
|
+
const statusMatch = block.text.match(statusRegex);
|
|
1136
|
+
if (statusMatch) {
|
|
1137
|
+
const statusText = statusMatch[1].trim();
|
|
1138
|
+
spinner.message(statusText);
|
|
1139
|
+
if (recentStatuses) {
|
|
1140
|
+
recentStatuses.push(statusText);
|
|
1141
|
+
if (recentStatuses.length > 3)
|
|
1142
|
+
recentStatuses.shift();
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
// Intercept TodoWrite tool_use blocks for task progression
|
|
1147
|
+
if (block.type === 'tool_use' &&
|
|
1148
|
+
block.name === 'TodoWrite' &&
|
|
1149
|
+
block.input &&
|
|
1150
|
+
Array.isArray(block.input.todos)) {
|
|
1151
|
+
(0, ui_1.getUI)().syncTodos(block.input.todos);
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
break;
|
|
1156
|
+
}
|
|
1157
|
+
case 'result': {
|
|
1158
|
+
// Check is_error flag - can be true even when subtype is 'success'
|
|
1159
|
+
if (message.is_error) {
|
|
1160
|
+
(0, debug_1.logToFile)('Agent result with error:', message.result);
|
|
1161
|
+
if (typeof message.result === 'string') {
|
|
1162
|
+
collectedText.push(message.result);
|
|
1163
|
+
}
|
|
1164
|
+
// Only show errors to user if we haven't already succeeded.
|
|
1165
|
+
// Post-success errors are SDK cleanup noise (telemetry failures, streaming
|
|
1166
|
+
// mode race conditions). Full message already logged above via JSON dump.
|
|
1167
|
+
if (message.errors && !receivedSuccessResult) {
|
|
1168
|
+
for (const err of message.errors) {
|
|
1169
|
+
(0, ui_1.getUI)().log.error(`Error: ${err}`);
|
|
1170
|
+
(0, debug_1.logToFile)('ERROR:', err);
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
else if (message.subtype === 'success') {
|
|
1175
|
+
(0, debug_1.logToFile)('Agent completed successfully');
|
|
1176
|
+
if (typeof message.result === 'string') {
|
|
1177
|
+
collectedText.push(message.result);
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
else {
|
|
1181
|
+
(0, debug_1.logToFile)('Agent result with error:', message.result);
|
|
1182
|
+
// Error result - only show to user if we haven't already succeeded.
|
|
1183
|
+
// Full message already logged above via JSON dump.
|
|
1184
|
+
if (message.errors && !receivedSuccessResult) {
|
|
1185
|
+
for (const err of message.errors) {
|
|
1186
|
+
(0, ui_1.getUI)().log.error(`Error: ${err}`);
|
|
1187
|
+
(0, debug_1.logToFile)('ERROR:', err);
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
break;
|
|
1192
|
+
}
|
|
1193
|
+
case 'system': {
|
|
1194
|
+
if (message.subtype === 'init') {
|
|
1195
|
+
const mcpStatuses = message.mcp_servers ?? [];
|
|
1196
|
+
(0, debug_1.logToFile)('Agent session initialized', {
|
|
1197
|
+
model: message.model,
|
|
1198
|
+
tools: message.tools?.length,
|
|
1199
|
+
mcpServers: mcpStatuses,
|
|
1200
|
+
});
|
|
1201
|
+
for (const server of mcpStatuses) {
|
|
1202
|
+
(0, debug_1.logToFile)(`MCP "${server.name}": ${server.status}`);
|
|
1203
|
+
if (server.status !== 'connected') {
|
|
1204
|
+
(0, ui_1.getUI)().log.warn(`MCP server "${server.name}" is not connected (${server.status})`);
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
break;
|
|
1209
|
+
}
|
|
1210
|
+
default:
|
|
1211
|
+
// Log other message types for debugging
|
|
1212
|
+
if (options.debug) {
|
|
1213
|
+
(0, debug_1.debug)(`Unhandled message type: ${message.type}`);
|
|
1214
|
+
}
|
|
1215
|
+
break;
|
|
1216
|
+
}
|
|
1217
|
+
}
|