@zibby/core 0.1.9 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zibby/core",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "Core test automation engine with multi-agent and multi-MCP support",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -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
- logger.debug(`[Cursor] Found agent at: ${path}`);
37
- return true;
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
- execSync(`which ${bin} 2>/dev/null`, { stdio: 'ignore', timeout: 2000 });
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('Cursor Agent CLI not found. Install it or add it to PATH.');
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 >= 90 && elapsed < 120 && modifiedFiles.size === 0) {
353
- logger.warn(`⚠️ [Agent] No output and no file changes after ${elapsed}s — agent may be stuck.`);
354
- try {
355
- const procInfo = execSync(`ps -p ${proc.pid} -o pid,stat,rss,time 2>/dev/null || echo "Process info unavailable"`, { encoding: 'utf-8', timeout: 5000 });
356
- logger.warn(`⚠️ [Agent] Process: ${procInfo.trim()}`);
357
- } catch {}
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.js with your workflow definition.`
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.js');
246
+ const localAgentPath = pathJoin(cwd, '.zibby/graph.mjs');
247
247
 
248
248
  if (!fsExistsSync(localAgentPath)) {
249
- return { available: [], default: null, error: 'No .zibby/graph.js found' };
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.js');
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.js');
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.js';
14
- import { BrowserTestResultHandler } from './result-handler.js';
13
+ } from './nodes/index.mjs';
14
+ import { BrowserTestResultHandler } from './result-handler.mjs';
15
15
 
16
16
  let memoryMiddleware = null;
17
17
  try {
@@ -10,7 +10,7 @@
10
10
  */
11
11
 
12
12
  import { z, SKILLS } from '@zibby/core';
13
- import { formatAssertionChecklist } from './utils.js';
13
+ import { formatAssertionChecklist } from './utils.mjs';
14
14
 
15
15
  export const executeLiveNode = {
16
16
  name: 'execute_live',
@@ -1,5 +1,5 @@
1
1
  import { z } from '@zibby/core';
2
- import { formatRecordedActions, formatAssertionsWithResults } from './utils.js';
2
+ import { formatRecordedActions, formatAssertionsWithResults } from './utils.mjs';
3
3
 
4
4
  const GenerateScriptOutputSchema = z.object({
5
5
  success: z.boolean(),
@@ -0,0 +1,3 @@
1
+ export { preflightNode } from './preflight.mjs';
2
+ export { executeLiveNode } from './execute-live.mjs';
3
+ export { generateScriptNode } from './generate-script.mjs';
@@ -41,7 +41,7 @@ export class TemplateFactory {
41
41
  }
42
42
 
43
43
  static validateTemplate(templatePath) {
44
- const requiredFiles = ['graph.js', 'nodes', 'README.md'];
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.js');
60
+ const resultHandlerPath = join(template.path, 'result-handler.mjs');
61
61
  return {
62
- graphPath: join(template.path, 'graph.js'),
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,
@@ -1,3 +0,0 @@
1
- export { preflightNode } from './preflight.js';
2
- export { executeLiveNode } from './execute-live.js';
3
- export { generateScriptNode } from './generate-script.js';