@cleocode/caamp 0.3.0 → 0.4.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/README.md +18 -2
- package/dist/{chunk-PCWTRJV2.js → chunk-6HQDRJLS.js} +1135 -172
- package/dist/chunk-6HQDRJLS.js.map +1 -0
- package/dist/cli.js +966 -50
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +330 -40
- package/dist/index.js +45 -1
- package/package.json +7 -3
- package/dist/chunk-PCWTRJV2.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
MarketplaceClient,
|
|
4
|
+
RECOMMENDATION_ERROR_CODES,
|
|
5
|
+
applyMcpInstallWithPolicy,
|
|
4
6
|
buildServerConfig,
|
|
7
|
+
buildSkillSubPathCandidates,
|
|
5
8
|
checkAllInjections,
|
|
6
9
|
checkSkillUpdate,
|
|
10
|
+
configureProviderGlobalAndProject,
|
|
7
11
|
detectAllProviders,
|
|
12
|
+
detectMcpConfigConflicts,
|
|
8
13
|
detectProjectProviders,
|
|
9
14
|
discoverSkillsMulti,
|
|
15
|
+
formatNetworkError,
|
|
16
|
+
formatSkillRecommendations,
|
|
10
17
|
generateInjectionContent,
|
|
11
18
|
getAllProviders,
|
|
12
19
|
getInstalledProviders,
|
|
@@ -17,6 +24,7 @@ import {
|
|
|
17
24
|
getTrackedSkills,
|
|
18
25
|
groupByInstructFile,
|
|
19
26
|
injectAll,
|
|
27
|
+
installBatchWithRollback,
|
|
20
28
|
installMcpServerToAll,
|
|
21
29
|
installSkill,
|
|
22
30
|
isMarketplaceScoped,
|
|
@@ -25,6 +33,7 @@ import {
|
|
|
25
33
|
parseSource,
|
|
26
34
|
readConfig,
|
|
27
35
|
readLockFile,
|
|
36
|
+
recommendSkills,
|
|
28
37
|
recordMcpInstall,
|
|
29
38
|
recordSkillInstall,
|
|
30
39
|
removeMcpFromLock,
|
|
@@ -32,13 +41,19 @@ import {
|
|
|
32
41
|
removeSkill,
|
|
33
42
|
removeSkillFromLock,
|
|
34
43
|
resolveConfigPath,
|
|
44
|
+
resolvePreferredConfigScope,
|
|
45
|
+
resolveProviderConfigPath,
|
|
46
|
+
resolveProviderSkillsDir,
|
|
35
47
|
scanDirectory,
|
|
36
48
|
scanFile,
|
|
49
|
+
selectProvidersByMinimumPriority,
|
|
37
50
|
setQuiet,
|
|
38
51
|
setVerbose,
|
|
39
52
|
toSarif,
|
|
53
|
+
tokenizeCriteriaValue,
|
|
54
|
+
updateInstructionsSingleOperation,
|
|
40
55
|
validateSkill
|
|
41
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-6HQDRJLS.js";
|
|
42
57
|
|
|
43
58
|
// src/cli.ts
|
|
44
59
|
import { Command } from "commander";
|
|
@@ -137,6 +152,7 @@ ${provider.toolName}`));
|
|
|
137
152
|
}
|
|
138
153
|
|
|
139
154
|
// src/commands/skills/install.ts
|
|
155
|
+
import { existsSync } from "fs";
|
|
140
156
|
import pc2 from "picocolors";
|
|
141
157
|
|
|
142
158
|
// src/core/sources/github.ts
|
|
@@ -215,7 +231,13 @@ function registerSkillsInstall(parent) {
|
|
|
215
231
|
if (isMarketplaceScoped(source)) {
|
|
216
232
|
console.log(pc2.dim(`Searching marketplace for ${source}...`));
|
|
217
233
|
const client = new MarketplaceClient();
|
|
218
|
-
|
|
234
|
+
let skill;
|
|
235
|
+
try {
|
|
236
|
+
skill = await client.getSkill(source);
|
|
237
|
+
} catch (error) {
|
|
238
|
+
console.error(pc2.red(`Marketplace lookup failed: ${formatNetworkError(error)}`));
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
219
241
|
if (!skill) {
|
|
220
242
|
console.error(pc2.red(`Skill not found: ${source}`));
|
|
221
243
|
process.exit(1);
|
|
@@ -226,25 +248,58 @@ function registerSkillsInstall(parent) {
|
|
|
226
248
|
console.error(pc2.red("Could not resolve GitHub source"));
|
|
227
249
|
process.exit(1);
|
|
228
250
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
251
|
+
try {
|
|
252
|
+
const subPathCandidates = buildSkillSubPathCandidates(skill.path, parsed.path);
|
|
253
|
+
let cloneError;
|
|
254
|
+
let cloned = false;
|
|
255
|
+
for (const subPath of subPathCandidates) {
|
|
256
|
+
try {
|
|
257
|
+
const result = await cloneRepo(parsed.owner, parsed.repo, parsed.ref, subPath);
|
|
258
|
+
if (subPath && !existsSync(result.localPath)) {
|
|
259
|
+
await result.cleanup();
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
localPath = result.localPath;
|
|
263
|
+
cleanup = result.cleanup;
|
|
264
|
+
cloned = true;
|
|
265
|
+
break;
|
|
266
|
+
} catch (error) {
|
|
267
|
+
cloneError = error;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
if (!cloned) {
|
|
271
|
+
throw cloneError ?? new Error("Unable to resolve skill path from marketplace metadata");
|
|
272
|
+
}
|
|
273
|
+
skillName = skill.name;
|
|
274
|
+
sourceValue = skill.githubUrl;
|
|
275
|
+
sourceType = parsed.type;
|
|
276
|
+
} catch (error) {
|
|
277
|
+
console.error(pc2.red(`Failed to fetch source repository: ${formatNetworkError(error)}`));
|
|
278
|
+
process.exit(1);
|
|
279
|
+
}
|
|
235
280
|
} else {
|
|
236
281
|
const parsed = parseSource(source);
|
|
237
282
|
skillName = parsed.inferredName;
|
|
238
283
|
sourceValue = parsed.value;
|
|
239
284
|
sourceType = parsed.type;
|
|
240
285
|
if (parsed.type === "github" && parsed.owner && parsed.repo) {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
286
|
+
try {
|
|
287
|
+
const result = await cloneRepo(parsed.owner, parsed.repo, parsed.ref, parsed.path);
|
|
288
|
+
localPath = result.localPath;
|
|
289
|
+
cleanup = result.cleanup;
|
|
290
|
+
} catch (error) {
|
|
291
|
+
console.error(pc2.red(`Failed to clone GitHub repository: ${formatNetworkError(error)}`));
|
|
292
|
+
process.exit(1);
|
|
293
|
+
}
|
|
244
294
|
} else if (parsed.type === "gitlab" && parsed.owner && parsed.repo) {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
295
|
+
try {
|
|
296
|
+
const result = await cloneGitLabRepo(parsed.owner, parsed.repo, parsed.ref, parsed.path);
|
|
297
|
+
localPath = result.localPath;
|
|
298
|
+
cleanup = result.cleanup;
|
|
299
|
+
} catch (error) {
|
|
300
|
+
console.error(pc2.red(`Failed to clone GitLab repository: ${formatNetworkError(error)}`));
|
|
301
|
+
process.exit(1);
|
|
302
|
+
}
|
|
248
303
|
} else if (parsed.type === "local") {
|
|
249
304
|
localPath = parsed.value;
|
|
250
305
|
} else {
|
|
@@ -253,6 +308,9 @@ function registerSkillsInstall(parent) {
|
|
|
253
308
|
}
|
|
254
309
|
}
|
|
255
310
|
try {
|
|
311
|
+
if (!localPath) {
|
|
312
|
+
throw new Error("No local skill path resolved for installation");
|
|
313
|
+
}
|
|
256
314
|
const result = await installSkill(
|
|
257
315
|
localPath,
|
|
258
316
|
skillName,
|
|
@@ -321,7 +379,6 @@ function registerSkillsRemove(parent) {
|
|
|
321
379
|
|
|
322
380
|
// src/commands/skills/list.ts
|
|
323
381
|
import pc4 from "picocolors";
|
|
324
|
-
import { join as join3 } from "path";
|
|
325
382
|
function registerSkillsList(parent) {
|
|
326
383
|
parent.command("list").description("List installed skills").option("-g, --global", "List global skills").option("-a, --agent <name>", "List skills for specific agent").option("--json", "Output as JSON").action(async (opts) => {
|
|
327
384
|
let dirs = [];
|
|
@@ -331,13 +388,13 @@ function registerSkillsList(parent) {
|
|
|
331
388
|
console.error(pc4.red(`Provider not found: ${opts.agent}`));
|
|
332
389
|
process.exit(1);
|
|
333
390
|
}
|
|
334
|
-
dirs = opts.global ? [provider
|
|
391
|
+
dirs = opts.global ? [resolveProviderSkillsDir(provider, "global")] : [resolveProviderSkillsDir(provider, "project")];
|
|
335
392
|
} else if (opts.global) {
|
|
336
393
|
const providers = getInstalledProviders();
|
|
337
|
-
dirs = providers.map((p) => p
|
|
394
|
+
dirs = providers.map((p) => resolveProviderSkillsDir(p, "global")).filter(Boolean);
|
|
338
395
|
} else {
|
|
339
396
|
const providers = getInstalledProviders();
|
|
340
|
-
dirs = providers.map((p) =>
|
|
397
|
+
dirs = providers.map((p) => resolveProviderSkillsDir(p, "project")).filter(Boolean);
|
|
341
398
|
}
|
|
342
399
|
const skills = await discoverSkillsMulti(dirs);
|
|
343
400
|
if (opts.json) {
|
|
@@ -359,19 +416,125 @@ ${skills.length} skill(s) found:
|
|
|
359
416
|
}
|
|
360
417
|
|
|
361
418
|
// src/commands/skills/find.ts
|
|
419
|
+
import { randomUUID } from "crypto";
|
|
420
|
+
import {
|
|
421
|
+
resolveOutputFormat
|
|
422
|
+
} from "@cleocode/lafs-protocol";
|
|
362
423
|
import pc5 from "picocolors";
|
|
424
|
+
var SkillsFindValidationError = class extends Error {
|
|
425
|
+
code;
|
|
426
|
+
constructor(code, message) {
|
|
427
|
+
super(message);
|
|
428
|
+
this.code = code;
|
|
429
|
+
this.name = "SkillsFindValidationError";
|
|
430
|
+
}
|
|
431
|
+
};
|
|
363
432
|
function registerSkillsFind(parent) {
|
|
364
|
-
parent.command("find").description("Search marketplace for skills").argument("[query]", "Search query").option("--json", "Output as JSON").option("-l, --limit <n>", "Max results", "20").action(async (query, opts) => {
|
|
433
|
+
parent.command("find").description("Search marketplace for skills").argument("[query]", "Search query").option("--recommend", "Recommend skills from constraints").option("--top <n>", "Number of recommendation candidates", "3").option("--must-have <term>", "Required criteria term", (value, previous) => [...previous, value], []).option("--prefer <term>", "Preferred criteria term", (value, previous) => [...previous, value], []).option("--exclude <term>", "Excluded criteria term", (value, previous) => [...previous, value], []).option("--details", "Include expanded machine output").option("--human", "Force human-readable output").option("--json", "Output as JSON").option("--select <indexes>", "Pre-select recommendation ranks (comma-separated)").option("-l, --limit <n>", "Max results", "20").action(async (query, opts) => {
|
|
434
|
+
const operation = opts.recommend ? "skills.find.recommend" : "skills.find.search";
|
|
435
|
+
const details = Boolean(opts.details);
|
|
436
|
+
const mvi = !details;
|
|
437
|
+
let format;
|
|
438
|
+
try {
|
|
439
|
+
format = resolveOutputFormat({
|
|
440
|
+
jsonFlag: opts.json ?? false,
|
|
441
|
+
humanFlag: opts.human ?? false,
|
|
442
|
+
projectDefault: opts.recommend ? "json" : "human"
|
|
443
|
+
}).format;
|
|
444
|
+
} catch (error) {
|
|
445
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
446
|
+
if (opts.json) {
|
|
447
|
+
emitJsonError(operation, mvi, "E_FORMAT_CONFLICT", message, "VALIDATION");
|
|
448
|
+
} else {
|
|
449
|
+
console.error(pc5.red(message));
|
|
450
|
+
}
|
|
451
|
+
process.exit(1);
|
|
452
|
+
}
|
|
453
|
+
if (opts.recommend) {
|
|
454
|
+
try {
|
|
455
|
+
const top = parseTop(opts.top);
|
|
456
|
+
const mustHave = parseConstraintList(opts.mustHave);
|
|
457
|
+
const prefer = parseConstraintList(opts.prefer);
|
|
458
|
+
const exclude = parseConstraintList(opts.exclude);
|
|
459
|
+
validateCriteriaConflicts(mustHave, prefer, exclude);
|
|
460
|
+
const selectedRanks = parseSelectList(opts.select);
|
|
461
|
+
const seedQuery = buildSeedQuery(query, mustHave, prefer, exclude);
|
|
462
|
+
const recommendation = await recommendSkills(
|
|
463
|
+
seedQuery,
|
|
464
|
+
{
|
|
465
|
+
mustHave,
|
|
466
|
+
prefer,
|
|
467
|
+
exclude
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
top,
|
|
471
|
+
includeDetails: details
|
|
472
|
+
}
|
|
473
|
+
);
|
|
474
|
+
const options = normalizeRecommendationOptions(recommendation.ranking, details);
|
|
475
|
+
validateSelectedRanks(selectedRanks, options.length);
|
|
476
|
+
const selected = selectedRanks.length > 0 ? options.filter((option) => selectedRanks.includes(option.rank)) : [];
|
|
477
|
+
if (format === "json") {
|
|
478
|
+
const result = formatSkillRecommendations(recommendation, { mode: "json", details });
|
|
479
|
+
const resultOptions = Array.isArray(result.options) ? result.options : [];
|
|
480
|
+
const selectedObjects = resultOptions.filter(
|
|
481
|
+
(option) => selectedRanks.includes(Number(option.rank ?? 0))
|
|
482
|
+
);
|
|
483
|
+
const envelope = buildEnvelope(
|
|
484
|
+
operation,
|
|
485
|
+
mvi,
|
|
486
|
+
{
|
|
487
|
+
...result,
|
|
488
|
+
selected: selectedObjects
|
|
489
|
+
},
|
|
490
|
+
null
|
|
491
|
+
);
|
|
492
|
+
console.log(JSON.stringify(envelope, null, 2));
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
const human = formatSkillRecommendations(recommendation, { mode: "human", details });
|
|
496
|
+
console.log(human);
|
|
497
|
+
if (selected.length > 0) {
|
|
498
|
+
console.log(`Selected: ${selected.map((option) => option.scopedName).join(", ")}`);
|
|
499
|
+
}
|
|
500
|
+
return;
|
|
501
|
+
} catch (error) {
|
|
502
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
503
|
+
const errorCode = error instanceof SkillsFindValidationError ? error.code : error.code ?? RECOMMENDATION_ERROR_CODES.SOURCE_UNAVAILABLE;
|
|
504
|
+
const category = errorCode === RECOMMENDATION_ERROR_CODES.CRITERIA_CONFLICT ? "CONFLICT" : errorCode === RECOMMENDATION_ERROR_CODES.NO_MATCHES ? "NOT_FOUND" : errorCode === RECOMMENDATION_ERROR_CODES.QUERY_INVALID ? "VALIDATION" : "INTERNAL";
|
|
505
|
+
if (format === "json") {
|
|
506
|
+
emitJsonError(operation, mvi, errorCode, message, category, {
|
|
507
|
+
query: query ?? null
|
|
508
|
+
});
|
|
509
|
+
} else {
|
|
510
|
+
console.error(pc5.red(`Recommendation failed: ${message}`));
|
|
511
|
+
}
|
|
512
|
+
process.exit(1);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
365
515
|
if (!query) {
|
|
366
516
|
console.log(pc5.dim("Usage: caamp skills find <query>"));
|
|
367
517
|
return;
|
|
368
518
|
}
|
|
369
519
|
const limit = parseInt(opts.limit, 10);
|
|
370
520
|
const client = new MarketplaceClient();
|
|
371
|
-
|
|
521
|
+
if (format === "human") {
|
|
522
|
+
console.log(pc5.dim(`Searching marketplaces for "${query}"...
|
|
372
523
|
`));
|
|
373
|
-
|
|
374
|
-
|
|
524
|
+
}
|
|
525
|
+
let results;
|
|
526
|
+
try {
|
|
527
|
+
results = await client.search(query, limit);
|
|
528
|
+
} catch (error) {
|
|
529
|
+
const message = formatNetworkError(error);
|
|
530
|
+
if (format === "json") {
|
|
531
|
+
console.log(JSON.stringify({ error: message }));
|
|
532
|
+
} else {
|
|
533
|
+
console.error(pc5.red(`Marketplace search failed: ${message}`));
|
|
534
|
+
}
|
|
535
|
+
process.exit(1);
|
|
536
|
+
}
|
|
537
|
+
if (format === "json") {
|
|
375
538
|
console.log(JSON.stringify(results, null, 2));
|
|
376
539
|
return;
|
|
377
540
|
}
|
|
@@ -386,13 +549,118 @@ function registerSkillsFind(parent) {
|
|
|
386
549
|
console.log(` ${pc5.dim(`from ${skill.source}`)}`);
|
|
387
550
|
console.log();
|
|
388
551
|
}
|
|
389
|
-
console.log(pc5.dim(
|
|
552
|
+
console.log(pc5.dim("Install with: caamp skills install <scopedName>"));
|
|
390
553
|
});
|
|
391
554
|
}
|
|
392
555
|
function formatStars(n) {
|
|
393
556
|
if (n >= 1e3) return `${(n / 1e3).toFixed(1)}k`;
|
|
394
557
|
return String(n);
|
|
395
558
|
}
|
|
559
|
+
function parseConstraintList(values) {
|
|
560
|
+
const normalized = values.flatMap((value) => tokenizeCriteriaValue(value));
|
|
561
|
+
return Array.from(new Set(normalized));
|
|
562
|
+
}
|
|
563
|
+
function parseTop(value) {
|
|
564
|
+
const parsed = Number.parseInt(value, 10);
|
|
565
|
+
if (!Number.isInteger(parsed) || parsed < 1 || parsed > 20) {
|
|
566
|
+
throw new SkillsFindValidationError(RECOMMENDATION_ERROR_CODES.QUERY_INVALID, "--top must be an integer between 1 and 20");
|
|
567
|
+
}
|
|
568
|
+
return parsed;
|
|
569
|
+
}
|
|
570
|
+
function parseSelectList(value) {
|
|
571
|
+
if (!value) return [];
|
|
572
|
+
const parsed = value.split(",").map((entry) => Number.parseInt(entry.trim(), 10)).filter((entry) => Number.isInteger(entry) && entry > 0);
|
|
573
|
+
return Array.from(new Set(parsed));
|
|
574
|
+
}
|
|
575
|
+
function buildSeedQuery(query, mustHave, prefer, exclude) {
|
|
576
|
+
if (query && query.trim().length > 0) {
|
|
577
|
+
return query;
|
|
578
|
+
}
|
|
579
|
+
const seedTerms = [...mustHave, ...prefer, ...exclude].filter((term) => term.length > 0);
|
|
580
|
+
if (seedTerms.length > 0) {
|
|
581
|
+
return seedTerms.join(" ");
|
|
582
|
+
}
|
|
583
|
+
throw new SkillsFindValidationError(
|
|
584
|
+
RECOMMENDATION_ERROR_CODES.QUERY_INVALID,
|
|
585
|
+
"Recommendation mode requires a query or at least one criteria flag."
|
|
586
|
+
);
|
|
587
|
+
}
|
|
588
|
+
function normalizeRecommendationOptions(ranking, details) {
|
|
589
|
+
return ranking.map((entry, index) => {
|
|
590
|
+
const whyCodes = entry.reasons.map((reason) => reason.code);
|
|
591
|
+
return {
|
|
592
|
+
rank: index + 1,
|
|
593
|
+
scopedName: entry.skill.scopedName,
|
|
594
|
+
description: entry.skill.description,
|
|
595
|
+
score: entry.score,
|
|
596
|
+
why: whyCodes.length > 0 ? whyCodes.join(", ") : "score-based match",
|
|
597
|
+
source: entry.skill.source,
|
|
598
|
+
...details ? {
|
|
599
|
+
evidence: {
|
|
600
|
+
reasons: entry.reasons,
|
|
601
|
+
breakdown: entry.breakdown
|
|
602
|
+
}
|
|
603
|
+
} : {}
|
|
604
|
+
};
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
function validateCriteriaConflicts(mustHave, prefer, exclude) {
|
|
608
|
+
const overlap = mustHave.filter((term) => exclude.includes(term));
|
|
609
|
+
if (overlap.length > 0) {
|
|
610
|
+
throw new SkillsFindValidationError(
|
|
611
|
+
RECOMMENDATION_ERROR_CODES.CRITERIA_CONFLICT,
|
|
612
|
+
"A criteria term cannot be both required and excluded."
|
|
613
|
+
);
|
|
614
|
+
}
|
|
615
|
+
const preferOverlap = prefer.filter((term) => exclude.includes(term));
|
|
616
|
+
if (preferOverlap.length > 0) {
|
|
617
|
+
throw new SkillsFindValidationError(
|
|
618
|
+
RECOMMENDATION_ERROR_CODES.CRITERIA_CONFLICT,
|
|
619
|
+
"A criteria term cannot be both preferred and excluded."
|
|
620
|
+
);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
function validateSelectedRanks(selectedRanks, total) {
|
|
624
|
+
for (const rank of selectedRanks) {
|
|
625
|
+
if (rank < 1 || rank > total) {
|
|
626
|
+
throw new SkillsFindValidationError(
|
|
627
|
+
RECOMMENDATION_ERROR_CODES.QUERY_INVALID,
|
|
628
|
+
`--select rank ${rank} is out of range (1-${total}).`
|
|
629
|
+
);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
function buildEnvelope(operation, mvi, result, error) {
|
|
634
|
+
return {
|
|
635
|
+
$schema: "https://lafs.dev/schemas/v1/envelope.schema.json",
|
|
636
|
+
_meta: {
|
|
637
|
+
specVersion: "1.0.0",
|
|
638
|
+
schemaVersion: "1.0.0",
|
|
639
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
640
|
+
operation,
|
|
641
|
+
requestId: randomUUID(),
|
|
642
|
+
transport: "cli",
|
|
643
|
+
strict: true,
|
|
644
|
+
mvi,
|
|
645
|
+
contextVersion: 0
|
|
646
|
+
},
|
|
647
|
+
success: error === null,
|
|
648
|
+
result,
|
|
649
|
+
error,
|
|
650
|
+
page: null
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
function emitJsonError(operation, mvi, code, message, category, details = {}) {
|
|
654
|
+
const envelope = buildEnvelope(operation, mvi, null, {
|
|
655
|
+
code,
|
|
656
|
+
message,
|
|
657
|
+
category,
|
|
658
|
+
retryable: false,
|
|
659
|
+
retryAfterMs: null,
|
|
660
|
+
details
|
|
661
|
+
});
|
|
662
|
+
console.error(JSON.stringify(envelope, null, 2));
|
|
663
|
+
}
|
|
396
664
|
|
|
397
665
|
// src/commands/skills/check.ts
|
|
398
666
|
import pc6 from "picocolors";
|
|
@@ -576,13 +844,13 @@ ${outdated.length} skill(s) have updates available:
|
|
|
576
844
|
// src/commands/skills/init.ts
|
|
577
845
|
import pc8 from "picocolors";
|
|
578
846
|
import { writeFile, mkdir } from "fs/promises";
|
|
579
|
-
import { existsSync } from "fs";
|
|
580
|
-
import { join as
|
|
847
|
+
import { existsSync as existsSync2 } from "fs";
|
|
848
|
+
import { join as join3 } from "path";
|
|
581
849
|
function registerSkillsInit(parent) {
|
|
582
850
|
parent.command("init").description("Create a new SKILL.md template").argument("[name]", "Skill name").option("-d, --dir <path>", "Output directory", ".").action(async (name, opts) => {
|
|
583
851
|
const skillName = name ?? "my-skill";
|
|
584
|
-
const skillDir =
|
|
585
|
-
if (
|
|
852
|
+
const skillDir = join3(opts.dir, skillName);
|
|
853
|
+
if (existsSync2(skillDir)) {
|
|
586
854
|
console.error(pc8.red(`Directory already exists: ${skillDir}`));
|
|
587
855
|
process.exit(1);
|
|
588
856
|
}
|
|
@@ -610,21 +878,21 @@ Provide detailed instructions for the AI agent here.
|
|
|
610
878
|
|
|
611
879
|
Show example inputs and expected outputs.
|
|
612
880
|
`;
|
|
613
|
-
await writeFile(
|
|
881
|
+
await writeFile(join3(skillDir, "SKILL.md"), template, "utf-8");
|
|
614
882
|
console.log(pc8.green(`\u2713 Created skill template: ${skillDir}/SKILL.md`));
|
|
615
883
|
console.log(pc8.dim("\nNext steps:"));
|
|
616
884
|
console.log(pc8.dim(" 1. Edit SKILL.md with your instructions"));
|
|
617
|
-
console.log(pc8.dim(" 2. Validate: caamp skills validate " +
|
|
885
|
+
console.log(pc8.dim(" 2. Validate: caamp skills validate " + join3(skillDir, "SKILL.md")));
|
|
618
886
|
console.log(pc8.dim(" 3. Install: caamp skills install " + skillDir));
|
|
619
887
|
});
|
|
620
888
|
}
|
|
621
889
|
|
|
622
890
|
// src/commands/skills/audit.ts
|
|
623
891
|
import pc9 from "picocolors";
|
|
624
|
-
import { existsSync as
|
|
892
|
+
import { existsSync as existsSync3, statSync } from "fs";
|
|
625
893
|
function registerSkillsAudit(parent) {
|
|
626
894
|
parent.command("audit").description("Security scan skill files (46+ rules, SARIF output)").argument("[path]", "Path to SKILL.md or directory", ".").option("--sarif", "Output in SARIF format").option("--json", "Output as JSON").action(async (path, opts) => {
|
|
627
|
-
if (!
|
|
895
|
+
if (!existsSync3(path)) {
|
|
628
896
|
console.error(pc9.red(`Path not found: ${path}`));
|
|
629
897
|
process.exit(1);
|
|
630
898
|
}
|
|
@@ -814,7 +1082,7 @@ function registerMcpList(parent) {
|
|
|
814
1082
|
const providers = opts.agent ? [getProvider(opts.agent)].filter((p) => p !== void 0) : getInstalledProviders();
|
|
815
1083
|
const allEntries = [];
|
|
816
1084
|
for (const provider of providers) {
|
|
817
|
-
const scope = opts.global
|
|
1085
|
+
const scope = resolvePreferredConfigScope(provider, opts.global);
|
|
818
1086
|
const entries = await listMcpServers(provider, scope);
|
|
819
1087
|
allEntries.push(...entries);
|
|
820
1088
|
}
|
|
@@ -842,7 +1110,7 @@ ${allEntries.length} MCP server(s) configured:
|
|
|
842
1110
|
|
|
843
1111
|
// src/commands/mcp/detect.ts
|
|
844
1112
|
import pc14 from "picocolors";
|
|
845
|
-
import { existsSync as
|
|
1113
|
+
import { existsSync as existsSync4 } from "fs";
|
|
846
1114
|
function registerMcpDetect(parent) {
|
|
847
1115
|
parent.command("detect").description("Auto-detect installed MCP tools and their configurations").option("--json", "Output as JSON").action(async (opts) => {
|
|
848
1116
|
const providers = getInstalledProviders();
|
|
@@ -854,8 +1122,8 @@ function registerMcpDetect(parent) {
|
|
|
854
1122
|
const projectEntries = await listMcpServers(provider, "project");
|
|
855
1123
|
detected.push({
|
|
856
1124
|
provider: provider.id,
|
|
857
|
-
hasGlobalConfig: globalPath !== null &&
|
|
858
|
-
hasProjectConfig: projectPath !== null &&
|
|
1125
|
+
hasGlobalConfig: globalPath !== null && existsSync4(globalPath),
|
|
1126
|
+
hasProjectConfig: projectPath !== null && existsSync4(projectPath),
|
|
859
1127
|
globalServers: globalEntries.map((e) => e.name),
|
|
860
1128
|
projectServers: projectEntries.map((e) => e.name)
|
|
861
1129
|
});
|
|
@@ -1015,8 +1283,7 @@ function registerInstructionsCommands(program2) {
|
|
|
1015
1283
|
|
|
1016
1284
|
// src/commands/config.ts
|
|
1017
1285
|
import pc18 from "picocolors";
|
|
1018
|
-
import {
|
|
1019
|
-
import { existsSync as existsSync4 } from "fs";
|
|
1286
|
+
import { existsSync as existsSync5 } from "fs";
|
|
1020
1287
|
function registerConfigCommand(program2) {
|
|
1021
1288
|
const config = program2.command("config").description("View provider configuration");
|
|
1022
1289
|
config.command("show").description("Show provider configuration").argument("<provider>", "Provider ID or alias").option("-g, --global", "Show global config").option("--json", "Output as JSON").action(async (providerId, opts) => {
|
|
@@ -1025,8 +1292,11 @@ function registerConfigCommand(program2) {
|
|
|
1025
1292
|
console.error(pc18.red(`Provider not found: ${providerId}`));
|
|
1026
1293
|
process.exit(1);
|
|
1027
1294
|
}
|
|
1028
|
-
const configPath =
|
|
1029
|
-
|
|
1295
|
+
const configPath = resolveProviderConfigPath(
|
|
1296
|
+
provider,
|
|
1297
|
+
opts.global ? "global" : "project"
|
|
1298
|
+
) ?? provider.configPathGlobal;
|
|
1299
|
+
if (!existsSync5(configPath)) {
|
|
1030
1300
|
console.log(pc18.dim(`No config file at: ${configPath}`));
|
|
1031
1301
|
return;
|
|
1032
1302
|
}
|
|
@@ -1054,8 +1324,9 @@ ${provider.toolName} config (${configPath}):
|
|
|
1054
1324
|
if (scope === "global") {
|
|
1055
1325
|
console.log(provider.configPathGlobal);
|
|
1056
1326
|
} else {
|
|
1057
|
-
|
|
1058
|
-
|
|
1327
|
+
const projectPath = resolveProviderConfigPath(provider, "project");
|
|
1328
|
+
if (projectPath) {
|
|
1329
|
+
console.log(projectPath);
|
|
1059
1330
|
} else {
|
|
1060
1331
|
console.log(pc18.dim(`${provider.toolName} has no project-level config`));
|
|
1061
1332
|
console.log(provider.configPathGlobal);
|
|
@@ -1067,9 +1338,9 @@ ${provider.toolName} config (${configPath}):
|
|
|
1067
1338
|
// src/commands/doctor.ts
|
|
1068
1339
|
import pc19 from "picocolors";
|
|
1069
1340
|
import { execFileSync } from "child_process";
|
|
1070
|
-
import { existsSync as
|
|
1341
|
+
import { existsSync as existsSync6, readdirSync, lstatSync } from "fs";
|
|
1071
1342
|
import { homedir } from "os";
|
|
1072
|
-
import { join as
|
|
1343
|
+
import { join as join4 } from "path";
|
|
1073
1344
|
var CAAMP_VERSION = "0.2.0";
|
|
1074
1345
|
function getNodeVersion() {
|
|
1075
1346
|
return process.version;
|
|
@@ -1145,8 +1416,8 @@ function checkInstalledProviders() {
|
|
|
1145
1416
|
}
|
|
1146
1417
|
function checkSkillSymlinks() {
|
|
1147
1418
|
const checks = [];
|
|
1148
|
-
const canonicalDir =
|
|
1149
|
-
if (!
|
|
1419
|
+
const canonicalDir = join4(homedir(), ".agents", "skills");
|
|
1420
|
+
if (!existsSync6(canonicalDir)) {
|
|
1150
1421
|
checks.push({ label: "0 canonical skills", status: "pass" });
|
|
1151
1422
|
checks.push({ label: "No broken symlinks", status: "pass" });
|
|
1152
1423
|
return { name: "Skills", checks };
|
|
@@ -1164,15 +1435,15 @@ function checkSkillSymlinks() {
|
|
|
1164
1435
|
const providers = getAllProviders();
|
|
1165
1436
|
for (const provider of providers) {
|
|
1166
1437
|
const skillDir = provider.pathSkills;
|
|
1167
|
-
if (!
|
|
1438
|
+
if (!existsSync6(skillDir)) continue;
|
|
1168
1439
|
try {
|
|
1169
1440
|
const entries = readdirSync(skillDir);
|
|
1170
1441
|
for (const entry of entries) {
|
|
1171
|
-
const fullPath =
|
|
1442
|
+
const fullPath = join4(skillDir, entry);
|
|
1172
1443
|
try {
|
|
1173
1444
|
const stat = lstatSync(fullPath);
|
|
1174
1445
|
if (stat.isSymbolicLink()) {
|
|
1175
|
-
if (!
|
|
1446
|
+
if (!existsSync6(fullPath)) {
|
|
1176
1447
|
broken.push(`${provider.id}/${entry}`);
|
|
1177
1448
|
}
|
|
1178
1449
|
}
|
|
@@ -1200,7 +1471,7 @@ async function checkLockFile() {
|
|
|
1200
1471
|
checks.push({ label: "Lock file valid", status: "pass" });
|
|
1201
1472
|
let orphaned = 0;
|
|
1202
1473
|
for (const [name, entry] of Object.entries(lock.skills)) {
|
|
1203
|
-
if (entry.canonicalPath && !
|
|
1474
|
+
if (entry.canonicalPath && !existsSync6(entry.canonicalPath)) {
|
|
1204
1475
|
orphaned++;
|
|
1205
1476
|
}
|
|
1206
1477
|
}
|
|
@@ -1229,7 +1500,7 @@ async function checkConfigFiles() {
|
|
|
1229
1500
|
for (const r of installed) {
|
|
1230
1501
|
const provider = r.provider;
|
|
1231
1502
|
const configPath = provider.configPathGlobal;
|
|
1232
|
-
if (!
|
|
1503
|
+
if (!existsSync6(configPath)) {
|
|
1233
1504
|
checks.push({
|
|
1234
1505
|
label: `${provider.id}: no config file found`,
|
|
1235
1506
|
status: "warn",
|
|
@@ -1317,6 +1588,650 @@ function registerDoctorCommand(program2) {
|
|
|
1317
1588
|
});
|
|
1318
1589
|
}
|
|
1319
1590
|
|
|
1591
|
+
// src/commands/advanced/common.ts
|
|
1592
|
+
import { readFile } from "fs/promises";
|
|
1593
|
+
|
|
1594
|
+
// src/commands/advanced/lafs.ts
|
|
1595
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
1596
|
+
import {
|
|
1597
|
+
isRegisteredErrorCode
|
|
1598
|
+
} from "@cleocode/lafs-protocol";
|
|
1599
|
+
var LAFSCommandError = class extends Error {
|
|
1600
|
+
code;
|
|
1601
|
+
category;
|
|
1602
|
+
recoverable;
|
|
1603
|
+
suggestion;
|
|
1604
|
+
retryAfterMs;
|
|
1605
|
+
details;
|
|
1606
|
+
constructor(code, message, suggestion, recoverable = true, details) {
|
|
1607
|
+
super(message);
|
|
1608
|
+
this.name = "LAFSCommandError";
|
|
1609
|
+
this.code = code;
|
|
1610
|
+
this.category = inferErrorCategory(code);
|
|
1611
|
+
this.recoverable = recoverable;
|
|
1612
|
+
this.suggestion = suggestion;
|
|
1613
|
+
this.retryAfterMs = null;
|
|
1614
|
+
this.details = details;
|
|
1615
|
+
}
|
|
1616
|
+
};
|
|
1617
|
+
function inferErrorCategory(code) {
|
|
1618
|
+
if (code.includes("VALIDATION")) return "VALIDATION";
|
|
1619
|
+
if (code.includes("NOT_FOUND")) return "NOT_FOUND";
|
|
1620
|
+
if (code.includes("CONFLICT")) return "CONFLICT";
|
|
1621
|
+
if (code.includes("AUTH")) return "AUTH";
|
|
1622
|
+
if (code.includes("PERMISSION")) return "PERMISSION";
|
|
1623
|
+
if (code.includes("RATE_LIMIT")) return "RATE_LIMIT";
|
|
1624
|
+
if (code.includes("MIGRATION")) return "MIGRATION";
|
|
1625
|
+
if (code.includes("CONTRACT")) return "CONTRACT";
|
|
1626
|
+
return "INTERNAL";
|
|
1627
|
+
}
|
|
1628
|
+
function baseMeta(operation, mvi) {
|
|
1629
|
+
return {
|
|
1630
|
+
specVersion: "1.0.0",
|
|
1631
|
+
schemaVersion: "1.0.0",
|
|
1632
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1633
|
+
operation,
|
|
1634
|
+
requestId: randomUUID2(),
|
|
1635
|
+
transport: "cli",
|
|
1636
|
+
strict: true,
|
|
1637
|
+
mvi,
|
|
1638
|
+
contextVersion: 0
|
|
1639
|
+
};
|
|
1640
|
+
}
|
|
1641
|
+
function emitSuccess(operation, result, mvi = true) {
|
|
1642
|
+
const envelope = {
|
|
1643
|
+
$schema: "https://lafs.dev/schemas/v1/envelope.schema.json",
|
|
1644
|
+
_meta: {
|
|
1645
|
+
...baseMeta(operation, mvi)
|
|
1646
|
+
},
|
|
1647
|
+
success: true,
|
|
1648
|
+
result,
|
|
1649
|
+
error: null,
|
|
1650
|
+
page: null
|
|
1651
|
+
};
|
|
1652
|
+
console.log(JSON.stringify(envelope, null, 2));
|
|
1653
|
+
}
|
|
1654
|
+
function emitError(operation, error, mvi = true) {
|
|
1655
|
+
let envelope;
|
|
1656
|
+
if (error instanceof LAFSCommandError) {
|
|
1657
|
+
envelope = {
|
|
1658
|
+
$schema: "https://lafs.dev/schemas/v1/envelope.schema.json",
|
|
1659
|
+
_meta: {
|
|
1660
|
+
...baseMeta(operation, mvi)
|
|
1661
|
+
},
|
|
1662
|
+
success: false,
|
|
1663
|
+
result: null,
|
|
1664
|
+
error: {
|
|
1665
|
+
code: isRegisteredErrorCode(error.code) ? error.code : "E_INTERNAL_UNEXPECTED",
|
|
1666
|
+
message: error.message,
|
|
1667
|
+
category: error.category,
|
|
1668
|
+
retryable: error.recoverable,
|
|
1669
|
+
retryAfterMs: error.retryAfterMs,
|
|
1670
|
+
details: {
|
|
1671
|
+
hint: error.suggestion,
|
|
1672
|
+
...error.details !== void 0 ? { payload: error.details } : {}
|
|
1673
|
+
}
|
|
1674
|
+
},
|
|
1675
|
+
page: null
|
|
1676
|
+
};
|
|
1677
|
+
} else {
|
|
1678
|
+
envelope = {
|
|
1679
|
+
$schema: "https://lafs.dev/schemas/v1/envelope.schema.json",
|
|
1680
|
+
_meta: {
|
|
1681
|
+
...baseMeta(operation, mvi)
|
|
1682
|
+
},
|
|
1683
|
+
success: false,
|
|
1684
|
+
result: null,
|
|
1685
|
+
error: {
|
|
1686
|
+
code: "E_INTERNAL_UNEXPECTED",
|
|
1687
|
+
message: error instanceof Error ? error.message : String(error),
|
|
1688
|
+
category: "INTERNAL",
|
|
1689
|
+
retryable: false,
|
|
1690
|
+
retryAfterMs: null,
|
|
1691
|
+
details: {
|
|
1692
|
+
hint: "Rerun with --verbose and validate your inputs."
|
|
1693
|
+
}
|
|
1694
|
+
},
|
|
1695
|
+
page: null
|
|
1696
|
+
};
|
|
1697
|
+
}
|
|
1698
|
+
console.error(JSON.stringify(envelope, null, 2));
|
|
1699
|
+
}
|
|
1700
|
+
async function runLafsCommand(command, mvi, action) {
|
|
1701
|
+
try {
|
|
1702
|
+
const result = await action();
|
|
1703
|
+
emitSuccess(command, result, mvi);
|
|
1704
|
+
} catch (error) {
|
|
1705
|
+
emitError(command, error, mvi);
|
|
1706
|
+
process.exit(1);
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
// src/commands/advanced/common.ts
|
|
1711
|
+
var VALID_PRIORITIES = /* @__PURE__ */ new Set(["high", "medium", "low"]);
|
|
1712
|
+
function parsePriority(value) {
|
|
1713
|
+
if (!VALID_PRIORITIES.has(value)) {
|
|
1714
|
+
throw new LAFSCommandError(
|
|
1715
|
+
"E_ADVANCED_VALIDATION_PRIORITY",
|
|
1716
|
+
`Invalid tier: ${value}`,
|
|
1717
|
+
"Use one of: high, medium, low."
|
|
1718
|
+
);
|
|
1719
|
+
}
|
|
1720
|
+
return value;
|
|
1721
|
+
}
|
|
1722
|
+
function resolveProviders(options) {
|
|
1723
|
+
if (options.all) {
|
|
1724
|
+
return getAllProviders();
|
|
1725
|
+
}
|
|
1726
|
+
const targetAgents = options.agent ?? [];
|
|
1727
|
+
if (targetAgents.length === 0) {
|
|
1728
|
+
return getInstalledProviders();
|
|
1729
|
+
}
|
|
1730
|
+
const providers = targetAgents.map((id) => getProvider(id)).filter((provider) => provider !== void 0);
|
|
1731
|
+
if (providers.length !== targetAgents.length) {
|
|
1732
|
+
const found = new Set(providers.map((provider) => provider.id));
|
|
1733
|
+
const missing = targetAgents.filter((id) => !found.has(id));
|
|
1734
|
+
throw new LAFSCommandError(
|
|
1735
|
+
"E_ADVANCED_PROVIDER_NOT_FOUND",
|
|
1736
|
+
`Unknown provider(s): ${missing.join(", ")}`,
|
|
1737
|
+
"Check `caamp providers list` for valid provider IDs/aliases."
|
|
1738
|
+
);
|
|
1739
|
+
}
|
|
1740
|
+
return providers;
|
|
1741
|
+
}
|
|
1742
|
+
async function readJsonFile(path) {
|
|
1743
|
+
try {
|
|
1744
|
+
const raw = await readFile(path, "utf-8");
|
|
1745
|
+
return JSON.parse(raw);
|
|
1746
|
+
} catch (error) {
|
|
1747
|
+
throw new LAFSCommandError(
|
|
1748
|
+
"E_ADVANCED_INPUT_JSON",
|
|
1749
|
+
`Failed to read JSON file: ${path}`,
|
|
1750
|
+
"Confirm the path exists and contains valid JSON.",
|
|
1751
|
+
true,
|
|
1752
|
+
{ reason: error instanceof Error ? error.message : String(error) }
|
|
1753
|
+
);
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
async function readMcpOperations(path) {
|
|
1757
|
+
const value = await readJsonFile(path);
|
|
1758
|
+
if (!Array.isArray(value)) {
|
|
1759
|
+
throw new LAFSCommandError(
|
|
1760
|
+
"E_ADVANCED_VALIDATION_MCP_ARRAY",
|
|
1761
|
+
`MCP operations file must be a JSON array: ${path}`,
|
|
1762
|
+
"Provide an array of objects with serverName and config fields."
|
|
1763
|
+
);
|
|
1764
|
+
}
|
|
1765
|
+
const operations = [];
|
|
1766
|
+
for (const [index, item] of value.entries()) {
|
|
1767
|
+
if (!item || typeof item !== "object") {
|
|
1768
|
+
throw new LAFSCommandError(
|
|
1769
|
+
"E_ADVANCED_VALIDATION_MCP_ITEM",
|
|
1770
|
+
`Invalid MCP operation at index ${index}`,
|
|
1771
|
+
"Each operation must be an object with serverName and config."
|
|
1772
|
+
);
|
|
1773
|
+
}
|
|
1774
|
+
const obj = item;
|
|
1775
|
+
const serverName = obj["serverName"];
|
|
1776
|
+
const config = obj["config"];
|
|
1777
|
+
const scope = obj["scope"];
|
|
1778
|
+
if (typeof serverName !== "string" || serverName.length === 0) {
|
|
1779
|
+
throw new LAFSCommandError(
|
|
1780
|
+
"E_ADVANCED_VALIDATION_MCP_NAME",
|
|
1781
|
+
`Invalid serverName at index ${index}`,
|
|
1782
|
+
"Set serverName to a non-empty string."
|
|
1783
|
+
);
|
|
1784
|
+
}
|
|
1785
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
1786
|
+
throw new LAFSCommandError(
|
|
1787
|
+
"E_ADVANCED_VALIDATION_MCP_CONFIG",
|
|
1788
|
+
`Invalid config at index ${index}`,
|
|
1789
|
+
"Set config to an object matching McpServerConfig."
|
|
1790
|
+
);
|
|
1791
|
+
}
|
|
1792
|
+
if (scope !== void 0 && scope !== "project" && scope !== "global") {
|
|
1793
|
+
throw new LAFSCommandError(
|
|
1794
|
+
"E_ADVANCED_VALIDATION_SCOPE",
|
|
1795
|
+
`Invalid scope at index ${index}: ${String(scope)}`,
|
|
1796
|
+
"Use scope value 'project' or 'global'."
|
|
1797
|
+
);
|
|
1798
|
+
}
|
|
1799
|
+
operations.push({
|
|
1800
|
+
serverName,
|
|
1801
|
+
config,
|
|
1802
|
+
...scope ? { scope } : {}
|
|
1803
|
+
});
|
|
1804
|
+
}
|
|
1805
|
+
return operations;
|
|
1806
|
+
}
|
|
1807
|
+
async function readSkillOperations(path) {
|
|
1808
|
+
const value = await readJsonFile(path);
|
|
1809
|
+
if (!Array.isArray(value)) {
|
|
1810
|
+
throw new LAFSCommandError(
|
|
1811
|
+
"E_ADVANCED_VALIDATION_SKILL_ARRAY",
|
|
1812
|
+
`Skill operations file must be a JSON array: ${path}`,
|
|
1813
|
+
"Provide an array of objects with sourcePath and skillName fields."
|
|
1814
|
+
);
|
|
1815
|
+
}
|
|
1816
|
+
const operations = [];
|
|
1817
|
+
for (const [index, item] of value.entries()) {
|
|
1818
|
+
if (!item || typeof item !== "object") {
|
|
1819
|
+
throw new LAFSCommandError(
|
|
1820
|
+
"E_ADVANCED_VALIDATION_SKILL_ITEM",
|
|
1821
|
+
`Invalid skill operation at index ${index}`,
|
|
1822
|
+
"Each operation must be an object with sourcePath and skillName."
|
|
1823
|
+
);
|
|
1824
|
+
}
|
|
1825
|
+
const obj = item;
|
|
1826
|
+
const sourcePath = obj["sourcePath"];
|
|
1827
|
+
const skillName = obj["skillName"];
|
|
1828
|
+
const isGlobal = obj["isGlobal"];
|
|
1829
|
+
if (typeof sourcePath !== "string" || sourcePath.length === 0) {
|
|
1830
|
+
throw new LAFSCommandError(
|
|
1831
|
+
"E_ADVANCED_VALIDATION_SKILL_SOURCE",
|
|
1832
|
+
`Invalid sourcePath at index ${index}`,
|
|
1833
|
+
"Set sourcePath to a non-empty string."
|
|
1834
|
+
);
|
|
1835
|
+
}
|
|
1836
|
+
if (typeof skillName !== "string" || skillName.length === 0) {
|
|
1837
|
+
throw new LAFSCommandError(
|
|
1838
|
+
"E_ADVANCED_VALIDATION_SKILL_NAME",
|
|
1839
|
+
`Invalid skillName at index ${index}`,
|
|
1840
|
+
"Set skillName to a non-empty string."
|
|
1841
|
+
);
|
|
1842
|
+
}
|
|
1843
|
+
if (isGlobal !== void 0 && typeof isGlobal !== "boolean") {
|
|
1844
|
+
throw new LAFSCommandError(
|
|
1845
|
+
"E_ADVANCED_VALIDATION_SKILL_SCOPE",
|
|
1846
|
+
`Invalid isGlobal value at index ${index}`,
|
|
1847
|
+
"Set isGlobal to true or false when provided."
|
|
1848
|
+
);
|
|
1849
|
+
}
|
|
1850
|
+
operations.push({
|
|
1851
|
+
sourcePath,
|
|
1852
|
+
skillName,
|
|
1853
|
+
...isGlobal !== void 0 ? { isGlobal } : {}
|
|
1854
|
+
});
|
|
1855
|
+
}
|
|
1856
|
+
return operations;
|
|
1857
|
+
}
|
|
1858
|
+
async function readTextInput(inlineContent, filePath) {
|
|
1859
|
+
if (inlineContent && filePath) {
|
|
1860
|
+
throw new LAFSCommandError(
|
|
1861
|
+
"E_ADVANCED_VALIDATION_INPUT_MODE",
|
|
1862
|
+
"Provide either inline content or a content file, not both.",
|
|
1863
|
+
"Use --content OR --content-file."
|
|
1864
|
+
);
|
|
1865
|
+
}
|
|
1866
|
+
if (inlineContent) return inlineContent;
|
|
1867
|
+
if (!filePath) return void 0;
|
|
1868
|
+
try {
|
|
1869
|
+
return await readFile(filePath, "utf-8");
|
|
1870
|
+
} catch (error) {
|
|
1871
|
+
throw new LAFSCommandError(
|
|
1872
|
+
"E_ADVANCED_INPUT_TEXT",
|
|
1873
|
+
`Failed to read content file: ${filePath}`,
|
|
1874
|
+
"Confirm the file exists and is readable.",
|
|
1875
|
+
true,
|
|
1876
|
+
{ reason: error instanceof Error ? error.message : String(error) }
|
|
1877
|
+
);
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1881
|
+
// src/commands/advanced/providers.ts
|
|
1882
|
+
function registerAdvancedProviders(parent) {
|
|
1883
|
+
parent.command("providers").description("Select providers by priority using advanced wrapper logic").option("-a, --agent <name>", "Target specific provider(s)", (v, prev) => [...prev, v], []).option("--all", "Use all registry providers (not only detected)").option("--min-tier <tier>", "Minimum priority tier: high|medium|low", "low").option("--details", "Include full provider objects").action(async (opts) => runLafsCommand("advanced.providers", !opts.details, async () => {
|
|
1884
|
+
const providers = resolveProviders({ all: opts.all, agent: opts.agent });
|
|
1885
|
+
const minTier = parsePriority(opts.minTier);
|
|
1886
|
+
const selected = selectProvidersByMinimumPriority(providers, minTier);
|
|
1887
|
+
return {
|
|
1888
|
+
objective: "Filter providers by minimum priority tier",
|
|
1889
|
+
constraints: {
|
|
1890
|
+
minTier,
|
|
1891
|
+
selectionMode: opts.all ? "registry" : "detected-or-explicit"
|
|
1892
|
+
},
|
|
1893
|
+
acceptanceCriteria: {
|
|
1894
|
+
selectedCount: selected.length,
|
|
1895
|
+
orderedByPriority: true
|
|
1896
|
+
},
|
|
1897
|
+
data: opts.details ? selected : selected.map((provider) => ({
|
|
1898
|
+
id: provider.id,
|
|
1899
|
+
priority: provider.priority,
|
|
1900
|
+
status: provider.status,
|
|
1901
|
+
configFormat: provider.configFormat
|
|
1902
|
+
}))
|
|
1903
|
+
};
|
|
1904
|
+
}));
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
// src/commands/advanced/batch.ts
|
|
1908
|
+
function registerAdvancedBatch(parent) {
|
|
1909
|
+
parent.command("batch").description("Run rollback-capable batch install for MCP + skills").option("-a, --agent <name>", "Target specific provider(s)", (v, prev) => [...prev, v], []).option("--all", "Use all registry providers (not only detected)").option("--min-tier <tier>", "Minimum priority tier: high|medium|low", "low").option("--mcp-file <path>", "JSON file containing McpBatchOperation[]").option("--skills-file <path>", "JSON file containing SkillBatchOperation[]").option("--project-dir <path>", "Project directory to resolve project-scope paths").option("--details", "Include detailed operation result").action(async (opts) => runLafsCommand("advanced.batch", !opts.details, async () => {
|
|
1910
|
+
const baseProviders = resolveProviders({ all: opts.all, agent: opts.agent });
|
|
1911
|
+
const minimumPriority = parsePriority(opts.minTier);
|
|
1912
|
+
const providers = selectProvidersByMinimumPriority(baseProviders, minimumPriority);
|
|
1913
|
+
const mcp = opts.mcpFile ? await readMcpOperations(opts.mcpFile) : [];
|
|
1914
|
+
const skills = opts.skillsFile ? await readSkillOperations(opts.skillsFile) : [];
|
|
1915
|
+
if (mcp.length === 0 && skills.length === 0) {
|
|
1916
|
+
throw new LAFSCommandError(
|
|
1917
|
+
"E_ADVANCED_VALIDATION_NO_OPS",
|
|
1918
|
+
"No operations provided.",
|
|
1919
|
+
"Provide --mcp-file and/or --skills-file."
|
|
1920
|
+
);
|
|
1921
|
+
}
|
|
1922
|
+
if (providers.length === 0) {
|
|
1923
|
+
throw new LAFSCommandError(
|
|
1924
|
+
"E_ADVANCED_NO_TARGET_PROVIDERS",
|
|
1925
|
+
"No target providers resolved for this batch operation.",
|
|
1926
|
+
"Use --all or pass provider IDs with --agent."
|
|
1927
|
+
);
|
|
1928
|
+
}
|
|
1929
|
+
const result = await installBatchWithRollback({
|
|
1930
|
+
providers,
|
|
1931
|
+
minimumPriority,
|
|
1932
|
+
mcp,
|
|
1933
|
+
skills,
|
|
1934
|
+
projectDir: opts.projectDir
|
|
1935
|
+
});
|
|
1936
|
+
if (!result.success) {
|
|
1937
|
+
throw new LAFSCommandError(
|
|
1938
|
+
"E_ADVANCED_BATCH_FAILED",
|
|
1939
|
+
result.error ?? "Batch operation failed.",
|
|
1940
|
+
"Check rollbackErrors and input configs, then retry.",
|
|
1941
|
+
true,
|
|
1942
|
+
result
|
|
1943
|
+
);
|
|
1944
|
+
}
|
|
1945
|
+
return {
|
|
1946
|
+
objective: "Install MCP and skills with rollback safety",
|
|
1947
|
+
constraints: {
|
|
1948
|
+
minimumPriority,
|
|
1949
|
+
providerCount: providers.length,
|
|
1950
|
+
mcpOps: mcp.length,
|
|
1951
|
+
skillOps: skills.length
|
|
1952
|
+
},
|
|
1953
|
+
acceptanceCriteria: {
|
|
1954
|
+
success: result.success,
|
|
1955
|
+
rollbackPerformed: result.rollbackPerformed
|
|
1956
|
+
},
|
|
1957
|
+
data: opts.details ? result : {
|
|
1958
|
+
providerCount: result.providerIds.length,
|
|
1959
|
+
mcpApplied: result.mcpApplied,
|
|
1960
|
+
skillsApplied: result.skillsApplied,
|
|
1961
|
+
rollbackPerformed: result.rollbackPerformed
|
|
1962
|
+
}
|
|
1963
|
+
};
|
|
1964
|
+
}));
|
|
1965
|
+
}
|
|
1966
|
+
|
|
1967
|
+
// src/commands/advanced/conflicts.ts
|
|
1968
|
+
function registerAdvancedConflicts(parent) {
|
|
1969
|
+
parent.command("conflicts").description("Preflight MCP conflict detection across providers").requiredOption("--mcp-file <path>", "JSON file containing McpBatchOperation[]").option("-a, --agent <name>", "Target specific provider(s)", (v, prev) => [...prev, v], []).option("--all", "Use all registry providers (not only detected)").option("--min-tier <tier>", "Minimum priority tier: high|medium|low", "low").option("--project-dir <path>", "Project directory to resolve project-scope paths").option("--details", "Include full conflict list").action(async (opts) => runLafsCommand("advanced.conflicts", !opts.details, async () => {
|
|
1970
|
+
const baseProviders = resolveProviders({ all: opts.all, agent: opts.agent });
|
|
1971
|
+
const minimumPriority = parsePriority(opts.minTier);
|
|
1972
|
+
const providers = selectProvidersByMinimumPriority(baseProviders, minimumPriority);
|
|
1973
|
+
const operations = await readMcpOperations(opts.mcpFile);
|
|
1974
|
+
if (providers.length === 0) {
|
|
1975
|
+
throw new LAFSCommandError(
|
|
1976
|
+
"E_ADVANCED_NO_TARGET_PROVIDERS",
|
|
1977
|
+
"No target providers resolved for conflict detection.",
|
|
1978
|
+
"Use --all or pass provider IDs with --agent."
|
|
1979
|
+
);
|
|
1980
|
+
}
|
|
1981
|
+
const conflicts = await detectMcpConfigConflicts(
|
|
1982
|
+
providers,
|
|
1983
|
+
operations,
|
|
1984
|
+
opts.projectDir
|
|
1985
|
+
);
|
|
1986
|
+
const countByCode = conflicts.reduce((acc, conflict) => {
|
|
1987
|
+
acc[conflict.code] = (acc[conflict.code] ?? 0) + 1;
|
|
1988
|
+
return acc;
|
|
1989
|
+
}, {});
|
|
1990
|
+
return {
|
|
1991
|
+
objective: "Detect MCP configuration conflicts before mutation",
|
|
1992
|
+
constraints: {
|
|
1993
|
+
minimumPriority,
|
|
1994
|
+
providerCount: providers.length,
|
|
1995
|
+
operationCount: operations.length
|
|
1996
|
+
},
|
|
1997
|
+
acceptanceCriteria: {
|
|
1998
|
+
conflictCount: conflicts.length
|
|
1999
|
+
},
|
|
2000
|
+
data: opts.details ? conflicts : {
|
|
2001
|
+
conflictCount: conflicts.length,
|
|
2002
|
+
countByCode,
|
|
2003
|
+
sample: conflicts.slice(0, 5)
|
|
2004
|
+
}
|
|
2005
|
+
};
|
|
2006
|
+
}));
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
// src/commands/advanced/apply.ts
|
|
2010
|
+
var VALID_POLICIES = /* @__PURE__ */ new Set(["fail", "skip", "overwrite"]);
|
|
2011
|
+
function parsePolicy(value) {
|
|
2012
|
+
if (!VALID_POLICIES.has(value)) {
|
|
2013
|
+
throw new LAFSCommandError(
|
|
2014
|
+
"E_ADVANCED_VALIDATION_POLICY",
|
|
2015
|
+
`Invalid policy: ${value}`,
|
|
2016
|
+
"Use one of: fail, skip, overwrite."
|
|
2017
|
+
);
|
|
2018
|
+
}
|
|
2019
|
+
return value;
|
|
2020
|
+
}
|
|
2021
|
+
function registerAdvancedApply(parent) {
|
|
2022
|
+
parent.command("apply").description("Apply MCP operations with configurable conflict policy").requiredOption("--mcp-file <path>", "JSON file containing McpBatchOperation[]").option("--policy <policy>", "Conflict policy: fail|skip|overwrite", "fail").option("-a, --agent <name>", "Target specific provider(s)", (v, prev) => [...prev, v], []).option("--all", "Use all registry providers (not only detected)").option("--min-tier <tier>", "Minimum priority tier: high|medium|low", "low").option("--project-dir <path>", "Project directory to resolve project-scope paths").option("--details", "Include detailed apply result").action(async (opts) => runLafsCommand("advanced.apply", !opts.details, async () => {
|
|
2023
|
+
const baseProviders = resolveProviders({ all: opts.all, agent: opts.agent });
|
|
2024
|
+
const minimumPriority = parsePriority(opts.minTier);
|
|
2025
|
+
const providers = selectProvidersByMinimumPriority(baseProviders, minimumPriority);
|
|
2026
|
+
const operations = await readMcpOperations(opts.mcpFile);
|
|
2027
|
+
const policy = parsePolicy(opts.policy);
|
|
2028
|
+
if (providers.length === 0) {
|
|
2029
|
+
throw new LAFSCommandError(
|
|
2030
|
+
"E_ADVANCED_NO_TARGET_PROVIDERS",
|
|
2031
|
+
"No target providers resolved for apply operation.",
|
|
2032
|
+
"Use --all or pass provider IDs with --agent."
|
|
2033
|
+
);
|
|
2034
|
+
}
|
|
2035
|
+
const result = await applyMcpInstallWithPolicy(
|
|
2036
|
+
providers,
|
|
2037
|
+
operations,
|
|
2038
|
+
policy,
|
|
2039
|
+
opts.projectDir
|
|
2040
|
+
);
|
|
2041
|
+
if (policy === "fail" && result.conflicts.length > 0) {
|
|
2042
|
+
throw new LAFSCommandError(
|
|
2043
|
+
"E_ADVANCED_CONFLICTS_BLOCKING",
|
|
2044
|
+
"Conflicts detected and policy is set to fail.",
|
|
2045
|
+
"Run `caamp advanced conflicts` to inspect, or rerun with --policy skip/overwrite.",
|
|
2046
|
+
true,
|
|
2047
|
+
result
|
|
2048
|
+
);
|
|
2049
|
+
}
|
|
2050
|
+
const failedWrites = result.applied.filter((entry) => !entry.success);
|
|
2051
|
+
if (failedWrites.length > 0) {
|
|
2052
|
+
throw new LAFSCommandError(
|
|
2053
|
+
"E_ADVANCED_APPLY_WRITE_FAILED",
|
|
2054
|
+
"One or more MCP writes failed.",
|
|
2055
|
+
"Check result details, fix provider config issues, and retry.",
|
|
2056
|
+
true,
|
|
2057
|
+
result
|
|
2058
|
+
);
|
|
2059
|
+
}
|
|
2060
|
+
return {
|
|
2061
|
+
objective: "Apply MCP operations with policy-driven conflict handling",
|
|
2062
|
+
constraints: {
|
|
2063
|
+
policy,
|
|
2064
|
+
minimumPriority,
|
|
2065
|
+
providerCount: providers.length,
|
|
2066
|
+
operationCount: operations.length
|
|
2067
|
+
},
|
|
2068
|
+
acceptanceCriteria: {
|
|
2069
|
+
conflicts: result.conflicts.length,
|
|
2070
|
+
writesSucceeded: result.applied.length
|
|
2071
|
+
},
|
|
2072
|
+
data: opts.details ? result : {
|
|
2073
|
+
conflicts: result.conflicts.length,
|
|
2074
|
+
applied: result.applied.length,
|
|
2075
|
+
skipped: result.skipped.length
|
|
2076
|
+
}
|
|
2077
|
+
};
|
|
2078
|
+
}));
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
// src/commands/advanced/instructions.ts
|
|
2082
|
+
function registerAdvancedInstructions(parent) {
|
|
2083
|
+
parent.command("instructions").description("Single-operation instruction update across providers").option("-a, --agent <name>", "Target specific provider(s)", (v, prev) => [...prev, v], []).option("--all", "Use all registry providers (not only detected)").option("--min-tier <tier>", "Minimum priority tier: high|medium|low", "low").option("--scope <scope>", "Instruction scope: project|global", "project").option("--content <text>", "Inline content to inject").option("--content-file <path>", "File containing content to inject").option("--project-dir <path>", "Project directory to resolve project-scope paths").option("--details", "Include detailed per-file actions").action(async (opts) => runLafsCommand("advanced.instructions", !opts.details, async () => {
|
|
2084
|
+
const minimumPriority = parsePriority(opts.minTier);
|
|
2085
|
+
const baseProviders = resolveProviders({ all: opts.all, agent: opts.agent });
|
|
2086
|
+
const providers = selectProvidersByMinimumPriority(baseProviders, minimumPriority);
|
|
2087
|
+
const scope = opts.scope === "global" ? "global" : opts.scope === "project" ? "project" : null;
|
|
2088
|
+
if (!scope) {
|
|
2089
|
+
throw new LAFSCommandError(
|
|
2090
|
+
"E_ADVANCED_VALIDATION_SCOPE",
|
|
2091
|
+
`Invalid scope: ${opts.scope}`,
|
|
2092
|
+
"Use --scope project or --scope global."
|
|
2093
|
+
);
|
|
2094
|
+
}
|
|
2095
|
+
const content = await readTextInput(opts.content, opts.contentFile);
|
|
2096
|
+
if (!content || content.trim().length === 0) {
|
|
2097
|
+
throw new LAFSCommandError(
|
|
2098
|
+
"E_ADVANCED_VALIDATION_CONTENT",
|
|
2099
|
+
"Instruction content is required.",
|
|
2100
|
+
"Provide --content or --content-file with non-empty text."
|
|
2101
|
+
);
|
|
2102
|
+
}
|
|
2103
|
+
if (providers.length === 0) {
|
|
2104
|
+
throw new LAFSCommandError(
|
|
2105
|
+
"E_ADVANCED_NO_TARGET_PROVIDERS",
|
|
2106
|
+
"No target providers resolved for instruction update.",
|
|
2107
|
+
"Use --all or pass provider IDs with --agent."
|
|
2108
|
+
);
|
|
2109
|
+
}
|
|
2110
|
+
const summary = await updateInstructionsSingleOperation(
|
|
2111
|
+
providers,
|
|
2112
|
+
content,
|
|
2113
|
+
scope,
|
|
2114
|
+
opts.projectDir
|
|
2115
|
+
);
|
|
2116
|
+
return {
|
|
2117
|
+
objective: "Update instruction files across providers in one operation",
|
|
2118
|
+
constraints: {
|
|
2119
|
+
scope,
|
|
2120
|
+
minimumPriority,
|
|
2121
|
+
providerCount: providers.length
|
|
2122
|
+
},
|
|
2123
|
+
acceptanceCriteria: {
|
|
2124
|
+
updatedFiles: summary.updatedFiles
|
|
2125
|
+
},
|
|
2126
|
+
data: opts.details ? summary : {
|
|
2127
|
+
updatedFiles: summary.updatedFiles,
|
|
2128
|
+
files: summary.actions.map((entry) => ({
|
|
2129
|
+
file: entry.file,
|
|
2130
|
+
action: entry.action
|
|
2131
|
+
}))
|
|
2132
|
+
}
|
|
2133
|
+
};
|
|
2134
|
+
}));
|
|
2135
|
+
}
|
|
2136
|
+
|
|
2137
|
+
// src/commands/advanced/configure.ts
|
|
2138
|
+
function registerAdvancedConfigure(parent) {
|
|
2139
|
+
parent.command("configure").description("Configure global + project scope for one provider in one operation").requiredOption("-a, --agent <name>", "Target provider ID or alias").option("--global-mcp-file <path>", "JSON file for global MCP operations").option("--project-mcp-file <path>", "JSON file for project MCP operations").option("--instruction <text>", "Instruction content for both scopes").option("--instruction-file <path>", "Instruction content file for both scopes").option("--instruction-global <text>", "Instruction content for global scope").option("--instruction-global-file <path>", "Instruction content file for global scope").option("--instruction-project <text>", "Instruction content for project scope").option("--instruction-project-file <path>", "Instruction content file for project scope").option("--project-dir <path>", "Project directory to resolve project-scope paths").option("--details", "Include detailed write results").action(async (opts) => runLafsCommand("advanced.configure", !opts.details, async () => {
|
|
2140
|
+
const provider = getProvider(opts.agent);
|
|
2141
|
+
if (!provider) {
|
|
2142
|
+
throw new LAFSCommandError(
|
|
2143
|
+
"E_ADVANCED_PROVIDER_NOT_FOUND",
|
|
2144
|
+
`Unknown provider: ${opts.agent}`,
|
|
2145
|
+
"Check `caamp providers list` for valid provider IDs/aliases."
|
|
2146
|
+
);
|
|
2147
|
+
}
|
|
2148
|
+
const globalMcp = opts.globalMcpFile ? await readMcpOperations(opts.globalMcpFile) : [];
|
|
2149
|
+
const projectMcp = opts.projectMcpFile ? await readMcpOperations(opts.projectMcpFile) : [];
|
|
2150
|
+
const sharedInstruction = await readTextInput(opts.instruction, opts.instructionFile);
|
|
2151
|
+
const globalInstruction = await readTextInput(
|
|
2152
|
+
opts.instructionGlobal,
|
|
2153
|
+
opts.instructionGlobalFile
|
|
2154
|
+
);
|
|
2155
|
+
const projectInstruction = await readTextInput(
|
|
2156
|
+
opts.instructionProject,
|
|
2157
|
+
opts.instructionProjectFile
|
|
2158
|
+
);
|
|
2159
|
+
let instructionContent;
|
|
2160
|
+
if (globalInstruction || projectInstruction) {
|
|
2161
|
+
instructionContent = {
|
|
2162
|
+
...globalInstruction ? { global: globalInstruction } : {},
|
|
2163
|
+
...projectInstruction ? { project: projectInstruction } : {}
|
|
2164
|
+
};
|
|
2165
|
+
} else if (sharedInstruction) {
|
|
2166
|
+
instructionContent = sharedInstruction;
|
|
2167
|
+
}
|
|
2168
|
+
if (globalMcp.length === 0 && projectMcp.length === 0 && !instructionContent) {
|
|
2169
|
+
throw new LAFSCommandError(
|
|
2170
|
+
"E_ADVANCED_VALIDATION_NO_OPS",
|
|
2171
|
+
"No configuration operations were provided.",
|
|
2172
|
+
"Provide MCP files and/or instruction content."
|
|
2173
|
+
);
|
|
2174
|
+
}
|
|
2175
|
+
const result = await configureProviderGlobalAndProject(provider, {
|
|
2176
|
+
globalMcp: globalMcp.map((entry) => ({
|
|
2177
|
+
serverName: entry.serverName,
|
|
2178
|
+
config: entry.config
|
|
2179
|
+
})),
|
|
2180
|
+
projectMcp: projectMcp.map((entry) => ({
|
|
2181
|
+
serverName: entry.serverName,
|
|
2182
|
+
config: entry.config
|
|
2183
|
+
})),
|
|
2184
|
+
instructionContent,
|
|
2185
|
+
projectDir: opts.projectDir
|
|
2186
|
+
});
|
|
2187
|
+
const globalFailures = result.mcp.global.filter((entry) => !entry.success);
|
|
2188
|
+
const projectFailures = result.mcp.project.filter((entry) => !entry.success);
|
|
2189
|
+
if (globalFailures.length > 0 || projectFailures.length > 0) {
|
|
2190
|
+
throw new LAFSCommandError(
|
|
2191
|
+
"E_ADVANCED_CONFIGURE_FAILED",
|
|
2192
|
+
"One or more MCP writes failed during configure operation.",
|
|
2193
|
+
"Inspect the failed write entries and provider config paths, then retry.",
|
|
2194
|
+
true,
|
|
2195
|
+
result
|
|
2196
|
+
);
|
|
2197
|
+
}
|
|
2198
|
+
return {
|
|
2199
|
+
objective: "Configure global and project settings in one operation",
|
|
2200
|
+
constraints: {
|
|
2201
|
+
provider: provider.id,
|
|
2202
|
+
globalMcpOps: globalMcp.length,
|
|
2203
|
+
projectMcpOps: projectMcp.length,
|
|
2204
|
+
instructionMode: instructionContent ? typeof instructionContent === "string" ? "shared" : "scoped" : "none"
|
|
2205
|
+
},
|
|
2206
|
+
acceptanceCriteria: {
|
|
2207
|
+
globalWrites: result.mcp.global.length,
|
|
2208
|
+
projectWrites: result.mcp.project.length
|
|
2209
|
+
},
|
|
2210
|
+
data: opts.details ? result : {
|
|
2211
|
+
providerId: result.providerId,
|
|
2212
|
+
configPaths: result.configPaths,
|
|
2213
|
+
globalWrites: result.mcp.global.length,
|
|
2214
|
+
projectWrites: result.mcp.project.length,
|
|
2215
|
+
instructionUpdates: {
|
|
2216
|
+
global: result.instructions.global?.size ?? 0,
|
|
2217
|
+
project: result.instructions.project?.size ?? 0
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
};
|
|
2221
|
+
}));
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2224
|
+
// src/commands/advanced/index.ts
|
|
2225
|
+
function registerAdvancedCommands(program2) {
|
|
2226
|
+
const advanced = program2.command("advanced").description("LAFS-compliant wrappers for advanced orchestration APIs");
|
|
2227
|
+
registerAdvancedProviders(advanced);
|
|
2228
|
+
registerAdvancedBatch(advanced);
|
|
2229
|
+
registerAdvancedConflicts(advanced);
|
|
2230
|
+
registerAdvancedApply(advanced);
|
|
2231
|
+
registerAdvancedInstructions(advanced);
|
|
2232
|
+
registerAdvancedConfigure(advanced);
|
|
2233
|
+
}
|
|
2234
|
+
|
|
1320
2235
|
// src/cli.ts
|
|
1321
2236
|
var program = new Command();
|
|
1322
2237
|
program.name("caamp").description("Central AI Agent Managed Packages - unified provider registry and package manager").version("0.3.0").option("-v, --verbose", "Show debug output").option("-q, --quiet", "Suppress non-error output");
|
|
@@ -1331,5 +2246,6 @@ registerMcpCommands(program);
|
|
|
1331
2246
|
registerInstructionsCommands(program);
|
|
1332
2247
|
registerConfigCommand(program);
|
|
1333
2248
|
registerDoctorCommand(program);
|
|
2249
|
+
registerAdvancedCommands(program);
|
|
1334
2250
|
program.parse();
|
|
1335
2251
|
//# sourceMappingURL=cli.js.map
|