create-byan-agent 1.2.4 → 1.2.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/CHANGELOG.md +4 -1
- package/README.md +11 -0
- package/bin/create-byan-agent.js +344 -6
- package/lib/yanstaller/interviewer.js +88 -65
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,10 +5,13 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [1.2.
|
|
8
|
+
## [1.2.6] - 2026-02-04
|
|
9
9
|
|
|
10
10
|
### Added
|
|
11
11
|
- **Interactive override**: `--interactive` flag to force prompts even without TTY (useful in npm scripts).
|
|
12
|
+
- **Agent-assisted interview**: Copilot CLI can answer installer questions automatically (fallback to classic prompts).
|
|
13
|
+
- **Provider fallback**: If Copilot CLI is unavailable, use Codex CLI, then Claude CLI when available.
|
|
14
|
+
- **Agent provider override**: `--agent-provider=codex|copilot|claude` to force the interview source.
|
|
12
15
|
|
|
13
16
|
### Changed
|
|
14
17
|
- **Interview defaults**: Preselect detected or provided platforms during the interview.
|
package/README.md
CHANGED
|
@@ -1025,6 +1025,17 @@ create-byan-agent --interactive
|
|
|
1025
1025
|
|
|
1026
1026
|
# Custom mode with specific platform
|
|
1027
1027
|
create-byan-agent --mode=custom --platforms=copilot-cli
|
|
1028
|
+
|
|
1029
|
+
# Install on all supported platforms
|
|
1030
|
+
create-byan-agent --platforms=all
|
|
1031
|
+
|
|
1032
|
+
# Disable agent-assisted interview (fallback to classic prompts)
|
|
1033
|
+
create-byan-agent --no-agent-interview
|
|
1034
|
+
|
|
1035
|
+
# Agent-assisted interview provider (auto selection)
|
|
1036
|
+
# Priority: Copilot CLI → Codex CLI → Claude CLI (if available)
|
|
1037
|
+
# Override provider explicitly (if installed):
|
|
1038
|
+
# create-byan-agent --agent-provider=codex
|
|
1028
1039
|
|
|
1029
1040
|
# Full installation without backup
|
|
1030
1041
|
create-byan-agent --mode=full --no-backup
|
package/bin/create-byan-agent.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const path = require('path');
|
|
4
|
-
const { program } = require('commander');
|
|
4
|
+
const { program } = require('commander');
|
|
5
|
+
const { spawnSync, execSync } = require('child_process');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const os = require('os');
|
|
5
8
|
const chalk = require('chalk');
|
|
6
9
|
|
|
7
10
|
// YANSTALLER Modules
|
|
@@ -14,7 +17,7 @@ const wizard = require('../lib/yanstaller/wizard');
|
|
|
14
17
|
const backuper = require('../lib/yanstaller/backuper');
|
|
15
18
|
const logger = require('../lib/utils/logger');
|
|
16
19
|
|
|
17
|
-
const YANSTALLER_VERSION = '1.2.
|
|
20
|
+
const YANSTALLER_VERSION = '1.2.6';
|
|
18
21
|
|
|
19
22
|
function parseList(value) {
|
|
20
23
|
if (!value) return [];
|
|
@@ -36,6 +39,246 @@ function normalizePlatforms(list) {
|
|
|
36
39
|
return list.map(normalizePlatformName).filter(Boolean);
|
|
37
40
|
}
|
|
38
41
|
|
|
42
|
+
function expandAllPlatforms(list) {
|
|
43
|
+
if (list.includes('all')) {
|
|
44
|
+
return ['copilot-cli', 'vscode', 'codex', 'claude-code'];
|
|
45
|
+
}
|
|
46
|
+
return list;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function getCopilotCommand() {
|
|
50
|
+
try {
|
|
51
|
+
execSync('copilot --version', { stdio: 'ignore' });
|
|
52
|
+
return 'copilot';
|
|
53
|
+
} catch {}
|
|
54
|
+
|
|
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;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function getCodexCommand() {
|
|
67
|
+
try {
|
|
68
|
+
execSync('codex --version', { stdio: 'ignore' });
|
|
69
|
+
return 'codex';
|
|
70
|
+
} catch {}
|
|
71
|
+
|
|
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
|
+
}
|
|
82
|
+
|
|
83
|
+
function getClaudeCommand() {
|
|
84
|
+
try {
|
|
85
|
+
execSync('claude --version', { stdio: 'ignore' });
|
|
86
|
+
return 'claude';
|
|
87
|
+
} catch {}
|
|
88
|
+
|
|
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;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
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
|
+
} 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' };
|
|
194
|
+
}
|
|
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' };
|
|
278
|
+
}
|
|
279
|
+
return { data: parsed };
|
|
280
|
+
}
|
|
281
|
+
|
|
39
282
|
// ASCII Art Banner
|
|
40
283
|
const banner = `
|
|
41
284
|
${chalk.blue('╔════════════════════════════════════════════════════════════╗')}
|
|
@@ -111,7 +354,7 @@ async function main(options = {}) {
|
|
|
111
354
|
logger.info(chalk.bold('\nSTEP 3/7: Interview (skipped - silent)\n'));
|
|
112
355
|
|
|
113
356
|
const parsedAgents = parseList(options.agents);
|
|
114
|
-
const parsedPlatforms = normalizePlatforms(parseList(options.platforms));
|
|
357
|
+
const parsedPlatforms = expandAllPlatforms(normalizePlatforms(parseList(options.platforms)));
|
|
115
358
|
|
|
116
359
|
let mode = options.mode || (parsedAgents.length > 0 ? 'custom' : (recommendations.mode || 'minimal'));
|
|
117
360
|
let agents = parsedAgents;
|
|
@@ -148,11 +391,104 @@ async function main(options = {}) {
|
|
|
148
391
|
createBackup: options.backup !== false
|
|
149
392
|
};
|
|
150
393
|
} 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
|
+
|
|
151
486
|
logger.info(chalk.bold('\nSTEP 3/7: Interview\n'));
|
|
152
|
-
const preferredPlatforms = normalizePlatforms(parseList(options.platforms));
|
|
487
|
+
const preferredPlatforms = expandAllPlatforms(normalizePlatforms(parseList(options.platforms)));
|
|
153
488
|
answers = await interviewer.ask(recommendations, {
|
|
154
489
|
detection,
|
|
155
|
-
preferredPlatforms
|
|
490
|
+
preferredPlatforms: agentDefaults ? agentDefaults.platforms : preferredPlatforms,
|
|
491
|
+
defaults: agentDefaults || undefined
|
|
156
492
|
});
|
|
157
493
|
|
|
158
494
|
if (options.backup === false) {
|
|
@@ -238,7 +574,9 @@ program
|
|
|
238
574
|
.version(YANSTALLER_VERSION)
|
|
239
575
|
.option('--silent', 'Silent installation (no prompts)')
|
|
240
576
|
.option('--interactive', 'Force interactive prompts even without TTY')
|
|
241
|
-
.option('--
|
|
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')
|
|
242
580
|
.option('--platforms <platforms>', 'Comma-separated list of platforms (copilot-cli,vscode,claude-code,codex)')
|
|
243
581
|
.option('--mode <mode>', 'Installation mode: recommended, custom, minimal, full')
|
|
244
582
|
.option('--no-backup', 'Skip pre-install backup')
|
|
@@ -53,6 +53,7 @@ function buildDefaultPlatforms(options = {}) {
|
|
|
53
53
|
* @returns {Promise<InterviewResult>}
|
|
54
54
|
*/
|
|
55
55
|
async function ask(recommendation, options = {}) {
|
|
56
|
+
const defaults = options.defaults || {};
|
|
56
57
|
logger.info(chalk.bold('\n🎙️ YANSTALLER Quick Interview\n'));
|
|
57
58
|
logger.info('Just 5-7 questions to personalize your BYAN installation (<5 min)\n');
|
|
58
59
|
|
|
@@ -62,7 +63,7 @@ async function ask(recommendation, options = {}) {
|
|
|
62
63
|
type: 'input',
|
|
63
64
|
name: 'userName',
|
|
64
65
|
message: 'What\'s your name?',
|
|
65
|
-
default: 'Developer',
|
|
66
|
+
default: defaults.userName || 'Developer',
|
|
66
67
|
validate: (input) => input.trim().length > 0 || 'Name cannot be empty'
|
|
67
68
|
}
|
|
68
69
|
]);
|
|
@@ -77,12 +78,13 @@ async function ask(recommendation, options = {}) {
|
|
|
77
78
|
{ name: 'English', value: 'English' },
|
|
78
79
|
{ name: 'Français', value: 'Francais' }
|
|
79
80
|
],
|
|
80
|
-
default: 'English'
|
|
81
|
+
default: (defaults.language === 'Francais' || defaults.language === 'English') ? defaults.language : 'English'
|
|
81
82
|
}
|
|
82
83
|
]);
|
|
83
84
|
|
|
84
85
|
// Q3: Installation mode (with recommendation)
|
|
85
|
-
const recommendedMode = recommendation ? recommendation.mode : 'recommended';
|
|
86
|
+
const recommendedMode = recommendation ? recommendation.mode : 'recommended';
|
|
87
|
+
const defaultMode = defaults.mode || recommendedMode;
|
|
86
88
|
const modeChoices = [
|
|
87
89
|
{
|
|
88
90
|
name: `Recommended - Based on your project (${recommendation ? recommendation.agents.length : 7} agents)`,
|
|
@@ -112,7 +114,7 @@ async function ask(recommendation, options = {}) {
|
|
|
112
114
|
name: 'mode',
|
|
113
115
|
message: 'Installation mode?',
|
|
114
116
|
choices: modeChoices,
|
|
115
|
-
default:
|
|
117
|
+
default: defaultMode
|
|
116
118
|
}
|
|
117
119
|
]);
|
|
118
120
|
|
|
@@ -124,7 +126,7 @@ async function ask(recommendation, options = {}) {
|
|
|
124
126
|
type: 'checkbox',
|
|
125
127
|
name: 'agents',
|
|
126
128
|
message: 'Select agents to install:',
|
|
127
|
-
choices: getAgentChoices(),
|
|
129
|
+
choices: getAgentChoices(defaults.agents),
|
|
128
130
|
pageSize: 15,
|
|
129
131
|
validate: (input) => input.length > 0 || 'Select at least one agent'
|
|
130
132
|
}
|
|
@@ -149,6 +151,7 @@ async function ask(recommendation, options = {}) {
|
|
|
149
151
|
name: 'platforms',
|
|
150
152
|
message: 'Which platforms to install on?',
|
|
151
153
|
choices: [
|
|
154
|
+
{ name: 'All detected platforms', value: '__all_detected__', checked: false },
|
|
152
155
|
{ name: 'GitHub Copilot CLI (.github/agents/)', value: 'copilot-cli', checked: isDefault('copilot-cli', true) },
|
|
153
156
|
{ name: 'VSCode Copilot Extension', value: 'vscode', checked: isDefault('vscode', true) },
|
|
154
157
|
{ name: 'Codex (.codex/prompts/)', value: 'codex', checked: isDefault('codex', false) },
|
|
@@ -157,6 +160,22 @@ async function ask(recommendation, options = {}) {
|
|
|
157
160
|
validate: (input) => input.length > 0 || 'Select at least one platform'
|
|
158
161
|
}
|
|
159
162
|
]);
|
|
163
|
+
|
|
164
|
+
let selectedPlatforms = platformAnswer.platforms;
|
|
165
|
+
if (selectedPlatforms.includes('__all_detected__')) {
|
|
166
|
+
const detected = buildDefaultPlatforms(options);
|
|
167
|
+
selectedPlatforms = detected.length > 0
|
|
168
|
+
? detected
|
|
169
|
+
: ['copilot-cli', 'vscode', 'codex', 'claude-code'];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const isFrench = langAnswer.language === 'Francais';
|
|
173
|
+
const platformSummary = selectedPlatforms.join(', ');
|
|
174
|
+
if (isFrench) {
|
|
175
|
+
logger.info(`Plateformes retenues: ${platformSummary}`);
|
|
176
|
+
} else {
|
|
177
|
+
logger.info(`Selected platforms: ${platformSummary}`);
|
|
178
|
+
}
|
|
160
179
|
|
|
161
180
|
// Q6: Create sample agent
|
|
162
181
|
const sampleAnswer = await inquirer.prompt([
|
|
@@ -164,7 +183,7 @@ async function ask(recommendation, options = {}) {
|
|
|
164
183
|
type: 'confirm',
|
|
165
184
|
name: 'createSample',
|
|
166
185
|
message: 'Launch BYAN agent creator after installation?',
|
|
167
|
-
default: false
|
|
186
|
+
default: typeof defaults.createSampleAgent === 'boolean' ? defaults.createSampleAgent : false
|
|
168
187
|
}
|
|
169
188
|
]);
|
|
170
189
|
|
|
@@ -174,22 +193,22 @@ async function ask(recommendation, options = {}) {
|
|
|
174
193
|
type: 'confirm',
|
|
175
194
|
name: 'createBackup',
|
|
176
195
|
message: 'Create backup of existing _bmad/ directory? (if exists)',
|
|
177
|
-
default: true
|
|
196
|
+
default: typeof defaults.createBackup === 'boolean' ? defaults.createBackup : true
|
|
178
197
|
}
|
|
179
198
|
]);
|
|
180
199
|
|
|
181
200
|
logger.info('');
|
|
182
201
|
|
|
183
|
-
return {
|
|
184
|
-
userName: nameAnswer.userName,
|
|
185
|
-
language: langAnswer.language,
|
|
186
|
-
mode: modeAnswer.mode,
|
|
187
|
-
agents: selectedAgents,
|
|
188
|
-
targetPlatforms:
|
|
189
|
-
createSampleAgent: sampleAnswer.createSample,
|
|
190
|
-
createBackup: backupAnswer.createBackup
|
|
191
|
-
};
|
|
192
|
-
}
|
|
202
|
+
return {
|
|
203
|
+
userName: nameAnswer.userName,
|
|
204
|
+
language: langAnswer.language,
|
|
205
|
+
mode: modeAnswer.mode,
|
|
206
|
+
agents: selectedAgents,
|
|
207
|
+
targetPlatforms: selectedPlatforms,
|
|
208
|
+
createSampleAgent: sampleAnswer.createSample,
|
|
209
|
+
createBackup: backupAnswer.createBackup
|
|
210
|
+
};
|
|
211
|
+
}
|
|
193
212
|
|
|
194
213
|
/**
|
|
195
214
|
* Ask single question
|
|
@@ -218,54 +237,58 @@ async function askQuestion(question, type, choices = []) {
|
|
|
218
237
|
*
|
|
219
238
|
* @returns {Array<{name: string, value: string, checked: boolean}>}
|
|
220
239
|
*/
|
|
221
|
-
function getAgentChoices() {
|
|
222
|
-
|
|
223
|
-
// BMB Module - Builders
|
|
224
|
-
{ name: '
|
|
225
|
-
{ name: '
|
|
226
|
-
{ name: '
|
|
227
|
-
{ name: '
|
|
228
|
-
{ name: '
|
|
229
|
-
|
|
230
|
-
// BMM Module - Development Team
|
|
231
|
-
{ name: '
|
|
232
|
-
{ name: '
|
|
233
|
-
{ name: '
|
|
234
|
-
{ name: '
|
|
235
|
-
{ name: '
|
|
236
|
-
{ name: '
|
|
237
|
-
{ name: '
|
|
238
|
-
{ name: '
|
|
239
|
-
|
|
240
|
-
// TEA Module - Testing
|
|
241
|
-
{ name: '
|
|
242
|
-
|
|
243
|
-
// CIS Module - Innovation
|
|
244
|
-
{ name: '
|
|
245
|
-
{ name: '
|
|
246
|
-
{ name: '
|
|
247
|
-
{ name: '
|
|
248
|
-
{ name: '
|
|
249
|
-
{ name: '
|
|
250
|
-
|
|
251
|
-
// Core Module
|
|
252
|
-
{ name: '
|
|
253
|
-
{ name: '
|
|
254
|
-
|
|
255
|
-
// Specialized
|
|
256
|
-
{ name: '
|
|
257
|
-
{ name: '
|
|
258
|
-
|
|
259
|
-
// Quick Flow Variants
|
|
260
|
-
{ name: '
|
|
261
|
-
];
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
240
|
+
function getAgentChoices(checkedAgents = []) {
|
|
241
|
+
const choices = [
|
|
242
|
+
// BMB Module - Builders
|
|
243
|
+
{ name: 'BYAN - Agent Creator & Intelligent Interview', value: 'byan', checked: true },
|
|
244
|
+
{ name: 'RACHID - NPM/NPX Deployment Specialist', value: 'rachid', checked: true },
|
|
245
|
+
{ name: 'Agent Builder - Direct agent creation', value: 'agent-builder', checked: false },
|
|
246
|
+
{ name: 'Module Builder - Module scaffolding', value: 'module-builder', checked: false },
|
|
247
|
+
{ name: 'Workflow Builder - Workflow creation', value: 'workflow-builder', checked: false },
|
|
248
|
+
|
|
249
|
+
// BMM Module - Development Team
|
|
250
|
+
{ name: 'MARY (Analyst) - Requirements & Domain Expert', value: 'analyst', checked: false },
|
|
251
|
+
{ name: 'JOHN (PM) - Product Management', value: 'pm', checked: false },
|
|
252
|
+
{ name: 'WINSTON (Architect) - System Architecture', value: 'architect', checked: false },
|
|
253
|
+
{ name: 'AMELIA (Dev) - Implementation Specialist', value: 'dev', checked: true },
|
|
254
|
+
{ name: 'BOB (SM) - Scrum Master', value: 'sm', checked: false },
|
|
255
|
+
{ name: 'QUINN (QA) - Quality Assurance', value: 'quinn', checked: false },
|
|
256
|
+
{ name: 'SALLY (UX) - UX/UI Design', value: 'ux-designer', checked: false },
|
|
257
|
+
{ name: 'PAIGE (Tech Writer) - Documentation', value: 'tech-writer', checked: true },
|
|
258
|
+
|
|
259
|
+
// TEA Module - Testing
|
|
260
|
+
{ name: 'MURAT (TEA) - Test Architecture Expert', value: 'tea', checked: false },
|
|
261
|
+
|
|
262
|
+
// CIS Module - Innovation
|
|
263
|
+
{ name: 'CARSON - Brainstorming Coach', value: 'brainstorming-coach', checked: false },
|
|
264
|
+
{ name: 'DR. QUINN - Design Thinking Coach', value: 'design-thinking-coach', checked: false },
|
|
265
|
+
{ name: 'MAYA - Creative Problem Solver', value: 'creative-problem-solver', checked: false },
|
|
266
|
+
{ name: 'VICTOR - Innovation Strategist', value: 'innovation-strategist', checked: false },
|
|
267
|
+
{ name: 'Presentation Master', value: 'presentation-master', checked: false },
|
|
268
|
+
{ name: 'Storyteller', value: 'storyteller', checked: false },
|
|
269
|
+
|
|
270
|
+
// Core Module
|
|
271
|
+
{ name: 'Party Mode - Multi-agent orchestration', value: 'party-mode', checked: false },
|
|
272
|
+
{ name: 'BMAD Master - Platform orchestrator', value: 'bmad-master', checked: false },
|
|
273
|
+
|
|
274
|
+
// Specialized
|
|
275
|
+
{ name: 'MARC - GitHub Copilot CLI Integration', value: 'marc', checked: false },
|
|
276
|
+
{ name: 'PATNOTE - Update Manager', value: 'patnote', checked: false },
|
|
277
|
+
|
|
278
|
+
// Quick Flow Variants
|
|
279
|
+
{ name: 'Quick Flow Solo Dev', value: 'quick-flow-solo-dev', checked: false }
|
|
280
|
+
];
|
|
281
|
+
|
|
282
|
+
if (Array.isArray(checkedAgents) && checkedAgents.length > 0) {
|
|
283
|
+
return choices.map(choice => ({
|
|
284
|
+
...choice,
|
|
285
|
+
checked: checkedAgents.includes(choice.value)
|
|
286
|
+
}));
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return choices;
|
|
290
|
+
}
|
|
291
|
+
|
|
269
292
|
function getAllAgents() {
|
|
270
293
|
return getAgentChoices().map(choice => choice.value);
|
|
271
294
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-byan-agent",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.6",
|
|
4
4
|
"description": "NPX installer for BYAN ecosystem - Agent creators (BYAN, BYAN-Test) with deployment (RACHID), integration (MARC), updates (PATNOTE), and optimization (CARMACK)",
|
|
5
5
|
"bin": {
|
|
6
6
|
"create-byan-agent": "bin/create-byan-agent.js"
|