agent-config-sync 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js ADDED
@@ -0,0 +1,733 @@
1
+ #!/usr/bin/env node
2
+ // CLI command handlers
3
+ import { catalogMcpList, catalogMcpShow, catalogMcpAdd, catalogMcpRemove, } from './cli-catalog.js';
4
+ import { mcpStatus, mcpAdd, mcpRemove, mcpEnable, mcpDisable, } from './cli-mcp.js';
5
+ import { skillStatus, skillAdd, skillRemove, skillEnable, skillDisable, } from './cli-skill.js';
6
+ import { validate, doctor } from './cli-diagnostics.js';
7
+ // ============================================================================
8
+ // Constants
9
+ // ============================================================================
10
+ const HELP = `acsync - Agent configuration sync tool
11
+
12
+ USAGE:
13
+ acsync [COMMAND]
14
+
15
+ COMMANDS:
16
+ catalog Manage reusable MCP and skill definitions
17
+ mcp Manage MCP servers for the current project
18
+ skill Manage skills for the current project
19
+ validate Validate current project configuration
20
+ doctor Run diagnostics and health checks
21
+
22
+ OPTIONS:
23
+ -h, --help Show this help message
24
+ -V, --version Show version information
25
+
26
+ EXAMPLES:
27
+ acsync mcp status Show MCP status for current project
28
+ acsync mcp add github --targets codex Add GitHub MCP to Codex
29
+ acsync catalog mcp list List all MCPs in local catalog
30
+ acsync skill add frontend-design --targets claude Add a skill
31
+
32
+ For more information, run: acsync <command> --help
33
+ `;
34
+ const CATALOG_HELP = `acsync catalog - Manage reusable MCP and skill definitions
35
+
36
+ USAGE:
37
+ acsync catalog <kind> <subcommand>
38
+
39
+ KINDS:
40
+ mcp Manage MCP definitions
41
+ skill Manage skill definitions
42
+
43
+ MCP SUBCOMMANDS:
44
+ list List all MCP entries in catalog
45
+ show <id> Show details of a specific MCP entry
46
+ add <pkg> Add a new MCP entry to catalog
47
+ remove <id> Remove an MCP entry from catalog
48
+
49
+ SKILL SUBCOMMANDS:
50
+ list List all skill entries in catalog
51
+ show <id> Show details of a specific skill entry
52
+ add <file> Add a new skill entry to catalog from file
53
+ import <path> Import a skill from a local directory
54
+ install <id> Install a skill from skills.directory registry
55
+ search <query> Search the skills.directory registry
56
+ remove <id> Remove a skill entry from catalog
57
+
58
+ OPTIONS (mcp add):
59
+ --url <url> HTTP/SSE URL for the MCP server
60
+ --command <cmd> Command to execute (stdio transport)
61
+ --args <json> Arguments for command (JSON array)
62
+ --cwd <path> Working directory for command
63
+ --display-name <name> Display name for the entry
64
+ --description <desc> Description for the entry
65
+ --env <json> Environment variables (JSON object)
66
+
67
+ OPTIONS (skill install):
68
+ --force Force reinstall if already exists
69
+
70
+ OPTIONS (skill import):
71
+ --name <name> Override skill name
72
+ --display-name <name> Display name for the entry
73
+ --description <desc> Description for the entry
74
+
75
+ EXAMPLES:
76
+ acsync catalog mcp list
77
+ acsync catalog skill install frontend-design
78
+ acsync catalog skill search typescript
79
+ acsync catalog skill import ~/.claude/skills/frontend-design
80
+ acsync catalog skill add my-skill --file ./skills/my-skill/SKILL.md
81
+ `;
82
+ const MCP_HELP = `acsync mcp - Manage MCP servers for the current project
83
+
84
+ USAGE:
85
+ acsync mcp [subcommand] [options]
86
+
87
+ SUBCOMMANDS:
88
+ status Show MCP status (default)
89
+ add <package> Add an MCP to the project
90
+ remove <server> Remove an MCP from the project
91
+ enable <server> Enable a disabled MCP
92
+ disable <server> Disable an MCP
93
+
94
+ OPTIONS:
95
+ --targets <list> Comma-separated target list (e.g., codex,claude)
96
+ --[no-]register Auto-register to catalog (default: yes)
97
+
98
+ EXAMPLES:
99
+ acsync mcp
100
+ acsync mcp add @modelcontextprotocol/server-github --targets codex
101
+ acsync mcp disable github --targets claude
102
+ acsync mcp remove github
103
+ `;
104
+ const SKILL_HELP = `acsync skill - Manage skills for the current project
105
+
106
+ USAGE:
107
+ acsync skill [subcommand] [options]
108
+
109
+ SUBCOMMANDS:
110
+ status Show skill status (default)
111
+ add <name> Add a skill to the project (from catalog)
112
+ install <github-url> Install a skill from a GitHub URL
113
+ remove <name> Remove a skill from the project
114
+ enable <name> Enable a disabled skill (no-op for skills)
115
+ disable <name> Disable a skill (equivalent to remove)
116
+
117
+ OPTIONS:
118
+ --targets <list> Comma-separated target list (e.g., codex,claude)
119
+ --[no-]register Auto-register to catalog (default: yes)
120
+
121
+ INSTALL OPTIONS:
122
+ --name <name> Override skill name
123
+ --no-catalog Don't add to catalog, only install to project
124
+
125
+ EXAMPLES:
126
+ acsync skill
127
+ acsync skill add frontend-design --targets claude
128
+ acsync skill install https://github.com/anthropics/skills --name frontend-design
129
+ acsync skill install https://github.com/anthropics/skills --targets claude,codex
130
+ acsync skill remove frontend-design
131
+ `;
132
+ const VALIDATE_HELP = `acsync validate - Validate current project configuration
133
+
134
+ USAGE:
135
+ acsync validate [options]
136
+
137
+ OPTIONS:
138
+ --strict Fail on warnings as well as errors
139
+
140
+ EXAMPLES:
141
+ acsync validate
142
+ acsync validate --strict
143
+ `;
144
+ const DOCTOR_HELP = `acsync doctor - Run diagnostics and health checks
145
+
146
+ USAGE:
147
+ acsync doctor [options]
148
+
149
+ OPTIONS:
150
+ --fix Attempt to auto-fix issues
151
+
152
+ EXAMPLES:
153
+ acsync doctor
154
+ acsync doctor --fix
155
+ `;
156
+ // ============================================================================
157
+ // Main
158
+ // ============================================================================
159
+ async function main() {
160
+ const argv = process.argv.slice(2);
161
+ // Top-level help
162
+ if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h') {
163
+ process.stdout.write(HELP);
164
+ return;
165
+ }
166
+ // Version
167
+ if (argv[0] === '--version' || argv[0] === '-V') {
168
+ const { version } = await getPackageVersion();
169
+ process.stdout.write(`acsync v${version}\n`);
170
+ return;
171
+ }
172
+ const command = argv[0];
173
+ switch (command) {
174
+ case 'catalog':
175
+ await handleCatalog(argv.slice(1));
176
+ break;
177
+ case 'mcp':
178
+ await handleMcp(argv.slice(1));
179
+ break;
180
+ case 'skill':
181
+ await handleSkill(argv.slice(1));
182
+ break;
183
+ case 'validate':
184
+ await handleValidate(argv.slice(1));
185
+ break;
186
+ case 'doctor':
187
+ await handleDoctor(argv.slice(1));
188
+ break;
189
+ default:
190
+ process.stderr.write(`Unknown command: ${command}\n\n`);
191
+ process.stderr.write(HELP);
192
+ process.exitCode = 1;
193
+ }
194
+ }
195
+ // ============================================================================
196
+ // Command Handlers
197
+ // ============================================================================
198
+ async function handleCatalog(argv) {
199
+ if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h') {
200
+ process.stdout.write(CATALOG_HELP);
201
+ return;
202
+ }
203
+ const resource = argv[0];
204
+ const subcommand = argv[1];
205
+ const args = argv.slice(2);
206
+ if (resource !== 'mcp' && resource !== 'skill') {
207
+ process.stderr.write(`Unknown catalog resource: ${resource}\n`);
208
+ process.stderr.write('Use "acsync catalog mcp" or "acsync catalog skill" for management.\n');
209
+ process.exitCode = 1;
210
+ return;
211
+ }
212
+ if (subcommand === '--help' || subcommand === '-h') {
213
+ process.stdout.write(CATALOG_HELP);
214
+ return;
215
+ }
216
+ switch (resource) {
217
+ case 'mcp':
218
+ await handleCatalogMcp(subcommand, args);
219
+ break;
220
+ case 'skill':
221
+ await handleCatalogSkill(subcommand, args);
222
+ break;
223
+ }
224
+ }
225
+ async function handleCatalogMcp(subcommand, args) {
226
+ if (!subcommand) {
227
+ process.stderr.write('Usage: acsync catalog mcp <subcommand>\n');
228
+ process.exitCode = 1;
229
+ return;
230
+ }
231
+ switch (subcommand) {
232
+ case 'list':
233
+ await catalogMcpList();
234
+ break;
235
+ case 'show':
236
+ if (args.length === 0) {
237
+ process.stderr.write('Usage: acsync catalog mcp show <id>\n');
238
+ process.exitCode = 1;
239
+ return;
240
+ }
241
+ await catalogMcpShow(args[0]);
242
+ break;
243
+ case 'add':
244
+ await handleCatalogMcpAdd(args);
245
+ break;
246
+ case 'remove':
247
+ if (args.length === 0) {
248
+ process.stderr.write('Usage: acsync catalog mcp remove <id>\n');
249
+ process.exitCode = 1;
250
+ return;
251
+ }
252
+ await catalogMcpRemove(args[0]);
253
+ break;
254
+ default:
255
+ process.stderr.write(`Unknown subcommand: ${subcommand}\n`);
256
+ process.stderr.write(CATALOG_HELP);
257
+ process.exitCode = 1;
258
+ }
259
+ }
260
+ async function handleCatalogMcpAdd(argv) {
261
+ if (argv.length === 0) {
262
+ process.stderr.write('Usage: acsync catalog mcp add <package-id> [options]\n');
263
+ process.exitCode = 1;
264
+ return;
265
+ }
266
+ const packageId = argv[0];
267
+ const options = parseCatalogMcpAddOptions(argv.slice(1));
268
+ await catalogMcpAdd({
269
+ packageId,
270
+ displayName: options.displayName,
271
+ description: options.description,
272
+ command: options.command,
273
+ args: options.args,
274
+ url: options.url,
275
+ cwd: options.cwd,
276
+ env: options.env,
277
+ });
278
+ }
279
+ async function handleCatalogSkill(subcommand, args) {
280
+ if (!subcommand) {
281
+ process.stderr.write('Usage: acsync catalog skill <subcommand>\n');
282
+ process.exitCode = 1;
283
+ return;
284
+ }
285
+ switch (subcommand) {
286
+ case 'list':
287
+ await (await import('./cli-catalog.js')).catalogSkillList();
288
+ break;
289
+ case 'show':
290
+ if (args.length === 0) {
291
+ process.stderr.write('Usage: acsync catalog skill show <id>\n');
292
+ process.exitCode = 1;
293
+ return;
294
+ }
295
+ await (await import('./cli-catalog.js')).catalogSkillShow(args[0]);
296
+ break;
297
+ case 'add':
298
+ await handleCatalogSkillAdd(args);
299
+ break;
300
+ case 'install':
301
+ await handleCatalogSkillInstall(args);
302
+ break;
303
+ case 'search':
304
+ if (args.length === 0) {
305
+ process.stderr.write('Usage: acsync catalog skill search <query>\n');
306
+ process.exitCode = 1;
307
+ return;
308
+ }
309
+ await (await import('./cli-catalog.js')).catalogSkillSearch(args[0]);
310
+ break;
311
+ case 'import':
312
+ await handleCatalogSkillImport(args);
313
+ break;
314
+ case 'remove':
315
+ if (args.length === 0) {
316
+ process.stderr.write('Usage: acsync catalog skill remove <id>\n');
317
+ process.exitCode = 1;
318
+ return;
319
+ }
320
+ await (await import('./cli-catalog.js')).catalogSkillRemove(args[0]);
321
+ break;
322
+ default:
323
+ process.stderr.write(`Unknown subcommand: ${subcommand}\n`);
324
+ process.stderr.write(CATALOG_HELP);
325
+ process.exitCode = 1;
326
+ }
327
+ }
328
+ async function handleCatalogSkillAdd(argv) {
329
+ if (argv.length === 0) {
330
+ process.stderr.write('Usage: acsync catalog skill add <skill-id> [options]\n');
331
+ process.exitCode = 1;
332
+ return;
333
+ }
334
+ const skillId = argv[0];
335
+ const options = parseCatalogSkillAddOptions(argv.slice(1));
336
+ await (await import('./cli-catalog.js')).catalogSkillAdd({
337
+ skillId,
338
+ file: options.file,
339
+ displayName: options.displayName,
340
+ description: options.description,
341
+ });
342
+ }
343
+ async function handleCatalogSkillInstall(argv) {
344
+ if (argv.length === 0) {
345
+ process.stderr.write('Usage: acsync catalog skill install <skill-id> [--force]\n');
346
+ process.exitCode = 1;
347
+ return;
348
+ }
349
+ const skillId = argv[0];
350
+ const force = parseFlag(argv, 'force');
351
+ await (await import('./cli-catalog.js')).catalogSkillInstall({ skillId, force });
352
+ }
353
+ async function handleCatalogSkillImport(argv) {
354
+ if (argv.length === 0) {
355
+ process.stderr.write('Usage: acsync catalog skill import <path> [options]\n');
356
+ process.exitCode = 1;
357
+ return;
358
+ }
359
+ const skillPath = argv[0];
360
+ const options = parseCatalogSkillImportOptions(argv.slice(1));
361
+ await (await import('./cli-catalog.js')).catalogSkillImport({
362
+ path: skillPath,
363
+ skillId: options.skillId,
364
+ displayName: options.displayName,
365
+ description: options.description,
366
+ });
367
+ }
368
+ async function handleMcp(argv) {
369
+ if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h') {
370
+ process.stdout.write(MCP_HELP);
371
+ return;
372
+ }
373
+ // Check if verbose flag is present
374
+ const verbose = parseFlag(argv, 'verbose', 'v');
375
+ // Remove verbose from argv for further parsing
376
+ const filteredArgs = argv.filter((arg) => arg !== '--verbose' && arg !== '-v');
377
+ const subcommand = filteredArgs[0];
378
+ // Default to status if no subcommand or status
379
+ if (!subcommand || subcommand === 'status') {
380
+ await mcpStatus(verbose);
381
+ return;
382
+ }
383
+ const options = parseMcpOptions(filteredArgs.slice(1), subcommand);
384
+ switch (subcommand) {
385
+ case 'add':
386
+ if (options.packageId === undefined) {
387
+ process.stderr.write('Usage: acsync mcp add <package> [options]\n');
388
+ process.exitCode = 1;
389
+ return;
390
+ }
391
+ await mcpAdd({
392
+ packageId: options.packageId,
393
+ targets: options.targets,
394
+ noRegister: options.noRegister,
395
+ });
396
+ break;
397
+ case 'remove':
398
+ if (options.packageId === undefined) {
399
+ process.stderr.write('Usage: acsync mcp remove <server> [options]\n');
400
+ process.exitCode = 1;
401
+ return;
402
+ }
403
+ await mcpRemove({
404
+ serverName: options.packageId,
405
+ targets: options.targets,
406
+ });
407
+ break;
408
+ case 'enable':
409
+ if (options.packageId === undefined) {
410
+ process.stderr.write('Usage: acsync mcp enable <server> [options]\n');
411
+ process.exitCode = 1;
412
+ return;
413
+ }
414
+ await mcpEnable({
415
+ serverName: options.packageId,
416
+ targets: options.targets,
417
+ });
418
+ break;
419
+ case 'disable':
420
+ if (options.packageId === undefined) {
421
+ process.stderr.write('Usage: acsync mcp disable <server> [options]\n');
422
+ process.exitCode = 1;
423
+ return;
424
+ }
425
+ await mcpDisable({
426
+ serverName: options.packageId,
427
+ targets: options.targets,
428
+ });
429
+ break;
430
+ default:
431
+ process.stderr.write(`Unknown subcommand: ${subcommand}\n`);
432
+ process.stderr.write(MCP_HELP);
433
+ process.exitCode = 1;
434
+ }
435
+ }
436
+ async function handleSkill(argv) {
437
+ if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h') {
438
+ process.stdout.write(SKILL_HELP);
439
+ return;
440
+ }
441
+ // Check if verbose flag is present
442
+ const verbose = parseFlag(argv, 'verbose', 'v');
443
+ // Remove verbose from argv for further parsing
444
+ const filteredArgs = argv.filter((arg) => arg !== '--verbose' && arg !== '-v');
445
+ const subcommand = filteredArgs[0];
446
+ // Default to status if no subcommand or status
447
+ if (!subcommand || subcommand === 'status') {
448
+ await skillStatus(verbose);
449
+ return;
450
+ }
451
+ const options = parseSkillOptions(filteredArgs.slice(1), subcommand);
452
+ switch (subcommand) {
453
+ case 'add':
454
+ if (options.skillId === undefined) {
455
+ process.stderr.write('Usage: acsync skill add <name> [options]\n');
456
+ process.exitCode = 1;
457
+ return;
458
+ }
459
+ await skillAdd({
460
+ skillId: options.skillId,
461
+ targets: options.targets,
462
+ noRegister: options.noRegister,
463
+ });
464
+ break;
465
+ case 'install':
466
+ if (options.githubUrl === undefined) {
467
+ process.stderr.write('Usage: acsync skill install <github-url> [options]\n');
468
+ process.exitCode = 1;
469
+ return;
470
+ }
471
+ await (await import('./cli-skill.js')).skillInstallFromGitHub({
472
+ githubUrl: options.githubUrl,
473
+ skillName: options.skillName,
474
+ targets: options.targets,
475
+ addToCatalog: options.addToCatalog,
476
+ });
477
+ break;
478
+ case 'remove':
479
+ if (options.skillId === undefined) {
480
+ process.stderr.write('Usage: acsync skill remove <name> [options]\n');
481
+ process.exitCode = 1;
482
+ return;
483
+ }
484
+ await skillRemove({
485
+ skillName: options.skillId,
486
+ targets: options.targets,
487
+ });
488
+ break;
489
+ case 'enable':
490
+ if (options.skillId === undefined) {
491
+ process.stderr.write('Usage: acsync skill enable <name> [options]\n');
492
+ process.exitCode = 1;
493
+ return;
494
+ }
495
+ await skillEnable({
496
+ skillName: options.skillId,
497
+ targets: options.targets,
498
+ });
499
+ break;
500
+ case 'disable':
501
+ if (options.skillId === undefined) {
502
+ process.stderr.write('Usage: acsync skill disable <name> [options]\n');
503
+ process.exitCode = 1;
504
+ return;
505
+ }
506
+ await skillDisable({
507
+ skillName: options.skillId,
508
+ targets: options.targets,
509
+ });
510
+ break;
511
+ default:
512
+ process.stderr.write(`Unknown subcommand: ${subcommand}\n`);
513
+ process.stderr.write(SKILL_HELP);
514
+ process.exitCode = 1;
515
+ }
516
+ }
517
+ async function handleValidate(argv) {
518
+ if (argv.includes('--help') || argv.includes('-h')) {
519
+ process.stdout.write(VALIDATE_HELP);
520
+ return;
521
+ }
522
+ const strict = parseFlag(argv, 'strict');
523
+ await validate({ strict });
524
+ }
525
+ async function handleDoctor(argv) {
526
+ if (argv.includes('--help') || argv.includes('-h')) {
527
+ process.stdout.write(DOCTOR_HELP);
528
+ return;
529
+ }
530
+ const fix = parseFlag(argv, 'fix');
531
+ await doctor({ fix });
532
+ }
533
+ function parseMcpOptions(argv, subcommand) {
534
+ const options = {
535
+ targets: ['claude', 'codex'], // Default targets
536
+ noRegister: false,
537
+ };
538
+ let i = 0;
539
+ while (i < argv.length) {
540
+ const arg = argv[i];
541
+ switch (arg) {
542
+ case '--targets':
543
+ options.targets = parseTargets(argv[++i]);
544
+ break;
545
+ case '--no-register':
546
+ options.noRegister = true;
547
+ break;
548
+ case '--register':
549
+ options.noRegister = false;
550
+ break;
551
+ case '--verbose':
552
+ case '-v':
553
+ options.verbose = true;
554
+ break;
555
+ default:
556
+ // Treat as package/server name (except for status subcommand which doesn't need it)
557
+ if (!options.packageId && subcommand !== 'status') {
558
+ options.packageId = arg;
559
+ }
560
+ break;
561
+ }
562
+ i++;
563
+ }
564
+ return options;
565
+ }
566
+ function parseCatalogMcpAddOptions(argv) {
567
+ const options = {};
568
+ let i = 0;
569
+ while (i < argv.length) {
570
+ const arg = argv[i];
571
+ switch (arg) {
572
+ case '--display-name':
573
+ options.displayName = argv[++i];
574
+ break;
575
+ case '--description':
576
+ options.description = argv[++i];
577
+ break;
578
+ case '--command':
579
+ options.command = argv[++i];
580
+ break;
581
+ case '--args':
582
+ options.args = JSON.parse(argv[++i]);
583
+ break;
584
+ case '--url':
585
+ options.url = argv[++i];
586
+ break;
587
+ case '--cwd':
588
+ options.cwd = argv[++i];
589
+ break;
590
+ case '--env':
591
+ options.env = JSON.parse(argv[++i]);
592
+ break;
593
+ default:
594
+ process.stderr.write(`Unknown option: ${arg}\n`);
595
+ process.exitCode = 1;
596
+ break;
597
+ }
598
+ i++;
599
+ }
600
+ return options;
601
+ }
602
+ function parseCatalogSkillAddOptions(argv) {
603
+ const options = {};
604
+ let i = 0;
605
+ while (i < argv.length) {
606
+ const arg = argv[i];
607
+ switch (arg) {
608
+ case '--file':
609
+ options.file = argv[++i];
610
+ break;
611
+ case '--display-name':
612
+ options.displayName = argv[++i];
613
+ break;
614
+ case '--description':
615
+ options.description = argv[++i];
616
+ break;
617
+ default:
618
+ process.stderr.write(`Unknown option: ${arg}\n`);
619
+ process.exitCode = 1;
620
+ break;
621
+ }
622
+ i++;
623
+ }
624
+ return options;
625
+ }
626
+ function parseCatalogSkillImportOptions(argv) {
627
+ const options = {};
628
+ let i = 0;
629
+ while (i < argv.length) {
630
+ const arg = argv[i];
631
+ switch (arg) {
632
+ case '--name':
633
+ options.skillId = argv[++i];
634
+ break;
635
+ case '--display-name':
636
+ options.displayName = argv[++i];
637
+ break;
638
+ case '--description':
639
+ options.description = argv[++i];
640
+ break;
641
+ default:
642
+ process.stderr.write(`Unknown option: ${arg}\n`);
643
+ process.exitCode = 1;
644
+ break;
645
+ }
646
+ i++;
647
+ }
648
+ return options;
649
+ }
650
+ function parseTargets(input) {
651
+ const validTargets = ['claude', 'codex', 'gemini'];
652
+ const targets = input.split(',').map((t) => t.trim().toLowerCase());
653
+ for (const target of targets) {
654
+ if (!validTargets.includes(target)) {
655
+ process.stderr.write(`Invalid target: ${target}\n`);
656
+ process.stderr.write(`Valid targets: ${validTargets.join(', ')}\n`);
657
+ process.exit(1);
658
+ }
659
+ }
660
+ return targets;
661
+ }
662
+ function parseSkillOptions(argv, subcommand) {
663
+ const options = {
664
+ targets: ['claude', 'codex'], // Default targets
665
+ noRegister: false,
666
+ };
667
+ let i = 0;
668
+ while (i < argv.length) {
669
+ const arg = argv[i];
670
+ switch (arg) {
671
+ case '--targets':
672
+ options.targets = parseTargets(argv[++i]);
673
+ break;
674
+ case '--no-register':
675
+ options.noRegister = true;
676
+ break;
677
+ case '--register':
678
+ options.noRegister = false;
679
+ break;
680
+ case '--verbose':
681
+ case '-v':
682
+ options.verbose = true;
683
+ break;
684
+ case '--from-github':
685
+ case '--github':
686
+ options.githubUrl = argv[++i];
687
+ break;
688
+ case '--name':
689
+ options.skillName = argv[++i];
690
+ break;
691
+ case '--no-catalog':
692
+ options.addToCatalog = false;
693
+ break;
694
+ default:
695
+ // Treat as skill name or GitHub URL (except for status subcommand)
696
+ if (subcommand === 'install' && arg.startsWith('http')) {
697
+ options.githubUrl = arg;
698
+ }
699
+ else if (!options.skillId && subcommand !== 'status') {
700
+ options.skillId = arg;
701
+ }
702
+ break;
703
+ }
704
+ i++;
705
+ }
706
+ return options;
707
+ }
708
+ function parseFlag(argv, longName, shortName) {
709
+ return argv.includes(`--${longName}`) || (shortName ? argv.includes(`-${shortName}`) : false);
710
+ }
711
+ // ============================================================================
712
+ // Utilities
713
+ // ============================================================================
714
+ async function getPackageVersion() {
715
+ // Read package.json dynamically to support global installation
716
+ const { readFile } = await import('node:fs/promises');
717
+ const { dirname, join } = await import('node:path');
718
+ const { fileURLToPath } = await import('node:url');
719
+ const __filename = fileURLToPath(import.meta.url);
720
+ const __dirname = dirname(__filename);
721
+ const pkgPath = join(__dirname, '..', 'package.json');
722
+ const content = await readFile(pkgPath, 'utf8');
723
+ return JSON.parse(content);
724
+ }
725
+ // ============================================================================
726
+ // Error Handling
727
+ // ============================================================================
728
+ main().catch((error) => {
729
+ const message = error instanceof Error ? error.message : String(error);
730
+ process.stderr.write(`Error: ${message}\n`);
731
+ process.exit(1);
732
+ });
733
+ //# sourceMappingURL=cli.js.map