UNPKG

@posthog/wizard

Version:

The PostHog wizard helps you to configure your project

256 lines (236 loc) 13.1 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.runAgentWizard = runAgentWizard; const framework_config_1 = require("./framework-config"); const clack_utils_1 = require("../utils/clack-utils"); const analytics_1 = require("../utils/analytics"); const constants_1 = require("./constants"); const clack_1 = __importDefault(require("../utils/clack")); const agent_interface_1 = require("./agent-interface"); const urls_1 = require("../utils/urls"); const chalk_1 = __importDefault(require("chalk")); const steps_1 = require("../steps"); const anthropic_status_1 = require("../utils/anthropic-status"); /** * Universal agent-powered wizard runner. * Handles the complete flow for any framework using PostHog MCP integration. */ async function runAgentWizard(config, options) { // Setup phase (0, clack_utils_1.printWelcome)({ wizardName: (0, framework_config_1.getWelcomeMessage)(config.metadata.name) }); clack_1.default.log.info(`🧙 The wizard has chosen you to try the next-generation agent integration for ${config.metadata.name}.\n\nStand by for the good stuff, and let the robot minders know how it goes:\n\nwizard@posthog.com`); const aiConsent = await (0, clack_utils_1.askForAIConsent)(options); if (!aiConsent) { await (0, clack_utils_1.abort)(`This wizard uses an LLM agent to intelligently modify your project. Please view the docs to set up ${config.metadata.name} manually instead: ${config.metadata.docsUrl}`, 0); } // Check Anthropic/Claude service status before proceeding const statusOk = await (0, anthropic_status_1.checkAnthropicStatusWithPrompt)({ ci: options.ci }); if (!statusOk) { await (0, clack_utils_1.abort)(`Please try again later, or set up ${config.metadata.name} manually: ${config.metadata.docsUrl}`, 0); } const cloudRegion = options.cloudRegion ?? (await (0, clack_utils_1.askForCloudRegion)()); const typeScriptDetected = (0, clack_utils_1.isUsingTypeScript)(options); await (0, clack_utils_1.confirmContinueIfNoOrDirtyGitRepo)(options); // Framework detection and version // Only check package.json for Node.js/JavaScript frameworks const usesPackageJson = config.detection.usesPackageJson !== false; let packageJson = null; let frameworkVersion; if (usesPackageJson) { packageJson = await (0, clack_utils_1.getPackageDotJson)(options); await (0, clack_utils_1.ensurePackageIsInstalled)(packageJson, config.detection.packageName, config.detection.packageDisplayName); frameworkVersion = config.detection.getVersion(packageJson); } else { // For non-Node frameworks (e.g., Django), version is handled differently frameworkVersion = config.detection.getVersion(null); } // Set analytics tags for framework version if (frameworkVersion && config.detection.getVersionBucket) { const versionBucket = config.detection.getVersionBucket(frameworkVersion); analytics_1.analytics.setTag(`${config.metadata.integration}-version`, versionBucket); } analytics_1.analytics.capture(constants_1.WIZARD_INTERACTION_EVENT_NAME, { action: 'started agent integration', integration: config.metadata.integration, }); // Get PostHog credentials const { projectApiKey, host, accessToken } = await (0, clack_utils_1.getOrAskForProjectData)({ ...options, cloudRegion, }); // Gather framework-specific context (e.g., Next.js router, React Native platform) const frameworkContext = config.metadata.gatherContext ? await config.metadata.gatherContext(options) : {}; // Set analytics tags from framework context const contextTags = config.analytics.getTags(frameworkContext); Object.entries(contextTags).forEach(([key, value]) => { analytics_1.analytics.setTag(key, value); }); // Build integration prompt const integrationPrompt = buildIntegrationPrompt(config, { frameworkVersion: frameworkVersion || 'latest', typescript: typeScriptDetected, projectApiKey, host, }, frameworkContext); // Initialize and run agent const spinner = clack_1.default.spinner(); // Determine MCP URL: CLI flag > env var > production default // Use EU subdomain for EU users to work around Claude Code's OAuth bug // See: https://github.com/anthropics/claude-code/issues/2267 const mcpUrl = options.localMcp ? 'http://localhost:8787/mcp' : process.env.MCP_URL || (cloudRegion === 'eu' ? 'https://mcp-eu.posthog.com/mcp' : 'https://mcp.posthog.com/mcp'); const agent = (0, agent_interface_1.initializeAgent)({ workingDirectory: options.installDir, posthogMcpUrl: mcpUrl, posthogApiKey: accessToken, posthogApiHost: host, }, options); const agentResult = await (0, agent_interface_1.runAgent)(agent, integrationPrompt, options, spinner, { estimatedDurationMinutes: config.ui.estimatedDurationMinutes, spinnerMessage: framework_config_1.SPINNER_MESSAGE, successMessage: config.ui.successMessage, errorMessage: 'Integration failed', }); // Handle error cases detected in agent output if (agentResult.error === agent_interface_1.AgentErrorType.MCP_MISSING) { analytics_1.analytics.captureException(new Error('Agent could not access PostHog MCP server'), { integration: config.metadata.integration, error_type: agent_interface_1.AgentErrorType.MCP_MISSING, signal: agent_interface_1.AgentSignals.ERROR_MCP_MISSING, }); const errorMessage = ` ${chalk_1.default.red('❌ Could not access the PostHog MCP server')} The wizard was unable to connect to the PostHog MCP server. This could be due to a network issue or a configuration problem. Please try again, or set up ${config.metadata.name} manually by following our documentation: ${chalk_1.default.cyan(config.metadata.docsUrl)}`; clack_1.default.outro(errorMessage); await analytics_1.analytics.shutdown('error'); process.exit(1); } if (agentResult.error === agent_interface_1.AgentErrorType.RESOURCE_MISSING) { analytics_1.analytics.captureException(new Error('Agent could not access setup resource'), { integration: config.metadata.integration, error_type: agent_interface_1.AgentErrorType.RESOURCE_MISSING, signal: agent_interface_1.AgentSignals.ERROR_RESOURCE_MISSING, }); const errorMessage = ` ${chalk_1.default.red('❌ Could not access the setup resource')} The wizard could not access the setup resource. This may indicate a version mismatch or a temporary service issue. Please try again, or set up ${config.metadata.name} manually by following our documentation: ${chalk_1.default.cyan(config.metadata.docsUrl)}`; clack_1.default.outro(errorMessage); await analytics_1.analytics.shutdown('error'); process.exit(1); } if (agentResult.error === agent_interface_1.AgentErrorType.RATE_LIMIT || agentResult.error === agent_interface_1.AgentErrorType.API_ERROR) { analytics_1.analytics.capture(constants_1.WIZARD_INTERACTION_EVENT_NAME, { action: 'api error', integration: config.metadata.integration, error_type: agentResult.error, error_message: agentResult.message, }); analytics_1.analytics.captureException(new Error(`API error: ${agentResult.message}`), { integration: config.metadata.integration, error_type: agentResult.error, }); const errorMessage = ` ${chalk_1.default.red('❌ API Error')} ${chalk_1.default.yellow(agentResult.message || 'Unknown error')} Please report this error to: ${chalk_1.default.cyan('wizard@posthog.com')}`; clack_1.default.outro(errorMessage); await analytics_1.analytics.shutdown('error'); process.exit(1); } // Build environment variables from OAuth credentials const envVars = config.environment.getEnvVars(projectApiKey, host); // Upload environment variables to hosting providers (if configured) let uploadedEnvVars = []; if (config.environment.uploadToHosting) { uploadedEnvVars = await (0, steps_1.uploadEnvironmentVariablesStep)(envVars, { integration: config.metadata.integration, options, }); } // Add MCP server to clients await (0, steps_1.addMCPServerToClientsStep)({ cloudRegion, integration: config.metadata.integration, ci: options.ci, }); // Build outro message const continueUrl = options.signup ? `${(0, urls_1.getCloudUrlFromRegion)(cloudRegion)}/products?source=wizard` : undefined; const changes = [ ...config.ui.getOutroChanges(frameworkContext), Object.keys(envVars).length > 0 ? `Added environment variables to .env file` : '', uploadedEnvVars.length > 0 ? `Uploaded environment variables to your hosting provider` : '', ].filter(Boolean); const nextSteps = [ ...config.ui.getOutroNextSteps(frameworkContext), uploadedEnvVars.length === 0 && config.environment.uploadToHosting ? `Upload your Project API key to your hosting provider` : '', ].filter(Boolean); const outroMessage = ` ${chalk_1.default.green('Successfully installed PostHog!')} ${chalk_1.default.cyan('What the agent did:')} ${changes.map((change) => `• ${change}`).join('\n')} ${chalk_1.default.yellow('Next steps:')} ${nextSteps.map((step) => `• ${step}`).join('\n')} Learn more: ${chalk_1.default.cyan(config.metadata.docsUrl)} ${continueUrl ? `\nContinue onboarding: ${chalk_1.default.cyan(continueUrl)}\n` : ``} ${chalk_1.default.dim('Note: This wizard uses an LLM agent to analyze and modify your project. Please review the changes made.')} ${chalk_1.default.dim(`How did this work for you? Drop us a line: wizard@posthog.com`)}`; clack_1.default.outro(outroMessage); await analytics_1.analytics.shutdown('success'); } /** * Build the integration prompt for the agent. * Uses shared base prompt with optional framework-specific addendum. */ function buildIntegrationPrompt(config, context, frameworkContext) { const additionalLines = config.prompts.getAdditionalContextLines ? config.prompts.getAdditionalContextLines(frameworkContext) : []; const additionalContext = additionalLines.length > 0 ? '\n' + additionalLines.map((line) => `- ${line}`).join('\n') : ''; return `You have access to the PostHog MCP server which provides skills to integrate PostHog into this ${config.metadata.name} project. Project context: - Framework: ${config.metadata.name} ${context.frameworkVersion} - TypeScript: ${context.typescript ? 'Yes' : 'No'} - PostHog API Key: ${context.projectApiKey} - PostHog Host: ${context.host}${additionalContext} Instructions (follow these steps IN ORDER - do not skip or reorder): STEP 1: List available skills from the PostHog MCP server using ListMcpResourcesTool. Review the skill descriptions and choose the one that best matches this project's framework and configuration. If no suitable skill is found, or you cannot access the MCP server, emit: ${agent_interface_1.AgentSignals.ERROR_RESOURCE_MISSING} Could not find a suitable skill for this project. STEP 2: Fetch the chosen skill resource (e.g., posthog://skills/{skill-id}). The resource returns a shell command to install the skill. STEP 3: Run the installation command using Bash: - Execute the EXACT command returned by the resource (do not modify it) - This will download and extract the skill to .claude/skills/{skill-id}/ STEP 4: Load the installed skill's SKILL.md file to understand what references are available. STEP 5: Follow the skill's workflow files in sequence. Look for numbered workflow files in the references (e.g., files with patterns like "1.0-", "1.1-", "1.2-"). Start with the first one and proceed through each step until completion. Each workflow file will tell you what to do and which file comes next. STEP 6: Set up environment variables for PostHog in a .env file with the API key and host provided above, using the appropriate naming convention for ${config.metadata.name}. Make sure to use these environment variables in the code files you create instead of hardcoding the API key and host. Important: Look for lockfiles (pnpm-lock.yaml, package-lock.json, yarn.lock, bun.lockb) to determine the package manager. Do not manually edit package.json. Always install packages as a background task. Don't await completion; proceed with other work immediately after starting the installation. `; } //# sourceMappingURL=agent-runner.js.map