ai-sprint-kit 2.0.4 → 2.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.
@@ -0,0 +1,264 @@
1
+ const fs = require('fs/promises');
2
+ const path = require('path');
3
+ const chalk = require('chalk');
4
+
5
+ /**
6
+ * Validation results
7
+ */
8
+ class ValidationResult {
9
+ constructor() {
10
+ this.passed = [];
11
+ this.failed = [];
12
+ this.warnings = [];
13
+ }
14
+
15
+ addPass(check) {
16
+ this.passed.push(check);
17
+ }
18
+
19
+ addFail(check, suggestion) {
20
+ this.failed.push({ check, suggestion });
21
+ }
22
+
23
+ addWarning(check, message) {
24
+ this.warnings.push({ check, message });
25
+ }
26
+
27
+ isValid() {
28
+ return this.failed.length === 0;
29
+ }
30
+
31
+ summary() {
32
+ const { passed, failed, warnings } = this;
33
+ return {
34
+ total: passed.length + failed.length + warnings.length,
35
+ passed: passed.length,
36
+ failed: failed.length,
37
+ warnings: warnings.length
38
+ };
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Validate AI Sprint Kit installation
44
+ * @param {string} targetDir - Directory to validate
45
+ * @returns {Promise<ValidationResult>}
46
+ */
47
+ async function validateInstallation(targetDir = process.cwd()) {
48
+ const result = new ValidationResult();
49
+
50
+ // 1. Check .claude directory structure
51
+ await validateDirectoryStructure(targetDir, result);
52
+
53
+ // 2. Check required files
54
+ await validateRequiredFiles(targetDir, result);
55
+
56
+ // 3. Check configuration files
57
+ await validateConfiguration(targetDir, result);
58
+
59
+ // 4. Check agents
60
+ await validateAgents(targetDir, result);
61
+
62
+ // 5. Check commands
63
+ await validateCommands(targetDir, result);
64
+
65
+ // 6. Check hooks
66
+ await validateHooks(targetDir, result);
67
+
68
+ return result;
69
+ }
70
+
71
+ /**
72
+ * Validate directory structure
73
+ */
74
+ async function validateDirectoryStructure(targetDir, result) {
75
+ const requiredDirs = [
76
+ '.claude',
77
+ '.claude/agents',
78
+ '.claude/commands',
79
+ '.claude/workflows',
80
+ 'ai_context',
81
+ 'ai_context/plans',
82
+ 'ai_context/reports',
83
+ 'ai_context/memory'
84
+ ];
85
+
86
+ for (const dir of requiredDirs) {
87
+ const dirPath = path.join(targetDir, dir);
88
+ try {
89
+ const stat = await fs.stat(dirPath);
90
+ if (stat.isDirectory()) {
91
+ result.addPass(`Directory exists: ${dir}/`);
92
+ } else {
93
+ result.addFail(`Directory exists but is not a directory: ${dir}/`, `Remove file and reinstall`);
94
+ }
95
+ } catch {
96
+ result.addFail(`Directory missing: ${dir}/`, `Run: ai-sprint repair`);
97
+ }
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Validate required files
103
+ */
104
+ async function validateRequiredFiles(targetDir, result) {
105
+ const requiredFiles = [
106
+ 'CLAUDE.md',
107
+ '.claude/settings.json',
108
+ '.claude/.env.example'
109
+ ];
110
+
111
+ for (const file of requiredFiles) {
112
+ const filePath = path.join(targetDir, file);
113
+ try {
114
+ await fs.access(filePath);
115
+ result.addPass(`File exists: ${file}`);
116
+ } catch {
117
+ result.addFail(`File missing: ${file}`, `Run: ai-sprint repair`);
118
+ }
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Validate configuration files
124
+ */
125
+ async function validateConfiguration(targetDir, result) {
126
+ // Check settings.json is valid JSON
127
+ const settingsPath = path.join(targetDir, '.claude/settings.json');
128
+ try {
129
+ const content = await fs.readFile(settingsPath, 'utf8');
130
+ JSON.parse(content);
131
+ result.addPass('settings.json is valid JSON');
132
+ } catch (error) {
133
+ if (error.code === 'ENOENT') {
134
+ result.addFail('settings.json missing', 'Run: ai-sprint repair');
135
+ } else {
136
+ result.addFail('settings.json is invalid JSON', 'Fix JSON syntax or run: ai-sprint repair');
137
+ }
138
+ }
139
+
140
+ // Check .env.example
141
+ const envExamplePath = path.join(targetDir, '.claude/.env.example');
142
+ try {
143
+ await fs.access(envExamplePath);
144
+ result.addPass('.env.example exists');
145
+ } catch {
146
+ result.addWarning('.env.example missing', 'Create .env.example with environment variable templates');
147
+ }
148
+
149
+ // Check .mcp.json.example
150
+ const mcpExamplePath = path.join(targetDir, '.mcp.json.example');
151
+ try {
152
+ await fs.access(mcpExamplePath);
153
+ result.addPass('.mcp.json.example exists');
154
+ } catch {
155
+ result.addWarning('.mcp.json.example missing', 'Create .mcp.json.example with MCP configuration template');
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Validate agents
161
+ */
162
+ async function validateAgents(targetDir, result) {
163
+ const agentsDir = path.join(targetDir, '.claude/agents');
164
+ try {
165
+ const files = await fs.readdir(agentsDir);
166
+ const mdFiles = files.filter(f => f.endsWith('.md'));
167
+
168
+ if (mdFiles.length >= 9) {
169
+ result.addPass(`Agents: ${mdFiles.length} agent files found`);
170
+ } else {
171
+ result.addWarning(`Agents: Only ${mdFiles.length} agent files (expected 9+)`, 'Consider adding missing agents');
172
+ }
173
+ } catch {
174
+ result.addFail('Agents directory missing', 'Run: ai-sprint repair');
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Validate commands
180
+ */
181
+ async function validateCommands(targetDir, result) {
182
+ const commandsDir = path.join(targetDir, '.claude/commands');
183
+ try {
184
+ const files = await fs.readdir(commandsDir);
185
+ const mdFiles = files.filter(f => f.endsWith('.md'));
186
+
187
+ if (mdFiles.length >= 13) {
188
+ result.addPass(`Commands: ${mdFiles.length} command files found`);
189
+ } else {
190
+ result.addWarning(`Commands: Only ${mdFiles.length} command files (expected 13+)`, 'Consider adding missing commands');
191
+ }
192
+ } catch {
193
+ result.addFail('Commands directory missing', 'Run: ai-sprint repair');
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Validate hooks
199
+ */
200
+ async function validateHooks(targetDir, result) {
201
+ const hooksDir = path.join(targetDir, '.claude/hooks');
202
+ try {
203
+ const stat = await fs.stat(hooksDir);
204
+ if (stat.isDirectory()) {
205
+ const files = await fs.readdir(hooksDir);
206
+ if (files.length > 0) {
207
+ result.addPass(`Hooks: ${files.length} hook files found`);
208
+ } else {
209
+ result.addWarning('Hooks directory exists but is empty', 'Add PostToolUse, Stop hooks for automation');
210
+ }
211
+ }
212
+ } catch {
213
+ result.addWarning('Hooks directory missing', 'Add hooks for automated formatting and verification');
214
+ }
215
+ }
216
+
217
+ /**
218
+ * Format validation results for display
219
+ */
220
+ function formatResults(result) {
221
+ const lines = [];
222
+ const summary = result.summary();
223
+
224
+ lines.push(chalk.bold('\nšŸ“‹ AI Sprint Kit Validation\n'));
225
+
226
+ if (result.passed.length > 0) {
227
+ lines.push(chalk.green.bold('\nāœ… Passed:'));
228
+ result.passed.forEach(check => {
229
+ lines.push(chalk.green(` āœ“ ${check}`));
230
+ });
231
+ }
232
+
233
+ if (result.warnings.length > 0) {
234
+ lines.push(chalk.yellow.bold('\nāš ļø Warnings:'));
235
+ result.warnings.forEach(({ check, message }) => {
236
+ lines.push(chalk.yellow(` ! ${check}`));
237
+ lines.push(chalk.gray(` → ${message}`));
238
+ });
239
+ }
240
+
241
+ if (result.failed.length > 0) {
242
+ lines.push(chalk.red.bold('\nāŒ Failed:'));
243
+ result.failed.forEach(({ check, suggestion }) => {
244
+ lines.push(chalk.red(` āœ— ${check}`));
245
+ lines.push(chalk.gray(` → ${suggestion}`));
246
+ });
247
+ }
248
+
249
+ lines.push(chalk.bold(`\nšŸ“Š Summary: ${summary.passed} passed, ${summary.warnings} warnings, ${summary.failed} failed`));
250
+
251
+ if (result.isValid()) {
252
+ lines.push(chalk.green.bold('\nāœ… Installation is valid!\n'));
253
+ } else {
254
+ lines.push(chalk.red.bold('\nāŒ Installation has issues. Run: ai-sprint repair\n'));
255
+ }
256
+
257
+ return lines.join('\n');
258
+ }
259
+
260
+ module.exports = {
261
+ validateInstallation,
262
+ ValidationResult,
263
+ formatResults
264
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-sprint-kit",
3
- "version": "2.0.4",
3
+ "version": "2.1.0",
4
4
  "description": "CLI installer for AI Sprint autonomous development framework - requires license",
5
5
  "main": "lib/installer.js",
6
6
  "bin": {
@@ -44,7 +44,8 @@
44
44
  "dependencies": {
45
45
  "commander": "^11.1.0",
46
46
  "chalk": "^4.1.2",
47
- "ora": "^5.4.1"
47
+ "ora": "^5.4.1",
48
+ "semver": "^7.6.0"
48
49
  },
49
50
  "publishConfig": {
50
51
  "access": "public"