create-byan-agent 1.2.6 → 2.0.0-alpha.1

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 (77) hide show
  1. package/CHANGELOG.md +196 -388
  2. package/LICENSE +21 -21
  3. package/README.md +420 -1264
  4. package/bin/create-byan-agent-backup.js +220 -220
  5. package/bin/create-byan-agent-fixed.js +301 -301
  6. package/bin/create-byan-agent-v2.js +492 -0
  7. package/bin/create-byan-agent.js +296 -561
  8. package/package.json +68 -64
  9. package/templates/.github/agents/bmad-agent-bmad-master.md +15 -15
  10. package/templates/.github/agents/bmad-agent-bmb-agent-builder.md +15 -15
  11. package/templates/.github/agents/bmad-agent-bmb-module-builder.md +15 -15
  12. package/templates/.github/agents/bmad-agent-bmb-workflow-builder.md +15 -15
  13. package/templates/.github/agents/bmad-agent-bmm-analyst.md +15 -15
  14. package/templates/.github/agents/bmad-agent-bmm-architect.md +15 -15
  15. package/templates/.github/agents/bmad-agent-bmm-dev.md +15 -15
  16. package/templates/.github/agents/bmad-agent-bmm-pm.md +15 -15
  17. package/templates/.github/agents/bmad-agent-bmm-quick-flow-solo-dev.md +15 -15
  18. package/templates/.github/agents/bmad-agent-bmm-quinn.md +15 -15
  19. package/templates/.github/agents/bmad-agent-bmm-sm.md +15 -15
  20. package/templates/.github/agents/bmad-agent-bmm-tech-writer.md +15 -15
  21. package/templates/.github/agents/bmad-agent-bmm-ux-designer.md +15 -15
  22. package/templates/.github/agents/bmad-agent-byan-test.md +32 -32
  23. package/templates/.github/agents/bmad-agent-byan.md +224 -224
  24. package/templates/.github/agents/bmad-agent-carmack.md +18 -18
  25. package/templates/.github/agents/bmad-agent-cis-brainstorming-coach.md +15 -15
  26. package/templates/.github/agents/bmad-agent-cis-creative-problem-solver.md +15 -15
  27. package/templates/.github/agents/bmad-agent-cis-design-thinking-coach.md +15 -15
  28. package/templates/.github/agents/bmad-agent-cis-innovation-strategist.md +15 -15
  29. package/templates/.github/agents/bmad-agent-cis-presentation-master.md +15 -15
  30. package/templates/.github/agents/bmad-agent-cis-storyteller.md +15 -15
  31. package/templates/.github/agents/bmad-agent-marc.md +48 -48
  32. package/templates/.github/agents/bmad-agent-patnote.md +48 -48
  33. package/templates/.github/agents/bmad-agent-rachid.md +47 -47
  34. package/templates/.github/agents/bmad-agent-tea-tea.md +15 -15
  35. package/templates/.github/agents/bmad-agent-test-dynamic.md +21 -21
  36. package/templates/.github/agents/franck.md +379 -379
  37. package/templates/_bmad/bmb/agents/agent-builder.md +59 -59
  38. package/templates/_bmad/bmb/agents/byan-test.md +116 -116
  39. package/templates/_bmad/bmb/agents/byan.md +215 -215
  40. package/templates/_bmad/bmb/agents/marc.md +303 -303
  41. package/templates/_bmad/bmb/agents/module-builder.md +60 -60
  42. package/templates/_bmad/bmb/agents/patnote.md +495 -495
  43. package/templates/_bmad/bmb/agents/rachid.md +184 -184
  44. package/templates/_bmad/bmb/agents/workflow-builder.md +61 -61
  45. package/templates/_bmad/bmb/workflows/byan/data/mantras.yaml +272 -272
  46. package/templates/_bmad/bmb/workflows/byan/data/templates.yaml +59 -59
  47. package/templates/_bmad/bmb/workflows/byan/delete-agent-workflow.md +657 -657
  48. package/templates/_bmad/bmb/workflows/byan/edit-agent-workflow.md +688 -688
  49. package/templates/_bmad/bmb/workflows/byan/interview-workflow.md +753 -753
  50. package/templates/_bmad/bmb/workflows/byan/quick-create-workflow.md +450 -450
  51. package/templates/_bmad/bmb/workflows/byan/templates/base-agent-template.md +79 -79
  52. package/templates/_bmad/bmb/workflows/byan/validate-agent-workflow.md +676 -676
  53. package/templates/_bmad/core/agents/carmack.md +238 -238
  54. package/lib/errors.js +0 -61
  55. package/lib/exit-codes.js +0 -54
  56. package/lib/platforms/claude-code.js +0 -113
  57. package/lib/platforms/codex.js +0 -92
  58. package/lib/platforms/copilot-cli.js +0 -123
  59. package/lib/platforms/index.js +0 -14
  60. package/lib/platforms/vscode.js +0 -51
  61. package/lib/utils/config-loader.js +0 -79
  62. package/lib/utils/file-utils.js +0 -117
  63. package/lib/utils/git-detector.js +0 -35
  64. package/lib/utils/logger.js +0 -64
  65. package/lib/utils/node-detector.js +0 -58
  66. package/lib/utils/os-detector.js +0 -74
  67. package/lib/utils/yaml-utils.js +0 -87
  68. package/lib/yanstaller/backuper.js +0 -308
  69. package/lib/yanstaller/detector.js +0 -141
  70. package/lib/yanstaller/index.js +0 -93
  71. package/lib/yanstaller/installer.js +0 -226
  72. package/lib/yanstaller/interviewer.js +0 -301
  73. package/lib/yanstaller/recommender.js +0 -308
  74. package/lib/yanstaller/troubleshooter.js +0 -498
  75. package/lib/yanstaller/validator.js +0 -602
  76. package/lib/yanstaller/wizard.js +0 -229
  77. package/templates/.github/agents/expert-merise-agile.md +0 -1
@@ -1,587 +1,322 @@
1
- #!/usr/bin/env node
2
-
3
- const path = require('path');
4
- const { program } = require('commander');
5
- const { spawnSync, execSync } = require('child_process');
6
- const fs = require('fs');
7
- const os = require('os');
8
- const chalk = require('chalk');
9
-
10
- // YANSTALLER Modules
11
- const detector = require('../lib/yanstaller/detector');
12
- const recommender = require('../lib/yanstaller/recommender');
13
- const interviewer = require('../lib/yanstaller/interviewer');
14
- const installer = require('../lib/yanstaller/installer');
15
- const validator = require('../lib/yanstaller/validator');
16
- const wizard = require('../lib/yanstaller/wizard');
17
- const backuper = require('../lib/yanstaller/backuper');
18
- const logger = require('../lib/utils/logger');
19
-
20
- const YANSTALLER_VERSION = '1.2.6';
1
+ #!/usr/bin/env node
21
2
 
22
- function parseList(value) {
23
- if (!value) return [];
24
- if (Array.isArray(value)) return value.map(v => String(v).trim()).filter(Boolean);
25
- return String(value)
26
- .split(',')
27
- .map(v => v.trim())
28
- .filter(Boolean);
29
- }
3
+ const fs = require('fs-extra');
4
+ const path = require('path');
5
+ const { program } = require('commander');
6
+ const inquirer = require('inquirer');
7
+ const chalk = require('chalk');
8
+ const ora = require('ora');
9
+ const yaml = require('js-yaml');
30
10
 
31
- function normalizePlatformName(name) {
32
- if (!name) return name;
33
- const lower = String(name).toLowerCase();
34
- if (lower === 'claude') return 'claude-code';
35
- return lower;
36
- }
11
+ const BYAN_VERSION = '1.1.3';
37
12
 
38
- function normalizePlatforms(list) {
39
- return list.map(normalizePlatformName).filter(Boolean);
40
- }
13
+ // ASCII Art Banner
14
+ const banner = `
15
+ ${chalk.blue('╔════════════════════════════════════════════════════════════╗')}
16
+ ${chalk.blue('║')} ${chalk.blue('║')}
17
+ ${chalk.blue('║')} ${chalk.bold('🏗️ BYAN INSTALLER v' + BYAN_VERSION)} ${chalk.blue('║')}
18
+ ${chalk.blue('║')} ${chalk.gray('Builder of YAN - Agent Creator')} ${chalk.blue('║')}
19
+ ${chalk.blue('║')} ${chalk.blue('║')}
20
+ ${chalk.blue('║')} ${chalk.gray('Methodology: Merise Agile + TDD + 64 Mantras')} ${chalk.blue('║')}
21
+ ${chalk.blue('║')} ${chalk.blue('║')}
22
+ ${chalk.blue('╚════════════════════════════════════════════════════════════╝')}
23
+ `;
41
24
 
42
- function expandAllPlatforms(list) {
43
- if (list.includes('all')) {
44
- return ['copilot-cli', 'vscode', 'codex', 'claude-code'];
25
+ // Source template directory (where BYAN package files are)
26
+ const getTemplateDir = () => {
27
+ // FIX #1: Correct path for npm/npx installation
28
+ // When running from node_modules/create-byan-agent/bin/
29
+ // We need to go up ONE level to reach templates/
30
+ const npmPackagePath = path.join(__dirname, '..', 'templates');
31
+ if (fs.existsSync(npmPackagePath)) {
32
+ console.log(chalk.gray(`[DEBUG] Template dir found: ${npmPackagePath}`));
33
+ return npmPackagePath;
45
34
  }
46
- return list;
47
- }
48
-
49
- function getCopilotCommand() {
50
- try {
51
- execSync('copilot --version', { stdio: 'ignore' });
52
- return 'copilot';
53
- } catch {}
54
35
 
55
- try {
56
- const isWin = process.platform === 'win32';
57
- const probe = isWin ? 'where copilot' : 'which copilot';
58
- const out = execSync(probe, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
59
- const first = String(out).split(/\r?\n/).find(Boolean);
60
- return first || null;
61
- } catch {
62
- return null;
36
+ // ✅ FIX #2: Alternative check for development mode
37
+ // If running from source during development
38
+ const devPath = path.join(__dirname, '..', '..', 'templates');
39
+ if (fs.existsSync(devPath)) {
40
+ console.log(chalk.gray(`[DEBUG] Dev template dir found: ${devPath}`));
41
+ return devPath;
63
42
  }
64
- }
65
-
66
- function getCodexCommand() {
67
- try {
68
- execSync('codex --version', { stdio: 'ignore' });
69
- return 'codex';
70
- } catch {}
71
43
 
72
- try {
73
- const isWin = process.platform === 'win32';
74
- const probe = isWin ? 'where codex' : 'which codex';
75
- const out = execSync(probe, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
76
- const first = String(out).split(/\r?\n/).find(Boolean);
77
- return first || null;
78
- } catch {
79
- return null;
80
- }
81
- }
44
+ // ❌ Fallback: This shouldn't happen in production
45
+ console.error(chalk.red('⚠️ WARNING: Template directory not found!'));
46
+ console.error(chalk.red(` Searched: ${npmPackagePath}`));
47
+ console.error(chalk.red(` Also searched: ${devPath}`));
48
+ return null;
49
+ };
82
50
 
83
- function getClaudeCommand() {
84
- try {
85
- execSync('claude --version', { stdio: 'ignore' });
86
- return 'claude';
87
- } catch {}
51
+ // Main installer
52
+ async function install() {
53
+ console.clear();
54
+ console.log(banner);
88
55
 
89
- try {
90
- const isWin = process.platform === 'win32';
91
- const probe = isWin ? 'where claude' : 'which claude';
92
- const out = execSync(probe, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
93
- const first = String(out).split(/\r?\n/).find(Boolean);
94
- return first || null;
95
- } catch {
96
- return null;
97
- }
98
- }
99
-
100
- function stripAnsi(input) {
101
- return input.replace(/\u001b\[[0-9;]*m/g, '');
102
- }
103
-
104
- function extractJson(text) {
105
- const cleaned = stripAnsi(text).trim();
106
- try {
107
- return JSON.parse(cleaned);
108
- } catch {
109
- const xmlMatch = cleaned.match(/<json>[\s\S]*?<\/json>/i);
110
- if (xmlMatch) {
111
- const inner = xmlMatch[0].replace(/<\/?json>/gi, '').trim();
112
- try {
113
- return JSON.parse(inner);
114
- } catch {
115
- return null;
56
+ const projectRoot = process.cwd();
57
+
58
+ // Step 1: Detect project type
59
+ const spinner = ora('Detecting project type...').start();
60
+
61
+ const isGitRepo = await fs.pathExists(path.join(projectRoot, '.git'));
62
+ const hasPackageJson = await fs.pathExists(path.join(projectRoot, 'package.json'));
63
+ const hasPyProject = await fs.pathExists(path.join(projectRoot, 'pyproject.toml'));
64
+
65
+ if (!isGitRepo && !hasPackageJson && !hasPyProject) {
66
+ spinner.warn('Not in a recognized project directory');
67
+
68
+ const { continueAnyway } = await inquirer.prompt([
69
+ {
70
+ type: 'confirm',
71
+ name: 'continueAnyway',
72
+ message: 'BYAN works best in a project with version control. Continue anyway?',
73
+ default: false
116
74
  }
75
+ ]);
76
+
77
+ if (!continueAnyway) {
78
+ console.log(chalk.yellow('Installation cancelled.'));
79
+ process.exit(0);
117
80
  }
118
- const match = cleaned.match(/\{[\s\S]*\}/);
119
- if (!match) return null;
120
- try {
121
- return JSON.parse(match[0]);
122
- } catch {
123
- return null;
124
- }
125
- }
126
- }
127
-
128
- function runCopilotInterview({ recommendation, detection, projectRoot }) {
129
- const copilotCmd = getCopilotCommand();
130
- if (!copilotCmd) {
131
- return { error: 'Copilot CLI not found in PATH' };
132
- }
133
- const platforms = (detection && Array.isArray(detection.platforms)) ? detection.platforms : [];
134
- const detectedNames = platforms.filter(p => p.detected).map(p => p.name);
135
- const recommendedAgents = (recommendation && recommendation.agents) ? recommendation.agents : [];
136
- const recommendedMode = (recommendation && recommendation.mode) ? recommendation.mode : 'recommended';
137
-
138
- const prompt = [
139
- 'You are BYAN installer assistant.',
140
- 'Based on the project context, provide installation preferences as STRICT JSON only.',
141
- 'Do not include any extra text, markdown, or code fences.',
142
- 'If you must include extra text, wrap JSON between <json> and </json>.',
143
- '',
144
- `Project root: ${projectRoot}`,
145
- `Detected platforms: ${detectedNames.join(', ') || 'none'}`,
146
- `Recommended agents: ${recommendedAgents.join(', ') || 'none'}`,
147
- `Recommended mode: ${recommendedMode}`,
148
- '',
149
- 'Return JSON with keys:',
150
- 'userName (string), language (English|Francais), mode (recommended|minimal|full|custom),',
151
- 'agents (array of strings; required if mode=custom),',
152
- 'platforms (array from: copilot-cli,vscode,codex,claude-code),',
153
- 'createSampleAgent (boolean), createBackup (boolean).',
154
- '',
155
- 'If unsure, choose recommended mode, recommended agents, and detected platforms.',
156
- 'JSON only.'
157
- ].join('\n');
158
-
159
- const spawnOptions = { encoding: 'utf8', maxBuffer: 10 * 1024 * 1024 };
160
- let result;
161
-
162
- if (process.platform === 'win32') {
163
- const tmpFile = path.join(os.tmpdir(), `byan-copilot-prompt-${Date.now()}.txt`);
164
- fs.writeFileSync(tmpFile, prompt, 'utf8');
165
- const psFile = path.join(os.tmpdir(), `byan-copilot-run-${Date.now()}.ps1`);
166
- const psContent = [
167
- `$p = Get-Content -Raw '${tmpFile}'`,
168
- 'copilot -p $p'
169
- ].join('\n');
170
- fs.writeFileSync(psFile, psContent, 'utf8');
171
- result = spawnSync('powershell.exe', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', psFile], spawnOptions);
172
- try { fs.unlinkSync(tmpFile); } catch {}
173
- try { fs.unlinkSync(psFile); } catch {}
174
81
  } else {
175
- result = spawnSync(copilotCmd, ['-p', prompt], spawnOptions);
176
- }
177
- if (result.error) {
178
- return { error: result.error.message };
179
- }
180
- if (result.status !== 0) {
181
- return { error: result.stderr || 'copilot returned non-zero status' };
182
- }
183
- const parsed = extractJson(result.stdout || '');
184
- if (!parsed) {
185
- return { error: 'Failed to parse JSON from copilot output' };
186
- }
187
- return { data: parsed };
188
- }
189
-
190
- function runCodexInterview({ recommendation, detection, projectRoot }) {
191
- const codexCmd = getCodexCommand();
192
- if (!codexCmd) {
193
- return { error: 'Codex CLI not found in PATH' };
82
+ spinner.succeed('Project detected');
194
83
  }
195
- const platforms = (detection && Array.isArray(detection.platforms)) ? detection.platforms : [];
196
- const detectedNames = platforms.filter(p => p.detected).map(p => p.name);
197
- const recommendedAgents = (recommendation && recommendation.agents) ? recommendation.agents : [];
198
- const recommendedMode = (recommendation && recommendation.mode) ? recommendation.mode : 'recommended';
199
-
200
- const prompt = [
201
- 'You are BYAN installer assistant.',
202
- 'Based on the project context, provide installation preferences as STRICT JSON only.',
203
- 'Do not include any extra text, markdown, or code fences.',
204
- 'If you must include extra text, wrap JSON between <json> and </json>.',
205
- '',
206
- `Project root: ${projectRoot}`,
207
- `Detected platforms: ${detectedNames.join(', ') || 'none'}`,
208
- `Recommended agents: ${recommendedAgents.join(', ') || 'none'}`,
209
- `Recommended mode: ${recommendedMode}`,
210
- '',
211
- 'Return JSON with keys:',
212
- 'userName (string), language (English|Francais), mode (recommended|minimal|full|custom),',
213
- 'agents (array of strings; required if mode=custom),',
214
- 'platforms (array from: copilot-cli,vscode,codex,claude-code),',
215
- 'createSampleAgent (boolean), createBackup (boolean).',
216
- '',
217
- 'If unsure, choose recommended mode, recommended agents, and detected platforms.',
218
- 'JSON only.'
219
- ].join('\n');
220
-
221
- const spawnOptions = { encoding: 'utf8', maxBuffer: 10 * 1024 * 1024, shell: process.platform === 'win32' };
222
- const result = spawnSync(codexCmd, ['exec', prompt], spawnOptions);
223
- if (result.error) {
224
- return { error: result.error.message };
225
- }
226
- if (result.status !== 0) {
227
- return { error: result.stderr || 'codex returned non-zero status' };
228
- }
229
- const parsed = extractJson(result.stdout || '');
230
- if (!parsed) {
231
- return { error: 'Failed to parse JSON from codex output' };
232
- }
233
- return { data: parsed };
234
- }
235
-
236
- function runClaudeInterview({ recommendation, detection, projectRoot }) {
237
- const claudeCmd = getClaudeCommand();
238
- if (!claudeCmd) {
239
- return { error: 'Claude CLI not found in PATH' };
240
- }
241
- const platforms = (detection && Array.isArray(detection.platforms)) ? detection.platforms : [];
242
- const detectedNames = platforms.filter(p => p.detected).map(p => p.name);
243
- const recommendedAgents = (recommendation && recommendation.agents) ? recommendation.agents : [];
244
- const recommendedMode = (recommendation && recommendation.mode) ? recommendation.mode : 'recommended';
245
-
246
- const prompt = [
247
- 'You are BYAN installer assistant.',
248
- 'Based on the project context, provide installation preferences as STRICT JSON only.',
249
- 'Do not include any extra text, markdown, or code fences.',
250
- 'If you must include extra text, wrap JSON between <json> and </json>.',
251
- '',
252
- `Project root: ${projectRoot}`,
253
- `Detected platforms: ${detectedNames.join(', ') || 'none'}`,
254
- `Recommended agents: ${recommendedAgents.join(', ') || 'none'}`,
255
- `Recommended mode: ${recommendedMode}`,
256
- '',
257
- 'Return JSON with keys:',
258
- 'userName (string), language (English|Francais), mode (recommended|minimal|full|custom),',
259
- 'agents (array of strings; required if mode=custom),',
260
- 'platforms (array from: copilot-cli,vscode,codex,claude-code),',
261
- 'createSampleAgent (boolean), createBackup (boolean).',
262
- '',
263
- 'If unsure, choose recommended mode, recommended agents, and detected platforms.',
264
- 'JSON only.'
265
- ].join('\n');
266
-
267
- const spawnOptions = { encoding: 'utf8', maxBuffer: 10 * 1024 * 1024 };
268
- const result = spawnSync(claudeCmd, ['-p', prompt], spawnOptions);
269
- if (result.error) {
270
- return { error: result.error.message };
271
- }
272
- if (result.status !== 0) {
273
- return { error: result.stderr || 'claude returned non-zero status' };
274
- }
275
- const parsed = extractJson(result.stdout || '');
276
- if (!parsed) {
277
- return { error: 'Failed to parse JSON from claude output' };
84
+
85
+ // Step 2: Platform selection
86
+ const { platform } = await inquirer.prompt([
87
+ {
88
+ type: 'list',
89
+ name: 'platform',
90
+ message: 'Select platform to install for:',
91
+ choices: [
92
+ { name: 'GitHub Copilot CLI', value: 'copilot' },
93
+ { name: 'VSCode', value: 'vscode' },
94
+ { name: 'Claude Code', value: 'claude' },
95
+ { name: 'Codex', value: 'codex' },
96
+ { name: 'All platforms', value: 'all' }
97
+ ]
98
+ }
99
+ ]);
100
+
101
+ // Step 3: User configuration
102
+ const config = await inquirer.prompt([
103
+ {
104
+ type: 'input',
105
+ name: 'userName',
106
+ message: 'Your name:',
107
+ default: 'Developer'
108
+ },
109
+ {
110
+ type: 'list',
111
+ name: 'language',
112
+ message: 'Communication language:',
113
+ choices: ['Francais', 'English'],
114
+ default: 'English'
115
+ }
116
+ ]);
117
+
118
+ // Step 4: Create directory structure
119
+ const installSpinner = ora('Creating directory structure...').start();
120
+
121
+ const bmadDir = path.join(projectRoot, '_bmad');
122
+ const bmbDir = path.join(bmadDir, 'bmb');
123
+ const githubAgentsDir = path.join(projectRoot, '.github', 'agents');
124
+
125
+ await fs.ensureDir(path.join(bmadDir, 'bmb', 'agents'));
126
+ await fs.ensureDir(path.join(bmadDir, 'bmb', 'workflows', 'byan', 'steps'));
127
+ await fs.ensureDir(path.join(bmadDir, 'bmb', 'workflows', 'byan', 'templates'));
128
+ await fs.ensureDir(path.join(bmadDir, 'bmb', 'workflows', 'byan', 'data'));
129
+ await fs.ensureDir(path.join(bmadDir, 'core'));
130
+ await fs.ensureDir(path.join(bmadDir, '_config'));
131
+ await fs.ensureDir(path.join(bmadDir, '_memory'));
132
+ await fs.ensureDir(path.join(bmadDir, '_output'));
133
+ await fs.ensureDir(githubAgentsDir);
134
+
135
+ installSpinner.succeed('Directory structure created');
136
+
137
+ // Step 5: Copy BYAN files from template
138
+ const copySpinner = ora('Installing BYAN files...').start();
139
+
140
+ const templateDir = getTemplateDir();
141
+
142
+ // ✅ FIX #3: Validate template directory before proceeding
143
+ if (!templateDir) {
144
+ copySpinner.fail('❌ Template directory not found! Cannot proceed.');
145
+ console.error(chalk.red('\nInstallation failed: Missing template files.'));
146
+ console.error(chalk.yellow('This usually means the package was not installed correctly.'));
147
+ console.error(chalk.yellow('Try reinstalling: npm install -g create-byan-agent'));
148
+ process.exit(1);
278
149
  }
279
- return { data: parsed };
280
- }
281
-
282
- // ASCII Art Banner
283
- const banner = `
284
- ${chalk.blue('╔════════════════════════════════════════════════════════════╗')}
285
- ${chalk.blue('║')} ${chalk.blue('║')}
286
- ${chalk.blue('║')} ${chalk.bold('🏗️ YANSTALLER v' + YANSTALLER_VERSION)} ${chalk.blue('║')}
287
- ${chalk.blue('║')} ${chalk.gray('Intelligent BYAN Installer')} ${chalk.blue('║')}
288
- ${chalk.blue('║')} ${chalk.blue('║')}
289
- ${chalk.blue('║')} ${chalk.gray('Methodology: Merise Agile + TDD + 64 Mantras')} ${chalk.blue('║')}
290
- ${chalk.blue('║')} ${chalk.gray('29 Agents • Multi-Platform • Auto-Fix')} ${chalk.blue('║')}
291
- ${chalk.blue('║')} ${chalk.blue('║')}
292
- ${chalk.blue('╚════════════════════════════════════════════════════════════╝')}
293
- `;
294
-
295
- /**
296
- * Main YANSTALLER Installation Flow
297
- *
298
- * Orchestrates the 7-step intelligent installation:
299
- * 1. DETECT - Platform & project analysis
300
- * 2. RECOMMEND - Intelligent agent recommendations
301
- * 3. INTERVIEW - 7-question personalization
302
- * 4. BACKUP - Pre-install safety (optional)
303
- * 5. INSTALL - Core installation
304
- * 6. VALIDATE - 10 automated checks
305
- * 7. WIZARD - Post-install actions
306
- */
307
- async function main(options = {}) {
308
- try {
309
- console.clear();
310
- console.log(banner);
311
-
312
- const projectRoot = process.cwd();
313
-
314
- // STEP 1: DETECT - Platform & Project Analysis
315
- logger.info(chalk.bold('\n🔍 STEP 1/7: Detection\n'));
316
- const detection = await detector.detect({ projectRoot });
317
-
318
- const platformNames = detection.platforms ? detection.platforms.map(p => p.name).join(', ') : 'none';
319
- logger.info(`✓ Platforms detected: ${chalk.cyan(platformNames)}`);
320
- if (detection.projectType) {
321
- logger.info(`✓ Project type: ${chalk.cyan(detection.projectType)}`);
322
- }
323
- if (detection.framework) {
324
- logger.info(`✓ Framework: ${chalk.cyan(detection.framework)}`);
325
- }
326
-
327
- // STEP 2: RECOMMEND - Intelligent Agent Selection
328
- logger.info(chalk.bold('\n🎯 STEP 2/7: Recommendations\n'));
329
- const recommendations = await recommender.recommend({
330
- projectRoot,
331
- detection
332
- });
333
-
334
- if (recommendations.agents && recommendations.agents.length > 0) {
335
- logger.info(`✓ Recommended agents: ${chalk.cyan(recommendations.agents.join(', '))}`);
336
- }
337
-
338
- // STEP 3: INTERVIEW - 7-Question Personalization
339
- const isSilent = !!options.silent;
340
- const forceInteractive = !!options.interactive;
341
- const hasTty = !!process.stdin.isTTY;
342
- const forceSilent = !hasTty && !isSilent && !forceInteractive;
150
+
151
+ try {
152
+ // ✅ FIX #4: Copy agent files from _bmad/bmb/agents
153
+ const agentsSource = path.join(templateDir, '_bmad', 'bmb', 'agents');
154
+ const agentsDest = path.join(bmbDir, 'agents');
343
155
 
344
- if (forceSilent) {
345
- logger.warn('No interactive TTY detected. Falling back to silent mode.');
346
- }
347
- if (!hasTty && forceInteractive) {
348
- logger.warn('Interactive mode forced without TTY. Prompts may not render correctly.');
156
+ if (await fs.pathExists(agentsSource)) {
157
+ await fs.copy(agentsSource, agentsDest, { overwrite: true });
158
+ copySpinner.text = 'Copied agent files...';
159
+ console.log(chalk.green(` ✓ Agents: ${agentsSource} → ${agentsDest}`));
160
+ } else {
161
+ copySpinner.warn(`⚠ Agent source not found: ${agentsSource}`);
349
162
  }
350
163
 
351
- let answers;
164
+ // ✅ FIX #5: Copy workflow files from _bmad/bmb/workflows/byan
165
+ const workflowsSource = path.join(templateDir, '_bmad', 'bmb', 'workflows', 'byan');
166
+ const workflowsDest = path.join(bmbDir, 'workflows', 'byan');
352
167
 
353
- if (isSilent || forceSilent) {
354
- logger.info(chalk.bold('\nSTEP 3/7: Interview (skipped - silent)\n'));
355
-
356
- const parsedAgents = parseList(options.agents);
357
- const parsedPlatforms = expandAllPlatforms(normalizePlatforms(parseList(options.platforms)));
358
-
359
- let mode = options.mode || (parsedAgents.length > 0 ? 'custom' : (recommendations.mode || 'minimal'));
360
- let agents = parsedAgents;
361
-
362
- if (agents.length === 0) {
363
- if (mode === 'recommended' && recommendations && recommendations.agents) {
364
- agents = recommendations.agents;
365
- } else if (mode === 'minimal' || mode === 'full') {
366
- agents = recommender.getAgentList(mode);
367
- } else if (mode === 'custom') {
368
- logger.warn('Custom mode selected without agents. Falling back to recommendations.');
369
- agents = recommendations.agents || ['byan'];
370
- mode = 'recommended';
371
- } else {
372
- agents = recommendations.agents || ['byan'];
373
- mode = recommendations.mode || 'minimal';
374
- }
375
- }
376
-
377
- let targetPlatforms = parsedPlatforms;
378
- if (targetPlatforms.length === 0) {
379
- targetPlatforms = (detection.platforms || [])
380
- .filter(p => p.detected)
381
- .map(p => normalizePlatformName(p.name));
382
- }
383
-
384
- answers = {
385
- userName: 'Developer',
386
- language: 'English',
387
- mode,
388
- agents,
389
- targetPlatforms,
390
- createSampleAgent: false,
391
- createBackup: options.backup !== false
392
- };
168
+ if (await fs.pathExists(workflowsSource)) {
169
+ await fs.copy(workflowsSource, workflowsDest, { overwrite: true });
170
+ copySpinner.text = 'Copied workflow files...';
171
+ console.log(chalk.green(` ✓ Workflows: ${workflowsSource} → ${workflowsDest}`));
393
172
  } else {
394
- const wantsAgentInterview = options.agentInterview !== false;
395
- const useAgentInterview = wantsAgentInterview;
396
-
397
- let agentDefaults = null;
398
-
399
- if (useAgentInterview) {
400
- let provider = null;
401
- const requestedProvider = options.agentProvider ? String(options.agentProvider).toLowerCase() : 'auto';
402
- const hasCopilot = !!getCopilotCommand();
403
- const hasCodex = !!getCodexCommand();
404
- const hasClaude = !!getClaudeCommand();
405
-
406
- if (requestedProvider !== 'auto') {
407
- if (requestedProvider === 'copilot' && hasCopilot) provider = 'copilot';
408
- if (requestedProvider === 'codex' && hasCodex) provider = 'codex';
409
- if (requestedProvider === 'claude' && hasClaude) provider = 'claude';
410
-
411
- if (!provider) {
412
- logger.info(`Requested agent provider "${requestedProvider}" is not available. Falling back to auto selection.`);
413
- }
414
- }
415
-
416
- if (!provider) {
417
- if (hasCopilot) {
418
- provider = 'copilot';
419
- } else if (hasCodex) {
420
- provider = 'codex';
421
- } else if (hasClaude) {
422
- provider = 'claude';
423
- }
424
- }
425
-
426
- if (provider) {
427
- const label = provider === 'copilot' ? 'Copilot CLI' : provider === 'codex' ? 'Codex CLI' : 'Claude CLI';
428
- logger.info(chalk.bold('\nSTEP 3/7: Interview (agent-assisted)\n'));
429
- logger.info(`Launching agent-assisted interview via ${label}...`);
430
-
431
- const agentResult = provider === 'copilot'
432
- ? runCopilotInterview({ recommendation: recommendations, detection, projectRoot })
433
- : provider === 'codex'
434
- ? runCodexInterview({ recommendation: recommendations, detection, projectRoot })
435
- : runClaudeInterview({ recommendation: recommendations, detection, projectRoot });
436
-
437
- if (agentResult && agentResult.data) {
438
- logger.info(`${label} returned JSON defaults.`);
439
- const data = agentResult.data;
440
- const agentMode = data.mode || 'recommended';
441
-
442
- let agentPlatforms = Array.isArray(data.platforms) ? data.platforms : [];
443
- agentPlatforms = expandAllPlatforms(normalizePlatforms(agentPlatforms));
444
- if (agentPlatforms.length === 0) {
445
- agentPlatforms = (detection.platforms || [])
446
- .filter(p => p.detected)
447
- .map(p => normalizePlatformName(p.name));
448
- }
449
-
450
- let agentAgents = Array.isArray(data.agents) ? data.agents : [];
451
- if (agentAgents.length === 0) {
452
- if (agentMode === 'recommended' && recommendations && recommendations.agents) {
453
- agentAgents = recommendations.agents;
454
- } else if (agentMode === 'minimal' || agentMode === 'full') {
455
- agentAgents = recommender.getAgentList(agentMode);
456
- } else if (agentMode === 'custom') {
457
- agentAgents = recommendations.agents || ['byan'];
458
- } else {
459
- agentAgents = recommendations.agents || ['byan'];
460
- }
461
- }
462
-
463
- const language = data.language === 'Francais' ? 'Francais' : 'English';
464
-
465
- agentDefaults = {
466
- userName: data.userName || 'Developer',
467
- language,
468
- mode: agentMode,
469
- agents: agentAgents,
470
- platforms: agentPlatforms,
471
- createSampleAgent: !!data.createSampleAgent,
472
- createBackup: data.createBackup !== false
473
- };
474
-
475
- logger.info('Agent provided recommended defaults. You can edit them below.');
476
- } else {
477
- const errMsg = agentResult && agentResult.error ? agentResult.error : 'unknown error';
478
- logger.info(`Agent interview unavailable: ${errMsg}`);
479
- logger.info('Continuing with standard interactive interview.');
480
- }
481
- } else {
482
- logger.info('No agent CLI detected (Copilot/Codex/Claude). Continuing with standard interactive interview.');
483
- }
484
- }
485
-
486
- logger.info(chalk.bold('\nSTEP 3/7: Interview\n'));
487
- const preferredPlatforms = expandAllPlatforms(normalizePlatforms(parseList(options.platforms)));
488
- answers = await interviewer.ask(recommendations, {
489
- detection,
490
- preferredPlatforms: agentDefaults ? agentDefaults.platforms : preferredPlatforms,
491
- defaults: agentDefaults || undefined
492
- });
493
-
494
- if (options.backup === false) {
495
- answers.createBackup = false;
496
- }
173
+ copySpinner.warn(`⚠ Workflow source not found: ${workflowsSource}`);
497
174
  }
498
175
 
499
- // STEP 4: BACKUP (optional)
500
- if (answers.createBackup) {
501
- logger.info(chalk.bold('\n💾 STEP 4/7: Backup\n'));
502
- try {
503
- const bmadPath = path.join(projectRoot, '_bmad');
504
- const backup = await backuper.backup(bmadPath);
505
- logger.info(`✓ Backup created: ${chalk.cyan(backup.backupPath)}`);
506
- } catch (error) {
507
- logger.warn(`⚠ Backup failed (non-critical): ${error.message}`);
508
- }
509
- } else {
510
- logger.info(chalk.bold('\n⏭️ STEP 4/7: Backup (skipped)\n'));
511
- }
512
-
513
- // STEP 5: INSTALL - Core Installation
514
- logger.info(chalk.bold('\n🚀 STEP 5/7: Installation\n'));
515
- const installResult = await installer.install({
516
- projectRoot,
517
- agents: answers.agents,
518
- targetPlatforms: answers.targetPlatforms,
519
- userName: answers.userName,
520
- language: answers.language,
521
- mode: answers.mode
522
- });
523
-
524
- logger.info(`✓ Installed ${chalk.cyan(installResult.agentsInstalled)} agents`);
525
- if (installResult.errors && installResult.errors.length > 0) {
526
- logger.warn(`⚠ ${installResult.errors.length} installation errors`);
527
- }
528
-
529
- // STEP 6: VALIDATE - 10 Automated Checks
530
- logger.info(chalk.bold('\n✅ STEP 6/7: Validation\n'));
531
- const validation = await validator.validate({ projectRoot });
532
-
533
- if (validation.valid) {
534
- logger.info(chalk.green('✓ All validation checks passed!'));
535
- } else {
536
- logger.warn(chalk.yellow(`⚠ ${validation.errors.length} errors, ${validation.warnings.length} warnings`));
537
- if (validation.errors.length > 0) {
538
- validation.errors.forEach(err => logger.error(` ✗ ${err}`));
539
- }
540
- if (validation.warnings.length > 0) {
541
- validation.warnings.forEach(warn => logger.warn(` ⚠ ${warn}`));
542
- }
543
- }
544
-
545
- // STEP 7: WIZARD - Post-Install Actions
546
- if (isSilent || forceSilent) {
547
- logger.info(chalk.bold('\nSTEP 7/7: Post-Install Wizard (skipped - silent)\n'));
176
+ // FIX #6: Copy .github/agents files (stubs for Copilot CLI detection)
177
+ const githubAgentsSource = path.join(templateDir, '.github', 'agents');
178
+
179
+ if (await fs.pathExists(githubAgentsSource)) {
180
+ await fs.copy(githubAgentsSource, githubAgentsDir, { overwrite: true });
181
+ copySpinner.text = 'Copied Copilot CLI agent stubs...';
182
+ console.log(chalk.green(` ✓ GitHub agents: ${githubAgentsSource} → ${githubAgentsDir}`));
548
183
  } else {
549
- logger.info(chalk.bold('\nSTEP 7/7: Post-Install Wizard\n'));
550
- await wizard.show({
551
- agents: answers.agents,
552
- targetPlatforms: answers.targetPlatforms,
553
- mode: answers.mode,
554
- projectRoot,
555
- userName: answers.userName,
556
- language: answers.language
557
- });
184
+ copySpinner.warn(`⚠ GitHub agents source not found: ${githubAgentsSource}`);
558
185
  }
559
186
 
187
+ copySpinner.succeed('BYAN files installed');
560
188
  } catch (error) {
561
- logger.error(chalk.red('\n❌ Installation failed:\n'));
562
- logger.error(error.message);
563
- if (error.stack) {
564
- logger.error(chalk.gray(error.stack));
565
- }
566
- process.exit(1);
567
- }
568
- }
569
-
570
- // CLI Program
571
- program
572
- .name('create-byan-agent')
573
- .description('YANSTALLER - Intelligent installer for BYAN ecosystem (29 agents, multi-platform)')
574
- .version(YANSTALLER_VERSION)
575
- .option('--silent', 'Silent installation (no prompts)')
576
- .option('--interactive', 'Force interactive prompts even without TTY')
577
- .option('--no-agent-interview', 'Disable agent-assisted interview (Copilot CLI)')
578
- .option('--agent-provider <provider>', 'Agent interview provider: auto|copilot|codex|claude')
579
- .option('--agents <agents>', 'Comma-separated list of agents to install')
580
- .option('--platforms <platforms>', 'Comma-separated list of platforms (copilot-cli,vscode,claude-code,codex)')
581
- .option('--mode <mode>', 'Installation mode: recommended, custom, minimal, full')
582
- .option('--no-backup', 'Skip pre-install backup')
583
- .option('--dry-run', 'Simulate installation without making changes')
584
- .option('--verbose', 'Verbose logging')
585
- .action((opts) => main(opts));
586
-
587
- program.parse(process.argv);
189
+ copySpinner.fail('Error copying files');
190
+ console.error(chalk.red('Details:'), error.message);
191
+ console.error(chalk.red('Stack:'), error.stack);
192
+ }
193
+
194
+ // Step 6: Create config.yaml
195
+ const configSpinner = ora('Generating configuration...').start();
196
+
197
+ const configContent = {
198
+ bmb_creations_output_folder: "{project-root}/_bmad-output/bmb-creations",
199
+ user_name: config.userName,
200
+ communication_language: config.language,
201
+ document_output_language: config.language,
202
+ output_folder: "{project-root}/_bmad-output",
203
+ platform: platform
204
+ };
205
+
206
+ const configPath = path.join(bmbDir, 'config.yaml');
207
+ await fs.writeFile(configPath, yaml.dump(configContent), 'utf8');
208
+
209
+ configSpinner.succeed('Configuration generated');
210
+
211
+ // Step 7: Create package.json script
212
+ const shortcutSpinner = ora('Creating shortcuts...').start();
213
+
214
+ if (hasPackageJson) {
215
+ const pkgPath = path.join(projectRoot, 'package.json');
216
+ const pkg = await fs.readJson(pkgPath);
217
+
218
+ if (!pkg.scripts) pkg.scripts = {};
219
+
220
+ if (!pkg.scripts.byan) {
221
+ pkg.scripts.byan = 'echo "BYAN agent installed. Use: copilot and type /agent"';
222
+ await fs.writeJson(pkgPath, pkg, { spaces: 2 });
223
+ shortcutSpinner.succeed('NPM script added');
224
+ } else {
225
+ shortcutSpinner.info('NPM script already exists');
226
+ }
227
+ } else {
228
+ shortcutSpinner.succeed('Shortcuts created');
229
+ }
230
+
231
+ // Step 8: Verification
232
+ const verifySpinner = ora('Verifying installation...').start();
233
+
234
+ const checks = [
235
+ { name: 'Agents directory', path: path.join(bmbDir, 'agents') },
236
+ { name: 'BYAN agent', path: path.join(bmbDir, 'agents', 'byan.md') },
237
+ { name: 'RACHID agent', path: path.join(bmbDir, 'agents', 'rachid.md') },
238
+ { name: 'MARC agent', path: path.join(bmbDir, 'agents', 'marc.md') },
239
+ { name: 'Workflows', path: path.join(bmbDir, 'workflows', 'byan') },
240
+ { name: 'Config', path: configPath },
241
+ { name: 'GitHub agents dir', path: githubAgentsDir },
242
+ { name: 'BYAN stub', path: path.join(githubAgentsDir, 'bmad-agent-byan.md') },
243
+ { name: 'RACHID stub', path: path.join(githubAgentsDir, 'bmad-agent-rachid.md') },
244
+ { name: 'MARC stub', path: path.join(githubAgentsDir, 'bmad-agent-marc.md') }
245
+ ];
246
+
247
+ let passed = 0;
248
+ let failed = [];
249
+
250
+ for (const check of checks) {
251
+ if (await fs.pathExists(check.path)) {
252
+ passed++;
253
+ } else {
254
+ failed.push(check.name);
255
+ }
256
+ }
257
+
258
+ if (passed === checks.length) {
259
+ verifySpinner.succeed(`Verification: ${passed}/${checks.length} checks passed ✅`);
260
+ } else {
261
+ verifySpinner.warn(`Verification: ${passed}/${checks.length} checks passed`);
262
+ if (failed.length > 0) {
263
+ console.log(chalk.yellow(' Missing:'), failed.join(', '));
264
+ }
265
+ }
266
+
267
+ // Success message
268
+ console.log('');
269
+ console.log(chalk.green('╔════════════════════════════════════════════════════════════╗'));
270
+ console.log(chalk.green('║ ║'));
271
+ console.log(chalk.green('║ ✅ BYAN INSTALLATION COMPLETE! ║'));
272
+ console.log(chalk.green('║ ║'));
273
+ console.log(chalk.green('╚════════════════════════════════════════════════════════════╝'));
274
+ console.log('');
275
+
276
+ console.log(chalk.bold('Installation Summary:'));
277
+ console.log(` • Platform: ${chalk.cyan(platform)}`);
278
+ console.log(` • Installation Directory: ${chalk.cyan(bmbDir)}`);
279
+ console.log(` • Configuration: ${chalk.cyan(configPath)}`);
280
+ console.log(` • User: ${chalk.cyan(config.userName)}`);
281
+ console.log(` • Language: ${chalk.cyan(config.language)}`);
282
+ console.log(` • Agents Installed: ${chalk.cyan('BYAN, RACHID, MARC')}`);
283
+ console.log('');
284
+
285
+ console.log(chalk.bold('Next Steps:'));
286
+ console.log('');
287
+ console.log(chalk.yellow('1. Activate agents in GitHub Copilot CLI:'));
288
+ console.log(` ${chalk.blue('copilot')}`);
289
+ console.log(` Then type: ${chalk.blue('/agent')}`);
290
+ console.log(` Select: ${chalk.cyan('byan')} (create agents)`);
291
+ console.log(` ${chalk.cyan('rachid')} (NPM deployment)`);
292
+ console.log(` ${chalk.cyan('marc')} (Copilot CLI integration)`);
293
+ console.log('');
294
+
295
+ console.log(chalk.yellow('2. Create your first agent with BYAN:'));
296
+ console.log(' [INT] Start Intelligent Interview (30-45 min)');
297
+ console.log(' [QC] Quick Create (10 min)');
298
+ console.log('');
299
+
300
+ console.log(chalk.yellow('3. Deploy with RACHID:'));
301
+ console.log(' Use RACHID to publish BYAN to npm');
302
+ console.log(' Validate package.json and dependencies');
303
+ console.log('');
304
+
305
+ console.log(chalk.yellow('4. Integrate with MARC:'));
306
+ console.log(' Use MARC to test /agent detection');
307
+ console.log(' Validate .github/agents/ structure');
308
+ console.log('');
309
+
310
+ console.log(chalk.gray('Need help? Type \'/bmad-help\' when BYAN is active'));
311
+ console.log('');
312
+ console.log(chalk.blue('Happy agent building! 🏗️'));
313
+ }
314
+
315
+ // CLI Program
316
+ program
317
+ .name('create-byan-agent')
318
+ .description('Install BYAN - Builder of YAN agent creator with RACHID and MARC')
319
+ .version(BYAN_VERSION)
320
+ .action(install);
321
+
322
+ program.parse(process.argv);