ai-sprint-kit 1.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.
Files changed (59) hide show
  1. package/README.md +299 -0
  2. package/bin/cli.js +135 -0
  3. package/lib/installer.js +205 -0
  4. package/lib/scanner.js +341 -0
  5. package/package.json +55 -0
  6. package/templates/.claude/.env.example +13 -0
  7. package/templates/.claude/agents/debugger.md +667 -0
  8. package/templates/.claude/agents/devops.md +727 -0
  9. package/templates/.claude/agents/docs.md +661 -0
  10. package/templates/.claude/agents/implementer.md +235 -0
  11. package/templates/.claude/agents/planner.md +243 -0
  12. package/templates/.claude/agents/researcher.md +448 -0
  13. package/templates/.claude/agents/reviewer.md +610 -0
  14. package/templates/.claude/agents/security.md +202 -0
  15. package/templates/.claude/agents/tester.md +604 -0
  16. package/templates/.claude/commands/auto.md +85 -0
  17. package/templates/.claude/commands/code.md +301 -0
  18. package/templates/.claude/commands/debug.md +449 -0
  19. package/templates/.claude/commands/deploy.md +475 -0
  20. package/templates/.claude/commands/docs.md +519 -0
  21. package/templates/.claude/commands/plan.md +57 -0
  22. package/templates/.claude/commands/review.md +412 -0
  23. package/templates/.claude/commands/scan.md +146 -0
  24. package/templates/.claude/commands/secure.md +88 -0
  25. package/templates/.claude/commands/test.md +352 -0
  26. package/templates/.claude/commands/validate.md +238 -0
  27. package/templates/.claude/settings.json +27 -0
  28. package/templates/.claude/skills/codebase-context/SKILL.md +68 -0
  29. package/templates/.claude/skills/codebase-context/references/reading-context.md +68 -0
  30. package/templates/.claude/skills/codebase-context/references/refresh-triggers.md +82 -0
  31. package/templates/.claude/skills/implementation/SKILL.md +70 -0
  32. package/templates/.claude/skills/implementation/references/error-handling.md +106 -0
  33. package/templates/.claude/skills/implementation/references/security-patterns.md +73 -0
  34. package/templates/.claude/skills/implementation/references/validation-patterns.md +107 -0
  35. package/templates/.claude/skills/memory/SKILL.md +67 -0
  36. package/templates/.claude/skills/memory/references/decisions-format.md +68 -0
  37. package/templates/.claude/skills/memory/references/learning-format.md +74 -0
  38. package/templates/.claude/skills/planning/SKILL.md +72 -0
  39. package/templates/.claude/skills/planning/references/plan-templates.md +81 -0
  40. package/templates/.claude/skills/planning/references/research-phase.md +62 -0
  41. package/templates/.claude/skills/planning/references/solution-design.md +66 -0
  42. package/templates/.claude/skills/quality-assurance/SKILL.md +79 -0
  43. package/templates/.claude/skills/quality-assurance/references/review-checklist.md +72 -0
  44. package/templates/.claude/skills/quality-assurance/references/security-checklist.md +70 -0
  45. package/templates/.claude/skills/quality-assurance/references/testing-strategy.md +85 -0
  46. package/templates/.claude/statusline.sh +126 -0
  47. package/templates/.claude/workflows/development-rules.md +97 -0
  48. package/templates/.claude/workflows/orchestration-protocol.md +194 -0
  49. package/templates/.mcp.json.example +36 -0
  50. package/templates/CLAUDE.md +409 -0
  51. package/templates/README.md +331 -0
  52. package/templates/ai_context/codebase/.gitkeep +0 -0
  53. package/templates/ai_context/memory/active.md +15 -0
  54. package/templates/ai_context/memory/decisions.md +18 -0
  55. package/templates/ai_context/memory/learning.md +22 -0
  56. package/templates/ai_context/plans/.gitkeep +0 -0
  57. package/templates/ai_context/reports/.gitkeep +0 -0
  58. package/templates/docs/user-guide-th.md +454 -0
  59. package/templates/docs/user-guide.md +595 -0
package/lib/scanner.js ADDED
@@ -0,0 +1,341 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const ora = require('ora');
4
+ const chalk = require('chalk');
5
+ const execa = require('execa');
6
+
7
+ // Common source code directories to detect
8
+ const SOURCE_DIRS = ['src', 'app', 'lib', 'pages', 'components', 'packages', 'modules'];
9
+ const SOURCE_EXTENSIONS = ['.js', '.ts', '.jsx', '.tsx', '.py', '.go', '.rs', '.java', '.rb', '.php'];
10
+
11
+ /**
12
+ * Check if target directory contains source code
13
+ * @param {string} targetDir - Directory to check
14
+ * @returns {Promise<boolean>} - True if source code detected
15
+ */
16
+ async function detectSourceCode(targetDir) {
17
+ // Check for common source directories
18
+ for (const dir of SOURCE_DIRS) {
19
+ const dirPath = path.join(targetDir, dir);
20
+ if (await fs.pathExists(dirPath)) {
21
+ const stats = await fs.stat(dirPath);
22
+ if (stats.isDirectory()) {
23
+ return true;
24
+ }
25
+ }
26
+ }
27
+
28
+ // Check for source files in root
29
+ try {
30
+ const files = await fs.readdir(targetDir);
31
+ for (const file of files) {
32
+ const ext = path.extname(file).toLowerCase();
33
+ if (SOURCE_EXTENSIONS.includes(ext)) {
34
+ return true;
35
+ }
36
+ }
37
+ } catch (error) {
38
+ // Ignore read errors
39
+ }
40
+
41
+ return false;
42
+ }
43
+
44
+ /**
45
+ * Check if repomix is available
46
+ * @returns {Promise<{available: boolean, command: string}>}
47
+ */
48
+ async function checkRepomix() {
49
+ // Check global installation
50
+ try {
51
+ await execa('repomix', ['--version']);
52
+ return { available: true, command: 'repomix' };
53
+ } catch (error) {
54
+ // Not globally installed, will use npx
55
+ }
56
+
57
+ // Check if npx is available
58
+ try {
59
+ await execa('npx', ['--version']);
60
+ return { available: true, command: 'npx repomix' };
61
+ } catch (error) {
62
+ return { available: false, command: null };
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Run repomix scan on target directory
68
+ * @param {string} targetDir - Directory to scan
69
+ * @param {string} outputDir - Output directory for scan results
70
+ * @param {object} options - Scan options
71
+ * @returns {Promise<object>} - Scan results
72
+ */
73
+ async function runRepomixScan(targetDir, outputDir, options = {}) {
74
+ const { useNpx = false } = options;
75
+
76
+ // Create output directory
77
+ await fs.ensureDir(outputDir);
78
+
79
+ const xmlOutput = path.join(outputDir, 'repomix-output.xml');
80
+ const mdOutput = path.join(outputDir, 'overview.md');
81
+
82
+ // Build base command
83
+ const baseCmd = useNpx ? 'npx' : 'repomix';
84
+ const baseArgs = useNpx ? ['repomix'] : [];
85
+
86
+ // Generate XML output (for AI consumption)
87
+ const xmlArgs = [
88
+ ...baseArgs,
89
+ '--compress',
90
+ '--style', 'xml',
91
+ '-o', xmlOutput
92
+ ];
93
+
94
+ await execa(baseCmd, xmlArgs, {
95
+ cwd: targetDir,
96
+ timeout: 300000 // 5 minute timeout
97
+ });
98
+
99
+ // Generate Markdown output (for human reading)
100
+ const mdArgs = [
101
+ ...baseArgs,
102
+ '--compress',
103
+ '--style', 'markdown',
104
+ '-o', mdOutput
105
+ ];
106
+
107
+ await execa(baseCmd, mdArgs, {
108
+ cwd: targetDir,
109
+ timeout: 300000
110
+ });
111
+
112
+ // Parse XML to get stats
113
+ let stats = {
114
+ totalFiles: 0,
115
+ totalTokens: 0,
116
+ compressedTokens: 0
117
+ };
118
+
119
+ try {
120
+ const xmlContent = await fs.readFile(xmlOutput, 'utf-8');
121
+ // Count file entries in XML
122
+ const fileMatches = xmlContent.match(/<file path="/g);
123
+ if (fileMatches) {
124
+ stats.totalFiles = fileMatches.length;
125
+ }
126
+ } catch (error) {
127
+ // Stats extraction failed, continue with defaults
128
+ }
129
+
130
+ return stats;
131
+ }
132
+
133
+ /**
134
+ * Generate directory structure file
135
+ * @param {string} targetDir - Directory to scan
136
+ * @param {string} outputDir - Output directory
137
+ */
138
+ async function generateStructure(targetDir, outputDir) {
139
+ const structureFile = path.join(outputDir, 'structure.md');
140
+ let content = '# Project Structure\n\n```\n';
141
+
142
+ try {
143
+ // Try using tree command
144
+ const { stdout } = await execa('tree', [
145
+ '-I', 'node_modules|.git|.venv|__pycache__|dist|build|.next|coverage',
146
+ '-L', '4',
147
+ '--noreport'
148
+ ], {
149
+ cwd: targetDir,
150
+ timeout: 30000
151
+ });
152
+ content += stdout;
153
+ } catch (error) {
154
+ // Fallback: simple directory listing
155
+ content += await generateSimpleTree(targetDir, '', 0, 4);
156
+ }
157
+
158
+ content += '\n```\n';
159
+ await fs.writeFile(structureFile, content);
160
+ }
161
+
162
+ /**
163
+ * Simple tree generator fallback
164
+ */
165
+ async function generateSimpleTree(dir, prefix, depth, maxDepth) {
166
+ if (depth >= maxDepth) return '';
167
+
168
+ const ignoreDirs = ['node_modules', '.git', '.venv', '__pycache__', 'dist', 'build', '.next', 'coverage'];
169
+ let result = '';
170
+
171
+ try {
172
+ const entries = await fs.readdir(dir, { withFileTypes: true });
173
+ const filtered = entries.filter(e => !ignoreDirs.includes(e.name) && !e.name.startsWith('.'));
174
+
175
+ for (let i = 0; i < filtered.length; i++) {
176
+ const entry = filtered[i];
177
+ const isLast = i === filtered.length - 1;
178
+ const connector = isLast ? '└── ' : '├── ';
179
+ const newPrefix = prefix + (isLast ? ' ' : '│ ');
180
+
181
+ result += prefix + connector + entry.name + '\n';
182
+
183
+ if (entry.isDirectory()) {
184
+ result += await generateSimpleTree(
185
+ path.join(dir, entry.name),
186
+ newPrefix,
187
+ depth + 1,
188
+ maxDepth
189
+ );
190
+ }
191
+ }
192
+ } catch (error) {
193
+ // Ignore errors
194
+ }
195
+
196
+ return result;
197
+ }
198
+
199
+ /**
200
+ * Create default .repomixignore file
201
+ * @param {string} outputDir - Output directory
202
+ */
203
+ async function createRepomixIgnore(outputDir) {
204
+ const ignorePath = path.join(outputDir, '.repomixignore');
205
+
206
+ if (await fs.pathExists(ignorePath)) {
207
+ return; // Don't overwrite existing
208
+ }
209
+
210
+ const content = `# AI Sprint default ignore patterns
211
+ node_modules/
212
+ .git/
213
+ dist/
214
+ build/
215
+ .next/
216
+ .venv/
217
+ __pycache__/
218
+ *.pyc
219
+ .env*
220
+ *.log
221
+ coverage/
222
+ .nyc_output/
223
+ *.min.js
224
+ *.min.css
225
+ package-lock.json
226
+ yarn.lock
227
+ pnpm-lock.yaml
228
+ `;
229
+
230
+ await fs.writeFile(ignorePath, content);
231
+ }
232
+
233
+ /**
234
+ * Write scan metadata
235
+ * @param {string} outputDir - Output directory
236
+ * @param {object} stats - Scan statistics
237
+ */
238
+ async function writeMetadata(outputDir, stats) {
239
+ const metadataPath = path.join(outputDir, 'scan-metadata.json');
240
+
241
+ const metadata = {
242
+ scanDate: new Date().toISOString(),
243
+ scanDuration: stats.duration || 0,
244
+ totalFiles: stats.totalFiles || 0,
245
+ totalTokens: stats.totalTokens || 0,
246
+ compressedTokens: stats.compressedTokens || 0,
247
+ compressionRatio: stats.totalTokens > 0
248
+ ? Math.round((1 - stats.compressedTokens / stats.totalTokens) * 100) / 100
249
+ : 0,
250
+ securityIssues: stats.securityIssues || 0
251
+ };
252
+
253
+ await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
254
+ return metadata;
255
+ }
256
+
257
+ /**
258
+ * Main entry point for codebase scanning
259
+ * @param {string} targetDir - Directory to scan
260
+ * @param {object} options - Scan options
261
+ * @returns {Promise<object>} - Scan results
262
+ */
263
+ async function scanCodebase(targetDir, options = {}) {
264
+ const { silent = false } = options;
265
+ const outputDir = path.join(targetDir, 'ai_context', 'codebase');
266
+ const startTime = Date.now();
267
+
268
+ // Check for source code
269
+ const hasSource = await detectSourceCode(targetDir);
270
+ if (!hasSource) {
271
+ if (!silent) {
272
+ console.log(chalk.gray(' No source code detected. Skipping scan.'));
273
+ }
274
+ return { skipped: true, reason: 'no-source' };
275
+ }
276
+
277
+ // Check repomix availability
278
+ const { available, command } = await checkRepomix();
279
+ if (!available) {
280
+ if (!silent) {
281
+ console.log(chalk.yellow(' ⚠️ Repomix not available. Skipping scan.'));
282
+ console.log(chalk.gray(' Install with: npm install -g repomix'));
283
+ }
284
+ return { skipped: true, reason: 'no-repomix' };
285
+ }
286
+
287
+ const spinner = silent ? null : ora('Scanning codebase...').start();
288
+
289
+ try {
290
+ // Create output directory
291
+ await fs.ensureDir(outputDir);
292
+
293
+ // Create default ignore file
294
+ await createRepomixIgnore(outputDir);
295
+
296
+ // Run repomix scan
297
+ const useNpx = command.includes('npx');
298
+ const stats = await runRepomixScan(targetDir, outputDir, { useNpx });
299
+
300
+ // Generate structure
301
+ if (spinner) spinner.text = 'Generating structure...';
302
+ await generateStructure(targetDir, outputDir);
303
+
304
+ // Calculate duration
305
+ stats.duration = Math.round((Date.now() - startTime) / 1000 * 10) / 10;
306
+
307
+ // Write metadata
308
+ const metadata = await writeMetadata(outputDir, stats);
309
+
310
+ if (spinner) {
311
+ spinner.succeed(`Codebase scanned (${stats.totalFiles} files, ${stats.duration}s)`);
312
+ }
313
+
314
+ return {
315
+ success: true,
316
+ outputDir,
317
+ stats: metadata
318
+ };
319
+
320
+ } catch (error) {
321
+ if (spinner) {
322
+ spinner.fail('Codebase scan failed');
323
+ }
324
+
325
+ if (!silent) {
326
+ console.log(chalk.yellow(` ⚠️ ${error.message}`));
327
+ console.log(chalk.gray(' Run /scan manually after fixing the issue.'));
328
+ }
329
+
330
+ return {
331
+ success: false,
332
+ error: error.message
333
+ };
334
+ }
335
+ }
336
+
337
+ module.exports = {
338
+ scanCodebase,
339
+ detectSourceCode,
340
+ checkRepomix
341
+ };
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "ai-sprint-kit",
3
+ "version": "1.1.0",
4
+ "description": "CLI installer for autonomous coding agent framework - security-first, production-grade Claude Code setup",
5
+ "main": "lib/installer.js",
6
+ "bin": {
7
+ "ai-sprint": "bin/cli.js"
8
+ },
9
+ "scripts": {
10
+ "test": "node bin/cli.js --help",
11
+ "link": "npm link",
12
+ "unlink": "npm unlink -g ai-sprint"
13
+ },
14
+ "keywords": [
15
+ "claude-code",
16
+ "autonomous-agents",
17
+ "ai-development",
18
+ "security",
19
+ "cli",
20
+ "devtools",
21
+ "code-generation",
22
+ "ai-sprint"
23
+ ],
24
+ "author": "Your Name",
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/yourusername/ai-sprint.git"
29
+ },
30
+ "bugs": {
31
+ "url": "https://github.com/yourusername/ai-sprint/issues"
32
+ },
33
+ "homepage": "https://github.com/yourusername/ai-sprint#readme",
34
+ "files": [
35
+ "bin/",
36
+ "lib/",
37
+ "templates/",
38
+ "README.md",
39
+ "LICENSE"
40
+ ],
41
+ "engines": {
42
+ "node": ">=18.0.0"
43
+ },
44
+ "dependencies": {
45
+ "commander": "^11.1.0",
46
+ "chalk": "^4.1.2",
47
+ "ora": "^5.4.1",
48
+ "inquirer": "^8.2.6",
49
+ "fs-extra": "^11.2.0",
50
+ "execa": "^5.1.1"
51
+ },
52
+ "publishConfig": {
53
+ "access": "public"
54
+ }
55
+ }
@@ -0,0 +1,13 @@
1
+ # AI Sprint Framework - Environment Variables
2
+
3
+ # Security Scanning (Optional)
4
+ # Get tokens from: https://snyk.io, https://semgrep.dev
5
+ SNYK_TOKEN=
6
+ SEMGREP_APP_TOKEN=
7
+
8
+ # Claude API (Optional - only if using custom models)
9
+ # Get from: https://console.anthropic.com
10
+ ANTHROPIC_API_KEY=
11
+
12
+ # Project Settings
13
+ NODE_ENV=development