create-byan-agent 2.7.1 → 2.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Generate project-agents.md from Phase 2 analysis results
3
+ * Creates a structured document describing the agent ecosystem for the project
4
+ */
5
+
6
+ const fs = require('fs-extra');
7
+ const path = require('path');
8
+
9
+ /**
10
+ * Generate the project-agents.md file
11
+ * @param {Object} phase2Results - JSON from yanstaller-phase2 agent
12
+ * @param {Object} genericAnswers - Q1-Q10 answers
13
+ * @param {Object} domainAnswers - Domain-specific answers
14
+ * @param {string} outputDir - Directory to write the file
15
+ * @returns {string} Path to generated file
16
+ */
17
+ async function generateProjectAgentsDoc(phase2Results, genericAnswers, domainAnswers, outputDir) {
18
+ const lines = [];
19
+
20
+ // Header
21
+ lines.push('# Project Agents Configuration');
22
+ lines.push('');
23
+ lines.push('> Generated by BYAN Yanstaller - Intelligent Interview');
24
+ lines.push(`> Date: ${new Date().toISOString().split('T')[0]}`);
25
+ lines.push('');
26
+
27
+ // Project Overview
28
+ lines.push('## Project Overview');
29
+ lines.push('');
30
+ lines.push(`- **Type**: ${genericAnswers.projectType}`);
31
+ lines.push(`- **Domain**: ${genericAnswers.domain}`);
32
+ lines.push(`- **Team Size**: ${genericAnswers.teamSize}`);
33
+ lines.push(`- **Methodology**: ${genericAnswers.methodology}`);
34
+ lines.push(`- **Quality Level**: ${genericAnswers.quality}`);
35
+ lines.push('');
36
+
37
+ // Domain Details
38
+ if (Object.keys(domainAnswers).length > 0) {
39
+ lines.push('### Tech Stack');
40
+ lines.push('');
41
+ for (const [key, value] of Object.entries(domainAnswers)) {
42
+ lines.push(`- **${formatKey(key)}**: ${value}`);
43
+ }
44
+ lines.push('');
45
+ }
46
+
47
+ // Core Agents
48
+ if (phase2Results.coreAgents && phase2Results.coreAgents.length > 0) {
49
+ lines.push('## Core Agents');
50
+ lines.push('');
51
+ lines.push('These agents are essential for your project workflow.');
52
+ lines.push('');
53
+
54
+ for (const agent of phase2Results.coreAgents) {
55
+ lines.push(`### ${formatAgentName(agent.name)}`);
56
+ lines.push('');
57
+ lines.push(`**Role**: ${agent.role}`);
58
+ lines.push('');
59
+ lines.push(`**Expertise**: ${agent.expertise.join(', ')}`);
60
+ lines.push('');
61
+ lines.push(`**Complexity**: ${getComplexityBadge(agent.complexity)}`);
62
+ lines.push('');
63
+ }
64
+ }
65
+
66
+ // Optional Agents
67
+ if (phase2Results.optionalAgents && phase2Results.optionalAgents.length > 0) {
68
+ lines.push('## Optional Agents');
69
+ lines.push('');
70
+ lines.push('Activate these agents when specific conditions are met.');
71
+ lines.push('');
72
+
73
+ for (const agent of phase2Results.optionalAgents) {
74
+ lines.push(`### ${formatAgentName(agent.name)}`);
75
+ lines.push('');
76
+ lines.push(`**Role**: ${agent.role}`);
77
+ lines.push('');
78
+ lines.push(`**When to use**: ${agent.when || 'As needed'}`);
79
+ lines.push('');
80
+ }
81
+ }
82
+
83
+ // Agent Relationships
84
+ if (phase2Results.agentRelationships && phase2Results.agentRelationships.length > 0) {
85
+ lines.push('## Agent Relationships');
86
+ lines.push('');
87
+ lines.push('```mermaid');
88
+ lines.push('graph LR');
89
+
90
+ for (const rel of phase2Results.agentRelationships) {
91
+ const arrow = getRelationshipArrow(rel.type);
92
+ lines.push(` ${rel.from}${arrow}${rel.to}`);
93
+ }
94
+
95
+ lines.push('```');
96
+ lines.push('');
97
+ lines.push('### Relationship Details');
98
+ lines.push('');
99
+ lines.push('| From | To | Type | Description |');
100
+ lines.push('|------|-----|------|-------------|');
101
+
102
+ for (const rel of phase2Results.agentRelationships) {
103
+ lines.push(`| ${rel.from} | ${rel.to} | ${rel.type} | ${rel.description || '-'} |`);
104
+ }
105
+ lines.push('');
106
+ }
107
+
108
+ // Project Structure
109
+ if (phase2Results.projectStructure) {
110
+ lines.push('## Project Structure');
111
+ lines.push('');
112
+ lines.push(`**Architecture**: ${phase2Results.projectStructure.type}`);
113
+ lines.push('');
114
+
115
+ if (phase2Results.projectStructure.folders) {
116
+ lines.push('### Recommended Folders');
117
+ lines.push('');
118
+ lines.push('```');
119
+ for (const folder of phase2Results.projectStructure.folders) {
120
+ lines.push(folder);
121
+ }
122
+ lines.push('```');
123
+ lines.push('');
124
+ }
125
+
126
+ if (phase2Results.projectStructure.keyFiles) {
127
+ lines.push('### Key Files');
128
+ lines.push('');
129
+ for (const file of phase2Results.projectStructure.keyFiles) {
130
+ lines.push(`- \`${file}\``);
131
+ }
132
+ lines.push('');
133
+ }
134
+ }
135
+
136
+ // Custom Agents to Create
137
+ if (phase2Results.customAgentsToCreate && phase2Results.customAgentsToCreate.length > 0) {
138
+ lines.push('## Custom Agents to Create');
139
+ lines.push('');
140
+ lines.push('These specialized agents will be generated for your project.');
141
+ lines.push('');
142
+
143
+ for (const agent of phase2Results.customAgentsToCreate) {
144
+ lines.push(`### ${formatAgentName(agent.name)}`);
145
+ lines.push('');
146
+ lines.push(`**Based on**: ${agent.template} template`);
147
+ lines.push('');
148
+ lines.push(`**Focus**: ${agent.focus}`);
149
+ lines.push('');
150
+ if (agent.mantras && agent.mantras.length > 0) {
151
+ lines.push('**Key Mantras**:');
152
+ for (const mantra of agent.mantras) {
153
+ lines.push(`- ${mantra}`);
154
+ }
155
+ lines.push('');
156
+ }
157
+ }
158
+ }
159
+
160
+ // Configuration
161
+ lines.push('## Configuration');
162
+ lines.push('');
163
+ lines.push(`**Recommended Model**: \`${phase2Results.recommendedModel || 'gpt-5-mini'}\``);
164
+ lines.push('');
165
+ if (phase2Results.rationale) {
166
+ lines.push('### Rationale');
167
+ lines.push('');
168
+ lines.push(phase2Results.rationale);
169
+ lines.push('');
170
+ }
171
+
172
+ // Usage Instructions
173
+ lines.push('## Usage');
174
+ lines.push('');
175
+ lines.push('### Activate Core Agents');
176
+ lines.push('');
177
+ lines.push('```bash');
178
+ lines.push('copilot');
179
+ lines.push('# Then type: /agent');
180
+ lines.push('# Select the agent you need');
181
+ lines.push('```');
182
+ lines.push('');
183
+ lines.push('### Create Custom Agents');
184
+ lines.push('');
185
+ lines.push('```bash');
186
+ lines.push('copilot --agent=byan');
187
+ lines.push('# Select: 1. Create New Agent');
188
+ lines.push('# Follow the interview process');
189
+ lines.push('```');
190
+ lines.push('');
191
+
192
+ // Write file
193
+ const content = lines.join('\n');
194
+ const filePath = path.join(outputDir, 'project-agents.md');
195
+ await fs.ensureDir(outputDir);
196
+ await fs.writeFile(filePath, content, 'utf8');
197
+
198
+ return filePath;
199
+ }
200
+
201
+ // Helper functions
202
+
203
+ function formatKey(key) {
204
+ return key
205
+ .replace(/([A-Z])/g, ' $1')
206
+ .replace(/^./, str => str.toUpperCase())
207
+ .trim();
208
+ }
209
+
210
+ function formatAgentName(name) {
211
+ return name
212
+ .split('-')
213
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
214
+ .join(' ');
215
+ }
216
+
217
+ function getComplexityBadge(complexity) {
218
+ switch (complexity) {
219
+ case 'simple': return '🟢 Simple (1-2 mantras)';
220
+ case 'medium': return '🟡 Medium (3-5 mantras)';
221
+ case 'complex': return '🔴 Complex (6+ mantras)';
222
+ default: return '⚪ Unknown';
223
+ }
224
+ }
225
+
226
+ function getRelationshipArrow(type) {
227
+ switch (type) {
228
+ case 'triggers': return ' -->|triggers| ';
229
+ case 'blocks': return ' -.->|blocks| ';
230
+ case 'informs': return ' -->|informs| ';
231
+ case 'depends': return ' ==>|depends| ';
232
+ default: return ' --> ';
233
+ }
234
+ }
235
+
236
+ module.exports = {
237
+ generateProjectAgentsDoc
238
+ };
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Config Loader Utility
3
+ *
4
+ * Loads configuration files with variable resolution.
5
+ *
6
+ * @module utils/config-loader
7
+ */
8
+
9
+ const path = require('path');
10
+ const yamlUtils = require('./yaml-utils');
11
+
12
+ /**
13
+ * Load config file and resolve variables
14
+ *
15
+ * @param {string} configPath - Path to config.yaml
16
+ * @param {Object} context - Context for variable resolution
17
+ * @returns {Promise<Object>}
18
+ */
19
+ async function loadConfig(configPath, context = {}) {
20
+ const config = await yamlUtils.readYAML(configPath);
21
+ return resolveVariables(config, context);
22
+ }
23
+
24
+ /**
25
+ * Resolve variables in config object
26
+ *
27
+ * @param {Object} config - Config object
28
+ * @param {Object} context - Context for variable resolution
29
+ * @returns {Object}
30
+ */
31
+ function resolveVariables(config, context) {
32
+ const resolved = {};
33
+
34
+ for (const [key, value] of Object.entries(config)) {
35
+ if (typeof value === 'string') {
36
+ resolved[key] = resolveVariable(value, context);
37
+ } else if (typeof value === 'object' && value !== null) {
38
+ resolved[key] = resolveVariables(value, context);
39
+ } else {
40
+ resolved[key] = value;
41
+ }
42
+ }
43
+
44
+ return resolved;
45
+ }
46
+
47
+ /**
48
+ * Resolve single variable string
49
+ *
50
+ * @param {string} value - Value with potential variables
51
+ * @param {Object} context - Context for variable resolution
52
+ * @returns {string}
53
+ */
54
+ function resolveVariable(value, context) {
55
+ let resolved = value;
56
+
57
+ // Replace {project-root}
58
+ if (context.projectRoot) {
59
+ resolved = resolved.replace(/\{project-root\}/g, context.projectRoot);
60
+ }
61
+
62
+ // Replace {output_folder}
63
+ if (context.outputFolder) {
64
+ resolved = resolved.replace(/\{output_folder\}/g, context.outputFolder);
65
+ }
66
+
67
+ // Replace {user_name}
68
+ if (context.userName) {
69
+ resolved = resolved.replace(/\{user_name\}/g, context.userName);
70
+ }
71
+
72
+ return resolved;
73
+ }
74
+
75
+ module.exports = {
76
+ loadConfig,
77
+ resolveVariables,
78
+ resolveVariable
79
+ };
@@ -0,0 +1,104 @@
1
+ /**
2
+ * File Utilities
3
+ *
4
+ * Wrapper around fs-extra for common file operations.
5
+ *
6
+ * @module utils/file-utils
7
+ */
8
+
9
+ const fs = require('fs-extra');
10
+ const path = require('path');
11
+
12
+ /**
13
+ * Copy file or directory
14
+ *
15
+ * @param {string} src - Source path
16
+ * @param {string} dest - Destination path
17
+ * @returns {Promise<void>}
18
+ */
19
+ async function copy(src, dest) {
20
+ await fs.copy(src, dest);
21
+ }
22
+
23
+ /**
24
+ * Check if path exists
25
+ *
26
+ * @param {string} filePath - File or directory path
27
+ * @returns {Promise<boolean>}
28
+ */
29
+ async function exists(filePath) {
30
+ return fs.pathExists(filePath);
31
+ }
32
+
33
+ /**
34
+ * Ensure directory exists (create if not)
35
+ *
36
+ * @param {string} dirPath - Directory path
37
+ * @returns {Promise<void>}
38
+ */
39
+ async function ensureDir(dirPath) {
40
+ await fs.ensureDir(dirPath);
41
+ }
42
+
43
+ /**
44
+ * Remove file or directory
45
+ *
46
+ * @param {string} filePath - File or directory path
47
+ * @returns {Promise<void>}
48
+ */
49
+ async function remove(filePath) {
50
+ await fs.remove(filePath);
51
+ }
52
+
53
+ /**
54
+ * Read JSON file
55
+ *
56
+ * @param {string} filePath - JSON file path
57
+ * @returns {Promise<Object>}
58
+ */
59
+ async function readJSON(filePath) {
60
+ return fs.readJSON(filePath);
61
+ }
62
+
63
+ /**
64
+ * Write JSON file
65
+ *
66
+ * @param {string} filePath - JSON file path
67
+ * @param {Object} data - Data to write
68
+ * @returns {Promise<void>}
69
+ */
70
+ async function writeJSON(filePath, data) {
71
+ await fs.writeJSON(filePath, data, { spaces: 2 });
72
+ }
73
+
74
+ /**
75
+ * Read text file
76
+ *
77
+ * @param {string} filePath - Text file path
78
+ * @returns {Promise<string>}
79
+ */
80
+ async function readFile(filePath) {
81
+ return fs.readFile(filePath, 'utf8');
82
+ }
83
+
84
+ /**
85
+ * Write text file
86
+ *
87
+ * @param {string} filePath - Text file path
88
+ * @param {string} content - Content to write
89
+ * @returns {Promise<void>}
90
+ */
91
+ async function writeFile(filePath, content) {
92
+ await fs.writeFile(filePath, content, 'utf8');
93
+ }
94
+
95
+ module.exports = {
96
+ copy,
97
+ exists,
98
+ ensureDir,
99
+ remove,
100
+ readJSON,
101
+ writeJSON,
102
+ readFile,
103
+ writeFile
104
+ };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Git Detector Utility
3
+ *
4
+ * Detects if Git is installed.
5
+ *
6
+ * @module utils/git-detector
7
+ */
8
+
9
+ const { execSync } = require('child_process');
10
+
11
+ /**
12
+ * Detect if Git is installed
13
+ *
14
+ * @returns {Promise<{installed: boolean, version: string | null}>}
15
+ */
16
+ async function detect() {
17
+ try {
18
+ const version = execSync('git --version', { encoding: 'utf8' }).trim();
19
+ const versionMatch = version.match(/git version ([\d.]+)/);
20
+
21
+ return {
22
+ installed: true,
23
+ version: versionMatch ? versionMatch[1] : null
24
+ };
25
+ } catch {
26
+ return {
27
+ installed: false,
28
+ version: null
29
+ };
30
+ }
31
+ }
32
+
33
+ module.exports = {
34
+ detect
35
+ };
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Logger Utility
3
+ *
4
+ * Wrapper around chalk and console for colored logging.
5
+ *
6
+ * @module utils/logger
7
+ */
8
+
9
+ const chalk = require('chalk');
10
+
11
+ /**
12
+ * Log info message
13
+ *
14
+ * @param {string} message - Message to log
15
+ */
16
+ function info(message) {
17
+ console.log(chalk.blue('ℹ'), message);
18
+ }
19
+
20
+ /**
21
+ * Log success message
22
+ *
23
+ * @param {string} message - Message to log
24
+ */
25
+ function success(message) {
26
+ console.log(chalk.green('✓'), message);
27
+ }
28
+
29
+ /**
30
+ * Log warning message
31
+ *
32
+ * @param {string} message - Message to log
33
+ */
34
+ function warn(message) {
35
+ console.log(chalk.yellow('⚠'), message);
36
+ }
37
+
38
+ /**
39
+ * Log error message
40
+ *
41
+ * @param {string} message - Message to log
42
+ */
43
+ function error(message) {
44
+ console.error(chalk.red('✖'), message);
45
+ }
46
+
47
+ /**
48
+ * Log debug message (only if DEBUG env var set)
49
+ *
50
+ * @param {string} message - Message to log
51
+ */
52
+ function debug(message) {
53
+ if (process.env.DEBUG) {
54
+ console.log(chalk.gray('[DEBUG]'), message);
55
+ }
56
+ }
57
+
58
+ module.exports = {
59
+ info,
60
+ success,
61
+ warn,
62
+ error,
63
+ debug
64
+ };
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Node.js Detector Utility
3
+ *
4
+ * Detects Node.js version.
5
+ *
6
+ * @module utils/node-detector
7
+ */
8
+
9
+ /**
10
+ * Detect Node.js version
11
+ *
12
+ * @returns {string} - Version string (e.g., '18.19.0')
13
+ */
14
+ function detect() {
15
+ return process.version.slice(1); // Remove 'v' prefix
16
+ }
17
+
18
+ /**
19
+ * Compare two semver versions
20
+ *
21
+ * Strips version suffixes (-beta, -rc1, etc.) before comparison.
22
+ *
23
+ * @param {string} version1 - First version
24
+ * @param {string} version2 - Second version
25
+ * @returns {number} - -1 if v1 < v2, 0 if equal, 1 if v1 > v2
26
+ */
27
+ function compareVersions(version1, version2) {
28
+ // Strip suffixes: '18.0.0-beta' → '18.0.0'
29
+ const cleanV1 = version1.replace(/-.*$/, '');
30
+ const cleanV2 = version2.replace(/-.*$/, '');
31
+
32
+ const v1Parts = cleanV1.split('.').map(Number);
33
+ const v2Parts = cleanV2.split('.').map(Number);
34
+
35
+ for (let i = 0; i < 3; i++) {
36
+ if (v1Parts[i] > v2Parts[i]) return 1;
37
+ if (v1Parts[i] < v2Parts[i]) return -1;
38
+ }
39
+
40
+ return 0;
41
+ }
42
+
43
+ /**
44
+ * Check if Node version meets minimum requirement
45
+ *
46
+ * @param {string} currentVersion - Current Node version
47
+ * @param {string} requiredVersion - Required Node version
48
+ * @returns {boolean}
49
+ */
50
+ function meetsRequirement(currentVersion, requiredVersion) {
51
+ return compareVersions(currentVersion, requiredVersion) >= 0;
52
+ }
53
+
54
+ module.exports = {
55
+ detect,
56
+ compareVersions,
57
+ meetsRequirement
58
+ };
@@ -0,0 +1,74 @@
1
+ /**
2
+ * OS Detector Utility
3
+ *
4
+ * Detects operating system and version.
5
+ *
6
+ * @module utils/os-detector
7
+ */
8
+
9
+ const os = require('os');
10
+
11
+ /**
12
+ * Detect operating system
13
+ *
14
+ * @returns {{name: string, version: string, platform: string}}
15
+ */
16
+ function detect() {
17
+ const platform = os.platform();
18
+ const release = os.release();
19
+
20
+ let name;
21
+ switch (platform) {
22
+ case 'win32':
23
+ name = 'windows';
24
+ break;
25
+ case 'darwin':
26
+ name = 'macos';
27
+ break;
28
+ case 'linux':
29
+ name = 'linux';
30
+ break;
31
+ default:
32
+ name = 'unknown';
33
+ }
34
+
35
+ return {
36
+ name,
37
+ version: release,
38
+ platform
39
+ };
40
+ }
41
+
42
+ /**
43
+ * Check if running on Windows
44
+ *
45
+ * @returns {boolean}
46
+ */
47
+ function isWindows() {
48
+ return os.platform() === 'win32';
49
+ }
50
+
51
+ /**
52
+ * Check if running on macOS
53
+ *
54
+ * @returns {boolean}
55
+ */
56
+ function isMacOS() {
57
+ return os.platform() === 'darwin';
58
+ }
59
+
60
+ /**
61
+ * Check if running on Linux
62
+ *
63
+ * @returns {boolean}
64
+ */
65
+ function isLinux() {
66
+ return os.platform() === 'linux';
67
+ }
68
+
69
+ module.exports = {
70
+ detect,
71
+ isWindows,
72
+ isMacOS,
73
+ isLinux
74
+ };