@posthog/wizard 1.21.0 → 1.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -18
- package/dist/bin.js +6 -0
- package/dist/bin.js.map +1 -1
- package/dist/src/lib/agent-interface.d.ts +22 -11
- package/dist/src/lib/agent-interface.js +292 -162
- package/dist/src/lib/agent-interface.js.map +1 -1
- package/dist/src/lib/agent-runner.js +14 -8
- package/dist/src/lib/agent-runner.js.map +1 -1
- package/dist/src/run.d.ts +1 -0
- package/dist/src/run.js +1 -0
- package/dist/src/run.js.map +1 -1
- package/dist/src/utils/clack-utils.js +1 -1
- package/dist/src/utils/clack-utils.js.map +1 -1
- package/dist/src/utils/debug.d.ts +11 -0
- package/dist/src/utils/debug.js +22 -0
- package/dist/src/utils/debug.js.map +1 -1
- package/dist/src/utils/types.d.ts +4 -0
- package/dist/src/utils/types.js.map +1 -1
- package/package.json +5 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
3
|
* Shared agent interface for PostHog wizards
|
|
4
|
-
*
|
|
4
|
+
* Uses Claude Agent SDK directly with PostHog LLM gateway
|
|
5
5
|
*/
|
|
6
6
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
7
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
@@ -11,33 +11,28 @@ exports.AgentErrorType = exports.AgentSignals = void 0;
|
|
|
11
11
|
exports.wizardCanUseTool = wizardCanUseTool;
|
|
12
12
|
exports.initializeAgent = initializeAgent;
|
|
13
13
|
exports.runAgent = runAgent;
|
|
14
|
+
const path_1 = __importDefault(require("path"));
|
|
14
15
|
const clack_1 = __importDefault(require("../utils/clack"));
|
|
15
16
|
const debug_1 = require("../utils/debug");
|
|
16
17
|
const analytics_1 = require("../utils/analytics");
|
|
17
18
|
const constants_1 = require("./constants");
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
// Dynamic import cache for ESM module
|
|
20
|
+
let _sdkModule = null;
|
|
21
|
+
async function getSDKModule() {
|
|
22
|
+
if (!_sdkModule) {
|
|
23
|
+
_sdkModule = await import('@anthropic-ai/claude-agent-sdk');
|
|
22
24
|
}
|
|
23
|
-
return
|
|
25
|
+
return _sdkModule;
|
|
24
26
|
}
|
|
25
|
-
// TODO: Remove these if/when posthog/agent exports an enum for events
|
|
26
|
-
const EventType = {
|
|
27
|
-
RAW_SDK_EVENT: 'raw_sdk_event',
|
|
28
|
-
TOKEN: 'token',
|
|
29
|
-
TOOL_CALL: 'tool_call',
|
|
30
|
-
TOOL_RESULT: 'tool_result',
|
|
31
|
-
ERROR: 'error',
|
|
32
|
-
DONE: 'done',
|
|
33
|
-
};
|
|
34
27
|
/**
|
|
35
|
-
*
|
|
28
|
+
* Get the path to the bundled Claude Code CLI from the SDK package.
|
|
29
|
+
* This ensures we use the SDK's bundled version rather than the user's installed Claude Code.
|
|
36
30
|
*/
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
31
|
+
function getClaudeCodeExecutablePath() {
|
|
32
|
+
// require.resolve finds the package's main entry, then we get cli.js from same dir
|
|
33
|
+
const sdkPackagePath = require.resolve('@anthropic-ai/claude-agent-sdk');
|
|
34
|
+
return path_1.default.join(path_1.default.dirname(sdkPackagePath), 'cli.js');
|
|
35
|
+
}
|
|
41
36
|
exports.AgentSignals = {
|
|
42
37
|
/** Signal emitted when the agent reports progress to the user */
|
|
43
38
|
STATUS: '[STATUS]',
|
|
@@ -58,226 +53,361 @@ var AgentErrorType;
|
|
|
58
53
|
AgentErrorType["RESOURCE_MISSING"] = "WIZARD_RESOURCE_MISSING";
|
|
59
54
|
})(AgentErrorType || (exports.AgentErrorType = AgentErrorType = {}));
|
|
60
55
|
/**
|
|
61
|
-
*
|
|
62
|
-
|
|
56
|
+
* Package managers that can be used to run commands.
|
|
57
|
+
*/
|
|
58
|
+
const PACKAGE_MANAGERS = ['npm', 'pnpm', 'yarn', 'bun', 'npx'];
|
|
59
|
+
/**
|
|
60
|
+
* Safe scripts/commands that can be run with any package manager.
|
|
61
|
+
* Uses startsWith matching, so 'build' matches 'build', 'build:prod', etc.
|
|
63
62
|
*/
|
|
64
|
-
const
|
|
63
|
+
const SAFE_SCRIPTS = [
|
|
65
64
|
// Package installation
|
|
66
|
-
'
|
|
67
|
-
'
|
|
68
|
-
'
|
|
69
|
-
|
|
70
|
-
'
|
|
71
|
-
|
|
72
|
-
'
|
|
73
|
-
'
|
|
65
|
+
'install',
|
|
66
|
+
'add',
|
|
67
|
+
'ci',
|
|
68
|
+
// Build
|
|
69
|
+
'build',
|
|
70
|
+
// Type checking (various naming conventions)
|
|
71
|
+
'tsc',
|
|
72
|
+
'typecheck',
|
|
73
|
+
'type-check',
|
|
74
|
+
'check-types',
|
|
75
|
+
'types',
|
|
76
|
+
// Linting
|
|
77
|
+
'lint',
|
|
78
|
+
'eslint',
|
|
79
|
+
'next lint',
|
|
80
|
+
// Formatting
|
|
81
|
+
'format',
|
|
82
|
+
'prettier',
|
|
74
83
|
];
|
|
75
84
|
/**
|
|
76
|
-
*
|
|
77
|
-
*
|
|
85
|
+
* Dangerous shell operators that could allow command injection.
|
|
86
|
+
* Note: We handle `2>&1` and `| tail/head` separately as safe patterns.
|
|
87
|
+
*/
|
|
88
|
+
const DANGEROUS_OPERATORS = /[;`$()]/;
|
|
89
|
+
/**
|
|
90
|
+
* Check if command is an allowed package manager command.
|
|
91
|
+
* Matches: <pkg-manager> [run|exec] <safe-script> [args...]
|
|
92
|
+
*/
|
|
93
|
+
function matchesAllowedPrefix(command) {
|
|
94
|
+
const parts = command.split(/\s+/);
|
|
95
|
+
if (parts.length === 0 || !PACKAGE_MANAGERS.includes(parts[0])) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
// Skip 'run' or 'exec' if present
|
|
99
|
+
let scriptIndex = 1;
|
|
100
|
+
if (parts[scriptIndex] === 'run' || parts[scriptIndex] === 'exec') {
|
|
101
|
+
scriptIndex++;
|
|
102
|
+
}
|
|
103
|
+
// Get the script/command portion (may include args)
|
|
104
|
+
const scriptPart = parts.slice(scriptIndex).join(' ');
|
|
105
|
+
// Check if script starts with any safe script name
|
|
106
|
+
return SAFE_SCRIPTS.some((safe) => scriptPart.startsWith(safe));
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Permission hook that allows only safe commands.
|
|
110
|
+
* - Package manager install commands
|
|
111
|
+
* - Build/typecheck/lint commands for verification
|
|
112
|
+
* - Piping to tail/head for output limiting is allowed
|
|
113
|
+
* - Stderr redirection (2>&1) is allowed
|
|
78
114
|
*/
|
|
79
115
|
function wizardCanUseTool(toolName, input) {
|
|
80
116
|
// Allow all non-Bash tools
|
|
81
117
|
if (toolName !== 'Bash') {
|
|
82
|
-
return { behavior: 'allow' };
|
|
118
|
+
return { behavior: 'allow', updatedInput: input };
|
|
83
119
|
}
|
|
84
|
-
const command = (input.command
|
|
85
|
-
// Block
|
|
86
|
-
if (
|
|
87
|
-
(0, debug_1.
|
|
120
|
+
const command = (typeof input.command === 'string' ? input.command : '').trim();
|
|
121
|
+
// Block definitely dangerous operators: ; ` $ ( )
|
|
122
|
+
if (DANGEROUS_OPERATORS.test(command)) {
|
|
123
|
+
(0, debug_1.logToFile)(`Denying bash command with dangerous operators: ${command}`);
|
|
124
|
+
(0, debug_1.debug)(`Denying bash command with dangerous operators: ${command}`);
|
|
125
|
+
analytics_1.analytics.capture(constants_1.WIZARD_INTERACTION_EVENT_NAME, {
|
|
126
|
+
action: 'bash command denied',
|
|
127
|
+
reason: 'dangerous operators',
|
|
128
|
+
command,
|
|
129
|
+
});
|
|
88
130
|
return {
|
|
89
131
|
behavior: 'deny',
|
|
90
|
-
message: `Bash command not allowed.
|
|
132
|
+
message: `Bash command not allowed. Shell operators like ; \` $ ( ) are not permitted.`,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
// Normalize: remove safe stderr redirection (2>&1, 2>&2, etc.)
|
|
136
|
+
const normalized = command.replace(/\s*\d*>&\d+\s*/g, ' ').trim();
|
|
137
|
+
// Check for pipe to tail/head (safe output limiting)
|
|
138
|
+
const pipeMatch = normalized.match(/^(.+?)\s*\|\s*(tail|head)(\s+\S+)*\s*$/);
|
|
139
|
+
if (pipeMatch) {
|
|
140
|
+
const baseCommand = pipeMatch[1].trim();
|
|
141
|
+
// Block if base command has pipes or & (multiple chaining)
|
|
142
|
+
if (/[|&]/.test(baseCommand)) {
|
|
143
|
+
(0, debug_1.logToFile)(`Denying bash command with multiple pipes: ${command}`);
|
|
144
|
+
(0, debug_1.debug)(`Denying bash command with multiple pipes: ${command}`);
|
|
145
|
+
analytics_1.analytics.capture(constants_1.WIZARD_INTERACTION_EVENT_NAME, {
|
|
146
|
+
action: 'bash command denied',
|
|
147
|
+
reason: 'multiple pipes',
|
|
148
|
+
command,
|
|
149
|
+
});
|
|
150
|
+
return {
|
|
151
|
+
behavior: 'deny',
|
|
152
|
+
message: `Bash command not allowed. Only single pipe to tail/head is permitted.`,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
if (matchesAllowedPrefix(baseCommand)) {
|
|
156
|
+
(0, debug_1.logToFile)(`Allowing bash command with output limiter: ${command}`);
|
|
157
|
+
(0, debug_1.debug)(`Allowing bash command with output limiter: ${command}`);
|
|
158
|
+
return { behavior: 'allow', updatedInput: input };
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// Block remaining pipes and & (not covered by tail/head case above)
|
|
162
|
+
if (/[|&]/.test(normalized)) {
|
|
163
|
+
(0, debug_1.logToFile)(`Denying bash command with pipe/&: ${command}`);
|
|
164
|
+
(0, debug_1.debug)(`Denying bash command with pipe/&: ${command}`);
|
|
165
|
+
analytics_1.analytics.capture(constants_1.WIZARD_INTERACTION_EVENT_NAME, {
|
|
166
|
+
action: 'bash command denied',
|
|
167
|
+
reason: 'disallowed pipe',
|
|
168
|
+
command,
|
|
169
|
+
});
|
|
170
|
+
return {
|
|
171
|
+
behavior: 'deny',
|
|
172
|
+
message: `Bash command not allowed. Pipes are only permitted with tail/head for output limiting.`,
|
|
91
173
|
};
|
|
92
174
|
}
|
|
93
175
|
// Check if command starts with any allowed prefix
|
|
94
|
-
|
|
95
|
-
|
|
176
|
+
if (matchesAllowedPrefix(normalized)) {
|
|
177
|
+
(0, debug_1.logToFile)(`Allowing bash command: ${command}`);
|
|
96
178
|
(0, debug_1.debug)(`Allowing bash command: ${command}`);
|
|
97
|
-
return { behavior: 'allow' };
|
|
179
|
+
return { behavior: 'allow', updatedInput: input };
|
|
98
180
|
}
|
|
181
|
+
(0, debug_1.logToFile)(`Denying bash command: ${command}`);
|
|
99
182
|
(0, debug_1.debug)(`Denying bash command: ${command}`);
|
|
183
|
+
analytics_1.analytics.capture(constants_1.WIZARD_INTERACTION_EVENT_NAME, {
|
|
184
|
+
action: 'bash command denied',
|
|
185
|
+
reason: 'not in allowlist',
|
|
186
|
+
command,
|
|
187
|
+
});
|
|
100
188
|
return {
|
|
101
189
|
behavior: 'deny',
|
|
102
|
-
message: `Bash command not allowed. Only
|
|
190
|
+
message: `Bash command not allowed. Only install, build, typecheck, and lint commands are permitted.`,
|
|
103
191
|
};
|
|
104
192
|
}
|
|
105
193
|
/**
|
|
106
|
-
* Initialize
|
|
194
|
+
* Initialize agent configuration for the LLM gateway
|
|
107
195
|
*/
|
|
108
|
-
|
|
109
|
-
|
|
196
|
+
function initializeAgent(config, options) {
|
|
197
|
+
// Initialize log file for this run
|
|
198
|
+
(0, debug_1.initLogFile)();
|
|
199
|
+
(0, debug_1.logToFile)('Agent initialization starting');
|
|
200
|
+
(0, debug_1.logToFile)('Install directory:', options.installDir);
|
|
201
|
+
clack_1.default.log.step('Initializing Claude agent...');
|
|
110
202
|
try {
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
203
|
+
// Configure LLM gateway environment variables (inherited by SDK subprocess)
|
|
204
|
+
const gatewayUrl = `${config.posthogApiHost}/api/projects/${config.posthogProjectId}/llm_gateway`;
|
|
205
|
+
process.env.ANTHROPIC_BASE_URL = gatewayUrl;
|
|
206
|
+
process.env.ANTHROPIC_AUTH_TOKEN = config.posthogApiKey;
|
|
207
|
+
// Disable experimental betas (like input_examples) that the LLM gateway doesn't support
|
|
208
|
+
process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS = 'true';
|
|
209
|
+
(0, debug_1.logToFile)('Configured LLM gateway:', gatewayUrl);
|
|
210
|
+
// Configure MCP server with PostHog authentication
|
|
211
|
+
const mcpServers = {
|
|
212
|
+
posthog: {
|
|
213
|
+
type: 'http',
|
|
214
|
+
url: config.posthogMcpUrl,
|
|
215
|
+
headers: {
|
|
216
|
+
Authorization: `Bearer ${config.posthogApiKey}`,
|
|
217
|
+
},
|
|
118
218
|
},
|
|
119
|
-
debug: config.debug ?? false,
|
|
120
219
|
};
|
|
220
|
+
const agentRunConfig = {
|
|
221
|
+
workingDirectory: config.workingDirectory,
|
|
222
|
+
mcpServers,
|
|
223
|
+
model: 'claude-opus-4-5-20251101',
|
|
224
|
+
};
|
|
225
|
+
(0, debug_1.logToFile)('Agent config:', {
|
|
226
|
+
workingDirectory: agentRunConfig.workingDirectory,
|
|
227
|
+
posthogMcpUrl: config.posthogMcpUrl,
|
|
228
|
+
gatewayUrl,
|
|
229
|
+
apiKeyPresent: !!config.posthogApiKey,
|
|
230
|
+
});
|
|
121
231
|
if (options.debug) {
|
|
122
232
|
(0, debug_1.debug)('Agent config:', {
|
|
123
|
-
workingDirectory:
|
|
124
|
-
posthogMcpUrl:
|
|
125
|
-
|
|
233
|
+
workingDirectory: agentRunConfig.workingDirectory,
|
|
234
|
+
posthogMcpUrl: config.posthogMcpUrl,
|
|
235
|
+
gatewayUrl,
|
|
236
|
+
apiKeyPresent: !!config.posthogApiKey,
|
|
126
237
|
});
|
|
127
238
|
}
|
|
128
|
-
|
|
239
|
+
clack_1.default.log.step(`Verbose logs: ${debug_1.LOG_FILE_PATH}`);
|
|
129
240
|
clack_1.default.log.success("Agent initialized. Let's get cooking!");
|
|
130
|
-
return
|
|
241
|
+
return agentRunConfig;
|
|
131
242
|
}
|
|
132
243
|
catch (error) {
|
|
133
244
|
clack_1.default.log.error(`Failed to initialize agent: ${error.message}`);
|
|
245
|
+
(0, debug_1.logToFile)('Agent initialization error:', error);
|
|
134
246
|
(0, debug_1.debug)('Agent initialization error:', error);
|
|
135
247
|
throw error;
|
|
136
248
|
}
|
|
137
249
|
}
|
|
138
|
-
/**
|
|
139
|
-
* Handle agent events and provide user feedback
|
|
140
|
-
* This function processes events from the agent SDK and provides appropriate
|
|
141
|
-
* user feedback through the CLI spinner and logging
|
|
142
|
-
*/
|
|
143
|
-
function handleAgentEvent(event, options, spinner) {
|
|
144
|
-
if (options.debug) {
|
|
145
|
-
(0, debug_1.debug)(`Event type: ${event.type}`, JSON.stringify(event, null, 2));
|
|
146
|
-
}
|
|
147
|
-
// Only show [STATUS] events to the user - everything else goes to debug log
|
|
148
|
-
switch (event.type) {
|
|
149
|
-
case EventType.RAW_SDK_EVENT:
|
|
150
|
-
if (event.sdkMessage?.type === ContentType.ASSISTANT) {
|
|
151
|
-
const message = event.sdkMessage.message;
|
|
152
|
-
if (message?.content && Array.isArray(message.content)) {
|
|
153
|
-
const textContent = message.content
|
|
154
|
-
.filter((block) => block.type === ContentType.TEXT)
|
|
155
|
-
.map((block) => block.text)
|
|
156
|
-
.join('\n');
|
|
157
|
-
// Check if the text contains a [STATUS] marker
|
|
158
|
-
const statusRegex = new RegExp(`^.*${exports.AgentSignals.STATUS.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*(.+?)$`, 'm');
|
|
159
|
-
const statusMatch = textContent.match(statusRegex);
|
|
160
|
-
if (statusMatch) {
|
|
161
|
-
// Stop spinner, log the status step, restart spinner
|
|
162
|
-
// This creates the progress list as the agent proceeds
|
|
163
|
-
spinner.stop(statusMatch[1].trim());
|
|
164
|
-
spinner.start('Integrating PostHog...');
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
break;
|
|
169
|
-
case EventType.TOKEN:
|
|
170
|
-
if (options.debug) {
|
|
171
|
-
(0, debug_1.debug)(event.content);
|
|
172
|
-
}
|
|
173
|
-
break;
|
|
174
|
-
case EventType.TOOL_CALL:
|
|
175
|
-
if (options.debug) {
|
|
176
|
-
(0, debug_1.debug)(`Tool: ${event.toolName}`);
|
|
177
|
-
(0, debug_1.debug)(' Args:', JSON.stringify(event.args, null, 2));
|
|
178
|
-
}
|
|
179
|
-
break;
|
|
180
|
-
case EventType.TOOL_RESULT:
|
|
181
|
-
if (options.debug) {
|
|
182
|
-
(0, debug_1.debug)(`✅ ${event.toolName} completed`);
|
|
183
|
-
const resultStr = typeof event.result === 'string'
|
|
184
|
-
? event.result
|
|
185
|
-
: JSON.stringify(event.result, null, 2);
|
|
186
|
-
const truncated = resultStr.length > 500
|
|
187
|
-
? `${resultStr.substring(0, 500)}...`
|
|
188
|
-
: resultStr;
|
|
189
|
-
(0, debug_1.debug)(' Result:', truncated);
|
|
190
|
-
}
|
|
191
|
-
break;
|
|
192
|
-
case EventType.ERROR:
|
|
193
|
-
// Always show errors to user
|
|
194
|
-
clack_1.default.log.error(`Error: ${event.message}`);
|
|
195
|
-
if (options.debug && event.error) {
|
|
196
|
-
(0, debug_1.debug)('Error details:', event.error);
|
|
197
|
-
}
|
|
198
|
-
if (event.error instanceof Error) {
|
|
199
|
-
analytics_1.analytics.captureException(event.error, {
|
|
200
|
-
event_type: event.type,
|
|
201
|
-
message: event.message,
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
break;
|
|
205
|
-
case EventType.DONE:
|
|
206
|
-
if (event.durationMs) {
|
|
207
|
-
if (options.debug) {
|
|
208
|
-
(0, debug_1.debug)(`Completed in ${Math.round(event.durationMs / 1000)}s`);
|
|
209
|
-
}
|
|
210
|
-
analytics_1.analytics.capture(constants_1.WIZARD_INTERACTION_EVENT_NAME, {
|
|
211
|
-
action: 'agent integration completed',
|
|
212
|
-
duration_ms: event.durationMs,
|
|
213
|
-
duration_seconds: Math.round(event.durationMs / 1000),
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
break;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
250
|
/**
|
|
220
251
|
* Execute an agent with the provided prompt and options
|
|
221
252
|
* Handles the full lifecycle: spinner, execution, error handling
|
|
222
253
|
*
|
|
223
254
|
* @returns An object containing any error detected in the agent's output
|
|
224
255
|
*/
|
|
225
|
-
async function runAgent(
|
|
256
|
+
async function runAgent(agentConfig, prompt, options, spinner, config) {
|
|
226
257
|
const { estimatedDurationMinutes = 8, spinnerMessage = 'Customizing your PostHog setup...', successMessage = 'PostHog integration complete', errorMessage = 'Integration failed', } = config ?? {};
|
|
227
|
-
const {
|
|
258
|
+
const { query } = await getSDKModule();
|
|
228
259
|
clack_1.default.log.step(`This whole process should take about ${estimatedDurationMinutes} minutes including error checking and fixes.\n\nGrab some coffee!`);
|
|
229
260
|
spinner.start(spinnerMessage);
|
|
261
|
+
const cliPath = getClaudeCodeExecutablePath();
|
|
262
|
+
(0, debug_1.logToFile)('Starting agent run');
|
|
263
|
+
(0, debug_1.logToFile)('Claude Code executable:', cliPath);
|
|
264
|
+
(0, debug_1.logToFile)('Prompt:', prompt);
|
|
265
|
+
const startTime = Date.now();
|
|
266
|
+
const collectedText = [];
|
|
230
267
|
try {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
268
|
+
// Workaround for SDK bug: stdin closes before canUseTool responses can be sent.
|
|
269
|
+
// The fix is to use an async generator for the prompt that stays open until
|
|
270
|
+
// the result is received, keeping the stdin stream alive for permission responses.
|
|
271
|
+
// See: https://github.com/anthropics/claude-code/issues/4775
|
|
272
|
+
// See: https://github.com/anthropics/claude-agent-sdk-typescript/issues/41
|
|
273
|
+
let signalDone;
|
|
274
|
+
const resultReceived = new Promise((resolve) => {
|
|
275
|
+
signalDone = resolve;
|
|
276
|
+
});
|
|
277
|
+
const createPromptStream = async function* () {
|
|
278
|
+
yield {
|
|
279
|
+
type: 'user',
|
|
280
|
+
session_id: '',
|
|
281
|
+
message: { role: 'user', content: prompt },
|
|
282
|
+
parent_tool_use_id: null,
|
|
283
|
+
};
|
|
284
|
+
await resultReceived;
|
|
285
|
+
};
|
|
286
|
+
const response = query({
|
|
287
|
+
prompt: createPromptStream(),
|
|
288
|
+
options: {
|
|
289
|
+
model: agentConfig.model,
|
|
290
|
+
cwd: agentConfig.workingDirectory,
|
|
291
|
+
permissionMode: 'acceptEdits',
|
|
292
|
+
mcpServers: agentConfig.mcpServers,
|
|
293
|
+
env: { ...process.env },
|
|
294
|
+
canUseTool: (toolName, input) => {
|
|
295
|
+
(0, debug_1.logToFile)('canUseTool called:', { toolName, input });
|
|
296
|
+
const result = wizardCanUseTool(toolName, input);
|
|
297
|
+
(0, debug_1.logToFile)('canUseTool result:', result);
|
|
298
|
+
return Promise.resolve(result);
|
|
299
|
+
},
|
|
300
|
+
tools: { type: 'preset', preset: 'claude_code' },
|
|
301
|
+
// Capture stderr from CLI subprocess for debugging
|
|
302
|
+
stderr: (data) => {
|
|
303
|
+
(0, debug_1.logToFile)('CLI stderr:', data);
|
|
304
|
+
if (options.debug) {
|
|
305
|
+
(0, debug_1.debug)('CLI stderr:', data);
|
|
306
|
+
}
|
|
307
|
+
},
|
|
237
308
|
},
|
|
238
309
|
});
|
|
310
|
+
// Process the async generator
|
|
311
|
+
for await (const message of response) {
|
|
312
|
+
handleSDKMessage(message, options, spinner, collectedText);
|
|
313
|
+
// Signal completion when result received
|
|
314
|
+
if (message.type === 'result') {
|
|
315
|
+
signalDone();
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
const durationMs = Date.now() - startTime;
|
|
319
|
+
const outputText = collectedText.join('\n');
|
|
239
320
|
// Check for error markers in the agent's output
|
|
240
|
-
const outputText = extractTextFromResults(result.results);
|
|
241
321
|
if (outputText.includes(exports.AgentSignals.ERROR_MCP_MISSING)) {
|
|
322
|
+
(0, debug_1.logToFile)('Agent error: MCP_MISSING');
|
|
242
323
|
spinner.stop('Agent could not access PostHog MCP');
|
|
243
324
|
return { error: AgentErrorType.MCP_MISSING };
|
|
244
325
|
}
|
|
245
326
|
if (outputText.includes(exports.AgentSignals.ERROR_RESOURCE_MISSING)) {
|
|
327
|
+
(0, debug_1.logToFile)('Agent error: RESOURCE_MISSING');
|
|
246
328
|
spinner.stop('Agent could not access setup resource');
|
|
247
329
|
return { error: AgentErrorType.RESOURCE_MISSING };
|
|
248
330
|
}
|
|
331
|
+
(0, debug_1.logToFile)(`Agent run completed in ${Math.round(durationMs / 1000)}s`);
|
|
332
|
+
analytics_1.analytics.capture(constants_1.WIZARD_INTERACTION_EVENT_NAME, {
|
|
333
|
+
action: 'agent integration completed',
|
|
334
|
+
duration_ms: durationMs,
|
|
335
|
+
duration_seconds: Math.round(durationMs / 1000),
|
|
336
|
+
});
|
|
249
337
|
spinner.stop(successMessage);
|
|
250
338
|
return {};
|
|
251
339
|
}
|
|
252
340
|
catch (error) {
|
|
253
341
|
spinner.stop(errorMessage);
|
|
254
342
|
clack_1.default.log.error(`Error: ${error.message}`);
|
|
343
|
+
(0, debug_1.logToFile)('Agent run failed:', error);
|
|
255
344
|
(0, debug_1.debug)('Full error:', error);
|
|
256
345
|
throw error;
|
|
257
346
|
}
|
|
258
347
|
}
|
|
259
348
|
/**
|
|
260
|
-
*
|
|
349
|
+
* Handle SDK messages and provide user feedback
|
|
261
350
|
*/
|
|
262
|
-
function
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
351
|
+
function handleSDKMessage(message, options, spinner, collectedText) {
|
|
352
|
+
(0, debug_1.logToFile)(`SDK Message: ${message.type}`, JSON.stringify(message, null, 2));
|
|
353
|
+
if (options.debug) {
|
|
354
|
+
(0, debug_1.debug)(`SDK Message type: ${message.type}`);
|
|
355
|
+
}
|
|
356
|
+
switch (message.type) {
|
|
357
|
+
case 'assistant': {
|
|
358
|
+
// Extract text content from assistant messages
|
|
359
|
+
const content = message.message?.content;
|
|
268
360
|
if (Array.isArray(content)) {
|
|
269
361
|
for (const block of content) {
|
|
270
|
-
if (block.type ===
|
|
271
|
-
|
|
362
|
+
if (block.type === 'text' && typeof block.text === 'string') {
|
|
363
|
+
collectedText.push(block.text);
|
|
364
|
+
// Check for [STATUS] markers
|
|
365
|
+
const statusRegex = new RegExp(`^.*${exports.AgentSignals.STATUS.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*(.+?)$`, 'm');
|
|
366
|
+
const statusMatch = block.text.match(statusRegex);
|
|
367
|
+
if (statusMatch) {
|
|
368
|
+
spinner.stop(statusMatch[1].trim());
|
|
369
|
+
spinner.start('Integrating PostHog...');
|
|
370
|
+
}
|
|
272
371
|
}
|
|
273
372
|
}
|
|
274
373
|
}
|
|
374
|
+
break;
|
|
275
375
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
376
|
+
case 'result': {
|
|
377
|
+
if (message.subtype === 'success') {
|
|
378
|
+
(0, debug_1.logToFile)('Agent completed successfully');
|
|
379
|
+
if (typeof message.result === 'string') {
|
|
380
|
+
collectedText.push(message.result);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
// Error result
|
|
385
|
+
(0, debug_1.logToFile)('Agent error result:', message.subtype);
|
|
386
|
+
if (message.errors) {
|
|
387
|
+
for (const err of message.errors) {
|
|
388
|
+
clack_1.default.log.error(`Error: ${err}`);
|
|
389
|
+
(0, debug_1.logToFile)('ERROR:', err);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
break;
|
|
279
394
|
}
|
|
395
|
+
case 'system': {
|
|
396
|
+
if (message.subtype === 'init') {
|
|
397
|
+
(0, debug_1.logToFile)('Agent session initialized', {
|
|
398
|
+
model: message.model,
|
|
399
|
+
tools: message.tools?.length,
|
|
400
|
+
mcpServers: message.mcp_servers,
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
break;
|
|
404
|
+
}
|
|
405
|
+
default:
|
|
406
|
+
// Log other message types for debugging
|
|
407
|
+
if (options.debug) {
|
|
408
|
+
(0, debug_1.debug)(`Unhandled message type: ${message.type}`);
|
|
409
|
+
}
|
|
410
|
+
break;
|
|
280
411
|
}
|
|
281
|
-
return textParts.join('\n');
|
|
282
412
|
}
|
|
283
413
|
//# sourceMappingURL=agent-interface.js.map
|