codeflash 0.0.1 → 0.1.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/README.md +104 -0
- package/bin/codeflash-setup.js +13 -0
- package/bin/codeflash.js +131 -0
- package/package.json +71 -6
- package/runtime/capture.js +707 -0
- package/runtime/comparator.js +406 -0
- package/runtime/compare-results.js +329 -0
- package/runtime/index.js +79 -0
- package/runtime/serializer.js +851 -0
- package/scripts/postinstall.js +265 -0
- package/index.js +0 -7
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Codeflash CLI Postinstall Script
|
|
5
|
+
*
|
|
6
|
+
* This script runs after `npm install codeflash` and:
|
|
7
|
+
* 1. Checks if uv (Python package manager) is installed
|
|
8
|
+
* 2. If not, installs uv automatically
|
|
9
|
+
* 3. Uses uv to install the Python codeflash CLI
|
|
10
|
+
*
|
|
11
|
+
* This approach follows the same pattern as aider and mistral-code,
|
|
12
|
+
* which use uv for Python distribution.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const { execSync, spawnSync } = require('child_process');
|
|
16
|
+
const os = require('os');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
|
|
20
|
+
// ANSI color codes for pretty output
|
|
21
|
+
const colors = {
|
|
22
|
+
reset: '\x1b[0m',
|
|
23
|
+
green: '\x1b[32m',
|
|
24
|
+
yellow: '\x1b[33m',
|
|
25
|
+
red: '\x1b[31m',
|
|
26
|
+
cyan: '\x1b[36m',
|
|
27
|
+
dim: '\x1b[2m',
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function log(message, color = 'reset') {
|
|
31
|
+
console.log(`${colors[color]}${message}${colors.reset}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function logStep(step, message) {
|
|
35
|
+
console.log(`${colors.cyan}[${step}]${colors.reset} ${message}`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function logSuccess(message) {
|
|
39
|
+
console.log(`${colors.green}✓${colors.reset} ${message}`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function logWarning(message) {
|
|
43
|
+
console.log(`${colors.yellow}⚠${colors.reset} ${message}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function logError(message) {
|
|
47
|
+
console.error(`${colors.red}✗${colors.reset} ${message}`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Check if a command exists in PATH
|
|
52
|
+
*/
|
|
53
|
+
function commandExists(command) {
|
|
54
|
+
try {
|
|
55
|
+
const result = spawnSync(command, ['--version'], {
|
|
56
|
+
stdio: 'ignore',
|
|
57
|
+
shell: true,
|
|
58
|
+
});
|
|
59
|
+
return result.status === 0;
|
|
60
|
+
} catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get the uv binary path
|
|
67
|
+
* uv installs to ~/.local/bin on Unix or %USERPROFILE%\.local\bin on Windows
|
|
68
|
+
*/
|
|
69
|
+
function getUvPath() {
|
|
70
|
+
const platform = os.platform();
|
|
71
|
+
const homeDir = os.homedir();
|
|
72
|
+
|
|
73
|
+
if (platform === 'win32') {
|
|
74
|
+
return path.join(homeDir, '.local', 'bin', 'uv.exe');
|
|
75
|
+
}
|
|
76
|
+
return path.join(homeDir, '.local', 'bin', 'uv');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Install uv using the official installer
|
|
81
|
+
*/
|
|
82
|
+
function installUv() {
|
|
83
|
+
const platform = os.platform();
|
|
84
|
+
|
|
85
|
+
logStep('1/3', 'Installing uv (Python package manager)...');
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
if (platform === 'win32') {
|
|
89
|
+
// Windows: Use PowerShell
|
|
90
|
+
execSync(
|
|
91
|
+
'powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"',
|
|
92
|
+
{ stdio: 'inherit', shell: true }
|
|
93
|
+
);
|
|
94
|
+
} else {
|
|
95
|
+
// macOS/Linux: Use curl
|
|
96
|
+
execSync(
|
|
97
|
+
'curl -LsSf https://astral.sh/uv/install.sh | sh',
|
|
98
|
+
{ stdio: 'inherit', shell: true }
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
logSuccess('uv installed successfully');
|
|
102
|
+
return true;
|
|
103
|
+
} catch (error) {
|
|
104
|
+
logError(`Failed to install uv: ${error.message}`);
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Install codeflash Python CLI using uv tool
|
|
111
|
+
*/
|
|
112
|
+
function installCodeflash(uvBin) {
|
|
113
|
+
logStep('2/3', 'Installing codeflash Python CLI...');
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
// Use uv tool install to install codeflash in an isolated environment
|
|
117
|
+
// This avoids conflicts with any existing Python environments
|
|
118
|
+
execSync(`"${uvBin}" tool install codeflash --force`, {
|
|
119
|
+
stdio: 'inherit',
|
|
120
|
+
shell: true,
|
|
121
|
+
});
|
|
122
|
+
logSuccess('codeflash CLI installed successfully');
|
|
123
|
+
return true;
|
|
124
|
+
} catch (error) {
|
|
125
|
+
// If codeflash is not on PyPI yet, try installing from the local package
|
|
126
|
+
logWarning('codeflash not found on PyPI, trying local installation...');
|
|
127
|
+
try {
|
|
128
|
+
// Try installing from the current codeflash repo if we're in development
|
|
129
|
+
const cliRoot = path.resolve(__dirname, '..', '..', '..');
|
|
130
|
+
const pyprojectPath = path.join(cliRoot, 'pyproject.toml');
|
|
131
|
+
|
|
132
|
+
if (fs.existsSync(pyprojectPath)) {
|
|
133
|
+
execSync(`"${uvBin}" tool install --force "${cliRoot}"`, {
|
|
134
|
+
stdio: 'inherit',
|
|
135
|
+
shell: true,
|
|
136
|
+
});
|
|
137
|
+
logSuccess('codeflash CLI installed from local source');
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
} catch (localError) {
|
|
141
|
+
logError(`Failed to install codeflash: ${localError.message}`);
|
|
142
|
+
}
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Update shell configuration to include uv tools in PATH
|
|
149
|
+
*/
|
|
150
|
+
function updateShellPath(uvBin) {
|
|
151
|
+
logStep('3/3', 'Updating shell configuration...');
|
|
152
|
+
|
|
153
|
+
try {
|
|
154
|
+
execSync(`"${uvBin}" tool update-shell`, {
|
|
155
|
+
stdio: 'inherit',
|
|
156
|
+
shell: true,
|
|
157
|
+
});
|
|
158
|
+
logSuccess('Shell configuration updated');
|
|
159
|
+
return true;
|
|
160
|
+
} catch (error) {
|
|
161
|
+
logWarning(`Could not update shell: ${error.message}`);
|
|
162
|
+
logWarning('You may need to add ~/.local/bin to your PATH manually');
|
|
163
|
+
return true; // Non-fatal
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Verify the installation works
|
|
169
|
+
*/
|
|
170
|
+
function verifyInstallation(uvBin) {
|
|
171
|
+
try {
|
|
172
|
+
const result = spawnSync(uvBin, ['tool', 'run', 'codeflash', '--version'], {
|
|
173
|
+
encoding: 'utf8',
|
|
174
|
+
shell: true,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
if (result.status === 0) {
|
|
178
|
+
const version = result.stdout.trim() || result.stderr.trim();
|
|
179
|
+
logSuccess(`Verified: codeflash ${version}`);
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
} catch {
|
|
183
|
+
// Ignore verification errors
|
|
184
|
+
}
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Main installation flow
|
|
190
|
+
*/
|
|
191
|
+
async function main() {
|
|
192
|
+
console.log('');
|
|
193
|
+
log('╔════════════════════════════════════════════╗', 'cyan');
|
|
194
|
+
log('║ Codeflash CLI Installation ║', 'cyan');
|
|
195
|
+
log('╚════════════════════════════════════════════╝', 'cyan');
|
|
196
|
+
console.log('');
|
|
197
|
+
|
|
198
|
+
// Check if running in CI or with --ignore-scripts
|
|
199
|
+
if (process.env.CI || process.env.CODEFLASH_SKIP_POSTINSTALL) {
|
|
200
|
+
logWarning('Skipping postinstall in CI environment');
|
|
201
|
+
logWarning('Run `npx codeflash-setup` to complete installation');
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
let uvBin = getUvPath();
|
|
206
|
+
|
|
207
|
+
// Step 1: Check/install uv
|
|
208
|
+
if (commandExists('uv')) {
|
|
209
|
+
logSuccess('uv is already installed');
|
|
210
|
+
uvBin = 'uv'; // Use the one in PATH
|
|
211
|
+
} else if (fs.existsSync(uvBin)) {
|
|
212
|
+
logSuccess('uv found at ' + uvBin);
|
|
213
|
+
} else {
|
|
214
|
+
if (!installUv()) {
|
|
215
|
+
logError('Failed to install uv. Please install it manually:');
|
|
216
|
+
logError(' curl -LsSf https://astral.sh/uv/install.sh | sh');
|
|
217
|
+
process.exit(1);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Check if uv is now available
|
|
221
|
+
if (!fs.existsSync(uvBin) && !commandExists('uv')) {
|
|
222
|
+
logError('uv installation completed but binary not found');
|
|
223
|
+
logError('Please restart your terminal and run: npx codeflash-setup');
|
|
224
|
+
process.exit(1);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Use 'uv' if it's in PATH, otherwise use full path
|
|
229
|
+
if (commandExists('uv')) {
|
|
230
|
+
uvBin = 'uv';
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Step 2: Install codeflash Python CLI
|
|
234
|
+
if (!installCodeflash(uvBin)) {
|
|
235
|
+
logError('Failed to install codeflash CLI');
|
|
236
|
+
logError('You can try manually: uv tool install codeflash');
|
|
237
|
+
process.exit(1);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Step 3: Update shell PATH
|
|
241
|
+
updateShellPath(uvBin);
|
|
242
|
+
|
|
243
|
+
// Verify installation
|
|
244
|
+
console.log('');
|
|
245
|
+
verifyInstallation(uvBin);
|
|
246
|
+
|
|
247
|
+
// Print success message
|
|
248
|
+
console.log('');
|
|
249
|
+
log('════════════════════════════════════════════', 'green');
|
|
250
|
+
logSuccess('Codeflash installation complete!');
|
|
251
|
+
log('════════════════════════════════════════════', 'green');
|
|
252
|
+
console.log('');
|
|
253
|
+
log('Get started:', 'cyan');
|
|
254
|
+
console.log(' npx codeflash --help');
|
|
255
|
+
console.log(' npx codeflash optimize --file src/utils.ts');
|
|
256
|
+
console.log('');
|
|
257
|
+
log('Documentation: https://docs.codeflash.ai', 'dim');
|
|
258
|
+
console.log('');
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Run the installer
|
|
262
|
+
main().catch((error) => {
|
|
263
|
+
logError(`Installation failed: ${error.message}`);
|
|
264
|
+
process.exit(1);
|
|
265
|
+
});
|