Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@ yargs(hideBin(process.argv))
'Show menu for manual integration selection instead of auto-detecting\nenv: POSTHOG_WIZARD_MENU',
type: 'boolean',
},
benchmark: {
default: false,
describe:
'Run in benchmark mode with per-phase token tracking\nenv: POSTHOG_WIZARD_BENCHMARK',
type: 'boolean',
},
});
},
(argv) => {
Expand Down
1 change: 1 addition & 0 deletions src/lib/__tests__/agent-interface.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ describe('runAgent', () => {
localMcp: false,
ci: false,
menu: false,
benchmark: false,
};

const defaultAgentConfig = {
Expand Down
26 changes: 22 additions & 4 deletions src/lib/agent-interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
} from './constants';
import { getLlmGatewayUrlFromHost } from '../utils/urls';
import { LINTING_TOOLS } from './safe-tools';
import type { BenchmarkData } from './benchmark';
import { BenchmarkTracker } from './benchmark';
import { createEnvFileServer, ENV_FILE_TOOL_NAMES } from './env-file-tools';

// Dynamic import cache for ESM module
Expand Down Expand Up @@ -416,7 +418,11 @@ export async function runAgent(
successMessage?: string;
errorMessage?: string;
},
): Promise<{ error?: AgentErrorType; message?: string }> {
): Promise<{
error?: AgentErrorType;
message?: string;
benchmark?: BenchmarkData;
}> {
const {
estimatedDurationMinutes = 8,
spinnerMessage = 'Customizing your PostHog setup...',
Expand All @@ -430,6 +436,9 @@ export async function runAgent(
`This whole process should take about ${estimatedDurationMinutes} minutes including error checking and fixes.\n\nGrab some coffee!`,
);

// Create benchmark tracker before spinner starts so its log output is visible
const tracker = options.benchmark ? new BenchmarkTracker(spinner) : null;

spinner.start(spinnerMessage);

const cliPath = getClaudeCodeExecutablePath();
Expand All @@ -441,6 +450,8 @@ export async function runAgent(
const collectedText: string[] = [];
// Track if we received a successful result (before any cleanup errors)
let receivedSuccessResult = false;
// Track the result message for benchmark data extraction
let resultMessage: SDKMessage = null;

// Workaround for SDK bug: stdin closes before canUseTool responses can be sent.
// The fix is to use an async generator for the prompt that stays open until
Expand All @@ -465,7 +476,11 @@ export async function runAgent(
// Helper to handle successful completion (used in normal path and race condition recovery)
const completeWithSuccess = (
suppressedError?: Error,
): { error?: AgentErrorType; message?: string } => {
): {
error?: AgentErrorType;
message?: string;
benchmark?: BenchmarkData;
} => {
const durationMs = Date.now() - startTime;
const durationSeconds = Math.round(durationMs / 1000);

Expand Down Expand Up @@ -501,7 +516,9 @@ export async function runAgent(
duration_seconds: durationSeconds,
});
spinner.stop(successMessage);
return {};

const benchmark = tracker?.finalize(resultMessage, durationMs);
return { benchmark };
};

try {
Expand Down Expand Up @@ -598,13 +615,15 @@ export async function runAgent(
collectedText,
receivedSuccessResult,
);
tracker?.onMessage(message);

// Signal completion when result received
if (message.type === 'result') {
// Track successful results before any potential cleanup errors
// The SDK may emit a second error result during cleanup due to a race condition
if (message.subtype === 'success' && !message.is_error) {
receivedSuccessResult = true;
resultMessage = message;
}
signalDone!();
}
Expand Down Expand Up @@ -776,7 +795,6 @@ function handleSDKMessage(
}

default:
// Log other message types for debugging
if (options.debug) {
debug(`Unhandled message type: ${message.type}`);
}
Expand Down
14 changes: 8 additions & 6 deletions src/lib/agent-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,17 +193,19 @@ export async function runAgentWizard(
options,
);

const agentRunConfig = {
estimatedDurationMinutes: config.ui.estimatedDurationMinutes,
spinnerMessage: SPINNER_MESSAGE,
successMessage: config.ui.successMessage,
errorMessage: 'Integration failed',
};

const agentResult = await runAgent(
agent,
integrationPrompt,
options,
spinner,
{
estimatedDurationMinutes: config.ui.estimatedDurationMinutes,
spinnerMessage: SPINNER_MESSAGE,
successMessage: config.ui.successMessage,
errorMessage: 'Integration failed',
},
agentRunConfig,
);

// Handle error cases detected in agent output
Expand Down
Loading
Loading