@zibby/core 0.1.13 → 0.1.16

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zibby/core",
3
- "version": "0.1.13",
3
+ "version": "0.1.16",
4
4
  "description": "Core test automation engine with multi-agent and multi-MCP support",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -26,14 +26,13 @@
26
26
  "./package.json": "./package.json"
27
27
  },
28
28
  "scripts": {
29
- "test": "vitest run",
29
+ "test": "vitest run --exclude '**/memory/**'",
30
30
  "test:watch": "vitest",
31
31
  "test:state-schema": "vitest run src/framework/__tests__/state-schema.test.js",
32
32
  "test:state-schema:e2e": "node src/framework/__tests__/state-schema.e2e.test.js",
33
33
  "export:workflows": "node scripts/export-default-workflows.js",
34
34
  "lint": "eslint .",
35
- "lint:fix": "eslint --fix .",
36
- "prepublishOnly": "npm run lint && npm test"
35
+ "lint:fix": "eslint --fix ."
37
36
  },
38
37
  "keywords": [
39
38
  "testing",
@@ -23,12 +23,15 @@ export class CursorAgentStrategy extends AgentStrategy {
23
23
 
24
24
  canHandle(_context) {
25
25
  const paths = [
26
- 'agent',
27
- '/usr/local/bin/agent',
28
- '/usr/local/bin/cursor-agent',
26
+ // Try absolute paths first (most reliable)
29
27
  join(homedir(), '.local', 'bin', 'cursor-agent'),
30
28
  join(homedir(), '.cursor', 'bin', 'cursor-agent'),
31
- '/Applications/Cursor.app/Contents/Resources/app/bin/cursor'
29
+ '/usr/local/bin/cursor-agent',
30
+ '/usr/local/bin/agent',
31
+ '/Applications/Cursor.app/Contents/Resources/app/bin/cursor',
32
+ // Try PATH last (may have symlink issues)
33
+ 'agent',
34
+ 'cursor-agent'
32
35
  ];
33
36
 
34
37
  for (const path of paths) {
@@ -83,12 +86,15 @@ export class CursorAgentStrategy extends AgentStrategy {
83
86
  this._setupMcpConfig(sessionPath, workspace, config);
84
87
 
85
88
  const possibleBins = [
86
- 'agent',
87
- '/usr/local/bin/agent',
88
- '/usr/local/bin/cursor-agent',
89
+ // Try absolute paths first (most reliable)
89
90
  join(homedir(), '.local', 'bin', 'cursor-agent'),
90
91
  join(homedir(), '.cursor', 'bin', 'cursor-agent'),
91
- '/Applications/Cursor.app/Contents/Resources/app/bin/cursor'
92
+ '/usr/local/bin/cursor-agent',
93
+ '/usr/local/bin/agent',
94
+ '/Applications/Cursor.app/Contents/Resources/app/bin/cursor',
95
+ // Try PATH last (may have symlink issues)
96
+ 'agent',
97
+ 'cursor-agent'
92
98
  ];
93
99
 
94
100
  let cursorBin = null;
@@ -145,28 +151,19 @@ export class CursorAgentStrategy extends AgentStrategy {
145
151
  writeFileSync(promptFile, prompt, 'utf-8');
146
152
  logger.debug(`📝 [Agent] Prompt written to ${promptFile} (${prompt.length} chars)`);
147
153
 
148
- let args;
149
- if (cursorBin === 'agent') {
150
- args = [
151
- 'chat',
152
- '--print',
153
- '--force',
154
- '--approve-mcps',
155
- '--output-format', 'stream-json',
156
- '--stream-partial-output',
157
- '--model', model || 'auto',
158
- ];
159
- if (process.env.CURSOR_API_KEY) {
160
- args.push('--api-key', process.env.CURSOR_API_KEY);
161
- }
162
- args.push(`@${promptFile}`);
163
- } else {
164
- args = ['agent', '--print', '--force', '--trust', '--approve-mcps'];
165
- if (process.env.CURSOR_API_KEY) {
166
- args.push('--api-key', process.env.CURSOR_API_KEY);
167
- }
168
- args.push('--model', model || 'auto', `@${promptFile}`);
154
+ // All cursor-agent binaries use the same command structure (no subcommand needed)
155
+ const args = [
156
+ '--print',
157
+ '--force',
158
+ '--approve-mcps',
159
+ '--output-format', 'stream-json',
160
+ '--stream-partial-output',
161
+ '--model', model || 'auto',
162
+ ];
163
+ if (process.env.CURSOR_API_KEY) {
164
+ args.push('--api-key', process.env.CURSOR_API_KEY);
169
165
  }
166
+ args.push(`@${promptFile}`);
170
167
 
171
168
  const fullCmd = [cursorBin, ...args].join(' ');
172
169
  logger.debug(`[Agent] Executing: ${fullCmd.slice(0, 200)}`);
@@ -330,6 +327,7 @@ export class CursorAgentStrategy extends AgentStrategy {
330
327
  let lineCount = 0;
331
328
  let killed = false;
332
329
  let processStarted = false;
330
+ let processClosed = false;
333
331
 
334
332
  const proc = spawn(bin, args, {
335
333
  cwd,
@@ -339,30 +337,21 @@ export class CursorAgentStrategy extends AgentStrategy {
339
337
 
340
338
  logger.debug(`[Agent] PID: ${proc.pid}`);
341
339
 
342
- const startupTimer = setTimeout(() => {
343
- if (!processStarted && lineCount === 0) {
344
- killed = true;
345
- logger.error(`❌ [Agent] Process failed to start within 5 seconds. Binary may not be in PATH.`);
346
- logger.error(` Binary: ${bin}`);
347
- logger.error(` PATH: ${process.env.PATH}`);
348
- logger.error(` Try: export PATH="$HOME/.local/bin:$PATH"`);
349
- proc.kill('SIGTERM');
350
- setTimeout(() => { if (!proc.killed) proc.kill('SIGKILL'); }, 2000);
351
- reject(new Error(
352
- `Cursor Agent failed to start. Binary '${bin}' not found or not executable.\n\n` +
353
- `Install cursor-agent and add ~/.local/bin to your PATH:\n` +
354
- ` curl https://cursor.com/install -fsS | bash\n` +
355
- ` echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc && source ~/.zshrc`
356
- ));
357
- }
358
- }, 5000);
359
-
340
+ // Handle stdin write errors gracefully
360
341
  if (stdinPrompt) {
361
- proc.stdin.write(stdinPrompt);
362
- proc.stdin.end();
363
- logger.debug(`[Agent] Prompt also piped to stdin (${stdinPrompt.length} chars)`);
342
+ try {
343
+ proc.stdin.write(stdinPrompt);
344
+ proc.stdin.end();
345
+ logger.debug(`[Agent] Prompt also piped to stdin (${stdinPrompt.length} chars)`);
346
+ } catch (err) {
347
+ logger.warn(`[Agent] Failed to write to stdin: ${err.message}`);
348
+ }
364
349
  } else {
365
- proc.stdin.end();
350
+ try {
351
+ proc.stdin.end();
352
+ } catch (err) {
353
+ // Process may have already closed
354
+ }
366
355
  }
367
356
 
368
357
  const modifiedFiles = new Set();
@@ -462,12 +451,18 @@ export class CursorAgentStrategy extends AgentStrategy {
462
451
 
463
452
  if (!processStarted) {
464
453
  processStarted = true;
465
- clearTimeout(startupTimer);
466
454
  }
467
455
 
468
456
  const displayText = streamParser.processChunk(chunk);
469
- if (displayText) {
470
- process.stdout.write(displayText);
457
+ if (displayText && !processClosed) {
458
+ try {
459
+ process.stdout.write(displayText);
460
+ } catch (err) {
461
+ // Handle EPIPE gracefully - parent process stdout may be closed
462
+ if (err.code !== 'EPIPE') {
463
+ logger.warn(`[Agent] stdout write error: ${err.message}`);
464
+ }
465
+ }
471
466
  }
472
467
 
473
468
  const lines = chunk.split('\n').filter(l => l.trim());
@@ -481,7 +476,6 @@ export class CursorAgentStrategy extends AgentStrategy {
481
476
 
482
477
  if (!processStarted) {
483
478
  processStarted = true;
484
- clearTimeout(startupTimer);
485
479
  }
486
480
 
487
481
  const lines = chunk.split('\n').filter(l => l.trim());
@@ -491,8 +485,8 @@ export class CursorAgentStrategy extends AgentStrategy {
491
485
  });
492
486
 
493
487
  proc.on('close', (code, signal) => {
488
+ processClosed = true;
494
489
  clearTimeout(timer);
495
- clearTimeout(startupTimer);
496
490
  clearInterval(heartbeat);
497
491
  streamParser.flush();
498
492
  const elapsed = Math.round((Date.now() - startTime) / 1000);
@@ -526,7 +520,6 @@ export class CursorAgentStrategy extends AgentStrategy {
526
520
 
527
521
  proc.on('error', (err) => {
528
522
  clearTimeout(timer);
529
- clearTimeout(startupTimer);
530
523
  clearInterval(heartbeat);
531
524
  reject(new Error(
532
525
  `Cursor Agent spawn error: ${err.message}\n` +