ai-sprint-kit 2.1.63 → 2.1.64
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 +50 -71
- package/lib/installer.js +59 -72
- 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
|
@@ -18,10 +18,9 @@ const {
|
|
|
18
18
|
cleanup,
|
|
19
19
|
checkExisting,
|
|
20
20
|
commandExists,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
setupRalphTuiConfig,
|
|
21
|
+
checkDocker,
|
|
22
|
+
setupRalphTemplate,
|
|
23
|
+
checkRalphTemplate,
|
|
25
24
|
installAgentBrowser,
|
|
26
25
|
checkAgentBrowser
|
|
27
26
|
} = require('../lib/installer');
|
|
@@ -68,60 +67,39 @@ function question(prompt) {
|
|
|
68
67
|
});
|
|
69
68
|
}
|
|
70
69
|
|
|
71
|
-
// Shared function for ralph-
|
|
72
|
-
// Returns: { success: boolean,
|
|
73
|
-
async function
|
|
70
|
+
// Shared function for ralph-template setup with UI feedback
|
|
71
|
+
// Returns: { success: boolean, dockerAvailable: boolean }
|
|
72
|
+
async function setupRalphWithUI(targetDir, options = {}) {
|
|
74
73
|
const { exitOnFail = false } = options;
|
|
75
74
|
|
|
76
|
-
// Check if
|
|
77
|
-
const
|
|
78
|
-
const
|
|
75
|
+
// Check if Docker is available (optional but recommended)
|
|
76
|
+
const dockerSpinner = ora('Checking Docker...').start();
|
|
77
|
+
const hasDocker = await checkDocker();
|
|
79
78
|
|
|
80
|
-
if (
|
|
81
|
-
|
|
82
|
-
const bunInstalled = await installBun();
|
|
83
|
-
if (bunInstalled) {
|
|
84
|
-
bunSpinner.succeed('Bun runtime installed');
|
|
85
|
-
} else {
|
|
86
|
-
if (exitOnFail) {
|
|
87
|
-
bunSpinner.fail('Bun installation failed');
|
|
88
|
-
console.log(chalk.yellow('\nInstall manually: curl -fsSL https://bun.sh/install | bash\n'));
|
|
89
|
-
process.exit(1);
|
|
90
|
-
} else {
|
|
91
|
-
bunSpinner.warn('Bun installation failed. Install manually: curl -fsSL https://bun.sh/install | bash');
|
|
92
|
-
return { success: false, bunInstalled: false, ralphInstalled: false };
|
|
93
|
-
}
|
|
94
|
-
}
|
|
79
|
+
if (hasDocker) {
|
|
80
|
+
dockerSpinner.succeed('Docker available (sandbox mode enabled)');
|
|
95
81
|
} else {
|
|
96
|
-
|
|
82
|
+
dockerSpinner.warn('Docker not found (manual mode only)');
|
|
83
|
+
console.log(chalk.gray(' Install Docker for sandboxed execution: https://docker.com\n'));
|
|
97
84
|
}
|
|
98
85
|
|
|
99
|
-
//
|
|
100
|
-
const
|
|
101
|
-
const
|
|
86
|
+
// Setup ralph-template files
|
|
87
|
+
const setupSpinner = ora('Setting up ralph-template...').start();
|
|
88
|
+
const setupSuccess = await setupRalphTemplate(targetDir);
|
|
102
89
|
|
|
103
|
-
if (
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
90
|
+
if (setupSuccess) {
|
|
91
|
+
setupSpinner.succeed('ralph-template configured');
|
|
92
|
+
} else {
|
|
93
|
+
if (exitOnFail) {
|
|
94
|
+
setupSpinner.fail('ralph-template setup failed');
|
|
95
|
+
process.exit(1);
|
|
107
96
|
} else {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
console.log(chalk.yellow('\nInstall manually: bun install -g ralph-tui\n'));
|
|
111
|
-
process.exit(1);
|
|
112
|
-
} else {
|
|
113
|
-
ralphSpinner.warn('ralph-tui installation failed. Install manually: bun install -g ralph-tui');
|
|
114
|
-
return { success: false, bunInstalled: true, ralphInstalled: false };
|
|
115
|
-
}
|
|
97
|
+
setupSpinner.warn('ralph-template setup incomplete');
|
|
98
|
+
return { success: false, dockerAvailable: hasDocker };
|
|
116
99
|
}
|
|
117
|
-
} else {
|
|
118
|
-
ralphSpinner.succeed('ralph-tui already installed');
|
|
119
100
|
}
|
|
120
101
|
|
|
121
|
-
|
|
122
|
-
await setupRalphTuiConfig(targetDir);
|
|
123
|
-
|
|
124
|
-
return { success: true, bunInstalled: !hasBun, ralphInstalled: !hasRalph };
|
|
102
|
+
return { success: true, dockerAvailable: hasDocker };
|
|
125
103
|
}
|
|
126
104
|
|
|
127
105
|
program
|
|
@@ -277,21 +255,21 @@ program
|
|
|
277
255
|
console.log(chalk.gray('\nRun later: ai-sprint setup-mcp\n'));
|
|
278
256
|
}
|
|
279
257
|
|
|
280
|
-
// Ask if user wants to
|
|
281
|
-
console.log(chalk.cyan('🔄 Ralph
|
|
282
|
-
console.log(chalk.gray('Ralph
|
|
283
|
-
console.log(chalk.gray('with
|
|
258
|
+
// Ask if user wants to setup ralph-template for autonomous loops
|
|
259
|
+
console.log(chalk.cyan('🔄 Ralph Template - Autonomous Agent Loop (Optional)\n'));
|
|
260
|
+
console.log(chalk.gray('Ralph runs Claude in autonomous loops, completing tasks one-by-one'));
|
|
261
|
+
console.log(chalk.gray('with Docker sandbox isolation (recommended) or manual mode.\n'));
|
|
284
262
|
|
|
285
|
-
const setupRalph = await question('
|
|
263
|
+
const setupRalph = await question('Setup ralph-template now? (Y/n): ');
|
|
286
264
|
if (setupRalph.toLowerCase() !== 'n') {
|
|
287
265
|
console.log();
|
|
288
|
-
const result = await
|
|
266
|
+
const result = await setupRalphWithUI(targetDir, { exitOnFail: false });
|
|
289
267
|
if (result.success) {
|
|
290
|
-
console.log(chalk.green('\n✅ ralph-
|
|
268
|
+
console.log(chalk.green('\n✅ ralph-template configured\n'));
|
|
291
269
|
console.log(chalk.cyan('Quick start:'));
|
|
292
|
-
console.log(chalk.gray(' 1. Create PRD: ralph
|
|
293
|
-
console.log(chalk.gray(' 2. Run loop: ralph-
|
|
294
|
-
console.log(chalk.gray(' 3.
|
|
270
|
+
console.log(chalk.gray(' 1. Create PRD: cd ralph && claude @START_PROMPT.md "your idea"'));
|
|
271
|
+
console.log(chalk.gray(' 2. Run loop: ./ralph/afk-ralph.sh 10'));
|
|
272
|
+
console.log(chalk.gray(' 3. Manual mode: claude @ralph/PROMPT_MANUAL.md\n'));
|
|
295
273
|
}
|
|
296
274
|
} else {
|
|
297
275
|
console.log(chalk.gray('\nRun later: ai-sprint setup-ralph\n'));
|
|
@@ -327,7 +305,7 @@ program
|
|
|
327
305
|
console.log(chalk.gray(' /ai-sprint-browser-test, /ai-sprint-orchestrate'));
|
|
328
306
|
console.log(chalk.gray(' /ai-sprint-setup, /ai-sprint-auto, /ai-sprint-full-cycle'));
|
|
329
307
|
console.log(chalk.cyan('\nAutonomous Loop:'));
|
|
330
|
-
console.log(chalk.gray(' ralph-
|
|
308
|
+
console.log(chalk.gray(' ralph-template (built-in) - ./ralph/afk-ralph.sh'));
|
|
331
309
|
console.log(chalk.cyan('\nCLI Commands:'));
|
|
332
310
|
console.log(chalk.gray(' init, list, validate, doctor, update, check-update'));
|
|
333
311
|
console.log(chalk.gray(' setup-env, setup-mcp, setup-ralph, repair, reinstall, init-ci\n'));
|
|
@@ -634,24 +612,25 @@ program
|
|
|
634
612
|
|
|
635
613
|
program
|
|
636
614
|
.command('setup-ralph')
|
|
637
|
-
.description('
|
|
615
|
+
.description('Setup ralph-template for autonomous loops')
|
|
638
616
|
.option('-d, --dir <directory>', 'Target directory', process.cwd())
|
|
639
617
|
.action(async (options) => {
|
|
640
|
-
console.log(chalk.blue.bold('\n🔄 Ralph
|
|
618
|
+
console.log(chalk.blue.bold('\n🔄 Ralph Template Setup\n'));
|
|
641
619
|
|
|
642
|
-
// Use shared
|
|
643
|
-
await
|
|
620
|
+
// Use shared setup function (exits on failure)
|
|
621
|
+
await setupRalphWithUI(options.dir, { exitOnFail: true });
|
|
644
622
|
|
|
645
|
-
console.log(chalk.green.bold('\n✅ ralph-
|
|
623
|
+
console.log(chalk.green.bold('\n✅ ralph-template configured\n'));
|
|
646
624
|
console.log(chalk.cyan('Quick start:'));
|
|
647
|
-
console.log(chalk.gray(' 1. Create PRD: ralph
|
|
648
|
-
console.log(chalk.gray(' 2. Run loop: ralph-
|
|
649
|
-
console.log(chalk.gray(' 3.
|
|
650
|
-
|
|
651
|
-
console.log(chalk.cyan('
|
|
652
|
-
console.log(chalk.gray(' •
|
|
653
|
-
console.log(chalk.gray(' •
|
|
654
|
-
console.log(chalk.gray(' •
|
|
625
|
+
console.log(chalk.gray(' 1. Create PRD: cd ralph && claude @START_PROMPT.md "your idea"'));
|
|
626
|
+
console.log(chalk.gray(' 2. Run loop: ./ralph/afk-ralph.sh 10'));
|
|
627
|
+
console.log(chalk.gray(' 3. Manual mode: claude @ralph/PROMPT_MANUAL.md\n'));
|
|
628
|
+
|
|
629
|
+
console.log(chalk.cyan('Files:'));
|
|
630
|
+
console.log(chalk.gray(' • Loop script: ralph/afk-ralph.sh'));
|
|
631
|
+
console.log(chalk.gray(' • Loop prompt: ralph/PROMPT.md'));
|
|
632
|
+
console.log(chalk.gray(' • Manual prompt: ralph/PROMPT_MANUAL.md'));
|
|
633
|
+
console.log(chalk.gray(' • PRD kickstart: ralph/START_PROMPT.md\n'));
|
|
655
634
|
});
|
|
656
635
|
|
|
657
636
|
program
|
package/lib/installer.js
CHANGED
|
@@ -35,8 +35,8 @@ 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
|
-
//
|
|
39
|
-
{ src: '
|
|
38
|
+
// ralph-template files (bash scripts + prompts)
|
|
39
|
+
{ src: 'ralph', dest: 'ralph' },
|
|
40
40
|
// CLAUDE.md handled specially below - append instead of replace
|
|
41
41
|
{ src: 'README.md', dest: 'AI-SPRINT-README.md' },
|
|
42
42
|
{ src: 'docs', dest: '.claude/docs' },
|
|
@@ -117,9 +117,7 @@ async function createAiContextStructure(targetDir) {
|
|
|
117
117
|
'plans',
|
|
118
118
|
'reports',
|
|
119
119
|
'codebase',
|
|
120
|
-
'memory'
|
|
121
|
-
'ralph-tui',
|
|
122
|
-
'ralph-tui/sessions'
|
|
120
|
+
'memory'
|
|
123
121
|
];
|
|
124
122
|
|
|
125
123
|
for (const dir of dirs) {
|
|
@@ -192,50 +190,59 @@ async function commandExists(cmd) {
|
|
|
192
190
|
}
|
|
193
191
|
|
|
194
192
|
/**
|
|
195
|
-
*
|
|
196
|
-
* @returns {Promise<boolean>}
|
|
193
|
+
* Check if Docker is available
|
|
194
|
+
* @returns {Promise<boolean>}
|
|
197
195
|
*/
|
|
198
|
-
async function
|
|
199
|
-
|
|
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
|
-
}
|
|
196
|
+
async function checkDocker() {
|
|
197
|
+
return commandExists('docker');
|
|
218
198
|
}
|
|
219
199
|
|
|
220
200
|
/**
|
|
221
|
-
*
|
|
222
|
-
* @
|
|
201
|
+
* Setup ralph-template in project (copy bash scripts and prompts)
|
|
202
|
+
* @param {string} targetDir - User's project directory
|
|
203
|
+
* @returns {Promise<boolean>} - Whether setup succeeded
|
|
223
204
|
*/
|
|
224
|
-
async function
|
|
205
|
+
async function setupRalphTemplate(targetDir) {
|
|
225
206
|
try {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
if
|
|
229
|
-
|
|
230
|
-
|
|
207
|
+
const ralphDir = path.join(targetDir, 'ralph');
|
|
208
|
+
|
|
209
|
+
// Create ralph directory if not exists
|
|
210
|
+
await fs.mkdir(ralphDir, { recursive: true });
|
|
211
|
+
|
|
212
|
+
// The ralph files should already be copied from pro/ralph/ during install
|
|
213
|
+
// Just verify they exist
|
|
214
|
+
const requiredFiles = ['afk-ralph.sh', 'PROMPT.md', 'START_PROMPT.md'];
|
|
215
|
+
for (const file of requiredFiles) {
|
|
231
216
|
try {
|
|
232
|
-
await fs.access(
|
|
217
|
+
await fs.access(path.join(ralphDir, file));
|
|
233
218
|
} catch {
|
|
234
|
-
|
|
219
|
+
// File missing, copy from .claude/templates/ralph if available
|
|
220
|
+
const templatePath = path.join(targetDir, '.claude', 'templates', 'ralph', file);
|
|
221
|
+
try {
|
|
222
|
+
await fs.access(templatePath);
|
|
223
|
+
await fs.copyFile(templatePath, path.join(ralphDir, file));
|
|
224
|
+
} catch {
|
|
225
|
+
// Template not found either, this is OK - files will be added later
|
|
226
|
+
}
|
|
235
227
|
}
|
|
236
228
|
}
|
|
237
|
-
|
|
238
|
-
|
|
229
|
+
|
|
230
|
+
// Make afk-ralph.sh executable
|
|
231
|
+
const scriptPath = path.join(ralphDir, 'afk-ralph.sh');
|
|
232
|
+
try {
|
|
233
|
+
await fs.chmod(scriptPath, 0o755);
|
|
234
|
+
} catch {
|
|
235
|
+
// Ignore chmod errors on Windows
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Create progress.txt if not exists
|
|
239
|
+
const progressPath = path.join(ralphDir, 'progress.txt');
|
|
240
|
+
try {
|
|
241
|
+
await fs.access(progressPath);
|
|
242
|
+
} catch {
|
|
243
|
+
await fs.writeFile(progressPath, '# Progress Log\n\nAutomatically updated by Ralph loop.\n');
|
|
244
|
+
}
|
|
245
|
+
|
|
239
246
|
return true;
|
|
240
247
|
} catch {
|
|
241
248
|
return false;
|
|
@@ -243,11 +250,18 @@ async function installRalphTui() {
|
|
|
243
250
|
}
|
|
244
251
|
|
|
245
252
|
/**
|
|
246
|
-
* Check if ralph-
|
|
253
|
+
* Check if ralph-template is set up
|
|
254
|
+
* @param {string} targetDir - User's project directory
|
|
247
255
|
* @returns {Promise<boolean>}
|
|
248
256
|
*/
|
|
249
|
-
async function
|
|
250
|
-
|
|
257
|
+
async function checkRalphTemplate(targetDir) {
|
|
258
|
+
try {
|
|
259
|
+
const scriptPath = path.join(targetDir, 'ralph', 'afk-ralph.sh');
|
|
260
|
+
await fs.access(scriptPath);
|
|
261
|
+
return true;
|
|
262
|
+
} catch {
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
251
265
|
}
|
|
252
266
|
|
|
253
267
|
/**
|
|
@@ -272,32 +286,6 @@ async function checkAgentBrowser() {
|
|
|
272
286
|
return commandExists('agent-browser');
|
|
273
287
|
}
|
|
274
288
|
|
|
275
|
-
/**
|
|
276
|
-
* Setup ralph-tui configuration in project
|
|
277
|
-
* @param {string} targetDir - User's project directory
|
|
278
|
-
*/
|
|
279
|
-
async function setupRalphTuiConfig(targetDir) {
|
|
280
|
-
const ralphTuiDir = path.join(targetDir, '.ralph-tui');
|
|
281
|
-
const configSource = path.join(targetDir, 'ai_context', 'ralph-tui', 'config.toml');
|
|
282
|
-
const configDest = path.join(ralphTuiDir, 'config.toml');
|
|
283
|
-
|
|
284
|
-
// Create .ralph-tui directory
|
|
285
|
-
await fs.mkdir(ralphTuiDir, { recursive: true });
|
|
286
|
-
|
|
287
|
-
// Copy config if source exists and dest doesn't
|
|
288
|
-
try {
|
|
289
|
-
await fs.access(configSource);
|
|
290
|
-
try {
|
|
291
|
-
await fs.access(configDest);
|
|
292
|
-
// Config exists, don't overwrite
|
|
293
|
-
} catch {
|
|
294
|
-
await fs.copyFile(configSource, configDest);
|
|
295
|
-
}
|
|
296
|
-
} catch {
|
|
297
|
-
// Source doesn't exist, skip
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
|
|
301
289
|
module.exports = {
|
|
302
290
|
cloneProRepo,
|
|
303
291
|
copyProContent,
|
|
@@ -305,10 +293,9 @@ module.exports = {
|
|
|
305
293
|
cleanup,
|
|
306
294
|
checkExisting,
|
|
307
295
|
commandExists,
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
setupRalphTuiConfig,
|
|
296
|
+
checkDocker,
|
|
297
|
+
setupRalphTemplate,
|
|
298
|
+
checkRalphTemplate,
|
|
312
299
|
installAgentBrowser,
|
|
313
300
|
checkAgentBrowser
|
|
314
301
|
};
|