aios-core 2.1.4 → 2.1.6
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/.aios-core/development/tasks/analyze-brownfield.md +456 -456
- package/.aios-core/development/tasks/setup-project-docs.md +440 -444
- package/.aios-core/infrastructure/scripts/documentation-integrity/brownfield-analyzer.js +501 -501
- package/.aios-core/infrastructure/scripts/documentation-integrity/config-generator.js +368 -329
- package/.aios-core/infrastructure/scripts/documentation-integrity/deployment-config-loader.js +308 -282
- package/.aios-core/infrastructure/scripts/documentation-integrity/doc-generator.js +331 -331
- package/.aios-core/infrastructure/scripts/documentation-integrity/gitignore-generator.js +312 -312
- package/.aios-core/infrastructure/scripts/documentation-integrity/index.js +74 -74
- package/.aios-core/infrastructure/scripts/documentation-integrity/mode-detector.js +389 -358
- package/.aios-core/infrastructure/scripts/llm-routing/install-llm-routing.js +6 -6
- package/.aios-core/infrastructure/templates/core-config/core-config-brownfield.tmpl.yaml +176 -182
- package/.aios-core/infrastructure/templates/core-config/core-config-greenfield.tmpl.yaml +127 -127
- package/.aios-core/infrastructure/templates/project-docs/coding-standards-tmpl.md +346 -346
- package/.aios-core/infrastructure/templates/project-docs/source-tree-tmpl.md +177 -177
- package/.aios-core/infrastructure/templates/project-docs/tech-stack-tmpl.md +267 -267
- package/package.json +1 -1
- package/packages/installer/src/config/templates/env-template.js +2 -2
- package/packages/installer/src/wizard/wizard.js +1 -1
- package/packages/installer/tests/integration/environment-configuration.test.js +2 -1
- package/packages/installer/tests/unit/env-template.test.js +3 -2
- package/src/wizard/index.js +2 -2
- package/.aios-core/development/tasks/validate-structure.md +0 -243
- package/.aios-core/infrastructure/scripts/source-tree-guardian/index.js +0 -375
- package/.aios-core/infrastructure/scripts/source-tree-guardian/manifest-generator.js +0 -410
- package/.aios-core/infrastructure/scripts/source-tree-guardian/rules/naming-rules.yaml +0 -285
- package/.aios-core/infrastructure/scripts/source-tree-guardian/rules/placement-rules.yaml +0 -262
- package/.aios-core/infrastructure/scripts/source-tree-guardian/validator.js +0 -468
|
@@ -1,410 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Source-Tree Guardian - Manifest Generator
|
|
3
|
-
*
|
|
4
|
-
* Generates a JSON manifest of the current codebase structure
|
|
5
|
-
* and compares it against the official source-tree.md.
|
|
6
|
-
*
|
|
7
|
-
* @module source-tree-guardian/manifest-generator
|
|
8
|
-
* @version 1.0.0
|
|
9
|
-
* @story 6.8
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
const fs = require('fs').promises;
|
|
13
|
-
const path = require('path');
|
|
14
|
-
const { glob } = require('glob');
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Default exclusion patterns for scanning
|
|
18
|
-
*/
|
|
19
|
-
const DEFAULT_EXCLUSIONS = [
|
|
20
|
-
'node_modules/**',
|
|
21
|
-
'.git/**',
|
|
22
|
-
'dist/**',
|
|
23
|
-
'build/**',
|
|
24
|
-
'coverage/**',
|
|
25
|
-
'.cache/**',
|
|
26
|
-
'*.log',
|
|
27
|
-
'*.tmp',
|
|
28
|
-
'.DS_Store',
|
|
29
|
-
'Thumbs.db',
|
|
30
|
-
'outputs/**',
|
|
31
|
-
'.ai/**',
|
|
32
|
-
];
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* File category definitions
|
|
36
|
-
*/
|
|
37
|
-
const FILE_CATEGORIES = {
|
|
38
|
-
agent: {
|
|
39
|
-
pattern: '.aios-core/development/agents/**/*.md',
|
|
40
|
-
description: 'Agent definitions',
|
|
41
|
-
},
|
|
42
|
-
task: {
|
|
43
|
-
pattern: '.aios-core/development/tasks/**/*.md',
|
|
44
|
-
description: 'Task workflows',
|
|
45
|
-
},
|
|
46
|
-
template: {
|
|
47
|
-
pattern: '.aios-core/product/templates/**/*',
|
|
48
|
-
description: 'Document templates',
|
|
49
|
-
},
|
|
50
|
-
checklist: {
|
|
51
|
-
pattern: '.aios-core/product/checklists/**/*.md',
|
|
52
|
-
description: 'Validation checklists',
|
|
53
|
-
},
|
|
54
|
-
script: {
|
|
55
|
-
pattern: '.aios-core/infrastructure/scripts/**/*.js',
|
|
56
|
-
description: 'Infrastructure scripts',
|
|
57
|
-
},
|
|
58
|
-
tool: {
|
|
59
|
-
pattern: '.aios-core/infrastructure/tools/**/*.yaml',
|
|
60
|
-
description: 'Tool integrations',
|
|
61
|
-
},
|
|
62
|
-
utility: {
|
|
63
|
-
pattern: '.aios-core/core/utils/**/*.js',
|
|
64
|
-
description: 'Utility functions',
|
|
65
|
-
},
|
|
66
|
-
story: {
|
|
67
|
-
pattern: 'docs/stories/**/*.md',
|
|
68
|
-
description: 'Development stories',
|
|
69
|
-
},
|
|
70
|
-
guide: {
|
|
71
|
-
pattern: 'docs/guides/**/*.md',
|
|
72
|
-
description: 'User guides',
|
|
73
|
-
},
|
|
74
|
-
architecture: {
|
|
75
|
-
pattern: 'docs/architecture/**/*.md',
|
|
76
|
-
description: 'Architecture documentation',
|
|
77
|
-
},
|
|
78
|
-
test: {
|
|
79
|
-
pattern: 'tests/**/*.test.js',
|
|
80
|
-
description: 'Test files',
|
|
81
|
-
},
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Generates a file structure tree
|
|
86
|
-
* @param {string} dir - Directory to scan
|
|
87
|
-
* @param {string} projectRoot - Project root for relative paths
|
|
88
|
-
* @param {number} depth - Current depth level
|
|
89
|
-
* @param {number} maxDepth - Maximum depth to scan
|
|
90
|
-
* @returns {Promise<Object>} Directory tree structure
|
|
91
|
-
*/
|
|
92
|
-
async function generateTree(dir, projectRoot, depth = 0, maxDepth = 10) {
|
|
93
|
-
if (depth > maxDepth) {
|
|
94
|
-
return { truncated: true };
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const result = {
|
|
98
|
-
name: path.basename(dir),
|
|
99
|
-
type: 'directory',
|
|
100
|
-
path: path.relative(projectRoot, dir).replace(/\\/g, '/') || '.',
|
|
101
|
-
children: [],
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
try {
|
|
105
|
-
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
106
|
-
|
|
107
|
-
for (const entry of entries) {
|
|
108
|
-
// Skip excluded directories
|
|
109
|
-
if (DEFAULT_EXCLUSIONS.some((ex) => entry.name === ex.split('/')[0])) {
|
|
110
|
-
continue;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const entryPath = path.join(dir, entry.name);
|
|
114
|
-
|
|
115
|
-
if (entry.isDirectory()) {
|
|
116
|
-
const subtree = await generateTree(entryPath, projectRoot, depth + 1, maxDepth);
|
|
117
|
-
result.children.push(subtree);
|
|
118
|
-
} else if (entry.isFile()) {
|
|
119
|
-
result.children.push({
|
|
120
|
-
name: entry.name,
|
|
121
|
-
type: 'file',
|
|
122
|
-
path: path.relative(projectRoot, entryPath).replace(/\\/g, '/'),
|
|
123
|
-
extension: path.extname(entry.name),
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Sort: directories first, then files, alphabetically
|
|
129
|
-
result.children.sort((a, b) => {
|
|
130
|
-
if (a.type !== b.type) {
|
|
131
|
-
return a.type === 'directory' ? -1 : 1;
|
|
132
|
-
}
|
|
133
|
-
return a.name.localeCompare(b.name);
|
|
134
|
-
});
|
|
135
|
-
} catch (error) {
|
|
136
|
-
result.error = error.message;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return result;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Counts files by category
|
|
144
|
-
* @param {string} projectRoot - Project root directory
|
|
145
|
-
* @returns {Promise<Object>} File counts by category
|
|
146
|
-
*/
|
|
147
|
-
async function countFilesByCategory(projectRoot) {
|
|
148
|
-
const counts = {};
|
|
149
|
-
|
|
150
|
-
for (const [category, config] of Object.entries(FILE_CATEGORIES)) {
|
|
151
|
-
try {
|
|
152
|
-
const files = await glob(config.pattern, {
|
|
153
|
-
cwd: projectRoot,
|
|
154
|
-
nodir: true,
|
|
155
|
-
});
|
|
156
|
-
counts[category] = {
|
|
157
|
-
count: files.length,
|
|
158
|
-
description: config.description,
|
|
159
|
-
files: files.slice(0, 10), // Sample of first 10 files
|
|
160
|
-
};
|
|
161
|
-
} catch (error) {
|
|
162
|
-
counts[category] = {
|
|
163
|
-
count: 0,
|
|
164
|
-
description: config.description,
|
|
165
|
-
error: error.message,
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return counts;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Gets file statistics
|
|
175
|
-
* @param {string} filePath - Path to the file
|
|
176
|
-
* @returns {Promise<Object>} File statistics
|
|
177
|
-
*/
|
|
178
|
-
async function getFileStats(filePath) {
|
|
179
|
-
try {
|
|
180
|
-
const stats = await fs.stat(filePath);
|
|
181
|
-
return {
|
|
182
|
-
size: stats.size,
|
|
183
|
-
created: stats.birthtime.toISOString(),
|
|
184
|
-
modified: stats.mtime.toISOString(),
|
|
185
|
-
};
|
|
186
|
-
} catch (error) {
|
|
187
|
-
return { error: error.message };
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Main ManifestGenerator class
|
|
193
|
-
*/
|
|
194
|
-
class ManifestGenerator {
|
|
195
|
-
/**
|
|
196
|
-
* Creates a new ManifestGenerator instance
|
|
197
|
-
* @param {Object} options - Generator options
|
|
198
|
-
* @param {string} options.projectRoot - Project root directory
|
|
199
|
-
* @param {string} options.outputPath - Path for manifest output
|
|
200
|
-
* @param {number} options.maxDepth - Maximum tree depth
|
|
201
|
-
*/
|
|
202
|
-
constructor(options = {}) {
|
|
203
|
-
this.projectRoot = options.projectRoot || process.cwd();
|
|
204
|
-
this.outputPath = options.outputPath || path.join(
|
|
205
|
-
this.projectRoot,
|
|
206
|
-
'docs',
|
|
207
|
-
'architecture',
|
|
208
|
-
'source-tree-manifest.json',
|
|
209
|
-
);
|
|
210
|
-
this.maxDepth = options.maxDepth || 10;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Generates the complete manifest
|
|
215
|
-
* @returns {Promise<Object>} Generated manifest
|
|
216
|
-
*/
|
|
217
|
-
async generate() {
|
|
218
|
-
const startTime = Date.now();
|
|
219
|
-
|
|
220
|
-
const manifest = {
|
|
221
|
-
version: '1.0.0',
|
|
222
|
-
generated: new Date().toISOString(),
|
|
223
|
-
generator: 'source-tree-guardian',
|
|
224
|
-
story: '6.8',
|
|
225
|
-
projectRoot: this.projectRoot,
|
|
226
|
-
summary: {
|
|
227
|
-
totalFiles: 0,
|
|
228
|
-
totalDirectories: 0,
|
|
229
|
-
categories: {},
|
|
230
|
-
},
|
|
231
|
-
tree: null,
|
|
232
|
-
categories: {},
|
|
233
|
-
duration: 0,
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
// Generate tree structure
|
|
237
|
-
manifest.tree = await generateTree(this.projectRoot, this.projectRoot, 0, this.maxDepth);
|
|
238
|
-
|
|
239
|
-
// Count total files and directories
|
|
240
|
-
const countItems = (node) => {
|
|
241
|
-
if (node.type === 'directory') {
|
|
242
|
-
manifest.summary.totalDirectories++;
|
|
243
|
-
if (node.children) {
|
|
244
|
-
node.children.forEach(countItems);
|
|
245
|
-
}
|
|
246
|
-
} else if (node.type === 'file') {
|
|
247
|
-
manifest.summary.totalFiles++;
|
|
248
|
-
}
|
|
249
|
-
};
|
|
250
|
-
countItems(manifest.tree);
|
|
251
|
-
|
|
252
|
-
// Count by category
|
|
253
|
-
manifest.categories = await countFilesByCategory(this.projectRoot);
|
|
254
|
-
manifest.summary.categories = Object.fromEntries(
|
|
255
|
-
Object.entries(manifest.categories).map(([k, v]) => [k, v.count]),
|
|
256
|
-
);
|
|
257
|
-
|
|
258
|
-
manifest.duration = Date.now() - startTime;
|
|
259
|
-
|
|
260
|
-
return manifest;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* Saves the manifest to a file
|
|
265
|
-
* @param {Object} manifest - The manifest to save
|
|
266
|
-
* @returns {Promise<string>} Path to saved manifest
|
|
267
|
-
*/
|
|
268
|
-
async save(manifest) {
|
|
269
|
-
const dir = path.dirname(this.outputPath);
|
|
270
|
-
await fs.mkdir(dir, { recursive: true });
|
|
271
|
-
await fs.writeFile(this.outputPath, JSON.stringify(manifest, null, 2));
|
|
272
|
-
return this.outputPath;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Loads an existing manifest
|
|
277
|
-
* @param {string} manifestPath - Path to the manifest file
|
|
278
|
-
* @returns {Promise<Object>} Loaded manifest
|
|
279
|
-
*/
|
|
280
|
-
async load(manifestPath) {
|
|
281
|
-
const content = await fs.readFile(manifestPath || this.outputPath, 'utf8');
|
|
282
|
-
return JSON.parse(content);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Compares two manifests and returns differences
|
|
287
|
-
* @param {Object} oldManifest - Previous manifest
|
|
288
|
-
* @param {Object} newManifest - Current manifest
|
|
289
|
-
* @returns {Object} Comparison results
|
|
290
|
-
*/
|
|
291
|
-
compare(oldManifest, newManifest) {
|
|
292
|
-
const diff = {
|
|
293
|
-
added: [],
|
|
294
|
-
removed: [],
|
|
295
|
-
modified: [],
|
|
296
|
-
summary: {
|
|
297
|
-
filesAdded: 0,
|
|
298
|
-
filesRemoved: 0,
|
|
299
|
-
categoriesChanged: {},
|
|
300
|
-
},
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
// Extract all file paths from tree
|
|
304
|
-
const extractPaths = (node, paths = new Set()) => {
|
|
305
|
-
if (node.type === 'file') {
|
|
306
|
-
paths.add(node.path);
|
|
307
|
-
} else if (node.children) {
|
|
308
|
-
node.children.forEach((child) => extractPaths(child, paths));
|
|
309
|
-
}
|
|
310
|
-
return paths;
|
|
311
|
-
};
|
|
312
|
-
|
|
313
|
-
const oldPaths = extractPaths(oldManifest.tree);
|
|
314
|
-
const newPaths = extractPaths(newManifest.tree);
|
|
315
|
-
|
|
316
|
-
// Find added files
|
|
317
|
-
for (const p of newPaths) {
|
|
318
|
-
if (!oldPaths.has(p)) {
|
|
319
|
-
diff.added.push(p);
|
|
320
|
-
diff.summary.filesAdded++;
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// Find removed files
|
|
325
|
-
for (const p of oldPaths) {
|
|
326
|
-
if (!newPaths.has(p)) {
|
|
327
|
-
diff.removed.push(p);
|
|
328
|
-
diff.summary.filesRemoved++;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// Compare categories
|
|
333
|
-
for (const [category, oldData] of Object.entries(oldManifest.categories)) {
|
|
334
|
-
const newData = newManifest.categories[category];
|
|
335
|
-
if (newData && newData.count !== oldData.count) {
|
|
336
|
-
diff.summary.categoriesChanged[category] = {
|
|
337
|
-
old: oldData.count,
|
|
338
|
-
new: newData.count,
|
|
339
|
-
delta: newData.count - oldData.count,
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
return diff;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Formats a diff report for console output
|
|
349
|
-
* @param {Object} diff - Comparison diff
|
|
350
|
-
* @returns {string} Formatted report
|
|
351
|
-
*/
|
|
352
|
-
formatDiffReport(diff) {
|
|
353
|
-
const lines = [];
|
|
354
|
-
|
|
355
|
-
lines.push('╔═══════════════════════════════════════════════════════════════════════╗');
|
|
356
|
-
lines.push('║ SOURCE-TREE MANIFEST COMPARISON ║');
|
|
357
|
-
lines.push('╠═══════════════════════════════════════════════════════════════════════╣');
|
|
358
|
-
lines.push(`║ Files Added: ${String(diff.summary.filesAdded).padEnd(58)}║`);
|
|
359
|
-
lines.push(`║ Files Removed: ${String(diff.summary.filesRemoved).padEnd(56)}║`);
|
|
360
|
-
lines.push('║ ║');
|
|
361
|
-
|
|
362
|
-
if (diff.added.length > 0) {
|
|
363
|
-
lines.push('╠═══════════════════════════════════════════════════════════════════════╣');
|
|
364
|
-
lines.push('║ ADDED FILES ║');
|
|
365
|
-
lines.push('╠═══════════════════════════════════════════════════════════════════════╣');
|
|
366
|
-
for (const file of diff.added.slice(0, 20)) {
|
|
367
|
-
lines.push(`║ + ${file.substring(0, 69).padEnd(69)}║`);
|
|
368
|
-
}
|
|
369
|
-
if (diff.added.length > 20) {
|
|
370
|
-
lines.push(`║ ... and ${diff.added.length - 20} more files ║`);
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
if (diff.removed.length > 0) {
|
|
375
|
-
lines.push('╠═══════════════════════════════════════════════════════════════════════╣');
|
|
376
|
-
lines.push('║ REMOVED FILES ║');
|
|
377
|
-
lines.push('╠═══════════════════════════════════════════════════════════════════════╣');
|
|
378
|
-
for (const file of diff.removed.slice(0, 20)) {
|
|
379
|
-
lines.push(`║ - ${file.substring(0, 69).padEnd(69)}║`);
|
|
380
|
-
}
|
|
381
|
-
if (diff.removed.length > 20) {
|
|
382
|
-
lines.push(`║ ... and ${diff.removed.length - 20} more files ║`);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
if (Object.keys(diff.summary.categoriesChanged).length > 0) {
|
|
387
|
-
lines.push('╠═══════════════════════════════════════════════════════════════════════╣');
|
|
388
|
-
lines.push('║ CATEGORY CHANGES ║');
|
|
389
|
-
lines.push('╠═══════════════════════════════════════════════════════════════════════╣');
|
|
390
|
-
for (const [category, change] of Object.entries(diff.summary.categoriesChanged)) {
|
|
391
|
-
const delta = change.delta > 0 ? `+${change.delta}` : String(change.delta);
|
|
392
|
-
lines.push(`║ ${category}: ${change.old} → ${change.new} (${delta})`.padEnd(72) + '║');
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
lines.push('╚═══════════════════════════════════════════════════════════════════════╝');
|
|
397
|
-
|
|
398
|
-
return lines.join('\n');
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
// Export for use as module
|
|
403
|
-
module.exports = {
|
|
404
|
-
ManifestGenerator,
|
|
405
|
-
generateTree,
|
|
406
|
-
countFilesByCategory,
|
|
407
|
-
getFileStats,
|
|
408
|
-
FILE_CATEGORIES,
|
|
409
|
-
DEFAULT_EXCLUSIONS,
|
|
410
|
-
};
|
|
@@ -1,285 +0,0 @@
|
|
|
1
|
-
# Naming Convention Rules for AIOS Source Tree
|
|
2
|
-
# Version: 1.0.0
|
|
3
|
-
# Last Updated: 2025-12-14
|
|
4
|
-
# Story: 6.8 - Source-Tree Guardian
|
|
5
|
-
|
|
6
|
-
version: "1.0"
|
|
7
|
-
last_updated: "2025-12-14"
|
|
8
|
-
|
|
9
|
-
# =============================================================================
|
|
10
|
-
# NAMING CONVENTIONS
|
|
11
|
-
# Defines how files and directories should be named
|
|
12
|
-
# =============================================================================
|
|
13
|
-
|
|
14
|
-
conventions:
|
|
15
|
-
# ---------------------------------------------------------------------------
|
|
16
|
-
# KEBAB-CASE (default for most files)
|
|
17
|
-
# ---------------------------------------------------------------------------
|
|
18
|
-
kebab-case:
|
|
19
|
-
pattern: "^[a-z][a-z0-9]*(-[a-z0-9]+)*$"
|
|
20
|
-
description: "Lowercase letters separated by hyphens"
|
|
21
|
-
examples:
|
|
22
|
-
valid:
|
|
23
|
-
- "agent-executor"
|
|
24
|
-
- "task-runner"
|
|
25
|
-
- "greeting-builder"
|
|
26
|
-
- "source-tree-guardian"
|
|
27
|
-
invalid:
|
|
28
|
-
- "AgentExecutor"
|
|
29
|
-
- "task_runner"
|
|
30
|
-
- "greetingBuilder"
|
|
31
|
-
- "SOURCE-TREE"
|
|
32
|
-
|
|
33
|
-
# ---------------------------------------------------------------------------
|
|
34
|
-
# CAMEL-CASE (for variables/functions in code)
|
|
35
|
-
# ---------------------------------------------------------------------------
|
|
36
|
-
camelCase:
|
|
37
|
-
pattern: "^[a-z][a-zA-Z0-9]*$"
|
|
38
|
-
description: "First letter lowercase, subsequent words capitalized"
|
|
39
|
-
examples:
|
|
40
|
-
valid:
|
|
41
|
-
- "agentExecutor"
|
|
42
|
-
- "taskRunner"
|
|
43
|
-
- "greetingBuilder"
|
|
44
|
-
invalid:
|
|
45
|
-
- "AgentExecutor"
|
|
46
|
-
- "agent-executor"
|
|
47
|
-
- "agent_executor"
|
|
48
|
-
|
|
49
|
-
# ---------------------------------------------------------------------------
|
|
50
|
-
# PASCAL-CASE (for classes)
|
|
51
|
-
# ---------------------------------------------------------------------------
|
|
52
|
-
PascalCase:
|
|
53
|
-
pattern: "^[A-Z][a-zA-Z0-9]*$"
|
|
54
|
-
description: "Each word starts with uppercase"
|
|
55
|
-
examples:
|
|
56
|
-
valid:
|
|
57
|
-
- "AgentExecutor"
|
|
58
|
-
- "TaskRunner"
|
|
59
|
-
- "GreetingBuilder"
|
|
60
|
-
invalid:
|
|
61
|
-
- "agentExecutor"
|
|
62
|
-
- "agent-executor"
|
|
63
|
-
- "AGENT_EXECUTOR"
|
|
64
|
-
|
|
65
|
-
# ---------------------------------------------------------------------------
|
|
66
|
-
# SCREAMING-SNAKE-CASE (for constants)
|
|
67
|
-
# ---------------------------------------------------------------------------
|
|
68
|
-
SCREAMING_SNAKE_CASE:
|
|
69
|
-
pattern: "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"
|
|
70
|
-
description: "Uppercase letters separated by underscores"
|
|
71
|
-
examples:
|
|
72
|
-
valid:
|
|
73
|
-
- "MAX_RETRIES"
|
|
74
|
-
- "DEFAULT_TIMEOUT"
|
|
75
|
-
- "API_BASE_URL"
|
|
76
|
-
invalid:
|
|
77
|
-
- "maxRetries"
|
|
78
|
-
- "default-timeout"
|
|
79
|
-
- "ApiBaseUrl"
|
|
80
|
-
|
|
81
|
-
# =============================================================================
|
|
82
|
-
# FILE TYPE RULES
|
|
83
|
-
# Maps file types to their required naming conventions
|
|
84
|
-
# =============================================================================
|
|
85
|
-
|
|
86
|
-
file_rules:
|
|
87
|
-
# JavaScript files
|
|
88
|
-
- extension: ".js"
|
|
89
|
-
convention: kebab-case
|
|
90
|
-
exceptions:
|
|
91
|
-
- pattern: "*.config.js"
|
|
92
|
-
allowed: true
|
|
93
|
-
- pattern: "*.test.js"
|
|
94
|
-
allowed: true
|
|
95
|
-
- pattern: "index.js"
|
|
96
|
-
allowed: true
|
|
97
|
-
|
|
98
|
-
# TypeScript files
|
|
99
|
-
- extension: ".ts"
|
|
100
|
-
convention: kebab-case
|
|
101
|
-
exceptions:
|
|
102
|
-
- pattern: "*.config.ts"
|
|
103
|
-
allowed: true
|
|
104
|
-
- pattern: "*.test.ts"
|
|
105
|
-
allowed: true
|
|
106
|
-
- pattern: "*.d.ts"
|
|
107
|
-
allowed: true
|
|
108
|
-
- pattern: "index.ts"
|
|
109
|
-
allowed: true
|
|
110
|
-
|
|
111
|
-
# Markdown files
|
|
112
|
-
- extension: ".md"
|
|
113
|
-
convention: kebab-case
|
|
114
|
-
exceptions:
|
|
115
|
-
- pattern: "README.md"
|
|
116
|
-
allowed: true
|
|
117
|
-
- pattern: "CHANGELOG.md"
|
|
118
|
-
allowed: true
|
|
119
|
-
- pattern: "CLAUDE.md"
|
|
120
|
-
allowed: true
|
|
121
|
-
- pattern: "LICENSE.md"
|
|
122
|
-
allowed: true
|
|
123
|
-
- pattern: "CONTRIBUTING.md"
|
|
124
|
-
allowed: true
|
|
125
|
-
- pattern: "STORY-BACKLOG.md"
|
|
126
|
-
allowed: true
|
|
127
|
-
|
|
128
|
-
# YAML files
|
|
129
|
-
- extension: ".yaml"
|
|
130
|
-
convention: kebab-case
|
|
131
|
-
exceptions:
|
|
132
|
-
- pattern: "*.config.yaml"
|
|
133
|
-
allowed: true
|
|
134
|
-
|
|
135
|
-
- extension: ".yml"
|
|
136
|
-
convention: kebab-case
|
|
137
|
-
|
|
138
|
-
# JSON files
|
|
139
|
-
- extension: ".json"
|
|
140
|
-
convention: kebab-case
|
|
141
|
-
exceptions:
|
|
142
|
-
- pattern: "package.json"
|
|
143
|
-
allowed: true
|
|
144
|
-
- pattern: "package-lock.json"
|
|
145
|
-
allowed: true
|
|
146
|
-
- pattern: "tsconfig.json"
|
|
147
|
-
allowed: true
|
|
148
|
-
- pattern: ".eslintrc.json"
|
|
149
|
-
allowed: true
|
|
150
|
-
|
|
151
|
-
# =============================================================================
|
|
152
|
-
# DIRECTORY RULES
|
|
153
|
-
# Naming conventions for directories
|
|
154
|
-
# =============================================================================
|
|
155
|
-
|
|
156
|
-
directory_rules:
|
|
157
|
-
- convention: kebab-case
|
|
158
|
-
exceptions:
|
|
159
|
-
- pattern: ".aios-core"
|
|
160
|
-
allowed: true
|
|
161
|
-
reason: "Framework standard directory"
|
|
162
|
-
- pattern: ".claude"
|
|
163
|
-
allowed: true
|
|
164
|
-
reason: "IDE configuration directory"
|
|
165
|
-
- pattern: ".cursor"
|
|
166
|
-
allowed: true
|
|
167
|
-
reason: "IDE configuration directory"
|
|
168
|
-
- pattern: ".vscode"
|
|
169
|
-
allowed: true
|
|
170
|
-
reason: "IDE configuration directory"
|
|
171
|
-
- pattern: ".husky"
|
|
172
|
-
allowed: true
|
|
173
|
-
reason: "Git hooks directory"
|
|
174
|
-
- pattern: ".git"
|
|
175
|
-
allowed: true
|
|
176
|
-
reason: "Git repository directory"
|
|
177
|
-
- pattern: ".ai"
|
|
178
|
-
allowed: true
|
|
179
|
-
reason: "AI artifacts directory"
|
|
180
|
-
- pattern: "node_modules"
|
|
181
|
-
allowed: true
|
|
182
|
-
reason: "npm packages directory"
|
|
183
|
-
|
|
184
|
-
# =============================================================================
|
|
185
|
-
# SPECIAL PATTERNS
|
|
186
|
-
# Files that follow specific naming patterns
|
|
187
|
-
# =============================================================================
|
|
188
|
-
|
|
189
|
-
special_patterns:
|
|
190
|
-
# Story files
|
|
191
|
-
- name: story
|
|
192
|
-
pattern: "^story-[0-9]+\\.[0-9]+(\\.[0-9]+)*(-[a-z-]+)?\\.md$"
|
|
193
|
-
description: "Story files follow story-{id}.md or story-{id}-{slug}.md pattern"
|
|
194
|
-
examples:
|
|
195
|
-
valid:
|
|
196
|
-
- "story-6.8.md"
|
|
197
|
-
- "story-6.8-source-tree-guardian.md"
|
|
198
|
-
- "story-6.1.2.5.md"
|
|
199
|
-
invalid:
|
|
200
|
-
- "Story-6.8.md"
|
|
201
|
-
- "story_6.8.md"
|
|
202
|
-
- "6.8-story.md"
|
|
203
|
-
|
|
204
|
-
# Epic files
|
|
205
|
-
- name: epic
|
|
206
|
-
pattern: "^epic-[0-9]+(\\.[0-9]+)*-[a-z-]+\\.md$"
|
|
207
|
-
description: "Epic files follow epic-{number}-{name}.md pattern"
|
|
208
|
-
examples:
|
|
209
|
-
valid:
|
|
210
|
-
- "epic-6.1-agent-identity-system.md"
|
|
211
|
-
- "epic-7-deployment-automation.md"
|
|
212
|
-
invalid:
|
|
213
|
-
- "Epic-6.1.md"
|
|
214
|
-
- "epic_6.1.md"
|
|
215
|
-
|
|
216
|
-
# Decision files (ADRs)
|
|
217
|
-
- name: decision
|
|
218
|
-
pattern: "^decision-[0-9]+-[a-z-]+(-FINAL)?\\.md$"
|
|
219
|
-
description: "Decision files follow decision-{number}-{name}.md pattern"
|
|
220
|
-
examples:
|
|
221
|
-
valid:
|
|
222
|
-
- "decision-005-repository-restructuring.md"
|
|
223
|
-
- "decision-005-repository-restructuring-FINAL.md"
|
|
224
|
-
invalid:
|
|
225
|
-
- "Decision-005.md"
|
|
226
|
-
- "decision_005.md"
|
|
227
|
-
|
|
228
|
-
# Template files
|
|
229
|
-
- name: template
|
|
230
|
-
pattern: "^[a-z-]+-tmpl\\.(yaml|md)$"
|
|
231
|
-
description: "Template files follow {name}-tmpl.{ext} pattern"
|
|
232
|
-
examples:
|
|
233
|
-
valid:
|
|
234
|
-
- "story-tmpl.yaml"
|
|
235
|
-
- "prd-tmpl.yaml"
|
|
236
|
-
- "epic-tmpl.md"
|
|
237
|
-
invalid:
|
|
238
|
-
- "story-template.yaml"
|
|
239
|
-
- "Story-tmpl.yaml"
|
|
240
|
-
|
|
241
|
-
# Checklist files
|
|
242
|
-
- name: checklist
|
|
243
|
-
pattern: "^[a-z-]+-checklist\\.md$"
|
|
244
|
-
description: "Checklist files follow {name}-checklist.md pattern"
|
|
245
|
-
examples:
|
|
246
|
-
valid:
|
|
247
|
-
- "po-master-checklist.md"
|
|
248
|
-
- "story-draft-checklist.md"
|
|
249
|
-
invalid:
|
|
250
|
-
- "po-master.checklist.md"
|
|
251
|
-
- "POChecklist.md"
|
|
252
|
-
|
|
253
|
-
# Test files
|
|
254
|
-
- name: test
|
|
255
|
-
pattern: "^[a-z-]+\\.test\\.(js|ts)$"
|
|
256
|
-
description: "Test files follow {name}.test.{ext} pattern"
|
|
257
|
-
examples:
|
|
258
|
-
valid:
|
|
259
|
-
- "validator.test.js"
|
|
260
|
-
- "manifest-generator.test.js"
|
|
261
|
-
invalid:
|
|
262
|
-
- "ValidatorTest.js"
|
|
263
|
-
- "validator_test.js"
|
|
264
|
-
|
|
265
|
-
# =============================================================================
|
|
266
|
-
# VALIDATION SETTINGS
|
|
267
|
-
# =============================================================================
|
|
268
|
-
|
|
269
|
-
validation:
|
|
270
|
-
strict_mode: false # If true, all files must match a rule
|
|
271
|
-
case_sensitive: true # Enforce exact case matching
|
|
272
|
-
allow_numbers: true # Allow numbers in names (after first character)
|
|
273
|
-
max_length: 100 # Maximum filename length (excluding extension)
|
|
274
|
-
min_length: 2 # Minimum filename length (excluding extension)
|
|
275
|
-
|
|
276
|
-
# =============================================================================
|
|
277
|
-
# SEVERITY LEVELS
|
|
278
|
-
# =============================================================================
|
|
279
|
-
|
|
280
|
-
severity:
|
|
281
|
-
wrong_convention: warning
|
|
282
|
-
invalid_characters: error
|
|
283
|
-
too_long: warning
|
|
284
|
-
too_short: error
|
|
285
|
-
special_pattern_mismatch: error
|