@nclamvn/vibecode-cli 1.1.0 → 1.3.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 +17 -0
- package/package.json +1 -1
- package/src/commands/build.js +496 -3
- package/src/commands/config.js +149 -0
- package/src/commands/plan.js +8 -2
- package/src/config/constants.js +1 -1
- package/src/config/templates.js +146 -15
- package/src/core/error-analyzer.js +237 -0
- package/src/core/fix-generator.js +195 -0
- package/src/core/iteration.js +226 -0
- package/src/core/session.js +18 -2
- package/src/core/test-runner.js +248 -0
- package/src/index.js +7 -0
- package/src/providers/claude-code.js +164 -0
- package/src/providers/index.js +45 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
2
|
+
// VIBECODE CLI - Claude Code Provider
|
|
3
|
+
// "Claude/LLM là PIPELINE, là KIẾN TRÚC SƯ"
|
|
4
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
5
|
+
|
|
6
|
+
import { spawn } from 'child_process';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { pathExists, appendToFile } from '../utils/files.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Claude Code optimal configuration
|
|
12
|
+
* Contract LOCKED = License to build (không cần hỏi thêm)
|
|
13
|
+
*/
|
|
14
|
+
export const CLAUDE_CODE_CONFIG = {
|
|
15
|
+
command: 'claude',
|
|
16
|
+
flags: [
|
|
17
|
+
'--dangerously-skip-permissions', // Trust the AI - Contract đã locked
|
|
18
|
+
'--print', // Non-interactive mode (no TTY required)
|
|
19
|
+
],
|
|
20
|
+
timeout: 30 * 60 * 1000, // 30 minutes max
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Check if Claude Code CLI is available
|
|
25
|
+
*/
|
|
26
|
+
export async function isClaudeCodeAvailable() {
|
|
27
|
+
return new Promise((resolve) => {
|
|
28
|
+
const proc = spawn('which', ['claude'], { shell: true });
|
|
29
|
+
proc.on('close', (code) => {
|
|
30
|
+
resolve(code === 0);
|
|
31
|
+
});
|
|
32
|
+
proc.on('error', () => {
|
|
33
|
+
resolve(false);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Spawn Claude Code with optimal settings
|
|
40
|
+
*
|
|
41
|
+
* @param {string} prompt - The coder pack / prompt to send
|
|
42
|
+
* @param {object} options - Configuration options
|
|
43
|
+
* @param {string} options.cwd - Working directory
|
|
44
|
+
* @param {string} options.logPath - Path to write build logs
|
|
45
|
+
* @param {function} options.onOutput - Callback for output
|
|
46
|
+
* @returns {Promise<{success: boolean, code: number}>}
|
|
47
|
+
*/
|
|
48
|
+
export async function spawnClaudeCode(prompt, options = {}) {
|
|
49
|
+
const { cwd, logPath, onOutput } = options;
|
|
50
|
+
const fs = await import('fs-extra');
|
|
51
|
+
const os = await import('os');
|
|
52
|
+
|
|
53
|
+
// Check if Claude Code is available
|
|
54
|
+
const available = await isClaudeCodeAvailable();
|
|
55
|
+
if (!available) {
|
|
56
|
+
throw new Error('Claude Code CLI not found. Install with: npm install -g @anthropic/claude-code');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Write prompt to temp file to avoid shell escaping issues
|
|
60
|
+
const tempDir = os.default.tmpdir();
|
|
61
|
+
const promptFile = path.join(tempDir, `vibecode-prompt-${Date.now()}.md`);
|
|
62
|
+
await fs.default.writeFile(promptFile, prompt, 'utf-8');
|
|
63
|
+
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
// Build command with --print mode and -p for prompt file
|
|
66
|
+
const args = [
|
|
67
|
+
...CLAUDE_CODE_CONFIG.flags,
|
|
68
|
+
'-p', promptFile
|
|
69
|
+
];
|
|
70
|
+
const command = `claude ${args.map(a => `"${a}"`).join(' ')}`;
|
|
71
|
+
|
|
72
|
+
// Log the command being run
|
|
73
|
+
if (logPath) {
|
|
74
|
+
appendToFile(logPath, `\n[${new Date().toISOString()}] Running: claude --print -p ${promptFile}\n`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const proc = spawn('claude', args, {
|
|
78
|
+
cwd: cwd || process.cwd(),
|
|
79
|
+
stdio: 'inherit', // Stream directly to terminal
|
|
80
|
+
shell: false, // No shell needed, safer
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
let timeoutId = setTimeout(() => {
|
|
84
|
+
proc.kill();
|
|
85
|
+
// Cleanup temp file
|
|
86
|
+
fs.default.remove(promptFile).catch(() => {});
|
|
87
|
+
reject(new Error('Claude Code process timed out'));
|
|
88
|
+
}, CLAUDE_CODE_CONFIG.timeout);
|
|
89
|
+
|
|
90
|
+
proc.on('close', async (code) => {
|
|
91
|
+
clearTimeout(timeoutId);
|
|
92
|
+
|
|
93
|
+
// Cleanup temp file
|
|
94
|
+
await fs.default.remove(promptFile).catch(() => {});
|
|
95
|
+
|
|
96
|
+
const result = {
|
|
97
|
+
success: code === 0,
|
|
98
|
+
code: code || 0,
|
|
99
|
+
timestamp: new Date().toISOString()
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
if (logPath) {
|
|
103
|
+
const status = result.success ? 'SUCCESS' : 'FAILED';
|
|
104
|
+
appendToFile(logPath, `\n[${result.timestamp}] Claude Code ${status} (exit code: ${code})\n`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
resolve(result);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
proc.on('error', async (error) => {
|
|
111
|
+
clearTimeout(timeoutId);
|
|
112
|
+
// Cleanup temp file
|
|
113
|
+
await fs.default.remove(promptFile).catch(() => {});
|
|
114
|
+
|
|
115
|
+
if (logPath) {
|
|
116
|
+
appendToFile(logPath, `\n[${new Date().toISOString()}] ERROR: ${error.message}\n`);
|
|
117
|
+
}
|
|
118
|
+
reject(error);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Build prompt with optional CLAUDE.md injection
|
|
125
|
+
*
|
|
126
|
+
* @param {string} coderPackContent - Content of coder_pack.md
|
|
127
|
+
* @param {string} projectRoot - Project root directory
|
|
128
|
+
* @returns {Promise<string>} - Final prompt
|
|
129
|
+
*/
|
|
130
|
+
export async function buildPromptWithContext(coderPackContent, projectRoot) {
|
|
131
|
+
let fullPrompt = coderPackContent;
|
|
132
|
+
|
|
133
|
+
// Check for CLAUDE.md in project root
|
|
134
|
+
const claudeMdPath = path.join(projectRoot, 'CLAUDE.md');
|
|
135
|
+
if (await pathExists(claudeMdPath)) {
|
|
136
|
+
const fs = await import('fs-extra');
|
|
137
|
+
const claudeMd = await fs.default.readFile(claudeMdPath, 'utf-8');
|
|
138
|
+
|
|
139
|
+
// Inject CLAUDE.md rules before coder pack
|
|
140
|
+
fullPrompt = `# PROJECT RULES (from CLAUDE.md)
|
|
141
|
+
|
|
142
|
+
${claudeMd}
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
# BUILD INSTRUCTIONS
|
|
147
|
+
|
|
148
|
+
${coderPackContent}`;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return fullPrompt;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Get provider info for status display
|
|
156
|
+
*/
|
|
157
|
+
export function getProviderInfo() {
|
|
158
|
+
return {
|
|
159
|
+
name: 'Claude Code',
|
|
160
|
+
command: CLAUDE_CODE_CONFIG.command,
|
|
161
|
+
mode: '--dangerously-skip-permissions --print',
|
|
162
|
+
description: 'AI coding in non-interactive mode (contract-approved)'
|
|
163
|
+
};
|
|
164
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
2
|
+
// VIBECODE CLI - AI Provider Manager
|
|
3
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
spawnClaudeCode,
|
|
7
|
+
isClaudeCodeAvailable,
|
|
8
|
+
buildPromptWithContext,
|
|
9
|
+
getProviderInfo,
|
|
10
|
+
CLAUDE_CODE_CONFIG
|
|
11
|
+
} from './claude-code.js';
|
|
12
|
+
|
|
13
|
+
// Future providers:
|
|
14
|
+
// export { callAnthropicAPI } from './anthropic-api.js';
|
|
15
|
+
// export { spawnCursor } from './cursor.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Available providers
|
|
19
|
+
*/
|
|
20
|
+
export const PROVIDERS = {
|
|
21
|
+
'claude-code': {
|
|
22
|
+
name: 'Claude Code',
|
|
23
|
+
description: 'Official Claude CLI for coding',
|
|
24
|
+
available: true
|
|
25
|
+
},
|
|
26
|
+
'anthropic-api': {
|
|
27
|
+
name: 'Anthropic API',
|
|
28
|
+
description: 'Direct API calls (coming soon)',
|
|
29
|
+
available: false
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Get provider by name
|
|
35
|
+
*/
|
|
36
|
+
export function getProvider(name) {
|
|
37
|
+
return PROVIDERS[name] || null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get default provider
|
|
42
|
+
*/
|
|
43
|
+
export function getDefaultProvider() {
|
|
44
|
+
return 'claude-code';
|
|
45
|
+
}
|