@zibby/cli 0.1.16 → 0.1.19

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/cli",
3
- "version": "0.1.16",
3
+ "version": "0.1.19",
4
4
  "description": "Zibby CLI - Test automation generator and runner",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,8 +32,9 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@aws-sdk/client-sqs": "^3.1000.0",
35
- "@zibby/skills": "^0.1.2",
36
- "@zibby/core": "^0.1.13",
35
+ "@zibby/skills": "^0.1.3",
36
+ "@zibby/core": "^0.1.15",
37
+ "@zibby/memory": "^0.1.3",
37
38
  "chalk": "^5.3.0",
38
39
  "commander": "^12.0.0",
39
40
  "dotenv": "^17.2.3",
@@ -55,9 +56,6 @@
55
56
  "engines": {
56
57
  "node": ">=18.0.0"
57
58
  },
58
- "optionalDependencies": {
59
- "@zibby/memory": "*"
60
- },
61
59
  "devDependencies": {
62
60
  "vitest": "^4.0.18"
63
61
  }
@@ -1,18 +1,120 @@
1
1
  import { mkdir, writeFile, readFile } from 'fs/promises';
2
2
  import { existsSync } from 'fs';
3
3
  import { join, resolve, dirname } from 'path';
4
+ import { homedir } from 'os';
4
5
  import inquirer from 'inquirer';
5
6
  import chalk from 'chalk';
6
7
  import ora from 'ora';
7
- import { spawn } from 'child_process';
8
+ import { spawn, execSync } from 'child_process';
8
9
  import { fileURLToPath } from 'url';
9
10
 
10
11
  const __filename = fileURLToPath(import.meta.url);
11
12
  const __dirname = dirname(__filename);
12
13
 
14
+ async function checkNpmGlobalBinInPath() {
15
+ try {
16
+ const isWindows = process.platform === 'win32';
17
+
18
+ // Get npm global bin directory
19
+ const npmPrefix = execSync('npm config get prefix', { encoding: 'utf-8' }).trim();
20
+ const npmGlobalBin = isWindows ? npmPrefix : `${npmPrefix}/bin`;
21
+ const npmGlobalBinExpanded = npmGlobalBin.replace(/^~/, homedir());
22
+
23
+ // Check if it's in PATH
24
+ const pathSeparator = isWindows ? ';' : ':';
25
+ const pathDirs = process.env.PATH.split(pathSeparator);
26
+ const isInPath = pathDirs.some(dir => {
27
+ const normalizedDir = dir.replace(/^~/, homedir());
28
+ return normalizedDir === npmGlobalBinExpanded || normalizedDir === npmGlobalBin;
29
+ });
30
+
31
+ if (isInPath) {
32
+ return; // Already configured
33
+ }
34
+
35
+ // Not in PATH - offer to add it
36
+ console.log(chalk.yellow('⚠️ npm global bin not in PATH'));
37
+ console.log(chalk.gray(` Location: ${npmGlobalBinExpanded}`));
38
+ console.log();
39
+
40
+ const { shouldAddPath } = await inquirer.prompt([{
41
+ type: 'confirm',
42
+ name: 'shouldAddPath',
43
+ message: 'Add npm global bin to your shell PATH automatically?',
44
+ default: true
45
+ }]);
46
+
47
+ if (!shouldAddPath) {
48
+ if (isWindows) {
49
+ console.log(chalk.gray('\n💡 To add manually on Windows:'));
50
+ console.log(chalk.gray(' 1. Search "Environment Variables" in Start menu'));
51
+ console.log(chalk.gray(' 2. Edit "Path" in User variables'));
52
+ console.log(chalk.gray(` 3. Add: ${npmGlobalBinExpanded}\n`));
53
+ } else {
54
+ console.log(chalk.gray('\n💡 To add manually, run:'));
55
+ console.log(chalk.gray(` echo 'export PATH="${npmGlobalBinExpanded}:$PATH"' >> ~/.zshrc`));
56
+ console.log(chalk.gray(` source ~/.zshrc\n`));
57
+ }
58
+ return;
59
+ }
60
+
61
+ // Windows: Can't auto-add to PATH (requires registry changes)
62
+ if (isWindows) {
63
+ console.log(chalk.yellow('⚠️ Cannot auto-add PATH on Windows'));
64
+ console.log(chalk.gray(' Please add manually:'));
65
+ console.log(chalk.gray(' 1. Search "Environment Variables" in Start menu'));
66
+ console.log(chalk.gray(' 2. Edit "Path" in User variables'));
67
+ console.log(chalk.gray(` 3. Add: ${npmGlobalBinExpanded}\n`));
68
+ return;
69
+ }
70
+
71
+ // Unix/Linux: Auto-add to shell config
72
+ const shell = process.env.SHELL || '';
73
+ let shellRc = '';
74
+
75
+ if (shell.includes('zsh')) {
76
+ shellRc = join(homedir(), '.zshrc');
77
+ } else if (shell.includes('bash')) {
78
+ // Linux often uses .bashrc, macOS uses .bash_profile
79
+ shellRc = existsSync(join(homedir(), '.bashrc'))
80
+ ? join(homedir(), '.bashrc')
81
+ : join(homedir(), '.bash_profile');
82
+ } else {
83
+ console.log(chalk.yellow(`⚠️ Unknown shell: ${shell}`));
84
+ console.log(chalk.gray(' Please add manually:'));
85
+ console.log(chalk.gray(` export PATH="${npmGlobalBinExpanded}:$PATH"`));
86
+ return;
87
+ }
88
+
89
+ // Check if already in shell config
90
+ if (existsSync(shellRc)) {
91
+ const rcContent = await readFile(shellRc, 'utf-8');
92
+ if (rcContent.includes(npmGlobalBinExpanded) || (rcContent.includes('npm') && rcContent.includes('global') && rcContent.includes('bin'))) {
93
+ console.log(chalk.yellow(`⚠️ PATH entry found in ${shellRc} but not active`));
94
+ console.log(chalk.gray(` Run: source ${shellRc}\n`));
95
+ return;
96
+ }
97
+ }
98
+
99
+ // Add to shell config
100
+ const pathEntry = `\n# npm global bin (added by zibby)\nexport PATH="${npmGlobalBinExpanded}:$PATH"\n`;
101
+ await writeFile(shellRc, (existsSync(shellRc) ? await readFile(shellRc, 'utf-8') : '') + pathEntry);
102
+
103
+ console.log(chalk.green(`✅ Added to ${shellRc}`));
104
+ console.log(chalk.yellow('\n💡 Run this to activate in current session:'));
105
+ console.log(chalk.gray(` source ${shellRc}\n`));
106
+
107
+ } catch {
108
+ // Silently fail - don't block init if this check fails
109
+ }
110
+ }
111
+
13
112
  export async function initCommand(projectName, options) {
14
113
  console.log(chalk.bold.cyan('\n🎭 Welcome to Zibby Test Automation!\n'));
15
114
 
115
+ // Check if npm global bin is in PATH
116
+ await checkNpmGlobalBinInPath();
117
+
16
118
  const targetDir = projectName ? resolve(process.cwd(), projectName) : process.cwd();
17
119
  const projectNameActual = projectName || 'zibby-tests';
18
120
  const isNewProject = !!projectName;
@@ -188,9 +290,25 @@ export async function initCommand(projectName, options) {
188
290
  const envContent = generateEnvFile(answers, options);
189
291
  await writeFile(join(targetDir, '.env.example'), envContent);
190
292
 
191
- // Create/update .env file if API key provided
293
+ // Create/update .env file
294
+ const envPath = join(targetDir, '.env');
192
295
  if (answers.apiKey && answers.apiKey.trim()) {
193
296
  await createOrUpdateEnvFile(targetDir, answers.apiKey.trim(), answers, options);
297
+ } else if (!existsSync(envPath)) {
298
+ // Create .env from .env.example if it doesn't exist
299
+ await writeFile(envPath, envContent);
300
+ } else if (options.force) {
301
+ // On force reinit, merge memory vars into existing .env if using --mem
302
+ if (options.mem) {
303
+ let existingEnv = await readFile(envPath, 'utf-8');
304
+ if (!existingEnv.includes('ZIBBY_MEMORY_MAX_RUNS')) {
305
+ existingEnv += `\n# Test Memory (Dolt DB) - Auto-compaction settings\n`;
306
+ existingEnv += `# ZIBBY_MEMORY_MAX_RUNS=3000 # Max test runs to keep per spec\n`;
307
+ existingEnv += `# ZIBBY_MEMORY_MAX_AGE=1095 # Max age in days for stale data (~3 years)\n`;
308
+ existingEnv += `# ZIBBY_MEMORY_COMPACT_EVERY=1500 # Auto-compact every N runs (0 to disable)\n`;
309
+ await writeFile(envPath, existingEnv);
310
+ }
311
+ }
194
312
  }
195
313
 
196
314
 
@@ -435,8 +553,8 @@ function generateConfig(answers, _options = {}) {
435
553
  `;
436
554
  }
437
555
 
438
- function generateEnvFile(answers, _options = {}) {
439
- const content = `# Zibby Test Automation - Environment Variables
556
+ function generateEnvFile(answers, options = {}) {
557
+ let content = `# Zibby Test Automation - Environment Variables
440
558
 
441
559
  # AI Provider Keys
442
560
  ${answers.agent === 'claude' ? '# Claude (Anthropic) - Direct API\nANTHROPIC_API_KEY=sk-ant-your_key_here\n' : '# ANTHROPIC_API_KEY=sk-ant-your_key_here\n'}
@@ -450,6 +568,16 @@ ${answers.agent === 'cursor' ? '# Cursor Agent (uses cursor-agent CLI)\n# No API
450
568
  # SLACK_WEBHOOK_URL=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
451
569
  `;
452
570
 
571
+ // Add memory configuration if --mem flag is used
572
+ if (options.mem) {
573
+ content += `
574
+ # Test Memory (Dolt DB) - Auto-compaction settings
575
+ # ZIBBY_MEMORY_MAX_RUNS=3000 # Max test runs to keep per spec
576
+ # ZIBBY_MEMORY_MAX_AGE=1095 # Max age in days for stale data (~3 years)
577
+ # ZIBBY_MEMORY_COMPACT_EVERY=1500 # Auto-compact every N runs (0 to disable)
578
+ `;
579
+ }
580
+
453
581
  return content;
454
582
  }
455
583
 
@@ -481,8 +609,8 @@ async function createOrUpdateEnvFile(targetDir, apiKey, answers, options = {}) {
481
609
  await writeFile(envPath, envContent);
482
610
  }
483
611
 
484
- function generateEnvFileWithKey(answers, apiKey, _options = {}) {
485
- const content = `# Zibby Test Automation - Environment Variables
612
+ function generateEnvFileWithKey(answers, apiKey, options = {}) {
613
+ let content = `# Zibby Test Automation - Environment Variables
486
614
 
487
615
  # AI Provider Keys
488
616
  ${answers.agent === 'claude' ? 'ANTHROPIC_API_KEY=sk-ant-your_key_here\n' : '# ANTHROPIC_API_KEY=sk-ant-your_key_here\n'}
@@ -494,6 +622,16 @@ ZIBBY_API_KEY=${apiKey}
494
622
  # SLACK_WEBHOOK_URL=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
495
623
  `;
496
624
 
625
+ // Add memory configuration if --mem flag is used
626
+ if (options.mem) {
627
+ content += `
628
+ # Test Memory (Dolt DB) - Auto-compaction settings
629
+ # ZIBBY_MEMORY_MAX_RUNS=3000 # Max test runs to keep per spec
630
+ # ZIBBY_MEMORY_MAX_AGE=1095 # Max age in days for stale data (~3 years)
631
+ # ZIBBY_MEMORY_COMPACT_EVERY=1500 # Auto-compact every N runs (0 to disable)
632
+ `;
633
+ }
634
+
497
635
  return content;
498
636
  }
499
637
 
@@ -509,8 +647,8 @@ function generatePackageJson(projectName, _answers) {
509
647
  'test:headed': 'playwright test --headed'
510
648
  },
511
649
  dependencies: {
512
- '@zibby/cli': '^0.1.0',
513
- '@zibby/core': '^0.1.0'
650
+ '@zibby/cli': '^0.1.19',
651
+ '@zibby/core': '^0.1.15'
514
652
  },
515
653
  devDependencies: {
516
654
  '@playwright/test': '^1.49.0',