@posthog/wizard 1.21.0 → 1.22.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.
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  /**
3
3
  * Shared agent interface for PostHog wizards
4
- * Provides common agent initialization and event handling
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
- let _agentModule = null;
19
- async function getAgentModule() {
20
- if (!_agentModule) {
21
- _agentModule = await import('@posthog/agent');
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 _agentModule;
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
- * Content types for agent messages and blocks
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
- const ContentType = {
38
- TEXT: 'text',
39
- ASSISTANT: 'assistant',
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
- * Allowed bash command prefixes for the wizard agent.
62
- * These are package manager commands needed for PostHog installation.
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 ALLOWED_BASH_PREFIXES = [
63
+ const SAFE_SCRIPTS = [
65
64
  // Package installation
66
- 'npm install',
67
- 'npm ci',
68
- 'pnpm install',
69
- 'pnpm add',
70
- 'bun install',
71
- 'bun add',
72
- 'yarn add',
73
- 'yarn install',
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
- * Permission hook that allows only safe package manager commands.
77
- * This prevents the agent from running arbitrary shell commands.
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 ?? '').trim();
85
- // Block commands with shell operators (chaining, subshells, etc.)
86
- if (/[;&|`$()]/.test(command)) {
87
- (0, debug_1.debug)(`Denying bash command with shell operators: ${command}`);
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. Chained commands are not permitted.`,
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
- const isAllowed = ALLOWED_BASH_PREFIXES.some((prefix) => command.startsWith(prefix));
95
- if (isAllowed) {
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 package manager commands (npm/pnpm/bun/yarn install) are permitted.`,
190
+ message: `Bash command not allowed. Only install, build, typecheck, and lint commands are permitted.`,
103
191
  };
104
192
  }
105
193
  /**
106
- * Initialize a PostHog Agent instance with the provided configuration
194
+ * Initialize agent configuration for the LLM gateway
107
195
  */
108
- async function initializeAgent(config, options, spinner) {
109
- clack_1.default.log.step('Initializing PostHog agent...');
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
- const { Agent } = await getAgentModule();
112
- const agentConfig = {
113
- workingDirectory: config.workingDirectory,
114
- posthogMcpUrl: config.posthogMcpUrl,
115
- posthogApiKey: config.posthogApiKey,
116
- onEvent: (event) => {
117
- handleAgentEvent(event, options, spinner);
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: agentConfig.workingDirectory,
124
- posthogMcpUrl: agentConfig.posthogMcpUrl,
125
- posthogApiKeyPresent: !!agentConfig.posthogApiKey,
233
+ workingDirectory: agentRunConfig.workingDirectory,
234
+ posthogMcpUrl: config.posthogMcpUrl,
235
+ gatewayUrl,
236
+ apiKeyPresent: !!config.posthogApiKey,
126
237
  });
127
238
  }
128
- const agent = new Agent(agentConfig);
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 agent;
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(agent, prompt, options, spinner, config) {
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 { PermissionMode } = await getAgentModule();
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
- const result = await agent.run(prompt, {
232
- repositoryPath: options.installDir,
233
- permissionMode: PermissionMode.ACCEPT_EDITS,
234
- queryOverrides: {
235
- model: 'claude-opus-4-5-20251101',
236
- canUseTool: wizardCanUseTool,
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
- * Extract text content from agent execution results
349
+ * Handle SDK messages and provide user feedback
261
350
  */
262
- function extractTextFromResults(results) {
263
- const textParts = [];
264
- for (const result of results) {
265
- // Handle assistant messages with content blocks
266
- if (result?.type === ContentType.ASSISTANT && result.message?.content) {
267
- const content = result.message.content;
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 === ContentType.TEXT && block.text) {
271
- textParts.push(block.text);
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
- // Handle direct text content
277
- if (typeof result === 'string') {
278
- textParts.push(result);
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