ai-sprint-kit 2.1.1 → 2.1.3
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/ai-sprint.js +11 -30
- package/lib/updater.js +49 -73
- package/package.json +2 -2
package/bin/ai-sprint.js
CHANGED
|
@@ -302,53 +302,34 @@ program
|
|
|
302
302
|
|
|
303
303
|
if (!updateInfo.hasUpdate && !options.force) {
|
|
304
304
|
checkSpinner.info(updateInfo.message);
|
|
305
|
-
console.log(chalk.gray('\nUse --force to
|
|
305
|
+
console.log(chalk.gray('\nUse --force to check anyway\n'));
|
|
306
306
|
process.exit(0);
|
|
307
307
|
}
|
|
308
308
|
|
|
309
309
|
checkSpinner.succeed(`Update available: ${updateInfo.installed} → ${updateInfo.latest}`);
|
|
310
310
|
|
|
311
|
-
//
|
|
312
|
-
if (!options.force) {
|
|
313
|
-
console.log(chalk.yellow('\nThis will:'));
|
|
314
|
-
console.log(chalk.gray(' • Download latest AI Sprint Pro'));
|
|
315
|
-
console.log(chalk.gray(' • Backup your config (.claude/settings.json, .env)'));
|
|
316
|
-
console.log(chalk.gray(' • Replace framework files'));
|
|
317
|
-
console.log(chalk.gray(' • Restore your config\n'));
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// Backup config
|
|
321
|
-
if (options.backup) {
|
|
322
|
-
const backupSpinner = ora('Backing up configuration...').start();
|
|
323
|
-
backupSpinner.succeed('Configuration backed up');
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// Download and install
|
|
327
|
-
const downloadSpinner = ora('Downloading latest version...').start();
|
|
328
|
-
|
|
311
|
+
// Get update instructions
|
|
329
312
|
const result = await updateInstallation(options.dir, {
|
|
330
313
|
force: options.force,
|
|
331
314
|
backup: options.backup
|
|
332
315
|
});
|
|
333
316
|
|
|
334
|
-
if (result.success) {
|
|
335
|
-
downloadSpinner.succeed('Update complete');
|
|
336
|
-
|
|
317
|
+
if (result.success && result.instructions) {
|
|
337
318
|
console.log(chalk.green.bold(`\n✅ ${result.message}\n`));
|
|
338
319
|
|
|
320
|
+
console.log(chalk.cyan('Instructions:'));
|
|
321
|
+
result.instructions.forEach(line => {
|
|
322
|
+
console.log(chalk.gray(line));
|
|
323
|
+
});
|
|
324
|
+
console.log();
|
|
325
|
+
|
|
339
326
|
if (result.changelog) {
|
|
340
327
|
console.log(chalk.cyan('What\'s new:'));
|
|
341
|
-
console.log(chalk.gray(result.changelog
|
|
342
|
-
if (result.changelog.split('\n').length > 10) {
|
|
343
|
-
console.log(chalk.gray('\n... (changelog truncated)'));
|
|
344
|
-
}
|
|
328
|
+
console.log(chalk.gray(result.changelog));
|
|
345
329
|
console.log();
|
|
346
330
|
}
|
|
347
|
-
|
|
348
|
-
console.log(chalk.gray('Run: ai-sprint validate\n'));
|
|
349
331
|
} else {
|
|
350
|
-
|
|
351
|
-
console.log(chalk.yellow(result.message));
|
|
332
|
+
console.log(chalk.yellow(result.message || 'No update available'));
|
|
352
333
|
process.exit(1);
|
|
353
334
|
}
|
|
354
335
|
} catch (error) {
|
package/lib/updater.js
CHANGED
|
@@ -4,9 +4,22 @@ const { execFileSync } = require('child_process');
|
|
|
4
4
|
const semver = require('semver');
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Get installed version from
|
|
7
|
+
* Get installed CLI version from package.json
|
|
8
8
|
*/
|
|
9
9
|
async function getInstalledVersion(targetDir) {
|
|
10
|
+
// Try to get CLI version from npm package
|
|
11
|
+
try {
|
|
12
|
+
const packageJsonPath = path.join(__dirname, '..', 'package.json');
|
|
13
|
+
const content = await fs.readFile(packageJsonPath, 'utf8');
|
|
14
|
+
const pkg = JSON.parse(content);
|
|
15
|
+
if (pkg.version) {
|
|
16
|
+
return pkg.version;
|
|
17
|
+
}
|
|
18
|
+
} catch {
|
|
19
|
+
// Fall back to checking CLAUDE.md in target directory
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Fallback: Check CLAUDE.md in project directory
|
|
10
23
|
const claudeMdPath = path.join(targetDir, 'CLAUDE.md');
|
|
11
24
|
try {
|
|
12
25
|
const content = await fs.readFile(claudeMdPath, 'utf8');
|
|
@@ -21,25 +34,20 @@ async function getInstalledVersion(targetDir) {
|
|
|
21
34
|
}
|
|
22
35
|
|
|
23
36
|
/**
|
|
24
|
-
* Get latest version from
|
|
37
|
+
* Get latest version from npm registry
|
|
25
38
|
*/
|
|
26
39
|
async function getLatestVersion() {
|
|
27
40
|
try {
|
|
28
|
-
// Use
|
|
29
|
-
const output = execFileSync('
|
|
30
|
-
'
|
|
31
|
-
'
|
|
32
|
-
'
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
// Output format: "v2.0.0 Release title"
|
|
37
|
-
const match = output.trim().match(/^v(\d+\.\d+\.\d+)/);
|
|
38
|
-
if (match) {
|
|
39
|
-
return match[1];
|
|
40
|
-
}
|
|
41
|
+
// Use npm view to get latest version
|
|
42
|
+
const output = execFileSync('npm', [
|
|
43
|
+
'view',
|
|
44
|
+
'ai-sprint-kit',
|
|
45
|
+
'version'
|
|
46
|
+
], { encoding: 'utf8', stdio: 'pipe' });
|
|
47
|
+
|
|
48
|
+
return output.trim();
|
|
41
49
|
} catch (error) {
|
|
42
|
-
throw new Error('Failed to fetch latest version from
|
|
50
|
+
throw new Error('Failed to fetch latest version from npm');
|
|
43
51
|
}
|
|
44
52
|
return null;
|
|
45
53
|
}
|
|
@@ -141,20 +149,20 @@ async function restoreConfig(targetDir, backupDir) {
|
|
|
141
149
|
}
|
|
142
150
|
|
|
143
151
|
/**
|
|
144
|
-
* Get changelog between versions
|
|
152
|
+
* Get changelog between versions from npm
|
|
145
153
|
*/
|
|
146
154
|
async function getChangelog(fromVersion, toVersion) {
|
|
147
155
|
try {
|
|
148
|
-
|
|
149
|
-
|
|
156
|
+
// Use npm view to get package metadata with changelog
|
|
157
|
+
const output = execFileSync('npm', [
|
|
150
158
|
'view',
|
|
151
|
-
|
|
152
|
-
'--
|
|
153
|
-
|
|
154
|
-
], { encoding: 'utf8' });
|
|
159
|
+
'ai-sprint-kit',
|
|
160
|
+
'--json'
|
|
161
|
+
], { encoding: 'utf8', stdio: 'pipe' });
|
|
155
162
|
|
|
156
163
|
const data = JSON.parse(output);
|
|
157
|
-
|
|
164
|
+
// npm doesn't store detailed changelog, return basic info
|
|
165
|
+
return `Version ${toVersion} is now available on npm.\n\nTo see what's new, visit: https://github.com/apiasak/ai-sprint-kit/releases`;
|
|
158
166
|
} catch {
|
|
159
167
|
return 'Changelog not available';
|
|
160
168
|
}
|
|
@@ -181,61 +189,29 @@ async function updateInstallation(targetDir = process.cwd(), options = {}) {
|
|
|
181
189
|
};
|
|
182
190
|
}
|
|
183
191
|
|
|
184
|
-
//
|
|
185
|
-
|
|
186
|
-
if (backup) {
|
|
187
|
-
backupDir = await backupConfig(targetDir);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Step 3: Clone latest version to temp directory
|
|
191
|
-
const tempDir = path.join(targetDir, '.ai-sprint-temp-update');
|
|
192
|
-
|
|
193
|
-
try {
|
|
194
|
-
// Remove temp dir if exists
|
|
195
|
-
await fs.rm(tempDir, { recursive: true, force: true });
|
|
196
|
-
|
|
197
|
-
// Clone latest version
|
|
198
|
-
execFileSync('git', [
|
|
199
|
-
'clone',
|
|
200
|
-
'--depth', '1',
|
|
201
|
-
'--branch', `v${updateInfo.latest}`,
|
|
202
|
-
'git@github.com:apiasak/ai-sprint-pro.git',
|
|
203
|
-
tempDir
|
|
204
|
-
], { stdio: 'pipe' });
|
|
205
|
-
|
|
206
|
-
// Step 4: Copy new files (similar to installer.js)
|
|
207
|
-
await copyProContent(tempDir, targetDir, { force: true });
|
|
208
|
-
|
|
209
|
-
// Step 5: Restore config
|
|
210
|
-
if (backup && backupDir) {
|
|
211
|
-
await restoreConfig(targetDir, backupDir);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// Step 6: Get changelog
|
|
215
|
-
const changelog = await getChangelog(updateInfo.installed, updateInfo.latest);
|
|
216
|
-
|
|
217
|
-
// Step 7: Cleanup
|
|
218
|
-
await fs.rm(tempDir, { recursive: true, force: true });
|
|
219
|
-
if (backupDir) {
|
|
220
|
-
await fs.rm(backupDir, { recursive: true, force: true });
|
|
221
|
-
}
|
|
222
|
-
|
|
192
|
+
// For CLI updates, guide user to use npm
|
|
193
|
+
if (updateInfo.hasUpdate) {
|
|
223
194
|
return {
|
|
224
195
|
success: true,
|
|
225
|
-
message: `
|
|
196
|
+
message: `CLI update available: ${updateInfo.installed} → ${updateInfo.latest}`,
|
|
226
197
|
from: updateInfo.installed,
|
|
227
198
|
to: updateInfo.latest,
|
|
228
|
-
|
|
199
|
+
instructions: [
|
|
200
|
+
'To update the CLI, run one of:',
|
|
201
|
+
' npx ai-sprint-kit@latest init',
|
|
202
|
+
' npm update -g ai-sprint-kit',
|
|
203
|
+
'',
|
|
204
|
+
'To update the Pro framework (.claude/), run:',
|
|
205
|
+
' ai-sprint init --force'
|
|
206
|
+
],
|
|
207
|
+
changelog: await getChangelog(updateInfo.installed, updateInfo.latest)
|
|
229
208
|
};
|
|
230
|
-
} catch (error) {
|
|
231
|
-
// Cleanup on failure
|
|
232
|
-
await fs.rm(tempDir, { recursive: true, force: true });
|
|
233
|
-
if (backupDir) {
|
|
234
|
-
await fs.rm(backupDir, { recursive: true, force: true });
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
throw new Error(`Update failed: ${error.message}`);
|
|
238
209
|
}
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
success: false,
|
|
213
|
+
message: 'No update available'
|
|
214
|
+
};
|
|
239
215
|
}
|
|
240
216
|
|
|
241
217
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-sprint-kit",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"description": "CLI installer for AI Sprint autonomous development framework - requires license",
|
|
5
5
|
"main": "lib/installer.js",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"ai-sprint-kit": "bin/ai-sprint.js"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"test": "node
|
|
11
|
+
"test": "node test/test.js",
|
|
12
12
|
"link": "npm link",
|
|
13
13
|
"unlink": "npm unlink -g ai-sprint-kit"
|
|
14
14
|
},
|