ai-sprint-kit 2.1.45 ā 2.1.48
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 +3 -3
- package/bin/ai-sprint.js +119 -11
- package/lib/installer.js +152 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
|
|
7
7
|
## What is AI Sprint?
|
|
8
8
|
|
|
9
|
-
AI Sprint transforms Claude Code into a team of **
|
|
9
|
+
AI Sprint transforms Claude Code into a team of **15 specialized AI agents** with **21 powerful commands**. Build production-grade software with security-first, autonomous development.
|
|
10
10
|
|
|
11
11
|
**Features:**
|
|
12
|
-
-
|
|
13
|
-
-
|
|
12
|
+
- 15 AI Agents (prd-writer, business-analyst, architect, planner, implementer, tester, reviewer, security, devops, docs, debugger, researcher, verifier, browser-tester, deployment-smoke)
|
|
13
|
+
- 21 Slash Commands for full development lifecycle
|
|
14
14
|
- Automation Hooks (auto-format, lint-check, sound notifications)
|
|
15
15
|
- Memory System for persistent context
|
|
16
16
|
- Security-First with built-in SAST, secrets scanning, dependency audit
|
package/bin/ai-sprint.js
CHANGED
|
@@ -16,7 +16,12 @@ const {
|
|
|
16
16
|
copyProContent,
|
|
17
17
|
createAiContextStructure,
|
|
18
18
|
cleanup,
|
|
19
|
-
checkExisting
|
|
19
|
+
checkExisting,
|
|
20
|
+
commandExists,
|
|
21
|
+
installBun,
|
|
22
|
+
installRalphTui,
|
|
23
|
+
checkRalphTui,
|
|
24
|
+
setupRalphTuiConfig
|
|
20
25
|
} = require('../lib/installer');
|
|
21
26
|
const {
|
|
22
27
|
validateInstallation,
|
|
@@ -61,6 +66,62 @@ function question(prompt) {
|
|
|
61
66
|
});
|
|
62
67
|
}
|
|
63
68
|
|
|
69
|
+
// Shared function for ralph-tui installation with UI feedback
|
|
70
|
+
// Returns: { success: boolean, bunInstalled: boolean, ralphInstalled: boolean }
|
|
71
|
+
async function installRalphTuiWithUI(targetDir, options = {}) {
|
|
72
|
+
const { exitOnFail = false } = options;
|
|
73
|
+
|
|
74
|
+
// Check if bun is installed
|
|
75
|
+
const bunSpinner = ora('Checking Bun runtime...').start();
|
|
76
|
+
const hasBun = await commandExists('bun');
|
|
77
|
+
|
|
78
|
+
if (!hasBun) {
|
|
79
|
+
bunSpinner.text = 'Installing Bun runtime...';
|
|
80
|
+
const bunInstalled = await installBun();
|
|
81
|
+
if (bunInstalled) {
|
|
82
|
+
bunSpinner.succeed('Bun runtime installed');
|
|
83
|
+
} else {
|
|
84
|
+
if (exitOnFail) {
|
|
85
|
+
bunSpinner.fail('Bun installation failed');
|
|
86
|
+
console.log(chalk.yellow('\nInstall manually: curl -fsSL https://bun.sh/install | bash\n'));
|
|
87
|
+
process.exit(1);
|
|
88
|
+
} else {
|
|
89
|
+
bunSpinner.warn('Bun installation failed. Install manually: curl -fsSL https://bun.sh/install | bash');
|
|
90
|
+
return { success: false, bunInstalled: false, ralphInstalled: false };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
bunSpinner.succeed('Bun runtime found');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Install ralph-tui
|
|
98
|
+
const ralphSpinner = ora('Installing ralph-tui...').start();
|
|
99
|
+
const hasRalph = await checkRalphTui();
|
|
100
|
+
|
|
101
|
+
if (!hasRalph) {
|
|
102
|
+
const ralphInstalled = await installRalphTui();
|
|
103
|
+
if (ralphInstalled) {
|
|
104
|
+
ralphSpinner.succeed('ralph-tui installed');
|
|
105
|
+
} else {
|
|
106
|
+
if (exitOnFail) {
|
|
107
|
+
ralphSpinner.fail('ralph-tui installation failed');
|
|
108
|
+
console.log(chalk.yellow('\nInstall manually: bun install -g ralph-tui\n'));
|
|
109
|
+
process.exit(1);
|
|
110
|
+
} else {
|
|
111
|
+
ralphSpinner.warn('ralph-tui installation failed. Install manually: bun install -g ralph-tui');
|
|
112
|
+
return { success: false, bunInstalled: true, ralphInstalled: false };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
ralphSpinner.succeed('ralph-tui already installed');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Setup project config
|
|
120
|
+
await setupRalphTuiConfig(targetDir);
|
|
121
|
+
|
|
122
|
+
return { success: true, bunInstalled: !hasBun, ralphInstalled: !hasRalph };
|
|
123
|
+
}
|
|
124
|
+
|
|
64
125
|
program
|
|
65
126
|
.name('ai-sprint')
|
|
66
127
|
.description('AI Sprint - Autonomous development framework for Claude Code')
|
|
@@ -199,6 +260,26 @@ program
|
|
|
199
260
|
} else {
|
|
200
261
|
console.log(chalk.gray('\nRun later: ai-sprint setup-mcp\n'));
|
|
201
262
|
}
|
|
263
|
+
|
|
264
|
+
// Ask if user wants to install ralph-tui for autonomous loops
|
|
265
|
+
console.log(chalk.cyan('š Ralph TUI - Autonomous Agent Loop (Optional)\n'));
|
|
266
|
+
console.log(chalk.gray('Ralph TUI runs AI agents autonomously through task lists'));
|
|
267
|
+
console.log(chalk.gray('with session persistence, TUI dashboard, and crash recovery.\n'));
|
|
268
|
+
|
|
269
|
+
const setupRalph = await question('Install ralph-tui now? (Y/n): ');
|
|
270
|
+
if (setupRalph.toLowerCase() !== 'n') {
|
|
271
|
+
console.log();
|
|
272
|
+
const result = await installRalphTuiWithUI(targetDir, { exitOnFail: false });
|
|
273
|
+
if (result.success) {
|
|
274
|
+
console.log(chalk.green('\nā
ralph-tui configured\n'));
|
|
275
|
+
console.log(chalk.cyan('Quick start:'));
|
|
276
|
+
console.log(chalk.gray(' 1. Create PRD: ralph-tui create-prd --chat'));
|
|
277
|
+
console.log(chalk.gray(' 2. Run loop: ralph-tui run --prd ./prd.json'));
|
|
278
|
+
console.log(chalk.gray(' 3. Check docs: https://ralph-tui.com/docs\n'));
|
|
279
|
+
}
|
|
280
|
+
} else {
|
|
281
|
+
console.log(chalk.gray('\nRun later: ai-sprint setup-ralph\n'));
|
|
282
|
+
}
|
|
202
283
|
} catch (error) {
|
|
203
284
|
progress.failStep(2, error.message);
|
|
204
285
|
cloneSpinner.fail('Installation failed');
|
|
@@ -216,19 +297,24 @@ program
|
|
|
216
297
|
.description('Show AI Sprint Pro features')
|
|
217
298
|
.action(() => {
|
|
218
299
|
console.log(chalk.blue.bold('\nAI Sprint Pro Framework\n'));
|
|
219
|
-
console.log(chalk.cyan('Agents (
|
|
220
|
-
console.log(chalk.gray('
|
|
221
|
-
console.log(chalk.gray('
|
|
300
|
+
console.log(chalk.cyan('Agents (15):'));
|
|
301
|
+
console.log(chalk.gray(' prd-writer, business-analyst, architect, planner'));
|
|
302
|
+
console.log(chalk.gray(' implementer, tester, reviewer, security, devops'));
|
|
303
|
+
console.log(chalk.gray(' docs, debugger, researcher, verifier'));
|
|
222
304
|
console.log(chalk.gray(' browser-tester, deployment-smoke'));
|
|
223
|
-
console.log(chalk.cyan('\nCommands (
|
|
224
|
-
console.log(chalk.gray(' /ai-sprint-
|
|
225
|
-
console.log(chalk.gray(' /ai-sprint-
|
|
226
|
-
console.log(chalk.gray(' /ai-sprint-
|
|
227
|
-
console.log(chalk.gray(' /ai-sprint-
|
|
228
|
-
console.log(chalk.gray(' /ai-sprint-
|
|
305
|
+
console.log(chalk.cyan('\nCommands (20):'));
|
|
306
|
+
console.log(chalk.gray(' /ai-sprint-prd, /ai-sprint-analyze, /ai-sprint-architect'));
|
|
307
|
+
console.log(chalk.gray(' /ai-sprint-init, /ai-sprint-plan, /ai-sprint-code'));
|
|
308
|
+
console.log(chalk.gray(' /ai-sprint-test, /ai-sprint-review, /ai-sprint-secure'));
|
|
309
|
+
console.log(chalk.gray(' /ai-sprint-deploy, /ai-sprint-docs, /ai-sprint-debug'));
|
|
310
|
+
console.log(chalk.gray(' /ai-sprint-fix, /ai-sprint-scan, /ai-sprint-validate'));
|
|
311
|
+
console.log(chalk.gray(' /ai-sprint-browser-test, /ai-sprint-orchestrate'));
|
|
312
|
+
console.log(chalk.gray(' /ai-sprint-setup, /ai-sprint-auto, /ai-sprint-full-cycle'));
|
|
313
|
+
console.log(chalk.cyan('\nAutonomous Loop:'));
|
|
314
|
+
console.log(chalk.gray(' ralph-tui (external) - https://ralph-tui.com'));
|
|
229
315
|
console.log(chalk.cyan('\nCLI Commands:'));
|
|
230
316
|
console.log(chalk.gray(' init, list, validate, doctor, update, check-update'));
|
|
231
|
-
console.log(chalk.gray(' setup-env, setup-mcp, repair, reinstall, init-ci\n'));
|
|
317
|
+
console.log(chalk.gray(' setup-env, setup-mcp, setup-ralph, repair, reinstall, init-ci\n'));
|
|
232
318
|
});
|
|
233
319
|
|
|
234
320
|
program
|
|
@@ -530,6 +616,28 @@ program
|
|
|
530
616
|
}
|
|
531
617
|
});
|
|
532
618
|
|
|
619
|
+
program
|
|
620
|
+
.command('setup-ralph')
|
|
621
|
+
.description('Install and configure ralph-tui for autonomous loops')
|
|
622
|
+
.option('-d, --dir <directory>', 'Target directory', process.cwd())
|
|
623
|
+
.action(async (options) => {
|
|
624
|
+
console.log(chalk.blue.bold('\nš Ralph TUI Setup\n'));
|
|
625
|
+
|
|
626
|
+
// Use shared installation function (exits on failure)
|
|
627
|
+
await installRalphTuiWithUI(options.dir, { exitOnFail: true });
|
|
628
|
+
|
|
629
|
+
console.log(chalk.green.bold('\nā
ralph-tui configured\n'));
|
|
630
|
+
console.log(chalk.cyan('Quick start:'));
|
|
631
|
+
console.log(chalk.gray(' 1. Create PRD: ralph-tui create-prd --chat'));
|
|
632
|
+
console.log(chalk.gray(' 2. Run loop: ralph-tui run --prd ./prd.json'));
|
|
633
|
+
console.log(chalk.gray(' 3. Check docs: https://ralph-tui.com/docs\n'));
|
|
634
|
+
|
|
635
|
+
console.log(chalk.cyan('AI Sprint integration:'));
|
|
636
|
+
console.log(chalk.gray(' ⢠Custom skill: ai_context/ralph-tui/skills/ai-sprint-prd/'));
|
|
637
|
+
console.log(chalk.gray(' ⢠Custom template: ai_context/ralph-tui/ai-sprint-template.hbs'));
|
|
638
|
+
console.log(chalk.gray(' ⢠Config: .ralph-tui/config.toml\n'));
|
|
639
|
+
});
|
|
640
|
+
|
|
533
641
|
program
|
|
534
642
|
.command('reinstall')
|
|
535
643
|
.description('Clean reinstall AI Sprint Kit')
|
package/lib/installer.js
CHANGED
|
@@ -35,7 +35,9 @@ async function copyProContent(sourceDir, targetDir, force = false) {
|
|
|
35
35
|
const items = [
|
|
36
36
|
{ src: '.claude', dest: '.claude' },
|
|
37
37
|
// ai_context is NOT copied - preserve user's plans, reports, memory
|
|
38
|
-
|
|
38
|
+
// EXCEPT ralph-tui config which contains skills and templates for ralph-tui integration
|
|
39
|
+
{ src: 'ai_context/ralph-tui', dest: 'ai_context/ralph-tui' },
|
|
40
|
+
// CLAUDE.md handled specially below - append instead of replace
|
|
39
41
|
{ src: 'README.md', dest: 'AI-SPRINT-README.md' },
|
|
40
42
|
{ src: 'docs', dest: '.claude/docs' },
|
|
41
43
|
{ src: 'scripts', dest: '.claude/scripts' }
|
|
@@ -61,6 +63,47 @@ async function copyProContent(sourceDir, targetDir, force = false) {
|
|
|
61
63
|
|
|
62
64
|
await fs.cp(srcPath, destPath, { recursive: true, force: true });
|
|
63
65
|
}
|
|
66
|
+
|
|
67
|
+
// Handle CLAUDE.md specially - append if exists, create if not
|
|
68
|
+
await handleClaudeMd(sourceDir, targetDir);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Handle CLAUDE.md - append AI Sprint content if file exists, create if not
|
|
73
|
+
* @param {string} sourceDir - Cloned repo path
|
|
74
|
+
* @param {string} targetDir - User's project directory
|
|
75
|
+
*/
|
|
76
|
+
async function handleClaudeMd(sourceDir, targetDir) {
|
|
77
|
+
const srcPath = path.join(sourceDir, 'CLAUDE.md');
|
|
78
|
+
const destPath = path.join(targetDir, 'CLAUDE.md');
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
await fs.access(srcPath);
|
|
82
|
+
} catch {
|
|
83
|
+
return; // Source doesn't exist, skip
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const aiSprintContent = await fs.readFile(srcPath, 'utf-8');
|
|
87
|
+
const separator = '\n\n---\n\n# AI Sprint Kit Framework\n\n';
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
// Check if CLAUDE.md exists
|
|
91
|
+
const existingContent = await fs.readFile(destPath, 'utf-8');
|
|
92
|
+
|
|
93
|
+
// Check if AI Sprint content already added
|
|
94
|
+
if (existingContent.includes('# AI Sprint Kit Framework') ||
|
|
95
|
+
existingContent.includes('AI Sprint - Security-first')) {
|
|
96
|
+
// Already has AI Sprint content, skip
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Append AI Sprint content to existing file
|
|
101
|
+
const mergedContent = existingContent.trimEnd() + separator + aiSprintContent;
|
|
102
|
+
await fs.writeFile(destPath, mergedContent);
|
|
103
|
+
} catch {
|
|
104
|
+
// CLAUDE.md doesn't exist, create new
|
|
105
|
+
await fs.copyFile(srcPath, destPath);
|
|
106
|
+
}
|
|
64
107
|
}
|
|
65
108
|
|
|
66
109
|
/**
|
|
@@ -74,7 +117,9 @@ async function createAiContextStructure(targetDir) {
|
|
|
74
117
|
'plans',
|
|
75
118
|
'reports',
|
|
76
119
|
'codebase',
|
|
77
|
-
'memory'
|
|
120
|
+
'memory',
|
|
121
|
+
'ralph-tui',
|
|
122
|
+
'ralph-tui/sessions'
|
|
78
123
|
];
|
|
79
124
|
|
|
80
125
|
for (const dir of dirs) {
|
|
@@ -132,10 +177,114 @@ async function checkExisting(targetDir) {
|
|
|
132
177
|
}
|
|
133
178
|
}
|
|
134
179
|
|
|
180
|
+
/**
|
|
181
|
+
* Check if a command exists
|
|
182
|
+
* @param {string} cmd - Command to check
|
|
183
|
+
* @returns {Promise<boolean>}
|
|
184
|
+
*/
|
|
185
|
+
async function commandExists(cmd) {
|
|
186
|
+
try {
|
|
187
|
+
await execFileAsync('which', [cmd]);
|
|
188
|
+
return true;
|
|
189
|
+
} catch {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Install Bun runtime
|
|
196
|
+
* @returns {Promise<boolean>} - Whether installation succeeded
|
|
197
|
+
*/
|
|
198
|
+
async function installBun() {
|
|
199
|
+
try {
|
|
200
|
+
// Use curl to install bun
|
|
201
|
+
const { exec } = require('child_process');
|
|
202
|
+
const { promisify } = require('util');
|
|
203
|
+
const execAsync = promisify(exec);
|
|
204
|
+
|
|
205
|
+
await execAsync('curl -fsSL https://bun.sh/install | bash');
|
|
206
|
+
|
|
207
|
+
// Check if bun is now available
|
|
208
|
+
const bunPath = path.join(process.env.HOME, '.bun', 'bin', 'bun');
|
|
209
|
+
try {
|
|
210
|
+
await fs.access(bunPath);
|
|
211
|
+
return true;
|
|
212
|
+
} catch {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
} catch {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Install ralph-tui globally via bun
|
|
222
|
+
* @returns {Promise<boolean>} - Whether installation succeeded
|
|
223
|
+
*/
|
|
224
|
+
async function installRalphTui() {
|
|
225
|
+
try {
|
|
226
|
+
// Try system bun first
|
|
227
|
+
let bunCmd = 'bun';
|
|
228
|
+
if (!await commandExists('bun')) {
|
|
229
|
+
// Try home directory bun
|
|
230
|
+
bunCmd = path.join(process.env.HOME, '.bun', 'bin', 'bun');
|
|
231
|
+
try {
|
|
232
|
+
await fs.access(bunCmd);
|
|
233
|
+
} catch {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
await execFileAsync(bunCmd, ['install', '-g', 'ralph-tui']);
|
|
239
|
+
return true;
|
|
240
|
+
} catch {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Check if ralph-tui is installed
|
|
247
|
+
* @returns {Promise<boolean>}
|
|
248
|
+
*/
|
|
249
|
+
async function checkRalphTui() {
|
|
250
|
+
return commandExists('ralph-tui');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Setup ralph-tui configuration in project
|
|
255
|
+
* @param {string} targetDir - User's project directory
|
|
256
|
+
*/
|
|
257
|
+
async function setupRalphTuiConfig(targetDir) {
|
|
258
|
+
const ralphTuiDir = path.join(targetDir, '.ralph-tui');
|
|
259
|
+
const configSource = path.join(targetDir, 'ai_context', 'ralph-tui', 'config.toml');
|
|
260
|
+
const configDest = path.join(ralphTuiDir, 'config.toml');
|
|
261
|
+
|
|
262
|
+
// Create .ralph-tui directory
|
|
263
|
+
await fs.mkdir(ralphTuiDir, { recursive: true });
|
|
264
|
+
|
|
265
|
+
// Copy config if source exists and dest doesn't
|
|
266
|
+
try {
|
|
267
|
+
await fs.access(configSource);
|
|
268
|
+
try {
|
|
269
|
+
await fs.access(configDest);
|
|
270
|
+
// Config exists, don't overwrite
|
|
271
|
+
} catch {
|
|
272
|
+
await fs.copyFile(configSource, configDest);
|
|
273
|
+
}
|
|
274
|
+
} catch {
|
|
275
|
+
// Source doesn't exist, skip
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
135
279
|
module.exports = {
|
|
136
280
|
cloneProRepo,
|
|
137
281
|
copyProContent,
|
|
138
282
|
createAiContextStructure,
|
|
139
283
|
cleanup,
|
|
140
|
-
checkExisting
|
|
284
|
+
checkExisting,
|
|
285
|
+
commandExists,
|
|
286
|
+
installBun,
|
|
287
|
+
installRalphTui,
|
|
288
|
+
checkRalphTui,
|
|
289
|
+
setupRalphTuiConfig
|
|
141
290
|
};
|