@zibby/core 0.1.8 → 0.1.10
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 +1 -1
- package/src/framework/agents/cursor-strategy.js +45 -15
- package/src/index.js +15 -12
- package/templates/browser-test-automation/{graph.js → graph.mjs} +2 -2
- package/templates/browser-test-automation/nodes/{execute-live.js → execute-live.mjs} +1 -1
- package/templates/browser-test-automation/nodes/{generate-script.js → generate-script.mjs} +1 -1
- package/templates/browser-test-automation/nodes/index.mjs +3 -0
- package/templates/index.js +3 -3
- package/templates/browser-test-automation/nodes/index.js +0 -3
- /package/templates/browser-test-automation/nodes/{preflight.js → preflight.mjs} +0 -0
- /package/templates/browser-test-automation/nodes/{utils.js → utils.mjs} +0 -0
- /package/templates/browser-test-automation/{result-handler.js → result-handler.mjs} +0 -0
package/package.json
CHANGED
|
@@ -32,19 +32,31 @@ export class CursorAgentStrategy extends AgentStrategy {
|
|
|
32
32
|
for (const path of paths) {
|
|
33
33
|
try {
|
|
34
34
|
if (path.startsWith('/')) {
|
|
35
|
+
// Check file exists and is executable
|
|
35
36
|
accessSync(path, constants.X_OK);
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
// Verify it actually runs
|
|
38
|
+
const out = execSync(`"${path}" --version 2>&1`, { encoding: 'utf-8', timeout: 3000, stdio: 'pipe' });
|
|
39
|
+
if (out && out.length > 0) {
|
|
40
|
+
logger.debug(`[Cursor] Found agent at: ${path} (version: ${out.trim().slice(0, 50)})`);
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
// Check if in PATH and runs
|
|
45
|
+
const which = execSync(`which ${path}`, { encoding: 'utf-8', timeout: 2000, stdio: 'pipe' }).trim();
|
|
46
|
+
if (!which) continue;
|
|
47
|
+
const out = execSync(`${path} --version 2>&1`, { encoding: 'utf-8', timeout: 3000, stdio: 'pipe' });
|
|
48
|
+
if (out && out.length > 0) {
|
|
49
|
+
logger.debug(`[Cursor] Found '${path}' in PATH at ${which} (version: ${out.trim().slice(0, 50)})`);
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
38
52
|
}
|
|
39
|
-
execSync(`${path} --version 2>/dev/null`, { stdio: 'ignore', timeout: 2000 });
|
|
40
|
-
logger.debug(`[Cursor] Found '${path}' in PATH`);
|
|
41
|
-
return true;
|
|
42
53
|
} catch (_e) {
|
|
54
|
+
// Binary doesn't exist or doesn't work
|
|
43
55
|
continue;
|
|
44
56
|
}
|
|
45
57
|
}
|
|
46
58
|
|
|
47
|
-
logger.warn('[Cursor] ❌ Cursor Agent CLI not found');
|
|
59
|
+
logger.warn('[Cursor] ❌ Cursor Agent CLI not found or not working. Run: agent --version');
|
|
48
60
|
return false;
|
|
49
61
|
}
|
|
50
62
|
|
|
@@ -79,20 +91,34 @@ export class CursorAgentStrategy extends AgentStrategy {
|
|
|
79
91
|
for (const bin of possibleBins) {
|
|
80
92
|
try {
|
|
81
93
|
if (bin.startsWith('/')) {
|
|
94
|
+
// For absolute paths, check file exists and is executable
|
|
82
95
|
accessSync(bin, constants.X_OK);
|
|
96
|
+
// Also verify it actually runs
|
|
97
|
+
execSync(`"${bin}" --version 2>&1`, { encoding: 'utf-8', timeout: 3000, stdio: 'pipe' });
|
|
83
98
|
} else {
|
|
84
|
-
|
|
99
|
+
// For commands in PATH, verify they exist and run
|
|
100
|
+
const which = execSync(`which ${bin}`, { encoding: 'utf-8', timeout: 2000 }).trim();
|
|
101
|
+
if (!which) throw new Error('not in PATH');
|
|
102
|
+
// Verify the binary works
|
|
103
|
+
execSync(`${bin} --version 2>&1`, { encoding: 'utf-8', timeout: 3000, stdio: 'pipe' });
|
|
85
104
|
}
|
|
86
105
|
cursorBin = bin;
|
|
87
106
|
logger.debug(`[Agent] Using binary: ${bin}`);
|
|
88
107
|
break;
|
|
89
|
-
} catch {
|
|
108
|
+
} catch (err) {
|
|
109
|
+
logger.debug(`[Agent] Binary '${bin}' check failed: ${err.message}`);
|
|
90
110
|
continue;
|
|
91
111
|
}
|
|
92
112
|
}
|
|
93
113
|
|
|
94
114
|
if (!cursorBin) {
|
|
95
|
-
throw new Error(
|
|
115
|
+
throw new Error(
|
|
116
|
+
'Cursor Agent CLI not found or not working.\n\n' +
|
|
117
|
+
'Install it with:\n' +
|
|
118
|
+
' npm install -g @cursor/agent\n\n' +
|
|
119
|
+
'Or set CURSOR_API_KEY and ensure "agent" is in your PATH.\n' +
|
|
120
|
+
'Test with: agent --version'
|
|
121
|
+
);
|
|
96
122
|
}
|
|
97
123
|
|
|
98
124
|
// File-based structured output: agent writes JSON to this file
|
|
@@ -349,12 +375,16 @@ export class CursorAgentStrategy extends AgentStrategy {
|
|
|
349
375
|
|
|
350
376
|
logger.debug(`💓 [Agent] Running for ${elapsed}s | ${lineCount} lines output${activity}`);
|
|
351
377
|
|
|
352
|
-
if (lineCount === 0 && elapsed >=
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
378
|
+
if (lineCount === 0 && elapsed >= 30 && modifiedFiles.size === 0) {
|
|
379
|
+
if (elapsed < 35) {
|
|
380
|
+
logger.warn(`⚠️ [Agent] No output after ${elapsed}s — agent may be stuck. Check your CURSOR_API_KEY.`);
|
|
381
|
+
}
|
|
382
|
+
if (elapsed >= 60) {
|
|
383
|
+
killed = true;
|
|
384
|
+
logger.error(`❌ [Agent] No response after ${elapsed}s — killing. Verify CURSOR_API_KEY is valid and agent CLI works: agent --version`);
|
|
385
|
+
proc.kill('SIGTERM');
|
|
386
|
+
setTimeout(() => { if (!proc.killed) proc.kill('SIGKILL'); }, 3000);
|
|
387
|
+
}
|
|
358
388
|
}
|
|
359
389
|
}, 30000);
|
|
360
390
|
|
package/src/index.js
CHANGED
|
@@ -101,7 +101,8 @@ export async function runTest(specPath, config = {}) {
|
|
|
101
101
|
const testSpec = readFileSync(specPath, 'utf-8');
|
|
102
102
|
|
|
103
103
|
const adapter = null;
|
|
104
|
-
|
|
104
|
+
const { agent: localAgent, error: localAgentError } = await loadLocalAgent(cwd, agentConfig);
|
|
105
|
+
let agent = localAgent;
|
|
105
106
|
|
|
106
107
|
if (!agent && config.fallbackAgentModule) {
|
|
107
108
|
const mod = config.fallbackAgentModule;
|
|
@@ -111,11 +112,15 @@ export async function runTest(specPath, config = {}) {
|
|
|
111
112
|
}
|
|
112
113
|
}
|
|
113
114
|
|
|
115
|
+
if (!agent && localAgentError) {
|
|
116
|
+
console.warn(`⚠️ Failed to load local agent: ${localAgentError}`);
|
|
117
|
+
}
|
|
118
|
+
|
|
114
119
|
if (!agent) {
|
|
115
120
|
throw new Error(
|
|
116
121
|
`No agent found. Please run:\n` +
|
|
117
122
|
` zibby init\n\n` +
|
|
118
|
-
`This will create .zibby/graph.
|
|
123
|
+
`This will create .zibby/graph.mjs with your workflow definition.`
|
|
119
124
|
);
|
|
120
125
|
}
|
|
121
126
|
|
|
@@ -238,10 +243,10 @@ export async function listWorkflows(cwd = process.cwd()) {
|
|
|
238
243
|
const { existsSync: fsExistsSync } = await import('fs');
|
|
239
244
|
const { pathToFileURL } = await import('url');
|
|
240
245
|
|
|
241
|
-
const localAgentPath = pathJoin(cwd, '.zibby/graph.
|
|
246
|
+
const localAgentPath = pathJoin(cwd, '.zibby/graph.mjs');
|
|
242
247
|
|
|
243
248
|
if (!fsExistsSync(localAgentPath)) {
|
|
244
|
-
return { available: [], default: null, error: 'No .zibby/graph.
|
|
249
|
+
return { available: [], default: null, error: 'No .zibby/graph.mjs found' };
|
|
245
250
|
}
|
|
246
251
|
|
|
247
252
|
const agentModule = await import(pathToFileURL(localAgentPath).href);
|
|
@@ -268,10 +273,10 @@ async function loadLocalAgent(cwd, config) {
|
|
|
268
273
|
const { existsSync: fsExistsSync } = await import('fs');
|
|
269
274
|
const { pathToFileURL } = await import('url');
|
|
270
275
|
|
|
271
|
-
const localAgentPath = pathJoin(cwd, '.zibby/graph.
|
|
276
|
+
const localAgentPath = pathJoin(cwd, '.zibby/graph.mjs');
|
|
272
277
|
|
|
273
278
|
if (!fsExistsSync(localAgentPath)) {
|
|
274
|
-
return null;
|
|
279
|
+
return { agent: null, error: null };
|
|
275
280
|
}
|
|
276
281
|
|
|
277
282
|
const agentModule = await import(pathToFileURL(localAgentPath).href);
|
|
@@ -311,19 +316,17 @@ async function loadLocalAgent(cwd, config) {
|
|
|
311
316
|
}
|
|
312
317
|
|
|
313
318
|
if (!AgentClass) {
|
|
314
|
-
|
|
315
|
-
return null;
|
|
319
|
+
return { agent: null, error: 'Could not find any WorkflowAgent export in local graph.js' };
|
|
316
320
|
}
|
|
317
321
|
|
|
318
322
|
if (!AgentClass.name?.includes('auto-detected')) {
|
|
319
|
-
console.log('✓ Using local agent from .zibby/graph.
|
|
323
|
+
console.log('✓ Using local agent from .zibby/graph.mjs');
|
|
320
324
|
}
|
|
321
325
|
}
|
|
322
326
|
|
|
323
|
-
return new AgentClass(config);
|
|
327
|
+
return { agent: new AgentClass(config), error: null };
|
|
324
328
|
} catch (error) {
|
|
325
|
-
|
|
326
|
-
return null;
|
|
329
|
+
return { agent: null, error: error.message };
|
|
327
330
|
}
|
|
328
331
|
}
|
|
329
332
|
|
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
preflightNode,
|
|
11
11
|
executeLiveNode,
|
|
12
12
|
generateScriptNode,
|
|
13
|
-
} from './nodes/index.
|
|
14
|
-
import { BrowserTestResultHandler } from './result-handler.
|
|
13
|
+
} from './nodes/index.mjs';
|
|
14
|
+
import { BrowserTestResultHandler } from './result-handler.mjs';
|
|
15
15
|
|
|
16
16
|
let memoryMiddleware = null;
|
|
17
17
|
try {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from '@zibby/core';
|
|
2
|
-
import { formatRecordedActions, formatAssertionsWithResults } from './utils.
|
|
2
|
+
import { formatRecordedActions, formatAssertionsWithResults } from './utils.mjs';
|
|
3
3
|
|
|
4
4
|
const GenerateScriptOutputSchema = z.object({
|
|
5
5
|
success: z.boolean(),
|
package/templates/index.js
CHANGED
|
@@ -41,7 +41,7 @@ export class TemplateFactory {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
static validateTemplate(templatePath) {
|
|
44
|
-
const requiredFiles = ['graph.
|
|
44
|
+
const requiredFiles = ['graph.mjs', 'nodes', 'README.md'];
|
|
45
45
|
|
|
46
46
|
for (const file of requiredFiles) {
|
|
47
47
|
const filePath = join(templatePath, file);
|
|
@@ -57,9 +57,9 @@ export class TemplateFactory {
|
|
|
57
57
|
const template = this.getTemplate(templateName);
|
|
58
58
|
this.validateTemplate(template.path);
|
|
59
59
|
|
|
60
|
-
const resultHandlerPath = join(template.path, 'result-handler.
|
|
60
|
+
const resultHandlerPath = join(template.path, 'result-handler.mjs');
|
|
61
61
|
return {
|
|
62
|
-
graphPath: join(template.path, 'graph.
|
|
62
|
+
graphPath: join(template.path, 'graph.mjs'),
|
|
63
63
|
nodesPath: join(template.path, 'nodes'),
|
|
64
64
|
readmePath: join(template.path, 'README.md'),
|
|
65
65
|
resultHandlerPath: existsSync(resultHandlerPath) ? resultHandlerPath : null,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|