@clfhhc/bmad-methods-skills 0.0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 David Chen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # BMAD-Methods-Skills
2
+
3
+ Automatically convert BMAD-METHOD agents and workflows to Claude Skills format.
4
+
5
+ ## Distribution (New Projects)
6
+
7
+ To install the BMAD bootstrap skill into a new project, you can use `npx`:
8
+
9
+ ```bash
10
+ npx @clfhhc/bmad-methods-skills init
11
+ ```
12
+
13
+ This will:
14
+ 1. Detect your AI tool (.agent, .cursor, or .claude)
15
+ 2. Install the `bootstrap-bmad-skills` and `enhance-bmad-skills` into your project
16
+ 3. Enable the `BS` command to fetch and install all other BMAD skills via `npx`
17
+
18
+ ## Documentation
19
+
20
+ For full documentation on development, manual usage, and technical details, please see:
21
+
22
+ - **[Getting Started](docs/getting-started.md)**: Installation, Usage, and Configuration
23
+ - **[Technical Reference](docs/technical-reference.md)**: Output structure and conversion details
24
+ - **[Development](docs/development.md)**: Project structure, contributing, and troubleshooting
25
+
26
+ ## License
27
+
28
+ MIT License - see [LICENSE](LICENSE) file for details.
29
+
30
+ ## Credits
31
+
32
+ - **BMAD-METHOD**: Created by [BMAD Code Organization](https://github.com/bmad-code-org/BMAD-METHOD)
33
+ - **Claude Skills**: Format by [Anthropic](https://github.com/anthropics/skills)
34
+
35
+ ## Contributing
36
+
37
+ Contributions welcome! Please:
38
+
39
+ 1. Fork the repository
40
+ 2. Create a feature branch
41
+ 3. Make your changes
42
+ 4. Test thoroughly
43
+ 5. Submit a pull request
44
+
45
+ ## Related Projects
46
+
47
+ - [BMAD-METHOD](https://github.com/bmad-code-org/BMAD-METHOD) - Original BMAD methodology
48
+ - [Claude Skills](https://github.com/anthropics/skills) - Claude Skills specification and examples
@@ -0,0 +1,217 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'fs-extra';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import readline from 'node:readline';
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+ const pkgRoot = path.resolve(__dirname, '../');
11
+
12
+ async function run() {
13
+ const args = process.argv.slice(2);
14
+ const command = args[0];
15
+
16
+ if (command === 'init') {
17
+ await init(args);
18
+ } else if (command === 'install') {
19
+ await install(args);
20
+ } else if (command === '--help' || command === '-h' || args.includes('--help') || args.includes('-h')) {
21
+ printHelp();
22
+ } else {
23
+ // Proxy to convert.js logic
24
+ await import('../convert.js');
25
+ }
26
+ }
27
+
28
+
29
+
30
+ /**
31
+ * Install specific skills from a source directory to the project's skill directory
32
+ */
33
+ async function install(args) {
34
+ const sourceArg = args.find(a => a.startsWith('--from='))?.split('=')[1];
35
+ const force = args.includes('--force');
36
+
37
+ if (!sourceArg) {
38
+ console.error('āŒ Missing required argument: --from=<path>');
39
+ return;
40
+ }
41
+
42
+ const sourcePath = path.resolve(process.cwd(), sourceArg);
43
+ if (!(await fs.pathExists(sourcePath))) {
44
+ console.error(`āŒ Source path does not exist: ${sourcePath}`);
45
+ return;
46
+ }
47
+
48
+ // Detect tool
49
+ const toolInfo = await detectTool(args);
50
+ if (!toolInfo) return;
51
+
52
+ console.log(`šŸ“¦ Installation Target: ${toolInfo.name} (${toolInfo.path})`);
53
+ console.log(`šŸ“‚ Source: ${sourcePath}`);
54
+
55
+ // Get skills from source
56
+ const skills = await fs.readdir(sourcePath);
57
+ const validSkills = [];
58
+
59
+ for (const skill of skills) {
60
+ if ((await fs.stat(path.join(sourcePath, skill))).isDirectory()) {
61
+ validSkills.push(skill);
62
+ }
63
+ }
64
+
65
+ if (validSkills.length === 0) {
66
+ console.warn('āš ļø No skill directories found in source.');
67
+ return;
68
+ }
69
+
70
+ console.log(`\nFound ${validSkills.length} skills to install.`);
71
+
72
+ // Install
73
+ for (const skillName of validSkills) {
74
+ await installSkill(
75
+ skillName,
76
+ path.join(sourcePath, skillName),
77
+ path.join(process.cwd(), toolInfo.path, skillName),
78
+ force
79
+ );
80
+ }
81
+
82
+ console.log(`\nāœ… Installation complete.`);
83
+ }
84
+
85
+ async function init(args) {
86
+ console.log('šŸš€ BMAD Skills Installer\n');
87
+
88
+ const toolInfo = await detectTool(args);
89
+ if (!toolInfo) return;
90
+
91
+ console.log(`šŸ“¦ Installing Bootstrap Skills for ${toolInfo.name}...`);
92
+
93
+ // Dynamically find skills in package
94
+ const skillsDir = path.join(pkgRoot, 'skills');
95
+ if (!(await fs.pathExists(skillsDir))) {
96
+ console.error('āŒ Critical Error: Package skills directory not found.');
97
+ return;
98
+ }
99
+
100
+ const skills = await fs.readdir(skillsDir);
101
+ const skillsToInstall = [];
102
+
103
+ for (const skill of skills) {
104
+ // Only install directories as skills
105
+ if ((await fs.stat(path.join(skillsDir, skill))).isDirectory()) {
106
+ skillsToInstall.push(skill);
107
+ }
108
+ }
109
+
110
+ if (skillsToInstall.length === 0) {
111
+ console.warn('āš ļø No skills found in package to install.');
112
+ return;
113
+ }
114
+
115
+ const force = args.includes('--force');
116
+
117
+ try {
118
+ for (const skillName of skillsToInstall) {
119
+ const sourceDir = path.join(skillsDir, skillName);
120
+ const targetDir = path.resolve(process.cwd(), toolInfo.path, skillName);
121
+
122
+ await installSkill(skillName, sourceDir, targetDir, force);
123
+ }
124
+
125
+ console.log(`\nāœ… Successfully initialized in: ${toolInfo.path}/`);
126
+ console.log('\nNext steps:');
127
+ console.log(`1. Open your AI chat (${toolInfo.name}).`);
128
+ console.log('2. Type "BS" or "bootstrap-skills" to fetch and install the full BMAD method suite.');
129
+ } catch (error) {
130
+ console.error(`\nāŒ Installation failed: ${error.message}`);
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Helpher to copy skill with checks
136
+ */
137
+ async function installSkill(name, source, target, force) {
138
+ if (await fs.pathExists(target)) {
139
+ if (!force) {
140
+ console.warn(` ⚠ Skill '${name}' already exists. Skipping.`);
141
+ console.warn(' (Use --force to overwrite)');
142
+ return;
143
+ }
144
+ console.log(` ↻ Updating ${name}...`);
145
+ } else {
146
+ console.log(` + Installing ${name}...`);
147
+ }
148
+
149
+ await fs.ensureDir(path.dirname(target));
150
+ await fs.copy(source, target, { overwrite: true });
151
+ }
152
+
153
+ /**
154
+ * Helper to detect AI tool
155
+ */
156
+ async function detectTool(args) {
157
+ const toolArg = args.find(a => a.startsWith('--tool='))?.split('=')[1];
158
+ const force = args.includes('--force');
159
+
160
+ const tools = [
161
+ { name: 'Antigravity', path: '.agent/skills', active: await fs.pathExists('.agent') },
162
+ { name: 'Cursor', path: '.cursor/skills', active: await fs.pathExists('.cursor') },
163
+ { name: 'Claude Code (Local)', path: '.claude/skills', active: await fs.pathExists('.claude') },
164
+ ];
165
+
166
+ let selectedTool = tools.find(t => t.active);
167
+
168
+ if (toolArg) {
169
+ selectedTool = tools.find(t => t.name.toLowerCase().includes(toolArg.toLowerCase()));
170
+ }
171
+
172
+ if (!selectedTool) {
173
+ if (force) {
174
+ // Default to antigravity if forced and not found
175
+ return tools[0];
176
+ }
177
+
178
+ console.log('āŒ No AI tool directory detected (.agent, .cursor, .claude).');
179
+ console.log(' Use --tool=<name> to force installation or ensure you are in the project root.');
180
+ console.log(' Available tools: antigravity, cursor, claude');
181
+ return null;
182
+ }
183
+
184
+ return selectedTool;
185
+ }
186
+
187
+ function printHelp() {
188
+ console.log(`
189
+ Usage: npx @clfhhc/bmad-methods-skills [command] [options]
190
+
191
+ Commands:
192
+ init Install bootstrap skills into the current project
193
+ install Install skills from a local directory
194
+ [no command] Run the BMAD-to-Skills converter (proxy to convert.js)
195
+
196
+ Options (for init/install):
197
+ --tool=<name> Specify tool (antigravity, cursor, claude)
198
+ --force Overwrite existing skills / Force installation
199
+ --from=<path> (install only) Source directory containing skills
200
+
201
+ Options (for conversion):
202
+ --repo <url> Override BMAD repository URL
203
+ --branch <name> Override BMAD branch
204
+ --output-dir <path> Custom output directory
205
+ --identity-limit <n> Character limit for identity
206
+ --[no-]examples Enable/disable examples
207
+ --[no-]best-practices Enable/disable best practices
208
+ ... (see convert.js --help for full list)
209
+
210
+ -h, --help Show this help
211
+ `);
212
+ }
213
+
214
+ run().catch(err => {
215
+ console.error(err);
216
+ process.exit(1);
217
+ });
package/config.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "bmadRepo": "https://github.com/bmad-code-org/BMAD-METHOD.git",
3
+ "bmadBranch": "main",
4
+ "outputDir": "./skills",
5
+ "tempDir": "./.temp/bmad-method",
6
+ "modules": ["bmm", "bmb", "cis", "core"],
7
+ "agentPaths": [
8
+ "src/core/agents",
9
+ "src/modules/*/agents"
10
+ ],
11
+ "workflowPaths": [
12
+ "src/core/workflows",
13
+ "src/modules/*/workflows"
14
+ ],
15
+ "enhancements": {
16
+ "optional": {
17
+ "addExamples": true,
18
+ "addBestPractices": true,
19
+ "addTroubleshooting": false,
20
+ "addRelatedSkills": true,
21
+ "generateMetaDocs": false
22
+ },
23
+ "identityCharLimit": null
24
+ }
25
+ }
package/convert.js ADDED
@@ -0,0 +1,381 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { fetchBmadRepo } from './src/utils/bmad-fetcher.js';
5
+ import { findAgentsAndWorkflows } from './src/utils/file-finder.js';
6
+ import { convertAgentToSkill } from './src/converters/agent-converter.js';
7
+ import { convertWorkflowToSkill } from './src/converters/workflow-converter.js';
8
+ import { writeSkill } from './src/utils/skill-writer.js';
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+
13
+ /**
14
+ * Parse command line arguments
15
+ */
16
+ function parseArgs() {
17
+ const args = process.argv.slice(2);
18
+ const options = {
19
+ outputDir: null,
20
+ repoUrl: null,
21
+ branch: null,
22
+ identityCharLimit: null,
23
+ addExamples: null,
24
+ addBestPractices: null,
25
+ addTroubleshooting: null,
26
+ addRelatedSkills: null,
27
+ generateMetaDocs: null,
28
+ };
29
+
30
+ for (let i = 0; i < args.length; i++) {
31
+ const arg = args[i];
32
+
33
+ if (arg === '--output-dir' && i + 1 < args.length) {
34
+ options.outputDir = args[++i];
35
+ } else if (arg === '--repo' && i + 1 < args.length) {
36
+ options.repoUrl = args[++i];
37
+ } else if (arg === '--branch' && i + 1 < args.length) {
38
+ options.branch = args[++i];
39
+ } else if (arg === '--identity-limit' && i + 1 < args.length) {
40
+ const limit = Number.parseInt(args[++i], 10);
41
+ options.identityCharLimit = Number.isNaN(limit) ? null : limit;
42
+ } else if (arg === '--no-examples') {
43
+ options.addExamples = false;
44
+ } else if (arg === '--examples') {
45
+ options.addExamples = true;
46
+ } else if (arg === '--no-best-practices') {
47
+ options.addBestPractices = false;
48
+ } else if (arg === '--best-practices') {
49
+ options.addBestPractices = true;
50
+ } else if (arg === '--no-troubleshooting') {
51
+ options.addTroubleshooting = false;
52
+ } else if (arg === '--troubleshooting') {
53
+ options.addTroubleshooting = true;
54
+ } else if (arg === '--no-related-skills') {
55
+ options.addRelatedSkills = false;
56
+ } else if (arg === '--related-skills') {
57
+ options.addRelatedSkills = true;
58
+ } else if (arg === '--no-meta-docs') {
59
+ options.generateMetaDocs = false;
60
+ } else if (arg === '--meta-docs') {
61
+ options.generateMetaDocs = true;
62
+ } else if (arg === '--help' || arg === '-h') {
63
+ printHelp();
64
+ process.exit(0);
65
+ }
66
+ }
67
+
68
+ return options;
69
+ }
70
+
71
+ /**
72
+ * Print help message
73
+ */
74
+ function printHelp() {
75
+ console.log(`
76
+ BMAD to Skills Converter
77
+
78
+ Usage: pnpm convert [options]
79
+
80
+ Options:
81
+ --output-dir <path> Custom output directory (default: ./skills)
82
+ Use a non-version-controlled folder for custom configs
83
+
84
+ --repo <url> Override BMAD repository URL
85
+ --branch <name> Override BMAD branch (default: main)
86
+
87
+ --identity-limit <num> Character limit for identity in description
88
+ (default: no limit, use --identity-limit 200 to enable old behavior)
89
+
90
+ Optional Enhancements (override config.json defaults):
91
+ --examples / --no-examples
92
+ --best-practices / --no-best-practices
93
+ --troubleshooting / --no-troubleshooting
94
+ --related-skills / --no-related-skills
95
+ --meta-docs / --no-meta-docs
96
+
97
+ -h, --help Show this help message
98
+
99
+ Examples:
100
+ # Use default config (outputs to ./skills, version controlled)
101
+ pnpm convert
102
+
103
+ # Output to custom directory with different settings
104
+ pnpm convert --output-dir ./custom-skills --identity-limit 200 --no-examples
105
+
106
+ # Enable troubleshooting for this run
107
+ pnpm convert --troubleshooting
108
+ `);
109
+ }
110
+
111
+ // Parse CLI arguments
112
+ const cliOptions = parseArgs();
113
+
114
+ // Load configuration
115
+ const configPath = path.join(__dirname, 'config.json');
116
+ let config;
117
+ try {
118
+ if (!(await fs.pathExists(configPath))) {
119
+ throw new Error(`Configuration file not found: ${configPath}`);
120
+ }
121
+ const configContent = await fs.readFile(configPath, 'utf-8');
122
+ config = JSON.parse(configContent);
123
+
124
+ // Validate required config fields
125
+ const requiredFields = ['bmadRepo', 'bmadBranch', 'outputDir', 'tempDir'];
126
+ for (const field of requiredFields) {
127
+ if (!config[field]) {
128
+ throw new Error(`Missing required configuration field: ${field}`);
129
+ }
130
+ }
131
+
132
+ // Merge CLI options with config
133
+ if (cliOptions.outputDir) {
134
+ config.outputDir = cliOptions.outputDir;
135
+ }
136
+ if (cliOptions.repoUrl) {
137
+ config.bmadRepo = cliOptions.repoUrl;
138
+ console.log(`ā„¹ļø Overriding BMAD Repo: ${config.bmadRepo}`);
139
+ }
140
+ if (cliOptions.branch) {
141
+ config.bmadBranch = cliOptions.branch;
142
+ console.log(`ā„¹ļø Overriding BMAD Branch: ${config.bmadBranch}`);
143
+ }
144
+
145
+ // Initialize enhancements config if not present
146
+ if (!config.enhancements) {
147
+ config.enhancements = {};
148
+ }
149
+ if (!config.enhancements.optional) {
150
+ config.enhancements.optional = {
151
+ addExamples: true,
152
+ addBestPractices: true,
153
+ addTroubleshooting: false,
154
+ addRelatedSkills: true,
155
+ generateMetaDocs: false,
156
+ };
157
+ }
158
+
159
+ // Override with CLI options
160
+ if (cliOptions.identityCharLimit !== null) {
161
+ config.enhancements.identityCharLimit = cliOptions.identityCharLimit;
162
+ }
163
+ if (cliOptions.addExamples !== null) {
164
+ config.enhancements.optional.addExamples = cliOptions.addExamples;
165
+ }
166
+ if (cliOptions.addBestPractices !== null) {
167
+ config.enhancements.optional.addBestPractices = cliOptions.addBestPractices;
168
+ }
169
+ if (cliOptions.addTroubleshooting !== null) {
170
+ config.enhancements.optional.addTroubleshooting = cliOptions.addTroubleshooting;
171
+ }
172
+ if (cliOptions.addRelatedSkills !== null) {
173
+ config.enhancements.optional.addRelatedSkills = cliOptions.addRelatedSkills;
174
+ }
175
+ if (cliOptions.generateMetaDocs !== null) {
176
+ config.enhancements.optional.generateMetaDocs = cliOptions.generateMetaDocs;
177
+ }
178
+ } catch (error) {
179
+ console.error(`āŒ Failed to load configuration: ${error.message}`);
180
+ process.exit(1);
181
+ }
182
+
183
+ // Statistics
184
+ const stats = {
185
+ agents: { total: 0, converted: 0, errors: 0 },
186
+ workflows: { total: 0, converted: 0, errors: 0 },
187
+ errors: [],
188
+ };
189
+
190
+ /**
191
+ * Main conversion function
192
+ */
193
+ async function main() {
194
+ console.log('šŸš€ BMAD to Skills Converter\n');
195
+
196
+ try {
197
+ // Step 1: Fetch BMAD repository
198
+ console.log('šŸ“„ Fetching BMAD-METHOD repository...');
199
+ const bmadRoot = await fetchBmadRepo(
200
+ config.bmadRepo,
201
+ config.bmadBranch,
202
+ path.resolve(process.cwd(), config.tempDir),
203
+ );
204
+ console.log(`āœ“ Repository ready at: ${bmadRoot}\n`);
205
+
206
+ // Step 2: Discover agents and workflows
207
+ console.log('šŸ” Discovering agents and workflows...');
208
+ const { agents, workflows } = await findAgentsAndWorkflows(
209
+ bmadRoot,
210
+ config.agentPaths,
211
+ config.workflowPaths,
212
+ );
213
+
214
+ stats.agents.total = agents.length;
215
+ stats.workflows.total = workflows.length;
216
+
217
+ console.log(
218
+ `āœ“ Found ${agents.length} agents and ${workflows.length} workflows\n`,
219
+ );
220
+
221
+ // Step 3: Prepare output directory
222
+ const outputDir = path.resolve(process.cwd(), config.outputDir);
223
+ await fs.ensureDir(outputDir);
224
+ console.log(`šŸ“ Output directory: ${outputDir}\n`);
225
+
226
+ // Step 4: Convert agents
227
+ if (agents.length > 0) {
228
+ console.log('šŸ¤– Converting agents...');
229
+ const agentOptions = {
230
+ identityCharLimit: config.enhancements.identityCharLimit ?? null,
231
+ allAgents: agents,
232
+ allWorkflows: workflows,
233
+ };
234
+ for (const agent of agents) {
235
+ try {
236
+ const skillContent = await convertAgentToSkill(agent.path, {
237
+ ...agentOptions,
238
+ currentModule: agent.module,
239
+ });
240
+ await writeSkill(
241
+ outputDir,
242
+ agent.module,
243
+ agent.name,
244
+ skillContent,
245
+ );
246
+ stats.agents.converted++;
247
+ console.log(` āœ“ ${agent.module}/${agent.name}`);
248
+ } catch (error) {
249
+ stats.agents.errors++;
250
+ stats.errors.push({
251
+ type: 'agent',
252
+ path: agent.path,
253
+ error: error.message,
254
+ });
255
+ console.error(
256
+ ` āœ— ${agent.module}/${agent.name}: ${error.message}`,
257
+ );
258
+ }
259
+ }
260
+ console.log();
261
+ }
262
+
263
+ // Step 5: Convert workflows
264
+ if (workflows.length > 0) {
265
+ console.log('āš™ļø Converting workflows...');
266
+ const workflowOptions = {};
267
+ for (const workflow of workflows) {
268
+ try {
269
+ const skillContent = await convertWorkflowToSkill(
270
+ workflow.path,
271
+ workflow.instructionsPath,
272
+ workflow.workflowDir,
273
+ workflow.instructionsType,
274
+ {
275
+ ...workflowOptions,
276
+ isMarkdown: workflow.isMarkdown || false,
277
+ },
278
+ );
279
+ await writeSkill(
280
+ outputDir,
281
+ workflow.module,
282
+ workflow.name,
283
+ skillContent,
284
+ { workflowDir: workflow.workflowDir },
285
+ );
286
+ stats.workflows.converted++;
287
+ console.log(` āœ“ ${workflow.module}/${workflow.name}`);
288
+ } catch (error) {
289
+ stats.workflows.errors++;
290
+ stats.errors.push({
291
+ type: 'workflow',
292
+ path: workflow.path,
293
+ error: error.message,
294
+ });
295
+ console.error(
296
+ ` āœ— ${workflow.module}/${workflow.name}: ${error.message}`,
297
+ );
298
+ }
299
+ }
300
+ console.log();
301
+ }
302
+
303
+ // Step 6: Generate summary
304
+ await printSummary();
305
+ } catch (error) {
306
+ console.error(`\nāŒ Fatal error: ${error.message}`);
307
+ console.error(error.stack);
308
+ process.exit(1);
309
+ }
310
+ }
311
+
312
+ /**
313
+ * Prints conversion summary
314
+ */
315
+ async function printSummary() {
316
+ console.log('šŸ“Š Conversion Summary\n');
317
+ console.log('Agents:');
318
+ console.log(` Total: ${stats.agents.total}`);
319
+ console.log(` Converted: ${stats.agents.converted}`);
320
+ console.log(` Errors: ${stats.agents.errors}`);
321
+ console.log();
322
+ console.log('Workflows:');
323
+ console.log(` Total: ${stats.workflows.total}`);
324
+ console.log(` Converted: ${stats.workflows.converted}`);
325
+ console.log(` Errors: ${stats.workflows.errors}`);
326
+ console.log();
327
+
328
+ const totalConverted =
329
+ stats.agents.converted + stats.workflows.converted;
330
+ const totalErrors = stats.agents.errors + stats.workflows.errors;
331
+
332
+ if (totalErrors > 0) {
333
+ console.log('āš ļø Errors encountered:');
334
+ for (const err of stats.errors) {
335
+ console.log(` - ${err.type}: ${err.path}`);
336
+ console.log(` ${err.error}`);
337
+ }
338
+ console.log();
339
+ }
340
+
341
+ console.log(`āœ… Successfully converted ${totalConverted} skills`);
342
+ console.log(
343
+ `šŸ“ Output directory: ${path.resolve(process.cwd(), config.outputDir)}`,
344
+ );
345
+
346
+ // Show configuration info
347
+ if (config.outputDir !== './skills') {
348
+ console.log('\nšŸ’” Note: Output directory is not the default (./skills)');
349
+ console.log(' This directory is not version controlled.');
350
+ console.log(' To use default settings, run without --output-dir flag.');
351
+ }
352
+
353
+ if (config.enhancements.identityCharLimit !== null) {
354
+ console.log(`\nšŸ’” Note: Identity character limit is set to ${config.enhancements.identityCharLimit}`);
355
+ console.log(' Default behavior (no limit) is recommended for better content.');
356
+ }
357
+
358
+ // Print per-module breakdown
359
+ if (totalConverted > 0) {
360
+ console.log('\nšŸ“¦ Per-module breakdown:');
361
+
362
+ // Count by module from output structure
363
+ const outputDir = path.resolve(process.cwd(), config.outputDir);
364
+ if (await fs.pathExists(outputDir)) {
365
+ const modules = await fs.readdir(outputDir);
366
+ for (const module of modules) {
367
+ const modulePath = path.join(outputDir, module);
368
+ if ((await fs.stat(modulePath)).isDirectory()) {
369
+ const skills = await fs.readdir(modulePath);
370
+ console.log(` ${module}: ${skills.length} skills`);
371
+ }
372
+ }
373
+ }
374
+ }
375
+ }
376
+
377
+ // Run the conversion
378
+ main().catch((error) => {
379
+ console.error('Unhandled error:', error);
380
+ process.exit(1);
381
+ });