create-byan-agent 1.1.2 → 1.2.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.
- package/CHANGELOG.md +250 -177
- package/LICENSE +21 -21
- package/README.md +1245 -421
- package/bin/create-byan-agent-backup.js +220 -220
- package/bin/create-byan-agent-fixed.js +301 -301
- package/bin/create-byan-agent.js +322 -301
- package/lib/errors.js +61 -0
- package/lib/exit-codes.js +54 -0
- package/lib/platforms/claude-code.js +113 -0
- package/lib/platforms/codex.js +92 -0
- package/lib/platforms/copilot-cli.js +123 -0
- package/lib/platforms/index.js +14 -0
- package/lib/platforms/vscode.js +51 -0
- package/lib/utils/config-loader.js +79 -0
- package/lib/utils/file-utils.js +104 -0
- package/lib/utils/git-detector.js +35 -0
- package/lib/utils/logger.js +64 -0
- package/lib/utils/node-detector.js +58 -0
- package/lib/utils/os-detector.js +74 -0
- package/lib/utils/yaml-utils.js +87 -0
- package/lib/yanstaller/backuper.js +308 -0
- package/lib/yanstaller/detector.js +141 -0
- package/lib/yanstaller/index.js +93 -0
- package/lib/yanstaller/installer.js +225 -0
- package/lib/yanstaller/interviewer.js +250 -0
- package/lib/yanstaller/recommender.js +298 -0
- package/lib/yanstaller/troubleshooter.js +498 -0
- package/lib/yanstaller/validator.js +578 -0
- package/lib/yanstaller/wizard.js +211 -0
- package/package.json +61 -55
- package/templates/.github/agents/bmad-agent-bmad-master.md +15 -15
- package/templates/.github/agents/bmad-agent-bmb-agent-builder.md +15 -15
- package/templates/.github/agents/bmad-agent-bmb-module-builder.md +15 -15
- package/templates/.github/agents/bmad-agent-bmb-workflow-builder.md +15 -15
- package/templates/.github/agents/bmad-agent-bmm-analyst.md +15 -15
- package/templates/.github/agents/bmad-agent-bmm-architect.md +15 -15
- package/templates/.github/agents/bmad-agent-bmm-dev.md +15 -15
- package/templates/.github/agents/bmad-agent-bmm-pm.md +15 -15
- package/templates/.github/agents/bmad-agent-bmm-quick-flow-solo-dev.md +15 -15
- package/templates/.github/agents/bmad-agent-bmm-quinn.md +15 -15
- package/templates/.github/agents/bmad-agent-bmm-sm.md +15 -15
- package/templates/.github/agents/bmad-agent-bmm-tech-writer.md +15 -15
- package/templates/.github/agents/bmad-agent-bmm-ux-designer.md +15 -15
- package/templates/.github/agents/bmad-agent-byan-test.md +32 -0
- package/templates/.github/agents/bmad-agent-byan.md +224 -224
- package/templates/.github/agents/bmad-agent-carmack.md +18 -0
- package/templates/.github/agents/bmad-agent-cis-brainstorming-coach.md +15 -15
- package/templates/.github/agents/bmad-agent-cis-creative-problem-solver.md +15 -15
- package/templates/.github/agents/bmad-agent-cis-design-thinking-coach.md +15 -15
- package/templates/.github/agents/bmad-agent-cis-innovation-strategist.md +15 -15
- package/templates/.github/agents/bmad-agent-cis-presentation-master.md +15 -15
- package/templates/.github/agents/bmad-agent-cis-storyteller.md +15 -15
- package/templates/.github/agents/bmad-agent-marc.md +48 -48
- package/templates/.github/agents/bmad-agent-patnote.md +48 -0
- package/templates/.github/agents/bmad-agent-rachid.md +47 -47
- package/templates/.github/agents/bmad-agent-tea-tea.md +15 -15
- package/templates/.github/agents/bmad-agent-test-dynamic.md +21 -0
- package/templates/.github/agents/expert-merise-agile.md +1 -0
- package/templates/.github/agents/franck.md +379 -0
- package/templates/_bmad/bmb/agents/agent-builder.md +59 -59
- package/templates/_bmad/bmb/agents/byan-test.md +116 -116
- package/templates/_bmad/bmb/agents/byan.md +215 -215
- package/templates/_bmad/bmb/agents/marc.md +303 -303
- package/templates/_bmad/bmb/agents/module-builder.md +60 -60
- package/templates/_bmad/bmb/agents/patnote.md +495 -495
- package/templates/_bmad/bmb/agents/rachid.md +184 -184
- package/templates/_bmad/bmb/agents/workflow-builder.md +61 -61
- package/templates/_bmad/bmb/workflows/byan/data/mantras.yaml +272 -272
- package/templates/_bmad/bmb/workflows/byan/data/templates.yaml +59 -59
- package/templates/_bmad/bmb/workflows/byan/delete-agent-workflow.md +657 -657
- package/templates/_bmad/bmb/workflows/byan/edit-agent-workflow.md +688 -688
- package/templates/_bmad/bmb/workflows/byan/interview-workflow.md +753 -753
- package/templates/_bmad/bmb/workflows/byan/quick-create-workflow.md +450 -450
- package/templates/_bmad/bmb/workflows/byan/templates/base-agent-template.md +79 -79
- package/templates/_bmad/bmb/workflows/byan/validate-agent-workflow.md +676 -676
- package/templates/_bmad/core/agents/carmack.md +238 -238
|
@@ -0,0 +1,578 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VALIDATOR Module
|
|
3
|
+
*
|
|
4
|
+
* Validates BYAN installation with 10 automated checks.
|
|
5
|
+
*
|
|
6
|
+
* Phase 4: 32h development
|
|
7
|
+
*
|
|
8
|
+
* @module yanstaller/validator
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const fileUtils = require('../utils/file-utils');
|
|
13
|
+
const yamlUtils = require('../utils/yaml-utils');
|
|
14
|
+
const { execSync } = require('child_process');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {Object} ValidationResult
|
|
18
|
+
* @property {boolean} success - All checks passed
|
|
19
|
+
* @property {CheckResult[]} checks - Individual check results
|
|
20
|
+
* @property {string[]} errors - Critical errors
|
|
21
|
+
* @property {string[]} warnings - Non-critical issues
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @typedef {Object} CheckResult
|
|
26
|
+
* @property {string} id - Check identifier
|
|
27
|
+
* @property {string} name - Human-readable check name
|
|
28
|
+
* @property {boolean} passed
|
|
29
|
+
* @property {string} [message] - Error/warning message if failed
|
|
30
|
+
* @property {string} severity - 'critical' | 'warning'
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Validate BYAN installation
|
|
35
|
+
*
|
|
36
|
+
* @param {import('./installer').InstallConfig} config - Installation config
|
|
37
|
+
* @returns {Promise<ValidationResult>}
|
|
38
|
+
*/
|
|
39
|
+
async function validate(config) {
|
|
40
|
+
const checks = [];
|
|
41
|
+
const errors = [];
|
|
42
|
+
const warnings = [];
|
|
43
|
+
|
|
44
|
+
// Run all 10 checks in sequence
|
|
45
|
+
checks.push(await checkBmadStructure(config));
|
|
46
|
+
checks.push(await checkAgentFiles(config));
|
|
47
|
+
checks.push(await checkStubsYamlFrontmatter(config));
|
|
48
|
+
checks.push(await checkConfigFiles(config));
|
|
49
|
+
checks.push(await checkPlatformDetection(config));
|
|
50
|
+
checks.push(await checkFilePermissions(config));
|
|
51
|
+
checks.push(await checkManifests(config));
|
|
52
|
+
checks.push(await checkWorkflows(config));
|
|
53
|
+
checks.push(await checkTemplates(config));
|
|
54
|
+
checks.push(await checkDependencies(config));
|
|
55
|
+
|
|
56
|
+
// Collect errors and warnings
|
|
57
|
+
for (const check of checks) {
|
|
58
|
+
if (!check.passed) {
|
|
59
|
+
if (check.severity === 'critical') {
|
|
60
|
+
errors.push(`[${check.id}] ${check.message}`);
|
|
61
|
+
} else {
|
|
62
|
+
warnings.push(`[${check.id}] ${check.message}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const allPassed = checks.every(c => c.passed || c.severity === 'warning');
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
success: allPassed,
|
|
71
|
+
checks,
|
|
72
|
+
errors,
|
|
73
|
+
warnings
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Check 1: _bmad/ structure exists
|
|
79
|
+
*/
|
|
80
|
+
async function checkBmadStructure(config) {
|
|
81
|
+
const projectRoot = config.projectRoot || process.cwd();
|
|
82
|
+
const requiredDirs = [
|
|
83
|
+
'_bmad',
|
|
84
|
+
'_bmad/_config',
|
|
85
|
+
'_bmad/_memory',
|
|
86
|
+
'_bmad/_output',
|
|
87
|
+
'_bmad/core/agents',
|
|
88
|
+
'_bmad/bmm/agents',
|
|
89
|
+
'_bmad/bmb/agents',
|
|
90
|
+
'_bmad/tea/agents',
|
|
91
|
+
'_bmad/cis/agents'
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
const missingDirs = [];
|
|
95
|
+
for (const dir of requiredDirs) {
|
|
96
|
+
const dirPath = path.join(projectRoot, dir);
|
|
97
|
+
if (!await fileUtils.exists(dirPath)) {
|
|
98
|
+
missingDirs.push(dir);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (missingDirs.length > 0) {
|
|
103
|
+
return {
|
|
104
|
+
id: 'bmad-structure',
|
|
105
|
+
name: '_bmad/ structure',
|
|
106
|
+
passed: false,
|
|
107
|
+
message: `Missing directories: ${missingDirs.join(', ')}`,
|
|
108
|
+
severity: 'critical'
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
id: 'bmad-structure',
|
|
114
|
+
name: '_bmad/ structure',
|
|
115
|
+
passed: true,
|
|
116
|
+
severity: 'critical'
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Check 2: Agent files copied correctly
|
|
122
|
+
*/
|
|
123
|
+
async function checkAgentFiles(config) {
|
|
124
|
+
const projectRoot = config.projectRoot || process.cwd();
|
|
125
|
+
const agents = config.agents || [];
|
|
126
|
+
|
|
127
|
+
if (agents.length === 0) {
|
|
128
|
+
return {
|
|
129
|
+
id: 'agent-files',
|
|
130
|
+
name: 'Agent files',
|
|
131
|
+
passed: true,
|
|
132
|
+
message: 'No agents to check',
|
|
133
|
+
severity: 'critical'
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const modules = ['core', 'bmm', 'bmb', 'tea', 'cis'];
|
|
138
|
+
const missingAgents = [];
|
|
139
|
+
|
|
140
|
+
for (const agentName of agents) {
|
|
141
|
+
let found = false;
|
|
142
|
+
for (const module of modules) {
|
|
143
|
+
const agentPath = path.join(projectRoot, '_bmad', module, 'agents', `${agentName}.md`);
|
|
144
|
+
if (await fileUtils.exists(agentPath)) {
|
|
145
|
+
found = true;
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (!found) {
|
|
150
|
+
missingAgents.push(agentName);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (missingAgents.length > 0) {
|
|
155
|
+
return {
|
|
156
|
+
id: 'agent-files',
|
|
157
|
+
name: 'Agent files',
|
|
158
|
+
passed: false,
|
|
159
|
+
message: `Missing agents: ${missingAgents.join(', ')}`,
|
|
160
|
+
severity: 'critical'
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
id: 'agent-files',
|
|
166
|
+
name: 'Agent files',
|
|
167
|
+
passed: true,
|
|
168
|
+
severity: 'critical'
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Check 3: Platform stubs have valid YAML frontmatter
|
|
174
|
+
*/
|
|
175
|
+
async function checkStubsYamlFrontmatter(config) {
|
|
176
|
+
const projectRoot = config.projectRoot || process.cwd();
|
|
177
|
+
const targetPlatforms = config.targetPlatforms || [];
|
|
178
|
+
|
|
179
|
+
if (targetPlatforms.length === 0) {
|
|
180
|
+
return {
|
|
181
|
+
id: 'yaml-frontmatter',
|
|
182
|
+
name: 'YAML frontmatter',
|
|
183
|
+
passed: true,
|
|
184
|
+
message: 'No platforms to check',
|
|
185
|
+
severity: 'critical'
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const invalidStubs = [];
|
|
190
|
+
|
|
191
|
+
// Check Copilot CLI / VSCode stubs
|
|
192
|
+
if (targetPlatforms.includes('copilot-cli') || targetPlatforms.includes('vscode')) {
|
|
193
|
+
const stubsDir = path.join(projectRoot, '.github', 'agents');
|
|
194
|
+
if (await fileUtils.exists(stubsDir)) {
|
|
195
|
+
const files = await fileUtils.readDir(stubsDir);
|
|
196
|
+
for (const file of files) {
|
|
197
|
+
if (file.endsWith('.md')) {
|
|
198
|
+
const content = await fileUtils.readFile(path.join(stubsDir, file), 'utf8');
|
|
199
|
+
if (!content.startsWith('---')) {
|
|
200
|
+
invalidStubs.push(`.github/agents/${file}`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Check Codex stubs
|
|
208
|
+
if (targetPlatforms.includes('codex')) {
|
|
209
|
+
const stubsDir = path.join(projectRoot, '.codex', 'prompts');
|
|
210
|
+
if (await fileUtils.exists(stubsDir)) {
|
|
211
|
+
const files = await fileUtils.readDir(stubsDir);
|
|
212
|
+
for (const file of files) {
|
|
213
|
+
if (file.endsWith('.md')) {
|
|
214
|
+
const content = await fileUtils.readFile(path.join(stubsDir, file), 'utf8');
|
|
215
|
+
if (!content.includes('<agent-activation')) {
|
|
216
|
+
invalidStubs.push(`.codex/prompts/${file}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (invalidStubs.length > 0) {
|
|
224
|
+
return {
|
|
225
|
+
id: 'yaml-frontmatter',
|
|
226
|
+
name: 'YAML frontmatter',
|
|
227
|
+
passed: false,
|
|
228
|
+
message: `Invalid stubs: ${invalidStubs.join(', ')}`,
|
|
229
|
+
severity: 'critical'
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return {
|
|
234
|
+
id: 'yaml-frontmatter',
|
|
235
|
+
name: 'YAML frontmatter',
|
|
236
|
+
passed: true,
|
|
237
|
+
severity: 'critical'
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Check 4: Module config files valid
|
|
243
|
+
*/
|
|
244
|
+
async function checkConfigFiles(config) {
|
|
245
|
+
const projectRoot = config.projectRoot || process.cwd();
|
|
246
|
+
const modules = ['bmb']; // For now only bmb has config
|
|
247
|
+
|
|
248
|
+
const invalidConfigs = [];
|
|
249
|
+
|
|
250
|
+
for (const module of modules) {
|
|
251
|
+
const configPath = path.join(projectRoot, '_bmad', module, 'config.yaml');
|
|
252
|
+
if (await fileUtils.exists(configPath)) {
|
|
253
|
+
try {
|
|
254
|
+
const configContent = await fileUtils.readFile(configPath, 'utf8');
|
|
255
|
+
const parsedConfig = yamlUtils.load(configContent);
|
|
256
|
+
|
|
257
|
+
// Validate required fields
|
|
258
|
+
if (!parsedConfig.user_name) {
|
|
259
|
+
invalidConfigs.push(`${module}/config.yaml: missing user_name`);
|
|
260
|
+
}
|
|
261
|
+
if (!parsedConfig.communication_language) {
|
|
262
|
+
invalidConfigs.push(`${module}/config.yaml: missing communication_language`);
|
|
263
|
+
}
|
|
264
|
+
} catch (error) {
|
|
265
|
+
invalidConfigs.push(`${module}/config.yaml: parse error - ${error.message}`);
|
|
266
|
+
}
|
|
267
|
+
} else {
|
|
268
|
+
invalidConfigs.push(`${module}/config.yaml: file not found`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (invalidConfigs.length > 0) {
|
|
273
|
+
return {
|
|
274
|
+
id: 'config-files',
|
|
275
|
+
name: 'Config files',
|
|
276
|
+
passed: false,
|
|
277
|
+
message: invalidConfigs.join(', '),
|
|
278
|
+
severity: 'critical'
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return {
|
|
283
|
+
id: 'config-files',
|
|
284
|
+
name: 'Config files',
|
|
285
|
+
passed: true,
|
|
286
|
+
severity: 'critical'
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Check 5: Platform detection works
|
|
292
|
+
*/
|
|
293
|
+
async function checkPlatformDetection(config) {
|
|
294
|
+
const targetPlatforms = config.targetPlatforms || [];
|
|
295
|
+
|
|
296
|
+
if (targetPlatforms.length === 0) {
|
|
297
|
+
return {
|
|
298
|
+
id: 'platform-detection',
|
|
299
|
+
name: 'Platform detection',
|
|
300
|
+
passed: true,
|
|
301
|
+
message: 'No platforms configured',
|
|
302
|
+
severity: 'critical'
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const failedPlatforms = [];
|
|
307
|
+
|
|
308
|
+
for (const platformName of targetPlatforms) {
|
|
309
|
+
try {
|
|
310
|
+
const platform = require(`../platforms/${platformName}`);
|
|
311
|
+
const detected = await platform.detect();
|
|
312
|
+
|
|
313
|
+
// If detection failed or returned error object
|
|
314
|
+
if (!detected || (typeof detected === 'object' && !detected.detected)) {
|
|
315
|
+
failedPlatforms.push(platformName);
|
|
316
|
+
}
|
|
317
|
+
} catch (error) {
|
|
318
|
+
failedPlatforms.push(`${platformName} (${error.message})`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (failedPlatforms.length > 0) {
|
|
323
|
+
return {
|
|
324
|
+
id: 'platform-detection',
|
|
325
|
+
name: 'Platform detection',
|
|
326
|
+
passed: false,
|
|
327
|
+
message: `Failed platforms: ${failedPlatforms.join(', ')}`,
|
|
328
|
+
severity: 'warning' // Warning because platform may be installed but not detected
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return {
|
|
333
|
+
id: 'platform-detection',
|
|
334
|
+
name: 'Platform detection',
|
|
335
|
+
passed: true,
|
|
336
|
+
severity: 'critical'
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Check 6: File permissions correct
|
|
342
|
+
*/
|
|
343
|
+
async function checkFilePermissions(config) {
|
|
344
|
+
const projectRoot = config.projectRoot || process.cwd();
|
|
345
|
+
const testPaths = [
|
|
346
|
+
'_bmad',
|
|
347
|
+
'_bmad/_config',
|
|
348
|
+
'_bmad/bmb/config.yaml'
|
|
349
|
+
];
|
|
350
|
+
|
|
351
|
+
const permissionIssues = [];
|
|
352
|
+
|
|
353
|
+
for (const testPath of testPaths) {
|
|
354
|
+
const fullPath = path.join(projectRoot, testPath);
|
|
355
|
+
if (await fileUtils.exists(fullPath)) {
|
|
356
|
+
try {
|
|
357
|
+
// Test read permission
|
|
358
|
+
await fileUtils.access(fullPath, fileUtils.constants.R_OK);
|
|
359
|
+
|
|
360
|
+
// Test write permission (only for directories and config files)
|
|
361
|
+
await fileUtils.access(fullPath, fileUtils.constants.W_OK);
|
|
362
|
+
} catch (error) {
|
|
363
|
+
permissionIssues.push(testPath);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (permissionIssues.length > 0) {
|
|
369
|
+
return {
|
|
370
|
+
id: 'file-permissions',
|
|
371
|
+
name: 'File permissions',
|
|
372
|
+
passed: false,
|
|
373
|
+
message: `Permission issues: ${permissionIssues.join(', ')}`,
|
|
374
|
+
severity: 'warning'
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return {
|
|
379
|
+
id: 'file-permissions',
|
|
380
|
+
name: 'File permissions',
|
|
381
|
+
passed: true,
|
|
382
|
+
severity: 'warning'
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Check 7: Manifest files valid
|
|
388
|
+
*/
|
|
389
|
+
async function checkManifests(config) {
|
|
390
|
+
const projectRoot = config.projectRoot || process.cwd();
|
|
391
|
+
const manifestFiles = [
|
|
392
|
+
'_bmad/_config/agent-manifest.csv',
|
|
393
|
+
'_bmad/_config/workflow-manifest.csv',
|
|
394
|
+
'_bmad/_config/task-manifest.csv'
|
|
395
|
+
];
|
|
396
|
+
|
|
397
|
+
const issues = [];
|
|
398
|
+
|
|
399
|
+
for (const manifestFile of manifestFiles) {
|
|
400
|
+
const manifestPath = path.join(projectRoot, manifestFile);
|
|
401
|
+
if (await fileUtils.exists(manifestPath)) {
|
|
402
|
+
try {
|
|
403
|
+
const content = await fileUtils.readFile(manifestPath, 'utf8');
|
|
404
|
+
const lines = content.split('\n').filter(l => l.trim());
|
|
405
|
+
|
|
406
|
+
// Check header exists
|
|
407
|
+
if (lines.length === 0 || !lines[0].includes(',')) {
|
|
408
|
+
issues.push(`${manifestFile}: invalid format`);
|
|
409
|
+
}
|
|
410
|
+
} catch (error) {
|
|
411
|
+
issues.push(`${manifestFile}: ${error.message}`);
|
|
412
|
+
}
|
|
413
|
+
} else {
|
|
414
|
+
// Manifests are optional, don't fail if missing
|
|
415
|
+
// issues.push(`${manifestFile}: not found`);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if (issues.length > 0) {
|
|
420
|
+
return {
|
|
421
|
+
id: 'manifests',
|
|
422
|
+
name: 'Manifest files',
|
|
423
|
+
passed: false,
|
|
424
|
+
message: issues.join(', '),
|
|
425
|
+
severity: 'warning'
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return {
|
|
430
|
+
id: 'manifests',
|
|
431
|
+
name: 'Manifest files',
|
|
432
|
+
passed: true,
|
|
433
|
+
severity: 'warning'
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Check 8: Workflows accessible
|
|
439
|
+
*/
|
|
440
|
+
async function checkWorkflows(config) {
|
|
441
|
+
const projectRoot = config.projectRoot || process.cwd();
|
|
442
|
+
const workflowDirs = [
|
|
443
|
+
'_bmad/core/workflows',
|
|
444
|
+
'_bmad/bmm/workflows',
|
|
445
|
+
'_bmad/bmb/workflows',
|
|
446
|
+
'_bmad/tea/workflows',
|
|
447
|
+
'_bmad/cis/workflows'
|
|
448
|
+
];
|
|
449
|
+
|
|
450
|
+
let workflowCount = 0;
|
|
451
|
+
const issues = [];
|
|
452
|
+
|
|
453
|
+
for (const workflowDir of workflowDirs) {
|
|
454
|
+
const dirPath = path.join(projectRoot, workflowDir);
|
|
455
|
+
if (await fileUtils.exists(dirPath)) {
|
|
456
|
+
try {
|
|
457
|
+
const workflows = await fileUtils.readDir(dirPath);
|
|
458
|
+
workflowCount += workflows.length;
|
|
459
|
+
} catch (error) {
|
|
460
|
+
issues.push(`${workflowDir}: ${error.message}`);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (issues.length > 0) {
|
|
466
|
+
return {
|
|
467
|
+
id: 'workflows',
|
|
468
|
+
name: 'Workflow files',
|
|
469
|
+
passed: false,
|
|
470
|
+
message: issues.join(', '),
|
|
471
|
+
severity: 'warning'
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
return {
|
|
476
|
+
id: 'workflows',
|
|
477
|
+
name: 'Workflow files',
|
|
478
|
+
passed: true,
|
|
479
|
+
message: `${workflowCount} workflows found`,
|
|
480
|
+
severity: 'warning'
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Check 9: Templates valid
|
|
486
|
+
*/
|
|
487
|
+
async function checkTemplates(config) {
|
|
488
|
+
const templatesDir = path.join(__dirname, '..', '..', 'templates', '_bmad');
|
|
489
|
+
|
|
490
|
+
if (!await fileUtils.exists(templatesDir)) {
|
|
491
|
+
return {
|
|
492
|
+
id: 'templates',
|
|
493
|
+
name: 'Template files',
|
|
494
|
+
passed: false,
|
|
495
|
+
message: 'Templates directory not found',
|
|
496
|
+
severity: 'warning'
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const modules = ['core', 'bmm', 'bmb', 'tea', 'cis'];
|
|
501
|
+
const issues = [];
|
|
502
|
+
|
|
503
|
+
for (const module of modules) {
|
|
504
|
+
const agentsDir = path.join(templatesDir, module, 'agents');
|
|
505
|
+
if (!await fileUtils.exists(agentsDir)) {
|
|
506
|
+
issues.push(`${module}/agents missing`);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
if (issues.length > 0) {
|
|
511
|
+
return {
|
|
512
|
+
id: 'templates',
|
|
513
|
+
name: 'Template files',
|
|
514
|
+
passed: false,
|
|
515
|
+
message: issues.join(', '),
|
|
516
|
+
severity: 'warning'
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
return {
|
|
521
|
+
id: 'templates',
|
|
522
|
+
name: 'Template files',
|
|
523
|
+
passed: true,
|
|
524
|
+
severity: 'warning'
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Check 10: Dependencies installed
|
|
530
|
+
*/
|
|
531
|
+
async function checkDependencies(config) {
|
|
532
|
+
const requiredDeps = [
|
|
533
|
+
'fs-extra',
|
|
534
|
+
'js-yaml',
|
|
535
|
+
'chalk'
|
|
536
|
+
];
|
|
537
|
+
|
|
538
|
+
const missingDeps = [];
|
|
539
|
+
|
|
540
|
+
for (const dep of requiredDeps) {
|
|
541
|
+
try {
|
|
542
|
+
require.resolve(dep);
|
|
543
|
+
} catch {
|
|
544
|
+
missingDeps.push(dep);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
if (missingDeps.length > 0) {
|
|
549
|
+
return {
|
|
550
|
+
id: 'dependencies',
|
|
551
|
+
name: 'Dependencies',
|
|
552
|
+
passed: false,
|
|
553
|
+
message: `Missing: ${missingDeps.join(', ')}. Run: npm install`,
|
|
554
|
+
severity: 'critical'
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
return {
|
|
559
|
+
id: 'dependencies',
|
|
560
|
+
name: 'Dependencies',
|
|
561
|
+
passed: true,
|
|
562
|
+
severity: 'critical'
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
module.exports = {
|
|
567
|
+
validate,
|
|
568
|
+
checkBmadStructure,
|
|
569
|
+
checkAgentFiles,
|
|
570
|
+
checkStubsYamlFrontmatter,
|
|
571
|
+
checkConfigFiles,
|
|
572
|
+
checkPlatformDetection,
|
|
573
|
+
checkFilePermissions,
|
|
574
|
+
checkManifests,
|
|
575
|
+
checkWorkflows,
|
|
576
|
+
checkTemplates,
|
|
577
|
+
checkDependencies
|
|
578
|
+
};
|