opc-agent 4.0.1 → 4.0.2

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.
@@ -332,6 +332,9 @@ class ClaudeCLIProvider {
332
332
  async chat(messages, systemPrompt, options) {
333
333
  const { execFile } = await Promise.resolve().then(() => __importStar(require('child_process')));
334
334
  const { promisify } = await Promise.resolve().then(() => __importStar(require('util')));
335
+ const { writeFileSync, unlinkSync, mkdtempSync } = await Promise.resolve().then(() => __importStar(require('fs')));
336
+ const { join } = await Promise.resolve().then(() => __importStar(require('path')));
337
+ const { tmpdir } = await Promise.resolve().then(() => __importStar(require('os')));
335
338
  const execFileAsync = promisify(execFile);
336
339
  // Build the prompt from messages
337
340
  const lastMessage = messages[messages.length - 1];
@@ -342,9 +345,14 @@ class ClaudeCLIProvider {
342
345
  if (options?.tools && options.tools.length > 0) {
343
346
  prompt += buildToolPrompt(options.tools);
344
347
  }
345
- const args = ['--print'];
348
+ const args = ['-p'];
349
+ // Write system prompt to temp file to avoid shell escaping issues
350
+ let tmpFile;
346
351
  if (systemPrompt) {
347
- args.push('--system-prompt', systemPrompt);
352
+ const tmpDir = mkdtempSync(join(tmpdir(), 'opc-'));
353
+ tmpFile = join(tmpDir, 'system.txt');
354
+ writeFileSync(tmpFile, systemPrompt, 'utf8');
355
+ args.push('--system-prompt-file', tmpFile);
348
356
  }
349
357
  if (this.model) {
350
358
  args.push('--model', this.model);
@@ -363,8 +371,20 @@ class ClaudeCLIProvider {
363
371
  throw new Error('Claude CLI not found. Install it: npm install -g @anthropic-ai/claude-code\n' +
364
372
  'Then authenticate: claude login');
365
373
  }
374
+ // If claude returns non-zero but has stdout, use it
375
+ if (err.stdout && err.stdout.trim()) {
376
+ return err.stdout.trim();
377
+ }
366
378
  throw new Error(`Claude CLI error: ${err.message}`);
367
379
  }
380
+ finally {
381
+ if (tmpFile) {
382
+ try {
383
+ unlinkSync(tmpFile);
384
+ }
385
+ catch { }
386
+ }
387
+ }
368
388
  }
369
389
  async *chatStream(messages, systemPrompt) {
370
390
  // Claude CLI --print doesn't support streaming well, so we do single-shot
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opc-agent",
3
- "version": "4.0.1",
3
+ "version": "4.0.2",
4
4
  "description": "Open Agent Framework — Build, test, and run AI Agents for business workstations",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -336,6 +336,9 @@ class ClaudeCLIProvider implements LLMProvider {
336
336
  async chat(messages: Message[], systemPrompt?: string, options?: ChatOptions): Promise<string> {
337
337
  const { execFile } = await import('child_process');
338
338
  const { promisify } = await import('util');
339
+ const { writeFileSync, unlinkSync, mkdtempSync } = await import('fs');
340
+ const { join } = await import('path');
341
+ const { tmpdir } = await import('os');
339
342
  const execFileAsync = promisify(execFile);
340
343
 
341
344
  // Build the prompt from messages
@@ -349,9 +352,14 @@ class ClaudeCLIProvider implements LLMProvider {
349
352
  prompt += buildToolPrompt(options.tools);
350
353
  }
351
354
 
352
- const args = ['--print'];
355
+ const args = ['-p'];
356
+ // Write system prompt to temp file to avoid shell escaping issues
357
+ let tmpFile: string | undefined;
353
358
  if (systemPrompt) {
354
- args.push('--system-prompt', systemPrompt);
359
+ const tmpDir = mkdtempSync(join(tmpdir(), 'opc-'));
360
+ tmpFile = join(tmpDir, 'system.txt');
361
+ writeFileSync(tmpFile, systemPrompt, 'utf8');
362
+ args.push('--system-prompt-file', tmpFile);
355
363
  }
356
364
  if (this.model) {
357
365
  args.push('--model', this.model);
@@ -372,7 +380,15 @@ class ClaudeCLIProvider implements LLMProvider {
372
380
  'Then authenticate: claude login'
373
381
  );
374
382
  }
383
+ // If claude returns non-zero but has stdout, use it
384
+ if (err.stdout && err.stdout.trim()) {
385
+ return err.stdout.trim();
386
+ }
375
387
  throw new Error(`Claude CLI error: ${err.message}`);
388
+ } finally {
389
+ if (tmpFile) {
390
+ try { unlinkSync(tmpFile); } catch {}
391
+ }
376
392
  }
377
393
  }
378
394