@nclamvn/vibecode-cli 1.6.0 → 1.8.0
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/bin/vibecode.js +101 -1
- package/docs-site/README.md +41 -0
- package/docs-site/blog/2019-05-28-first-blog-post.md +12 -0
- package/docs-site/blog/2019-05-29-long-blog-post.md +44 -0
- package/docs-site/blog/2021-08-01-mdx-blog-post.mdx +24 -0
- package/docs-site/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg +0 -0
- package/docs-site/blog/2021-08-26-welcome/index.md +29 -0
- package/docs-site/blog/authors.yml +25 -0
- package/docs-site/blog/tags.yml +19 -0
- package/docs-site/docs/commands/agent.md +162 -0
- package/docs-site/docs/commands/assist.md +71 -0
- package/docs-site/docs/commands/build.md +53 -0
- package/docs-site/docs/commands/config.md +30 -0
- package/docs-site/docs/commands/debug.md +173 -0
- package/docs-site/docs/commands/doctor.md +34 -0
- package/docs-site/docs/commands/go.md +128 -0
- package/docs-site/docs/commands/index.md +79 -0
- package/docs-site/docs/commands/init.md +42 -0
- package/docs-site/docs/commands/learn.md +82 -0
- package/docs-site/docs/commands/lock.md +33 -0
- package/docs-site/docs/commands/plan.md +29 -0
- package/docs-site/docs/commands/review.md +31 -0
- package/docs-site/docs/commands/snapshot.md +34 -0
- package/docs-site/docs/commands/start.md +32 -0
- package/docs-site/docs/commands/status.md +37 -0
- package/docs-site/docs/commands/undo.md +83 -0
- package/docs-site/docs/configuration.md +72 -0
- package/docs-site/docs/faq.md +83 -0
- package/docs-site/docs/getting-started.md +119 -0
- package/docs-site/docs/guides/agent-mode.md +94 -0
- package/docs-site/docs/guides/debug-mode.md +83 -0
- package/docs-site/docs/guides/magic-mode.md +107 -0
- package/docs-site/docs/installation.md +98 -0
- package/docs-site/docs/intro.md +67 -0
- package/docs-site/docusaurus.config.ts +141 -0
- package/docs-site/package-lock.json +18039 -0
- package/docs-site/package.json +48 -0
- package/docs-site/sidebars.ts +70 -0
- package/docs-site/src/components/HomepageFeatures/index.tsx +72 -0
- package/docs-site/src/components/HomepageFeatures/styles.module.css +16 -0
- package/docs-site/src/css/custom.css +30 -0
- package/docs-site/src/pages/index.module.css +23 -0
- package/docs-site/src/pages/index.tsx +44 -0
- package/docs-site/src/pages/markdown-page.md +7 -0
- package/docs-site/src/theme/Footer/index.tsx +127 -0
- package/docs-site/src/theme/Footer/styles.module.css +285 -0
- package/docs-site/static/.nojekyll +0 -0
- package/docs-site/static/img/docusaurus-social-card.jpg +0 -0
- package/docs-site/static/img/docusaurus.png +0 -0
- package/docs-site/static/img/favicon.ico +0 -0
- package/docs-site/static/img/logo.svg +1 -0
- package/docs-site/static/img/undraw_docusaurus_mountain.svg +171 -0
- package/docs-site/static/img/undraw_docusaurus_react.svg +170 -0
- package/docs-site/static/img/undraw_docusaurus_tree.svg +40 -0
- package/docs-site/tsconfig.json +8 -0
- package/package.json +2 -1
- package/src/commands/ask.js +230 -0
- package/src/commands/debug.js +109 -1
- package/src/commands/docs.js +167 -0
- package/src/commands/git.js +1024 -0
- package/src/commands/migrate.js +341 -0
- package/src/commands/refactor.js +205 -0
- package/src/commands/review.js +126 -1
- package/src/commands/security.js +229 -0
- package/src/commands/shell.js +486 -0
- package/src/commands/test.js +194 -0
- package/src/commands/watch.js +556 -0
- package/src/debug/image-analyzer.js +304 -0
- package/src/index.js +27 -0
- package/src/utils/image.js +222 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
2
|
+
// VIBECODE CLI - Test Command
|
|
3
|
+
// Phase K2: AI Test Generation
|
|
4
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
5
|
+
|
|
6
|
+
import { spawn } from 'child_process';
|
|
7
|
+
import fs from 'fs/promises';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
import inquirer from 'inquirer';
|
|
11
|
+
|
|
12
|
+
export async function testCommand(targetPath, options = {}) {
|
|
13
|
+
const cwd = process.cwd();
|
|
14
|
+
|
|
15
|
+
// Generate tests
|
|
16
|
+
if (options.generate) {
|
|
17
|
+
return generateTests(cwd, targetPath, options);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Run tests (pass through to npm test)
|
|
21
|
+
if (options.run) {
|
|
22
|
+
const { exec } = await import('child_process');
|
|
23
|
+
const child = exec('npm test', { cwd });
|
|
24
|
+
child.stdout?.pipe(process.stdout);
|
|
25
|
+
child.stderr?.pipe(process.stderr);
|
|
26
|
+
return new Promise(resolve => child.on('close', resolve));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Coverage
|
|
30
|
+
if (options.coverage) {
|
|
31
|
+
const { exec } = await import('child_process');
|
|
32
|
+
const child = exec('npm run test:coverage || npm test -- --coverage', { cwd });
|
|
33
|
+
child.stdout?.pipe(process.stdout);
|
|
34
|
+
child.stderr?.pipe(process.stderr);
|
|
35
|
+
return new Promise(resolve => child.on('close', resolve));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Default: show menu
|
|
39
|
+
const { action } = await inquirer.prompt([{
|
|
40
|
+
type: 'list',
|
|
41
|
+
name: 'action',
|
|
42
|
+
message: 'Test options:',
|
|
43
|
+
choices: [
|
|
44
|
+
{ name: '🧪 Run tests (npm test)', value: 'run' },
|
|
45
|
+
{ name: '✨ Generate tests for file/folder', value: 'generate' },
|
|
46
|
+
{ name: '📊 Show coverage', value: 'coverage' },
|
|
47
|
+
{ name: '👋 Exit', value: 'exit' }
|
|
48
|
+
]
|
|
49
|
+
}]);
|
|
50
|
+
|
|
51
|
+
if (action === 'run') {
|
|
52
|
+
return testCommand(null, { run: true });
|
|
53
|
+
}
|
|
54
|
+
if (action === 'generate') {
|
|
55
|
+
const { target } = await inquirer.prompt([{
|
|
56
|
+
type: 'input',
|
|
57
|
+
name: 'target',
|
|
58
|
+
message: 'Path to generate tests for:',
|
|
59
|
+
default: 'src/'
|
|
60
|
+
}]);
|
|
61
|
+
return generateTests(cwd, target, options);
|
|
62
|
+
}
|
|
63
|
+
if (action === 'coverage') {
|
|
64
|
+
return testCommand(null, { coverage: true });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function generateTests(cwd, targetPath, options) {
|
|
69
|
+
console.log(chalk.cyan(`
|
|
70
|
+
╭────────────────────────────────────────────────────────────────────╮
|
|
71
|
+
│ 🧪 TEST GENERATION │
|
|
72
|
+
│ │
|
|
73
|
+
│ Target: ${(targetPath || 'src/').padEnd(52)}│
|
|
74
|
+
│ │
|
|
75
|
+
╰────────────────────────────────────────────────────────────────────╯
|
|
76
|
+
`));
|
|
77
|
+
|
|
78
|
+
// Detect test framework
|
|
79
|
+
const framework = await detectTestFramework(cwd);
|
|
80
|
+
console.log(chalk.gray(` Test framework: ${framework}\n`));
|
|
81
|
+
|
|
82
|
+
// Get files to generate tests for
|
|
83
|
+
const files = await getFilesToTest(cwd, targetPath || 'src/');
|
|
84
|
+
|
|
85
|
+
if (files.length === 0) {
|
|
86
|
+
console.log(chalk.yellow(' No files found to generate tests for.\n'));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
console.log(chalk.gray(` Found ${files.length} files\n`));
|
|
91
|
+
|
|
92
|
+
const prompt = `
|
|
93
|
+
# Test Generation Request
|
|
94
|
+
|
|
95
|
+
## Project: ${path.basename(cwd)}
|
|
96
|
+
## Test Framework: ${framework}
|
|
97
|
+
|
|
98
|
+
## Files to Generate Tests For:
|
|
99
|
+
${files.map(f => `- ${f}`).join('\n')}
|
|
100
|
+
|
|
101
|
+
## Instructions:
|
|
102
|
+
1. Read each source file
|
|
103
|
+
2. Generate comprehensive tests including:
|
|
104
|
+
- Unit tests for each function/method
|
|
105
|
+
- Edge cases (null, undefined, empty, boundary values)
|
|
106
|
+
- Error handling tests
|
|
107
|
+
- Mock external dependencies
|
|
108
|
+
- Integration tests where appropriate
|
|
109
|
+
|
|
110
|
+
3. Use ${framework} syntax and conventions
|
|
111
|
+
4. Follow AAA pattern (Arrange, Act, Assert)
|
|
112
|
+
5. Add descriptive test names
|
|
113
|
+
6. Include setup/teardown if needed
|
|
114
|
+
|
|
115
|
+
## Output:
|
|
116
|
+
Create test files in __tests__/ or *.test.ts/js format.
|
|
117
|
+
For each source file, create corresponding test file.
|
|
118
|
+
|
|
119
|
+
Generate tests now.
|
|
120
|
+
`;
|
|
121
|
+
|
|
122
|
+
const promptFile = path.join(cwd, '.vibecode', 'test-gen-prompt.md');
|
|
123
|
+
await fs.mkdir(path.dirname(promptFile), { recursive: true });
|
|
124
|
+
await fs.writeFile(promptFile, prompt);
|
|
125
|
+
|
|
126
|
+
console.log(chalk.gray(' Generating tests with Claude Code...\n'));
|
|
127
|
+
|
|
128
|
+
await runClaudeCode(prompt, cwd);
|
|
129
|
+
|
|
130
|
+
console.log(chalk.green('\n✅ Tests generated!'));
|
|
131
|
+
console.log(chalk.gray(' Run: npm test\n'));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function detectTestFramework(cwd) {
|
|
135
|
+
try {
|
|
136
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
137
|
+
const pkg = JSON.parse(await fs.readFile(pkgPath, 'utf-8'));
|
|
138
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
139
|
+
|
|
140
|
+
if (deps.vitest) return 'vitest';
|
|
141
|
+
if (deps.jest) return 'jest';
|
|
142
|
+
if (deps.mocha) return 'mocha';
|
|
143
|
+
if (deps['@testing-library/react']) return 'jest + @testing-library/react';
|
|
144
|
+
if (deps.ava) return 'ava';
|
|
145
|
+
if (deps.tap) return 'tap';
|
|
146
|
+
if (deps.uvu) return 'uvu';
|
|
147
|
+
|
|
148
|
+
return 'jest'; // default
|
|
149
|
+
} catch {
|
|
150
|
+
return 'jest';
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async function getFilesToTest(cwd, targetPath) {
|
|
155
|
+
const files = [];
|
|
156
|
+
const fullPath = path.join(cwd, targetPath);
|
|
157
|
+
|
|
158
|
+
async function scan(dir) {
|
|
159
|
+
try {
|
|
160
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
161
|
+
|
|
162
|
+
for (const entry of entries) {
|
|
163
|
+
if (entry.name.startsWith('.')) continue;
|
|
164
|
+
if (entry.name.includes('.test.') || entry.name.includes('.spec.')) continue;
|
|
165
|
+
if (entry.name === '__tests__') continue;
|
|
166
|
+
if (entry.name === 'node_modules') continue;
|
|
167
|
+
if (entry.name === 'dist' || entry.name === 'build') continue;
|
|
168
|
+
|
|
169
|
+
const entryPath = path.join(dir, entry.name);
|
|
170
|
+
|
|
171
|
+
if (entry.isDirectory()) {
|
|
172
|
+
await scan(entryPath);
|
|
173
|
+
} else if (/\.(js|ts|jsx|tsx)$/.test(entry.name)) {
|
|
174
|
+
files.push(path.relative(cwd, entryPath));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
} catch {}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
await scan(fullPath);
|
|
181
|
+
return files.slice(0, 20); // Limit
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async function runClaudeCode(prompt, cwd) {
|
|
185
|
+
return new Promise((resolve) => {
|
|
186
|
+
const child = spawn('claude', ['-p', prompt, '--dangerously-skip-permissions'], {
|
|
187
|
+
cwd,
|
|
188
|
+
stdio: 'inherit'
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
child.on('close', resolve);
|
|
192
|
+
child.on('error', () => resolve());
|
|
193
|
+
});
|
|
194
|
+
}
|