@yama662607/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.
Files changed (60) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +174 -0
  3. package/dist/catalog.d.ts +65 -0
  4. package/dist/catalog.js +328 -0
  5. package/dist/catalog.js.map +1 -0
  6. package/dist/cli-catalog.d.ts +70 -0
  7. package/dist/cli-catalog.js +433 -0
  8. package/dist/cli-catalog.js.map +1 -0
  9. package/dist/cli-diagnostics.d.ts +14 -0
  10. package/dist/cli-diagnostics.js +177 -0
  11. package/dist/cli-diagnostics.js.map +1 -0
  12. package/dist/cli-init.d.ts +8 -0
  13. package/dist/cli-init.js +77 -0
  14. package/dist/cli-init.js.map +1 -0
  15. package/dist/cli-mcp.d.ts +38 -0
  16. package/dist/cli-mcp.js +179 -0
  17. package/dist/cli-mcp.js.map +1 -0
  18. package/dist/cli-skill.d.ts +51 -0
  19. package/dist/cli-skill.js +239 -0
  20. package/dist/cli-skill.js.map +1 -0
  21. package/dist/cli.d.ts +2 -0
  22. package/dist/cli.js +868 -0
  23. package/dist/cli.js.map +1 -0
  24. package/dist/config-adapters.d.ts +32 -0
  25. package/dist/config-adapters.js +410 -0
  26. package/dist/config-adapters.js.map +1 -0
  27. package/dist/fs.d.ts +2 -0
  28. package/dist/fs.js +20 -0
  29. package/dist/fs.js.map +1 -0
  30. package/dist/project-discovery.d.ts +20 -0
  31. package/dist/project-discovery.js +79 -0
  32. package/dist/project-discovery.js.map +1 -0
  33. package/dist/prompts/confirm-prompt.d.ts +9 -0
  34. package/dist/prompts/confirm-prompt.js +54 -0
  35. package/dist/prompts/confirm-prompt.js.map +1 -0
  36. package/dist/prompts/custom-multiselect.d.ts +9 -0
  37. package/dist/prompts/custom-multiselect.js +28 -0
  38. package/dist/prompts/custom-multiselect.js.map +1 -0
  39. package/dist/prompts/index.d.ts +5 -0
  40. package/dist/prompts/index.js +6 -0
  41. package/dist/prompts/index.js.map +1 -0
  42. package/dist/prompts/mcp-prompt.d.ts +5 -0
  43. package/dist/prompts/mcp-prompt.js +57 -0
  44. package/dist/prompts/mcp-prompt.js.map +1 -0
  45. package/dist/prompts/skill-prompt.d.ts +5 -0
  46. package/dist/prompts/skill-prompt.js +57 -0
  47. package/dist/prompts/skill-prompt.js.map +1 -0
  48. package/dist/prompts/target-prompt.d.ts +7 -0
  49. package/dist/prompts/target-prompt.js +47 -0
  50. package/dist/prompts/target-prompt.js.map +1 -0
  51. package/dist/registry.d.ts +49 -0
  52. package/dist/registry.js +121 -0
  53. package/dist/registry.js.map +1 -0
  54. package/dist/skill-adapters.d.ts +53 -0
  55. package/dist/skill-adapters.js +183 -0
  56. package/dist/skill-adapters.js.map +1 -0
  57. package/dist/types.d.ts +151 -0
  58. package/dist/types.js +9 -0
  59. package/dist/types.js.map +1 -0
  60. package/package.json +68 -0
package/dist/cli.js ADDED
@@ -0,0 +1,868 @@
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
+ init Interactive setup for the current project
17
+ catalog Manage reusable MCP and skill definitions in your personal catalog
18
+ mcp Manage MCP servers for the current project
19
+ skill Manage skills for the current project
20
+ validate Validate current project configuration
21
+ doctor Run diagnostics and health checks
22
+
23
+ OPTIONS:
24
+ -h, --help Show this help message
25
+ -V, --version Show version information
26
+
27
+ TARGETS:
28
+ claude Claude Code (.mcp.json, .claude/skills/)
29
+ codex Codex (.codex/config.toml, .codex/skills/)
30
+ gemini Gemini CLI (.gemini/settings.json, .gemini/antigravity/skills/)
31
+
32
+ ABOUT CATALOG:
33
+ Your personal catalog (~/.acsync/) stores reusable MCP and skill definitions.
34
+ Use "acsync catalog" to manage the catalog, then add items to projects.
35
+
36
+ EXAMPLES:
37
+ acsync init Interactive setup for current project
38
+ acsync mcp Show MCP status for current project
39
+ acsync skill Show skill status for current project
40
+ acsync catalog mcp list List all MCPs in your personal catalog
41
+ acsync mcp add github --targets claude Add GitHub MCP to Claude Code
42
+ acsync skill add frontend-design --targets claude Add skill from catalog
43
+ acsync skill install <github-url> --targets claude,codex Install from GitHub
44
+
45
+ For more information, run: acsync <command> --help
46
+ `;
47
+ const CATALOG_HELP = `acsync catalog - Manage reusable MCP and skill definitions
48
+
49
+ USAGE:
50
+ acsync catalog <kind> <subcommand>
51
+
52
+ ABOUT CATALOG:
53
+ Your personal catalog (~/.acsync/catalog.json) stores reusable MCP servers
54
+ and skills. Once added to the catalog, you can easily add them to any project.
55
+
56
+ KINDS:
57
+ mcp Manage MCP definitions
58
+ skill Manage skill definitions
59
+
60
+ MCP SUBCOMMANDS:
61
+ list List all MCP entries in catalog
62
+ show <id> Show details of a specific MCP entry
63
+ add <pkg> Add a new MCP entry to catalog
64
+ remove <id> Remove an MCP entry from catalog
65
+
66
+ SKILL SUBCOMMANDS:
67
+ list List all skill entries in catalog
68
+ show <id> Show details of a specific skill entry
69
+ add <name> Add a new skill entry to catalog from file
70
+ import <path> Import a skill from a local directory
71
+ install <id> Install a skill from skills.directory registry
72
+ search <query> Search the skills.directory registry
73
+ remove <id> Remove a skill entry from catalog
74
+
75
+ OPTIONS (mcp add):
76
+ --url <url> HTTP/SSE URL for the MCP server
77
+ --command <cmd> Command to execute (stdio transport)
78
+ --args <json> Arguments for command (JSON array)
79
+ --cwd <path> Working directory for command
80
+ --display-name <name> Display name for the entry
81
+ --description <desc> Description for the entry
82
+ --env <json> Environment variables (JSON object)
83
+
84
+ OPTIONS (skill install):
85
+ --force Force reinstall if already exists
86
+
87
+ OPTIONS (skill import):
88
+ --name <name> Override skill name
89
+ --display-name <name> Display name for the entry
90
+ --description <desc> Description for the entry
91
+
92
+ EXAMPLES:
93
+ # Catalog operations
94
+ acsync catalog mcp list
95
+ acsync catalog mcp show @modelcontextprotocol/server-github
96
+ acsync catalog mcp add @modelcontextprotocol/server-filesystem
97
+
98
+ # Skill catalog operations
99
+ acsync catalog skill list
100
+ acsync catalog skill install frontend-design
101
+ acsync catalog skill search typescript
102
+ acsync catalog skill import ~/.claude/skills/frontend-design
103
+ acsync catalog skill add my-skill --file ./my-skill/SKILL.md
104
+
105
+ # After adding to catalog, use with project commands:
106
+ acsync mcp add @modelcontextprotocol/server-github --targets claude
107
+ acsync skill add frontend-design --targets claude,codex
108
+ `;
109
+ const MCP_HELP = `acsync mcp - Manage MCP servers for the current project
110
+
111
+ USAGE:
112
+ acsync mcp [subcommand] [options]
113
+
114
+ SUBCOMMANDS:
115
+ status Show MCP status (default)
116
+ add <package> Add an MCP to the project (from catalog or npm)
117
+ remove <server> Remove an MCP from the project
118
+ enable <server> Enable a disabled MCP
119
+ disable <server> Disable an MCP
120
+
121
+ OPTIONS:
122
+ --targets <list> Comma-separated target list (default: claude,codex,gemini)
123
+ --[no-]register Auto-register to catalog (default: yes)
124
+
125
+ TARGETS:
126
+ claude Claude Code (.mcp.json)
127
+ codex Codex (.codex/config.toml)
128
+ gemini Gemini CLI (.gemini/settings.json)
129
+
130
+ EXAMPLES:
131
+ # Show status
132
+ acsync mcp
133
+ acsync mcp status
134
+
135
+ # Add from npm package (auto-registers to catalog)
136
+ acsync mcp add @modelcontextprotocol/server-github --targets claude
137
+ acsync mcp add @modelcontextprotocol/server-filesystem --targets claude,codex
138
+
139
+ # Add with custom configuration
140
+ acsync mcp add custom-mcp --url "https://mcp.example.com" --targets claude
141
+ acsync mcp add local-mcp --command "node" --args '["server.js"]' --targets claude
142
+
143
+ # Enable/disable/remove
144
+ acsync mcp disable github --targets claude
145
+ acsync mcp enable github --targets codex
146
+ acsync mcp remove github
147
+
148
+ # Work with catalog
149
+ acsync catalog mcp list # List catalog entries
150
+ acsync catalog mcp add <package> # Add to catalog first
151
+ `;
152
+ const SKILL_HELP = `acsync skill - Manage skills for the current project
153
+
154
+ USAGE:
155
+ acsync skill [subcommand] [options]
156
+
157
+ SUBCOMMANDS:
158
+ status Show skill status (default)
159
+ add <name> Add a skill to the project from your catalog
160
+ install <github-url> Install a skill directly from GitHub URL
161
+ remove <name> Remove a skill from the project
162
+ enable <name> Enable a skill (skills are always enabled if present)
163
+ disable <name> Disable a skill (equivalent to remove)
164
+
165
+ OPTIONS:
166
+ --targets <list> Comma-separated target list (default: claude,codex,gemini)
167
+ --[no-]register Auto-register to catalog (default: yes)
168
+
169
+ INSTALL OPTIONS (for GitHub install):
170
+ --name <name> Override skill name from GitHub
171
+ --no-catalog Don't add to catalog, only install to project
172
+
173
+ TARGETS:
174
+ claude Claude Code (.claude/skills/)
175
+ codex Codex (.codex/skills/)
176
+ gemini Gemini CLI (.gemini/antigravity/skills/)
177
+
178
+ COMMAND DIFFERENCES:
179
+ add <name> Add from your catalog (must exist in catalog first)
180
+ install <github-url> Install directly from GitHub (adds to catalog + project)
181
+
182
+ EXAMPLES:
183
+ # Show status
184
+ acsync skill
185
+ acsync skill status
186
+
187
+ # Add from catalog (requires catalog entry)
188
+ acsync skill add frontend-design --targets claude
189
+ acsync skill add skill-creator --targets claude,codex
190
+
191
+ # Install directly from GitHub (adds to catalog + project)
192
+ acsync skill install https://github.com/anthropics/skills/tree/main/skill-creator
193
+ acsync skill install https://github.com/user/repo --name my-skill --targets claude
194
+
195
+ # Install without adding to catalog
196
+ acsync skill install <github-url> --no-catalog --targets claude
197
+
198
+ # Remove from project
199
+ acsync skill remove frontend-design
200
+
201
+ # Work with catalog
202
+ acsync catalog skill list # List catalog entries
203
+ acsync catalog skill import <path> # Import local skill to catalog
204
+ acsync catalog skill search <query> # Search skills.directory registry
205
+ `;
206
+ const VALIDATE_HELP = `acsync validate - Validate current project configuration
207
+
208
+ USAGE:
209
+ acsync validate [options]
210
+
211
+ OPTIONS:
212
+ --strict Fail on warnings as well as errors
213
+
214
+ DESCRIPTION:
215
+ Validates MCP and skill configurations across all target agents.
216
+ Checks for missing files, invalid configurations, and common issues.
217
+
218
+ EXAMPLES:
219
+ acsync validate # Show warnings but don't fail
220
+ acsync validate --strict # Fail on any warnings or errors
221
+ `;
222
+ const DOCTOR_HELP = `acsync doctor - Run diagnostics and health checks
223
+
224
+ USAGE:
225
+ acsync doctor [options]
226
+
227
+ OPTIONS:
228
+ --fix Attempt to auto-fix issues
229
+
230
+ DESCRIPTION:
231
+ Runs comprehensive diagnostics on your acsync setup and project configurations.
232
+ Checks catalog integrity, config file validity, and common issues.
233
+
234
+ EXAMPLES:
235
+ acsync doctor # Diagnose issues without fixing
236
+ acsync doctor --fix # Attempt to auto-fix found issues
237
+ `;
238
+ // ============================================================================
239
+ // Main
240
+ // ============================================================================
241
+ async function main() {
242
+ const argv = process.argv.slice(2);
243
+ // Top-level help
244
+ if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h') {
245
+ process.stdout.write(HELP);
246
+ return;
247
+ }
248
+ // Version
249
+ if (argv[0] === '--version' || argv[0] === '-V') {
250
+ const { version } = await getPackageVersion();
251
+ process.stdout.write(`acsync v${version}\n`);
252
+ return;
253
+ }
254
+ const command = argv[0];
255
+ switch (command) {
256
+ case 'init':
257
+ await handleInit(argv.slice(1));
258
+ break;
259
+ case 'catalog':
260
+ await handleCatalog(argv.slice(1));
261
+ break;
262
+ case 'mcp':
263
+ await handleMcp(argv.slice(1));
264
+ break;
265
+ case 'skill':
266
+ await handleSkill(argv.slice(1));
267
+ break;
268
+ case 'validate':
269
+ await handleValidate(argv.slice(1));
270
+ break;
271
+ case 'doctor':
272
+ await handleDoctor(argv.slice(1));
273
+ break;
274
+ default:
275
+ process.stderr.write(`Unknown command: ${command}\n\n`);
276
+ process.stderr.write(HELP);
277
+ process.exitCode = 1;
278
+ }
279
+ }
280
+ // ============================================================================
281
+ // Command Handlers
282
+ // ============================================================================
283
+ async function handleCatalog(argv) {
284
+ if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h') {
285
+ process.stdout.write(CATALOG_HELP);
286
+ return;
287
+ }
288
+ const resource = argv[0];
289
+ const subcommand = argv[1];
290
+ const args = argv.slice(2);
291
+ if (resource !== 'mcp' && resource !== 'skill') {
292
+ process.stderr.write(`Unknown catalog resource: ${resource}\n`);
293
+ process.stderr.write('Use "acsync catalog mcp" or "acsync catalog skill" for management.\n');
294
+ process.exitCode = 1;
295
+ return;
296
+ }
297
+ if (subcommand === '--help' || subcommand === '-h') {
298
+ process.stdout.write(CATALOG_HELP);
299
+ return;
300
+ }
301
+ switch (resource) {
302
+ case 'mcp':
303
+ await handleCatalogMcp(subcommand, args);
304
+ break;
305
+ case 'skill':
306
+ await handleCatalogSkill(subcommand, args);
307
+ break;
308
+ }
309
+ }
310
+ async function handleCatalogMcp(subcommand, args) {
311
+ if (!subcommand) {
312
+ process.stderr.write('Usage: acsync catalog mcp <subcommand>\n');
313
+ process.exitCode = 1;
314
+ return;
315
+ }
316
+ switch (subcommand) {
317
+ case 'list':
318
+ await catalogMcpList();
319
+ break;
320
+ case 'show':
321
+ if (args.length === 0) {
322
+ process.stderr.write('Usage: acsync catalog mcp show <id>\n');
323
+ process.exitCode = 1;
324
+ return;
325
+ }
326
+ await catalogMcpShow(args[0]);
327
+ break;
328
+ case 'add':
329
+ await handleCatalogMcpAdd(args);
330
+ break;
331
+ case 'remove':
332
+ if (args.length === 0) {
333
+ process.stderr.write('Usage: acsync catalog mcp remove <id>\n');
334
+ process.exitCode = 1;
335
+ return;
336
+ }
337
+ await catalogMcpRemove(args[0]);
338
+ break;
339
+ default:
340
+ process.stderr.write(`Unknown subcommand: ${subcommand}\n`);
341
+ process.stderr.write(CATALOG_HELP);
342
+ process.exitCode = 1;
343
+ }
344
+ }
345
+ async function handleCatalogMcpAdd(argv) {
346
+ if (argv.length === 0) {
347
+ process.stderr.write('Usage: acsync catalog mcp add <package-id> [options]\n');
348
+ process.exitCode = 1;
349
+ return;
350
+ }
351
+ const packageId = argv[0];
352
+ const options = parseCatalogMcpAddOptions(argv.slice(1));
353
+ await catalogMcpAdd({
354
+ packageId,
355
+ displayName: options.displayName,
356
+ description: options.description,
357
+ command: options.command,
358
+ args: options.args,
359
+ url: options.url,
360
+ cwd: options.cwd,
361
+ env: options.env,
362
+ });
363
+ }
364
+ async function handleCatalogSkill(subcommand, args) {
365
+ if (!subcommand) {
366
+ process.stderr.write('Usage: acsync catalog skill <subcommand>\n');
367
+ process.exitCode = 1;
368
+ return;
369
+ }
370
+ switch (subcommand) {
371
+ case 'list':
372
+ await (await import('./cli-catalog.js')).catalogSkillList();
373
+ break;
374
+ case 'show':
375
+ if (args.length === 0) {
376
+ process.stderr.write('Usage: acsync catalog skill show <id>\n');
377
+ process.exitCode = 1;
378
+ return;
379
+ }
380
+ await (await import('./cli-catalog.js')).catalogSkillShow(args[0]);
381
+ break;
382
+ case 'add':
383
+ await handleCatalogSkillAdd(args);
384
+ break;
385
+ case 'install':
386
+ await handleCatalogSkillInstall(args);
387
+ break;
388
+ case 'search':
389
+ if (args.length === 0) {
390
+ process.stderr.write('Usage: acsync catalog skill search <query>\n');
391
+ process.exitCode = 1;
392
+ return;
393
+ }
394
+ await (await import('./cli-catalog.js')).catalogSkillSearch(args[0]);
395
+ break;
396
+ case 'import':
397
+ await handleCatalogSkillImport(args);
398
+ break;
399
+ case 'remove':
400
+ if (args.length === 0) {
401
+ process.stderr.write('Usage: acsync catalog skill remove <id>\n');
402
+ process.exitCode = 1;
403
+ return;
404
+ }
405
+ await (await import('./cli-catalog.js')).catalogSkillRemove(args[0]);
406
+ break;
407
+ default:
408
+ process.stderr.write(`Unknown subcommand: ${subcommand}\n`);
409
+ process.stderr.write(CATALOG_HELP);
410
+ process.exitCode = 1;
411
+ }
412
+ }
413
+ async function handleCatalogSkillAdd(argv) {
414
+ if (argv.length === 0) {
415
+ process.stderr.write('Usage: acsync catalog skill add <skill-id> [options]\n');
416
+ process.exitCode = 1;
417
+ return;
418
+ }
419
+ const skillId = argv[0];
420
+ const options = parseCatalogSkillAddOptions(argv.slice(1));
421
+ await (await import('./cli-catalog.js')).catalogSkillAdd({
422
+ skillId,
423
+ file: options.file,
424
+ displayName: options.displayName,
425
+ description: options.description,
426
+ });
427
+ }
428
+ async function handleCatalogSkillInstall(argv) {
429
+ if (argv.length === 0) {
430
+ process.stderr.write('Usage: acsync catalog skill install <skill-id> [--force]\n');
431
+ process.exitCode = 1;
432
+ return;
433
+ }
434
+ const skillId = argv[0];
435
+ const force = parseFlag(argv, 'force');
436
+ await (await import('./cli-catalog.js')).catalogSkillInstall({ skillId, force });
437
+ }
438
+ async function handleCatalogSkillImport(argv) {
439
+ if (argv.length === 0) {
440
+ process.stderr.write('Usage: acsync catalog skill import <path> [options]\n');
441
+ process.exitCode = 1;
442
+ return;
443
+ }
444
+ const skillPath = argv[0];
445
+ const options = parseCatalogSkillImportOptions(argv.slice(1));
446
+ await (await import('./cli-catalog.js')).catalogSkillImport({
447
+ path: skillPath,
448
+ skillId: options.skillId,
449
+ displayName: options.displayName,
450
+ description: options.description,
451
+ });
452
+ }
453
+ async function handleMcp(argv) {
454
+ if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h') {
455
+ process.stdout.write(MCP_HELP);
456
+ return;
457
+ }
458
+ // Check if verbose flag is present
459
+ const verbose = parseFlag(argv, 'verbose', 'v');
460
+ // Remove verbose from argv for further parsing
461
+ const filteredArgs = argv.filter((arg) => arg !== '--verbose' && arg !== '-v');
462
+ const subcommand = filteredArgs[0];
463
+ // Default to status if no subcommand or status
464
+ if (!subcommand || subcommand === 'status') {
465
+ await mcpStatus(verbose);
466
+ return;
467
+ }
468
+ const options = parseMcpOptions(filteredArgs.slice(1), subcommand);
469
+ switch (subcommand) {
470
+ case 'add':
471
+ if (options.packageId === undefined) {
472
+ process.stderr.write('Usage: acsync mcp add <package> [options]\n');
473
+ process.exitCode = 1;
474
+ return;
475
+ }
476
+ await mcpAdd({
477
+ packageId: options.packageId,
478
+ targets: options.targets,
479
+ noRegister: options.noRegister,
480
+ });
481
+ break;
482
+ case 'remove':
483
+ if (options.packageId === undefined) {
484
+ process.stderr.write('Usage: acsync mcp remove <server> [options]\n');
485
+ process.exitCode = 1;
486
+ return;
487
+ }
488
+ await mcpRemove({
489
+ serverName: options.packageId,
490
+ targets: options.targets,
491
+ });
492
+ break;
493
+ case 'enable':
494
+ if (options.packageId === undefined) {
495
+ process.stderr.write('Usage: acsync mcp enable <server> [options]\n');
496
+ process.exitCode = 1;
497
+ return;
498
+ }
499
+ await mcpEnable({
500
+ serverName: options.packageId,
501
+ targets: options.targets,
502
+ });
503
+ break;
504
+ case 'disable':
505
+ if (options.packageId === undefined) {
506
+ process.stderr.write('Usage: acsync mcp disable <server> [options]\n');
507
+ process.exitCode = 1;
508
+ return;
509
+ }
510
+ await mcpDisable({
511
+ serverName: options.packageId,
512
+ targets: options.targets,
513
+ });
514
+ break;
515
+ default:
516
+ process.stderr.write(`Unknown subcommand: ${subcommand}\n`);
517
+ process.stderr.write(MCP_HELP);
518
+ process.exitCode = 1;
519
+ }
520
+ }
521
+ async function handleSkill(argv) {
522
+ if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h') {
523
+ process.stdout.write(SKILL_HELP);
524
+ return;
525
+ }
526
+ // Check if verbose flag is present
527
+ const verbose = parseFlag(argv, 'verbose', 'v');
528
+ // Remove verbose from argv for further parsing
529
+ const filteredArgs = argv.filter((arg) => arg !== '--verbose' && arg !== '-v');
530
+ const subcommand = filteredArgs[0];
531
+ // Default to status if no subcommand or status
532
+ if (!subcommand || subcommand === 'status') {
533
+ await skillStatus(verbose);
534
+ return;
535
+ }
536
+ const options = parseSkillOptions(filteredArgs.slice(1), subcommand);
537
+ switch (subcommand) {
538
+ case 'add':
539
+ if (options.skillId === undefined) {
540
+ process.stderr.write('Usage: acsync skill add <name> [options]\n');
541
+ process.exitCode = 1;
542
+ return;
543
+ }
544
+ await skillAdd({
545
+ skillId: options.skillId,
546
+ targets: options.targets,
547
+ noRegister: options.noRegister,
548
+ });
549
+ break;
550
+ case 'install':
551
+ if (options.githubUrl === undefined) {
552
+ process.stderr.write('Usage: acsync skill install <github-url> [options]\n');
553
+ process.exitCode = 1;
554
+ return;
555
+ }
556
+ await (await import('./cli-skill.js')).skillInstallFromGitHub({
557
+ githubUrl: options.githubUrl,
558
+ skillName: options.skillName,
559
+ targets: options.targets,
560
+ addToCatalog: options.addToCatalog,
561
+ });
562
+ break;
563
+ case 'remove':
564
+ if (options.skillId === undefined) {
565
+ process.stderr.write('Usage: acsync skill remove <name> [options]\n');
566
+ process.exitCode = 1;
567
+ return;
568
+ }
569
+ await skillRemove({
570
+ skillName: options.skillId,
571
+ targets: options.targets,
572
+ });
573
+ break;
574
+ case 'enable':
575
+ if (options.skillId === undefined) {
576
+ process.stderr.write('Usage: acsync skill enable <name> [options]\n');
577
+ process.exitCode = 1;
578
+ return;
579
+ }
580
+ await skillEnable({
581
+ skillName: options.skillId,
582
+ targets: options.targets,
583
+ });
584
+ break;
585
+ case 'disable':
586
+ if (options.skillId === undefined) {
587
+ process.stderr.write('Usage: acsync skill disable <name> [options]\n');
588
+ process.exitCode = 1;
589
+ return;
590
+ }
591
+ await skillDisable({
592
+ skillName: options.skillId,
593
+ targets: options.targets,
594
+ });
595
+ break;
596
+ default:
597
+ process.stderr.write(`Unknown subcommand: ${subcommand}\n`);
598
+ process.stderr.write(SKILL_HELP);
599
+ process.exitCode = 1;
600
+ }
601
+ }
602
+ async function handleValidate(argv) {
603
+ if (argv.includes('--help') || argv.includes('-h')) {
604
+ process.stdout.write(VALIDATE_HELP);
605
+ return;
606
+ }
607
+ const strict = parseFlag(argv, 'strict');
608
+ await validate({ strict });
609
+ }
610
+ async function handleDoctor(argv) {
611
+ if (argv.includes('--help') || argv.includes('-h')) {
612
+ process.stdout.write(DOCTOR_HELP);
613
+ return;
614
+ }
615
+ const fix = parseFlag(argv, 'fix');
616
+ await doctor({ fix });
617
+ }
618
+ // ============================================================================
619
+ // Init Command
620
+ // ============================================================================
621
+ const INIT_HELP = `acsync init - Interactive setup for the current project
622
+
623
+ USAGE:
624
+ acsync init [options]
625
+
626
+ OPTIONS:
627
+ --targets <list> Pre-select targets (e.g., claude,codex)
628
+
629
+ DESCRIPTION:
630
+ Interactive setup wizard for configuring your project.
631
+ Guides you through selecting MCP servers and skills from your catalog.
632
+
633
+ EXAMPLES:
634
+ acsync init # Full interactive setup
635
+ acsync init --targets claude # Skip target selection
636
+ `;
637
+ async function handleInit(argv) {
638
+ if (argv.includes('--help') || argv.includes('-h')) {
639
+ process.stdout.write(INIT_HELP);
640
+ return;
641
+ }
642
+ const options = parseInitOptions(argv);
643
+ await init(options);
644
+ }
645
+ function parseInitOptions(argv) {
646
+ const options = {};
647
+ for (let i = 0; i < argv.length; i++) {
648
+ const arg = argv[i];
649
+ switch (arg) {
650
+ case '--targets':
651
+ options.targets = argv[++i].split(',').map(t => t.trim());
652
+ break;
653
+ default:
654
+ process.stderr.write(`Unknown option: ${arg}\n`);
655
+ process.stderr.write(INIT_HELP);
656
+ process.exitCode = 1;
657
+ break;
658
+ }
659
+ }
660
+ return options;
661
+ }
662
+ async function init(options) {
663
+ console.log('🚀 acsync init - Interactive Project Setup\n');
664
+ // Import the interactive init module
665
+ const { runInteractiveInit } = await import('./cli-init.js');
666
+ await runInteractiveInit(options);
667
+ }
668
+ function parseMcpOptions(argv, subcommand) {
669
+ const options = {
670
+ targets: ['claude', 'codex'], // Default targets
671
+ noRegister: false,
672
+ };
673
+ let i = 0;
674
+ while (i < argv.length) {
675
+ const arg = argv[i];
676
+ switch (arg) {
677
+ case '--targets':
678
+ options.targets = parseTargets(argv[++i]);
679
+ break;
680
+ case '--no-register':
681
+ options.noRegister = true;
682
+ break;
683
+ case '--register':
684
+ options.noRegister = false;
685
+ break;
686
+ case '--verbose':
687
+ case '-v':
688
+ options.verbose = true;
689
+ break;
690
+ default:
691
+ // Treat as package/server name (except for status subcommand which doesn't need it)
692
+ if (!options.packageId && subcommand !== 'status') {
693
+ options.packageId = arg;
694
+ }
695
+ break;
696
+ }
697
+ i++;
698
+ }
699
+ return options;
700
+ }
701
+ function parseCatalogMcpAddOptions(argv) {
702
+ const options = {};
703
+ let i = 0;
704
+ while (i < argv.length) {
705
+ const arg = argv[i];
706
+ switch (arg) {
707
+ case '--display-name':
708
+ options.displayName = argv[++i];
709
+ break;
710
+ case '--description':
711
+ options.description = argv[++i];
712
+ break;
713
+ case '--command':
714
+ options.command = argv[++i];
715
+ break;
716
+ case '--args':
717
+ options.args = JSON.parse(argv[++i]);
718
+ break;
719
+ case '--url':
720
+ options.url = argv[++i];
721
+ break;
722
+ case '--cwd':
723
+ options.cwd = argv[++i];
724
+ break;
725
+ case '--env':
726
+ options.env = JSON.parse(argv[++i]);
727
+ break;
728
+ default:
729
+ process.stderr.write(`Unknown option: ${arg}\n`);
730
+ process.exitCode = 1;
731
+ break;
732
+ }
733
+ i++;
734
+ }
735
+ return options;
736
+ }
737
+ function parseCatalogSkillAddOptions(argv) {
738
+ const options = {};
739
+ let i = 0;
740
+ while (i < argv.length) {
741
+ const arg = argv[i];
742
+ switch (arg) {
743
+ case '--file':
744
+ options.file = argv[++i];
745
+ break;
746
+ case '--display-name':
747
+ options.displayName = argv[++i];
748
+ break;
749
+ case '--description':
750
+ options.description = argv[++i];
751
+ break;
752
+ default:
753
+ process.stderr.write(`Unknown option: ${arg}\n`);
754
+ process.exitCode = 1;
755
+ break;
756
+ }
757
+ i++;
758
+ }
759
+ return options;
760
+ }
761
+ function parseCatalogSkillImportOptions(argv) {
762
+ const options = {};
763
+ let i = 0;
764
+ while (i < argv.length) {
765
+ const arg = argv[i];
766
+ switch (arg) {
767
+ case '--name':
768
+ options.skillId = argv[++i];
769
+ break;
770
+ case '--display-name':
771
+ options.displayName = argv[++i];
772
+ break;
773
+ case '--description':
774
+ options.description = argv[++i];
775
+ break;
776
+ default:
777
+ process.stderr.write(`Unknown option: ${arg}\n`);
778
+ process.exitCode = 1;
779
+ break;
780
+ }
781
+ i++;
782
+ }
783
+ return options;
784
+ }
785
+ function parseTargets(input) {
786
+ const validTargets = ['claude', 'codex', 'gemini'];
787
+ const targets = input.split(',').map((t) => t.trim().toLowerCase());
788
+ for (const target of targets) {
789
+ if (!validTargets.includes(target)) {
790
+ process.stderr.write(`Invalid target: ${target}\n`);
791
+ process.stderr.write(`Valid targets: ${validTargets.join(', ')}\n`);
792
+ process.exit(1);
793
+ }
794
+ }
795
+ return targets;
796
+ }
797
+ function parseSkillOptions(argv, subcommand) {
798
+ const options = {
799
+ targets: ['claude', 'codex'], // Default targets
800
+ noRegister: false,
801
+ };
802
+ let i = 0;
803
+ while (i < argv.length) {
804
+ const arg = argv[i];
805
+ switch (arg) {
806
+ case '--targets':
807
+ options.targets = parseTargets(argv[++i]);
808
+ break;
809
+ case '--no-register':
810
+ options.noRegister = true;
811
+ break;
812
+ case '--register':
813
+ options.noRegister = false;
814
+ break;
815
+ case '--verbose':
816
+ case '-v':
817
+ options.verbose = true;
818
+ break;
819
+ case '--from-github':
820
+ case '--github':
821
+ options.githubUrl = argv[++i];
822
+ break;
823
+ case '--name':
824
+ options.skillName = argv[++i];
825
+ break;
826
+ case '--no-catalog':
827
+ options.addToCatalog = false;
828
+ break;
829
+ default:
830
+ // Treat as skill name or GitHub URL (except for status subcommand)
831
+ if (subcommand === 'install' && arg.startsWith('http')) {
832
+ options.githubUrl = arg;
833
+ }
834
+ else if (!options.skillId && subcommand !== 'status') {
835
+ options.skillId = arg;
836
+ }
837
+ break;
838
+ }
839
+ i++;
840
+ }
841
+ return options;
842
+ }
843
+ function parseFlag(argv, longName, shortName) {
844
+ return argv.includes(`--${longName}`) || (shortName ? argv.includes(`-${shortName}`) : false);
845
+ }
846
+ // ============================================================================
847
+ // Utilities
848
+ // ============================================================================
849
+ async function getPackageVersion() {
850
+ // Read package.json dynamically to support global installation
851
+ const { readFile } = await import('node:fs/promises');
852
+ const { dirname, join } = await import('node:path');
853
+ const { fileURLToPath } = await import('node:url');
854
+ const __filename = fileURLToPath(import.meta.url);
855
+ const __dirname = dirname(__filename);
856
+ const pkgPath = join(__dirname, '..', 'package.json');
857
+ const content = await readFile(pkgPath, 'utf8');
858
+ return JSON.parse(content);
859
+ }
860
+ // ============================================================================
861
+ // Error Handling
862
+ // ============================================================================
863
+ main().catch((error) => {
864
+ const message = error instanceof Error ? error.message : String(error);
865
+ process.stderr.write(`Error: ${message}\n`);
866
+ process.exit(1);
867
+ });
868
+ //# sourceMappingURL=cli.js.map