@zibby/core 0.1.9 → 0.1.11
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/scripts/setup-official-playwright-mcp.sh +20 -3
- package/src/framework/agents/cursor-strategy.js +45 -15
- package/src/index.js +5 -5
- package/templates/browser-test-automation/{graph.js → graph.mjs} +2 -2
- package/templates/browser-test-automation/nodes/{execute-live.js → execute-live.mjs} +2 -2
- 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
|
@@ -5,13 +5,30 @@ set -e
|
|
|
5
5
|
# Get script directory for relative imports
|
|
6
6
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
7
7
|
|
|
8
|
-
# Step 1: Check cursor-agent
|
|
9
|
-
|
|
8
|
+
# Step 1: Check cursor-agent (check actual locations, not just PATH)
|
|
9
|
+
CURSOR_AGENT_PATH=""
|
|
10
|
+
if command -v cursor-agent &> /dev/null; then
|
|
11
|
+
CURSOR_AGENT_PATH=$(command -v cursor-agent)
|
|
12
|
+
elif [ -x "$HOME/.local/bin/cursor-agent" ]; then
|
|
13
|
+
CURSOR_AGENT_PATH="$HOME/.local/bin/cursor-agent"
|
|
14
|
+
elif [ -x "$HOME/.cursor/bin/cursor-agent" ]; then
|
|
15
|
+
CURSOR_AGENT_PATH="$HOME/.cursor/bin/cursor-agent"
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
if [ -z "$CURSOR_AGENT_PATH" ]; then
|
|
10
19
|
echo "⚠️ cursor-agent not found. Installing..."
|
|
11
20
|
curl https://cursor.com/install -fsS | bash
|
|
12
|
-
|
|
21
|
+
# Check again after install
|
|
22
|
+
if [ -x "$HOME/.local/bin/cursor-agent" ]; then
|
|
23
|
+
CURSOR_AGENT_PATH="$HOME/.local/bin/cursor-agent"
|
|
24
|
+
elif [ -x "$HOME/.cursor/bin/cursor-agent" ]; then
|
|
25
|
+
CURSOR_AGENT_PATH="$HOME/.cursor/bin/cursor-agent"
|
|
26
|
+
fi
|
|
13
27
|
fi
|
|
14
28
|
|
|
29
|
+
# Always ensure these directories are in PATH for this script
|
|
30
|
+
export PATH="$HOME/.cursor/bin:$HOME/.local/bin:$PATH"
|
|
31
|
+
|
|
15
32
|
# Step 2: Find Node.js absolute paths (Cursor GUI doesn't have shell PATH)
|
|
16
33
|
NODE_PATH=$(which node 2>/dev/null || echo "")
|
|
17
34
|
NPX_PATH=$(which npx 2>/dev/null || echo "")
|
|
@@ -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
|
@@ -120,7 +120,7 @@ export async function runTest(specPath, config = {}) {
|
|
|
120
120
|
throw new Error(
|
|
121
121
|
`No agent found. Please run:\n` +
|
|
122
122
|
` zibby init\n\n` +
|
|
123
|
-
`This will create .zibby/graph.
|
|
123
|
+
`This will create .zibby/graph.mjs with your workflow definition.`
|
|
124
124
|
);
|
|
125
125
|
}
|
|
126
126
|
|
|
@@ -243,10 +243,10 @@ export async function listWorkflows(cwd = process.cwd()) {
|
|
|
243
243
|
const { existsSync: fsExistsSync } = await import('fs');
|
|
244
244
|
const { pathToFileURL } = await import('url');
|
|
245
245
|
|
|
246
|
-
const localAgentPath = pathJoin(cwd, '.zibby/graph.
|
|
246
|
+
const localAgentPath = pathJoin(cwd, '.zibby/graph.mjs');
|
|
247
247
|
|
|
248
248
|
if (!fsExistsSync(localAgentPath)) {
|
|
249
|
-
return { available: [], default: null, error: 'No .zibby/graph.
|
|
249
|
+
return { available: [], default: null, error: 'No .zibby/graph.mjs found' };
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
const agentModule = await import(pathToFileURL(localAgentPath).href);
|
|
@@ -273,7 +273,7 @@ async function loadLocalAgent(cwd, config) {
|
|
|
273
273
|
const { existsSync: fsExistsSync } = await import('fs');
|
|
274
274
|
const { pathToFileURL } = await import('url');
|
|
275
275
|
|
|
276
|
-
const localAgentPath = pathJoin(cwd, '.zibby/graph.
|
|
276
|
+
const localAgentPath = pathJoin(cwd, '.zibby/graph.mjs');
|
|
277
277
|
|
|
278
278
|
if (!fsExistsSync(localAgentPath)) {
|
|
279
279
|
return { agent: null, error: null };
|
|
@@ -320,7 +320,7 @@ async function loadLocalAgent(cwd, config) {
|
|
|
320
320
|
}
|
|
321
321
|
|
|
322
322
|
if (!AgentClass.name?.includes('auto-detected')) {
|
|
323
|
-
console.log('✓ Using local agent from .zibby/graph.
|
|
323
|
+
console.log('✓ Using local agent from .zibby/graph.mjs');
|
|
324
324
|
}
|
|
325
325
|
}
|
|
326
326
|
|
|
@@ -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 {
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { z, SKILLS } from '@zibby/core';
|
|
13
|
-
import { formatAssertionChecklist } from './utils.
|
|
13
|
+
import { formatAssertionChecklist } from './utils.mjs';
|
|
14
14
|
|
|
15
15
|
export const executeLiveNode = {
|
|
16
16
|
name: 'execute_live',
|
|
17
|
-
skills: [SKILLS.BROWSER, SKILLS.MEMORY],
|
|
17
|
+
skills: [SKILLS.BROWSER, ...(process.env.ZIBBY_MEMORY ? [SKILLS.MEMORY] : [])],
|
|
18
18
|
timeout: 600000,
|
|
19
19
|
|
|
20
20
|
prompt: (state) => {
|
|
@@ -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
|