@sureliving/n8n-nodes-claudecode 0.1.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.
@@ -0,0 +1,690 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ClaudeCode = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ const claude_agent_sdk_1 = require("@anthropic-ai/claude-agent-sdk");
6
+ function buildSanitizedEnv(overrides) {
7
+ const env = {};
8
+ for (const [key, value] of Object.entries(process.env)) {
9
+ if (typeof value !== 'string')
10
+ continue;
11
+ env[key] = value;
12
+ }
13
+ const authKeysToStrip = [
14
+ 'ANTHROPIC_API_KEY',
15
+ 'ANTHROPIC_AUTH_TOKEN',
16
+ 'ANTHROPIC_TOKEN',
17
+ 'CLAUDE_API_KEY',
18
+ 'CLAUDE_CODE_OAUTH_TOKEN',
19
+ 'CLAUDE_CODE_SESSION_TOKEN',
20
+ ];
21
+ for (const k of authKeysToStrip)
22
+ delete env[k];
23
+ for (const [k, v] of Object.entries(overrides)) {
24
+ if (typeof v === 'string' && v.length > 0)
25
+ env[k] = v;
26
+ }
27
+ return env;
28
+ }
29
+ function redactString(input, secrets) {
30
+ let out = input;
31
+ for (const secret of secrets) {
32
+ if (!secret)
33
+ continue;
34
+ out = out.split(secret).join('***REDACTED***');
35
+ }
36
+ return out;
37
+ }
38
+ function redactSecretsDeep(value, secrets) {
39
+ if (value === null || value === undefined)
40
+ return value;
41
+ if (typeof value === 'string')
42
+ return redactString(value, secrets);
43
+ if (typeof value !== 'object')
44
+ return value;
45
+ if (Array.isArray(value))
46
+ return value.map((v) => redactSecretsDeep(v, secrets));
47
+ const obj = value;
48
+ const out = {};
49
+ for (const [k, v] of Object.entries(obj)) {
50
+ out[k] = redactSecretsDeep(v, secrets);
51
+ }
52
+ return out;
53
+ }
54
+ class ClaudeCode {
55
+ constructor() {
56
+ this.description = {
57
+ displayName: 'Claude Code',
58
+ name: 'claudeCode',
59
+ icon: 'file:claudecode.svg',
60
+ group: ['transform'],
61
+ version: 1,
62
+ subtitle: '={{$parameter["operation"] + ": " + $parameter["prompt"]}}',
63
+ description: 'Use Claude Code SDK to execute AI-powered coding tasks with customizable tool support',
64
+ defaults: {
65
+ name: 'Claude Code',
66
+ },
67
+ credentials: [
68
+ {
69
+ name: 'anthropicApi',
70
+ required: true,
71
+ },
72
+ ],
73
+ inputs: [{ type: "main" }],
74
+ outputs: [{ type: "main" }],
75
+ properties: [
76
+ {
77
+ displayName: 'Operation',
78
+ name: 'operation',
79
+ type: 'options',
80
+ noDataExpression: true,
81
+ options: [
82
+ {
83
+ name: 'Query',
84
+ value: 'query',
85
+ description: 'Start a new conversation with Claude Code',
86
+ action: 'Start a new conversation with claude code',
87
+ },
88
+ {
89
+ name: 'Continue',
90
+ value: 'continue',
91
+ description: 'Continue a previous conversation (requires prior query)',
92
+ action: 'Continue a previous conversation requires prior query',
93
+ },
94
+ ],
95
+ default: 'query',
96
+ },
97
+ {
98
+ displayName: 'Prompt',
99
+ name: 'prompt',
100
+ type: 'string',
101
+ typeOptions: {
102
+ rows: 4,
103
+ },
104
+ default: '',
105
+ description: 'The prompt or instruction to send to Claude Code',
106
+ required: true,
107
+ placeholder: 'e.g., "Create a Python function to parse CSV files"',
108
+ hint: 'Use expressions like {{$json.prompt}} to use data from previous nodes',
109
+ },
110
+ {
111
+ displayName: 'Model',
112
+ name: 'model',
113
+ type: 'options',
114
+ options: [
115
+ {
116
+ name: 'Sonnet',
117
+ value: 'sonnet',
118
+ description: 'Fast and efficient model for most tasks',
119
+ },
120
+ {
121
+ name: 'Opus',
122
+ value: 'opus',
123
+ description: 'Most capable model for complex tasks',
124
+ },
125
+ ],
126
+ default: 'sonnet',
127
+ description: 'Claude model to use',
128
+ },
129
+ {
130
+ displayName: 'Max Turns',
131
+ name: 'maxTurns',
132
+ type: 'number',
133
+ default: 25,
134
+ description: 'Maximum number of conversation turns (back-and-forth exchanges) allowed. Complex tasks may require more turns.',
135
+ },
136
+ {
137
+ displayName: 'Timeout',
138
+ name: 'timeout',
139
+ type: 'number',
140
+ default: 300,
141
+ description: 'Maximum time to wait for completion (in seconds) before aborting',
142
+ },
143
+ {
144
+ displayName: 'Project Path',
145
+ name: 'projectPath',
146
+ type: 'string',
147
+ default: '',
148
+ description: 'The directory path where Claude Code should run (e.g., /path/to/project). If empty, uses the current working directory.',
149
+ placeholder: '/home/user/projects/my-app',
150
+ hint: 'This sets the working directory for Claude Code, allowing it to access files and run commands in the specified project location',
151
+ },
152
+ {
153
+ displayName: 'Output Format',
154
+ name: 'outputFormat',
155
+ type: 'options',
156
+ noDataExpression: true,
157
+ options: [
158
+ {
159
+ name: 'Structured',
160
+ value: 'structured',
161
+ description: 'Returns a structured object with messages, summary, result, and metrics',
162
+ },
163
+ {
164
+ name: 'Messages',
165
+ value: 'messages',
166
+ description: 'Returns the raw array of all messages exchanged',
167
+ },
168
+ {
169
+ name: 'Text',
170
+ value: 'text',
171
+ description: 'Returns only the final result text',
172
+ },
173
+ ],
174
+ default: 'structured',
175
+ description: 'Choose how to format the output data',
176
+ },
177
+ {
178
+ displayName: 'Allowed Tools',
179
+ name: 'allowedTools',
180
+ type: 'multiOptions',
181
+ options: [
182
+ { name: 'Bash', value: 'Bash', description: 'Execute bash commands' },
183
+ { name: 'Edit', value: 'Edit', description: 'Edit files' },
184
+ { name: 'Exit Plan Mode', value: 'exit_plan_mode', description: 'Exit planning mode' },
185
+ { name: 'Glob', value: 'Glob', description: 'Find files by pattern' },
186
+ { name: 'Grep', value: 'Grep', description: 'Search file contents' },
187
+ { name: 'LS', value: 'LS', description: 'List directory contents' },
188
+ { name: 'MultiEdit', value: 'MultiEdit', description: 'Make multiple edits' },
189
+ { name: 'Notebook Edit', value: 'NotebookEdit', description: 'Edit Jupyter notebooks' },
190
+ { name: 'Notebook Read', value: 'NotebookRead', description: 'Read Jupyter notebooks' },
191
+ { name: 'Read', value: 'Read', description: 'Read file contents' },
192
+ { name: 'Task', value: 'Task', description: 'Launch agents for complex searches' },
193
+ { name: 'Todo Write', value: 'TodoWrite', description: 'Manage todo lists' },
194
+ { name: 'Web Fetch', value: 'WebFetch', description: 'Fetch web content' },
195
+ { name: 'Web Search', value: 'WebSearch', description: 'Search the web' },
196
+ { name: 'Write', value: 'Write', description: 'Write files' },
197
+ ],
198
+ default: ['WebFetch', 'TodoWrite', 'WebSearch', 'exit_plan_mode', 'Task'],
199
+ description: 'Select which built-in tools Claude Code is allowed to use during execution',
200
+ },
201
+ {
202
+ displayName: 'Disallowed Tools',
203
+ name: 'disallowedTools',
204
+ type: 'multiOptions',
205
+ options: [
206
+ { name: 'Bash', value: 'Bash', description: 'Execute bash commands' },
207
+ { name: 'Edit', value: 'Edit', description: 'Edit files' },
208
+ { name: 'Exit Plan Mode', value: 'exit_plan_mode', description: 'Exit planning mode' },
209
+ { name: 'Glob', value: 'Glob', description: 'Find files by pattern' },
210
+ { name: 'Grep', value: 'Grep', description: 'Search file contents' },
211
+ { name: 'LS', value: 'LS', description: 'List directory contents' },
212
+ { name: 'MultiEdit', value: 'MultiEdit', description: 'Make multiple edits' },
213
+ { name: 'Notebook Edit', value: 'NotebookEdit', description: 'Edit Jupyter notebooks' },
214
+ { name: 'Notebook Read', value: 'NotebookRead', description: 'Read Jupyter notebooks' },
215
+ { name: 'Read', value: 'Read', description: 'Read file contents' },
216
+ { name: 'Task', value: 'Task', description: 'Launch agents for complex searches' },
217
+ { name: 'Todo Write', value: 'TodoWrite', description: 'Manage todo lists' },
218
+ { name: 'Web Fetch', value: 'WebFetch', description: 'Fetch web content' },
219
+ { name: 'Web Search', value: 'WebSearch', description: 'Search the web' },
220
+ { name: 'Write', value: 'Write', description: 'Write files' },
221
+ ],
222
+ default: [],
223
+ description: 'Select which built-in tools Claude Code is explicitly blocked from using. Takes precedence over Allowed Tools.',
224
+ },
225
+ {
226
+ displayName: 'Additional Options',
227
+ name: 'additionalOptions',
228
+ type: 'collection',
229
+ placeholder: 'Add Option',
230
+ default: {},
231
+ options: [
232
+ {
233
+ displayName: 'Debug Mode',
234
+ name: 'debug',
235
+ type: 'boolean',
236
+ default: false,
237
+ description: 'Whether to enable debug logging',
238
+ },
239
+ {
240
+ displayName: 'Fallback Model',
241
+ name: 'fallbackModel',
242
+ type: 'options',
243
+ options: [
244
+ {
245
+ name: 'None',
246
+ value: '',
247
+ description: 'No fallback model',
248
+ },
249
+ {
250
+ name: 'Sonnet',
251
+ value: 'sonnet',
252
+ description: 'Fallback to Sonnet when primary model is overloaded',
253
+ },
254
+ {
255
+ name: 'Opus',
256
+ value: 'opus',
257
+ description: 'Fallback to Opus when primary model is overloaded',
258
+ },
259
+ ],
260
+ default: '',
261
+ description: 'Automatically switch to fallback model when primary model is overloaded',
262
+ },
263
+ {
264
+ displayName: 'Max Thinking Tokens',
265
+ name: 'maxThinkingTokens',
266
+ type: 'number',
267
+ default: 0,
268
+ description: 'Maximum number of thinking tokens (0 for unlimited)',
269
+ hint: 'Controls how many tokens Claude can use for internal reasoning',
270
+ },
271
+ {
272
+ displayName: 'Permission Mode',
273
+ name: 'permissionMode',
274
+ type: 'options',
275
+ options: [
276
+ {
277
+ name: 'Default',
278
+ value: 'default',
279
+ description: 'Standard permission prompts',
280
+ },
281
+ {
282
+ name: 'Accept Edits',
283
+ value: 'acceptEdits',
284
+ description: 'Automatically accept file edits',
285
+ },
286
+ {
287
+ name: 'Bypass Permissions',
288
+ value: 'bypassPermissions',
289
+ description: 'Skip all permission checks',
290
+ },
291
+ {
292
+ name: 'Plan',
293
+ value: 'plan',
294
+ description: 'Planning mode - Claude will plan before executing',
295
+ },
296
+ ],
297
+ default: 'bypassPermissions',
298
+ description: 'How to handle permission requests for tool usage',
299
+ },
300
+ {
301
+ displayName: 'System Prompt',
302
+ name: 'systemPrompt',
303
+ type: 'string',
304
+ typeOptions: {
305
+ rows: 4,
306
+ },
307
+ default: '',
308
+ description: 'Additional context or instructions for Claude Code',
309
+ placeholder: 'You are helping with a Python project. Focus on clean, readable code with proper error handling.',
310
+ },
311
+ ],
312
+ },
313
+ ],
314
+ };
315
+ }
316
+ async execute() {
317
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
318
+ const items = this.getInputData();
319
+ const returnData = [];
320
+ for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
321
+ let timeout = 300;
322
+ try {
323
+ const operation = this.getNodeParameter('operation', itemIndex);
324
+ const prompt = this.getNodeParameter('prompt', itemIndex);
325
+ const model = this.getNodeParameter('model', itemIndex);
326
+ const maxTurns = this.getNodeParameter('maxTurns', itemIndex);
327
+ timeout = this.getNodeParameter('timeout', itemIndex);
328
+ const projectPath = this.getNodeParameter('projectPath', itemIndex);
329
+ const outputFormat = this.getNodeParameter('outputFormat', itemIndex);
330
+ const allowedTools = this.getNodeParameter('allowedTools', itemIndex, []);
331
+ const disallowedTools = this.getNodeParameter('disallowedTools', itemIndex, []);
332
+ const additionalOptions = this.getNodeParameter('additionalOptions', itemIndex);
333
+ const abortController = new AbortController();
334
+ const timeoutMs = timeout * 1000;
335
+ const timeoutId = setTimeout(() => abortController.abort(), timeoutMs);
336
+ if (!prompt || prompt.trim() === '') {
337
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Prompt is required and cannot be empty', {
338
+ itemIndex,
339
+ });
340
+ }
341
+ if (additionalOptions.debug) {
342
+ this.logger.debug('Starting Claude Code execution', {
343
+ itemIndex,
344
+ prompt: prompt.substring(0, 100) + '...',
345
+ model,
346
+ maxTurns,
347
+ timeout: `${timeout}s`,
348
+ allowedTools,
349
+ disallowedTools,
350
+ fallbackModel: additionalOptions.fallbackModel || 'none',
351
+ });
352
+ }
353
+ const queryOptions = {
354
+ prompt,
355
+ abortController,
356
+ options: {
357
+ maxTurns,
358
+ permissionMode: (additionalOptions.permissionMode || 'bypassPermissions'),
359
+ model,
360
+ systemPrompt: additionalOptions.systemPrompt
361
+ ? { type: 'preset', preset: 'claude_code', append: additionalOptions.systemPrompt }
362
+ : { type: 'preset', preset: 'claude_code' },
363
+ settingSources: ['user', 'project', 'local'],
364
+ },
365
+ };
366
+ const credentials = (await this.getCredentials('anthropicApi'));
367
+ const apiKey = (_a = credentials.apiKey) === null || _a === void 0 ? void 0 : _a.trim();
368
+ if (!apiKey) {
369
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Anthropic API Key credential is required', {
370
+ itemIndex,
371
+ });
372
+ }
373
+ const secretsToRedact = [apiKey];
374
+ queryOptions.options.env = buildSanitizedEnv({
375
+ ANTHROPIC_API_KEY: apiKey,
376
+ });
377
+ if (projectPath && projectPath.trim() !== '') {
378
+ queryOptions.options.cwd = projectPath.trim();
379
+ if (additionalOptions.debug) {
380
+ this.logger.debug('Working directory set', { cwd: queryOptions.options.cwd });
381
+ }
382
+ }
383
+ if (allowedTools.length > 0) {
384
+ queryOptions.options.allowedTools = allowedTools;
385
+ if (additionalOptions.debug) {
386
+ this.logger.debug('Allowed tools configured', { allowedTools });
387
+ }
388
+ }
389
+ if (disallowedTools.length > 0) {
390
+ queryOptions.options.disallowedTools = disallowedTools;
391
+ if (additionalOptions.debug) {
392
+ this.logger.debug('Disallowed tools configured', { disallowedTools });
393
+ }
394
+ }
395
+ if (additionalOptions.fallbackModel) {
396
+ queryOptions.options.fallbackModel = additionalOptions.fallbackModel;
397
+ }
398
+ if (additionalOptions.maxThinkingTokens && additionalOptions.maxThinkingTokens > 0) {
399
+ queryOptions.options.maxThinkingTokens = additionalOptions.maxThinkingTokens;
400
+ }
401
+ if (operation === 'continue') {
402
+ queryOptions.options.continue = true;
403
+ }
404
+ const messages = [];
405
+ const startTime = Date.now();
406
+ try {
407
+ for await (const message of (0, claude_agent_sdk_1.query)(queryOptions)) {
408
+ messages.push(message);
409
+ if (additionalOptions.debug) {
410
+ if (message.type === 'system' && message.subtype === 'init') {
411
+ this.logger.debug('System init message', {
412
+ type: message.type,
413
+ subtype: message.subtype,
414
+ model: message.model,
415
+ toolCount: ((_b = message.tools) === null || _b === void 0 ? void 0 : _b.length) || 0,
416
+ });
417
+ }
418
+ else if (message.type === 'assistant') {
419
+ const content = (_c = message.message) === null || _c === void 0 ? void 0 : _c.content;
420
+ this.logger.debug('Assistant message', {
421
+ type: message.type,
422
+ contentTypes: (content === null || content === void 0 ? void 0 : content.map((c) => c.type)) || [],
423
+ textLength: ((_e = (_d = content === null || content === void 0 ? void 0 : content.find((c) => c.type === 'text')) === null || _d === void 0 ? void 0 : _d.text) === null || _e === void 0 ? void 0 : _e.length) || 0,
424
+ hasToolUse: (content === null || content === void 0 ? void 0 : content.some((c) => c.type === 'tool_use')) || false,
425
+ });
426
+ }
427
+ else if (message.type === 'user') {
428
+ this.logger.debug('User message', {
429
+ type: message.type,
430
+ hasToolResult: !!((_g = (_f = message.message) === null || _f === void 0 ? void 0 : _f.content) === null || _g === void 0 ? void 0 : _g.some((c) => c.type === 'tool_result')),
431
+ });
432
+ }
433
+ else if (message.type === 'result') {
434
+ const resultMsg = message;
435
+ this.logger.debug('Result message', {
436
+ type: message.type,
437
+ subtype: resultMsg.subtype,
438
+ hasResult: !!resultMsg.result,
439
+ hasError: !!resultMsg.error,
440
+ resultLength: resultMsg.result ? String(resultMsg.result).length : 0,
441
+ error: resultMsg.error || 'none',
442
+ duration_ms: resultMsg.duration_ms,
443
+ total_cost: resultMsg.total_cost_usd,
444
+ });
445
+ if (resultMsg.subtype === 'error_during_execution') {
446
+ this.logger.error('Claude Code execution error', {
447
+ subtype: resultMsg.subtype,
448
+ error: resultMsg.error,
449
+ details: JSON.stringify(resultMsg).substring(0, 500),
450
+ });
451
+ }
452
+ }
453
+ else {
454
+ this.logger.debug('Other message', {
455
+ type: message.type,
456
+ message: JSON.stringify(message).substring(0, 200),
457
+ });
458
+ }
459
+ }
460
+ if (message.type === 'assistant' && ((_h = message.message) === null || _h === void 0 ? void 0 : _h.content)) {
461
+ const content = message.message.content[0];
462
+ if (additionalOptions.debug) {
463
+ if (content.type === 'text') {
464
+ this.logger.debug('Assistant response', {
465
+ text: content.text.substring(0, 100) + '...',
466
+ });
467
+ }
468
+ else if (content.type === 'tool_use') {
469
+ this.logger.debug('Tool use', { toolName: content.name });
470
+ }
471
+ }
472
+ }
473
+ }
474
+ clearTimeout(timeoutId);
475
+ const duration = Date.now() - startTime;
476
+ if (additionalOptions.debug) {
477
+ this.logger.debug('Execution completed', {
478
+ durationMs: duration,
479
+ messageCount: messages.length,
480
+ });
481
+ const messageTypes = messages.map((m) => ({
482
+ type: m.type,
483
+ subtype: m.subtype,
484
+ }));
485
+ this.logger.debug('All messages in order', { messageTypes });
486
+ }
487
+ if (outputFormat === 'text') {
488
+ const resultMessage = messages.find((m) => m.type === 'result');
489
+ if (additionalOptions.debug) {
490
+ this.logger.debug('Processing text output format', {
491
+ foundResultMessage: !!resultMessage,
492
+ messageCount: messages.length,
493
+ });
494
+ }
495
+ let finalText = '';
496
+ let errorText = '';
497
+ if (resultMessage) {
498
+ if (resultMessage.result) {
499
+ finalText = resultMessage.result;
500
+ }
501
+ else if (resultMessage.error) {
502
+ errorText = resultMessage.error;
503
+ finalText = `Error: ${resultMessage.error}`;
504
+ }
505
+ else if (resultMessage.subtype === 'error_max_turns') {
506
+ errorText = 'Maximum turns reached';
507
+ const assistantMessages = messages.filter((m) => { var _a; return m.type === 'assistant' && ((_a = m.message) === null || _a === void 0 ? void 0 : _a.content); });
508
+ if (assistantMessages.length > 0) {
509
+ const lastMessage = assistantMessages[assistantMessages.length - 1];
510
+ const textContent = (_k = (_j = lastMessage.message) === null || _j === void 0 ? void 0 : _j.content) === null || _k === void 0 ? void 0 : _k.find((c) => c.type === 'text');
511
+ if (textContent === null || textContent === void 0 ? void 0 : textContent.text) {
512
+ finalText = `[PARTIAL - Max turns reached]\n\n${textContent.text}\n\n[Note: Task incomplete. Increase maxTurns parameter to complete.]`;
513
+ }
514
+ else {
515
+ finalText =
516
+ 'Error: Maximum conversation turns reached. Consider increasing maxTurns parameter.';
517
+ }
518
+ }
519
+ else {
520
+ finalText =
521
+ 'Error: Maximum conversation turns reached. Consider increasing maxTurns parameter.';
522
+ }
523
+ }
524
+ else if (resultMessage.subtype === 'error_during_execution') {
525
+ errorText = 'Error during execution';
526
+ const assistantMessages = messages.filter((m) => { var _a; return m.type === 'assistant' && ((_a = m.message) === null || _a === void 0 ? void 0 : _a.content); });
527
+ if (assistantMessages.length > 0) {
528
+ const lastMessage = assistantMessages[assistantMessages.length - 1];
529
+ const textContent = (_m = (_l = lastMessage.message) === null || _l === void 0 ? void 0 : _l.content) === null || _m === void 0 ? void 0 : _m.find((c) => c.type === 'text');
530
+ if (textContent === null || textContent === void 0 ? void 0 : textContent.text) {
531
+ finalText = `[ERROR - Execution failed]\n\n${textContent.text}\n\n[Note: An error occurred during execution. Check logs for details.]`;
532
+ }
533
+ else {
534
+ finalText = 'Error: Execution failed. Check debug logs for details.';
535
+ }
536
+ }
537
+ else {
538
+ finalText = 'Error: Execution failed. No output available.';
539
+ }
540
+ }
541
+ if (additionalOptions.debug) {
542
+ this.logger.debug('Result message details', {
543
+ type: resultMessage.type,
544
+ subtype: resultMessage.subtype,
545
+ hasResult: !!resultMessage.result,
546
+ hasError: !!resultMessage.error,
547
+ resultLength: resultMessage.result ? String(resultMessage.result).length : 0,
548
+ errorMessage: resultMessage.error || 'none',
549
+ });
550
+ }
551
+ }
552
+ else {
553
+ const assistantMessages = messages.filter((m) => { var _a; return m.type === 'assistant' && ((_a = m.message) === null || _a === void 0 ? void 0 : _a.content); });
554
+ if (assistantMessages.length > 0) {
555
+ const lastMessage = assistantMessages[assistantMessages.length - 1];
556
+ const textContent = (_p = (_o = lastMessage.message) === null || _o === void 0 ? void 0 : _o.content) === null || _p === void 0 ? void 0 : _p.find((c) => c.type === 'text');
557
+ finalText = (textContent === null || textContent === void 0 ? void 0 : textContent.text) || '';
558
+ }
559
+ if (!finalText) {
560
+ finalText = 'No response generated - check debug logs for details';
561
+ }
562
+ }
563
+ const outputData = {
564
+ result: redactString(String(finalText || 'No response generated'), secretsToRedact),
565
+ success: (resultMessage === null || resultMessage === void 0 ? void 0 : resultMessage.subtype) === 'success' ? true : false,
566
+ duration_ms: Number((resultMessage === null || resultMessage === void 0 ? void 0 : resultMessage.duration_ms) || 0),
567
+ total_cost_usd: Number((resultMessage === null || resultMessage === void 0 ? void 0 : resultMessage.total_cost_usd) || 0),
568
+ };
569
+ if (additionalOptions.debug) {
570
+ this.logger.debug('Text output format data', {
571
+ outputData,
572
+ resultPreview: outputData.result.substring(0, 200) +
573
+ (outputData.result.length > 200 ? '...' : ''),
574
+ outputDataTypes: {
575
+ result: typeof outputData.result,
576
+ success: typeof outputData.success,
577
+ duration_ms: typeof outputData.duration_ms,
578
+ total_cost_usd: typeof outputData.total_cost_usd,
579
+ },
580
+ });
581
+ const messageSummary = messages.reduce((acc, msg) => {
582
+ acc[msg.type] = (acc[msg.type] || 0) + 1;
583
+ return acc;
584
+ }, {});
585
+ this.logger.debug('Message summary', {
586
+ messageSummary,
587
+ totalMessages: messages.length,
588
+ hasResultMessage: !!resultMessage,
589
+ resultError: errorText || 'none',
590
+ });
591
+ try {
592
+ JSON.stringify(outputData);
593
+ }
594
+ catch (e) {
595
+ this.logger.error('Output data is not JSON-compatible', { error: e });
596
+ }
597
+ }
598
+ returnData.push({
599
+ json: outputData,
600
+ pairedItem: { item: itemIndex },
601
+ });
602
+ }
603
+ else if (outputFormat === 'messages') {
604
+ returnData.push({
605
+ json: {
606
+ messages: redactSecretsDeep(messages, secretsToRedact),
607
+ messageCount: messages.length,
608
+ },
609
+ pairedItem: { item: itemIndex },
610
+ });
611
+ }
612
+ else if (outputFormat === 'structured') {
613
+ const userMessages = messages.filter((m) => m.type === 'user');
614
+ const assistantMessages = messages.filter((m) => m.type === 'assistant');
615
+ const toolUses = messages.filter((m) => { var _a, _b, _c; return m.type === 'assistant' && ((_c = (_b = (_a = m.message) === null || _a === void 0 ? void 0 : _a.content) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.type) === 'tool_use'; });
616
+ const systemInit = messages.find((m) => m.type === 'system' && m.subtype === 'init');
617
+ const resultMessage = messages.find((m) => m.type === 'result');
618
+ returnData.push({
619
+ json: {
620
+ messages: redactSecretsDeep(messages, secretsToRedact),
621
+ summary: {
622
+ userMessageCount: userMessages.length,
623
+ assistantMessageCount: assistantMessages.length,
624
+ toolUseCount: toolUses.length,
625
+ hasResult: !!resultMessage,
626
+ toolsAvailable: (systemInit === null || systemInit === void 0 ? void 0 : systemInit.tools) || [],
627
+ },
628
+ result: redactSecretsDeep((resultMessage === null || resultMessage === void 0 ? void 0 : resultMessage.result) || (resultMessage === null || resultMessage === void 0 ? void 0 : resultMessage.error) || null, secretsToRedact),
629
+ metrics: resultMessage
630
+ ? {
631
+ duration_ms: resultMessage.duration_ms,
632
+ num_turns: resultMessage.num_turns,
633
+ total_cost_usd: resultMessage.total_cost_usd,
634
+ usage: resultMessage.usage,
635
+ }
636
+ : null,
637
+ success: (resultMessage === null || resultMessage === void 0 ? void 0 : resultMessage.subtype) === 'success',
638
+ },
639
+ pairedItem: { item: itemIndex },
640
+ });
641
+ }
642
+ }
643
+ catch (queryError) {
644
+ clearTimeout(timeoutId);
645
+ if (outputFormat === 'text') {
646
+ const errorMessage = queryError instanceof Error ? queryError.message : String(queryError);
647
+ returnData.push({
648
+ json: {
649
+ result: `Error during execution: ${errorMessage}`,
650
+ success: false,
651
+ duration_ms: Date.now() - startTime,
652
+ total_cost_usd: 0,
653
+ },
654
+ pairedItem: { item: itemIndex },
655
+ });
656
+ }
657
+ else {
658
+ throw queryError;
659
+ }
660
+ }
661
+ }
662
+ catch (error) {
663
+ const errorMessage = error instanceof Error ? error.message : 'An unknown error occurred';
664
+ const isTimeout = error instanceof Error && error.name === 'AbortError';
665
+ if (this.continueOnFail()) {
666
+ returnData.push({
667
+ json: {
668
+ error: errorMessage,
669
+ errorType: isTimeout ? 'timeout' : 'execution_error',
670
+ errorDetails: error instanceof Error ? error.stack : undefined,
671
+ itemIndex,
672
+ },
673
+ pairedItem: itemIndex,
674
+ });
675
+ continue;
676
+ }
677
+ const userFriendlyMessage = isTimeout
678
+ ? `Operation timed out after ${timeout} seconds. Consider increasing the timeout in Additional Options.`
679
+ : `Claude Code execution failed: ${errorMessage}`;
680
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), userFriendlyMessage, {
681
+ itemIndex,
682
+ description: errorMessage,
683
+ });
684
+ }
685
+ }
686
+ return [returnData];
687
+ }
688
+ }
689
+ exports.ClaudeCode = ClaudeCode;
690
+ //# sourceMappingURL=ClaudeCode.node.js.map