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/LICENSE +21 -0
- package/README.md +174 -0
- package/dist/catalog.d.ts +65 -0
- package/dist/catalog.js +328 -0
- package/dist/catalog.js.map +1 -0
- package/dist/cli-catalog.d.ts +70 -0
- package/dist/cli-catalog.js +433 -0
- package/dist/cli-catalog.js.map +1 -0
- package/dist/cli-diagnostics.d.ts +14 -0
- package/dist/cli-diagnostics.js +177 -0
- package/dist/cli-diagnostics.js.map +1 -0
- package/dist/cli-mcp.d.ts +38 -0
- package/dist/cli-mcp.js +179 -0
- package/dist/cli-mcp.js.map +1 -0
- package/dist/cli-skill.d.ts +51 -0
- package/dist/cli-skill.js +239 -0
- package/dist/cli-skill.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +733 -0
- package/dist/cli.js.map +1 -0
- package/dist/config-adapters.d.ts +32 -0
- package/dist/config-adapters.js +409 -0
- package/dist/config-adapters.js.map +1 -0
- package/dist/fs.d.ts +2 -0
- package/dist/fs.js +20 -0
- package/dist/fs.js.map +1 -0
- package/dist/project-discovery.d.ts +24 -0
- package/dist/project-discovery.js +129 -0
- package/dist/project-discovery.js.map +1 -0
- package/dist/registry.d.ts +49 -0
- package/dist/registry.js +121 -0
- package/dist/registry.js.map +1 -0
- package/dist/skill-adapters.d.ts +53 -0
- package/dist/skill-adapters.js +183 -0
- package/dist/skill-adapters.js.map +1 -0
- package/dist/types.d.ts +151 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/package.json +64 -0
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
|