@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.
|
|
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
|
-
|
|
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
|
-
'/
|
|
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
|
-
|
|
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
|
-
'/
|
|
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
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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
|
-
|
|
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
|
-
|
|
362
|
-
|
|
363
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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` +
|