@cleocode/caamp 2026.9.18 → 2026.9.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-G3CEXEW2.js → chunk-JELNPPLN.js} +168 -25
- package/dist/chunk-JELNPPLN.js.map +1 -0
- package/dist/{chunk-52ZWZXEN.js → chunk-QC6CHW72.js} +3175 -2449
- package/dist/chunk-QC6CHW72.js.map +1 -0
- package/dist/cli.js +287 -728
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +776 -2
- package/dist/index.js +37 -3
- package/dist/index.js.map +1 -1
- package/dist/{injector-X5FN7WMR.js → injector-7NNSGPGQ.js} +6 -2
- package/package.json +7 -7
- package/dist/chunk-52ZWZXEN.js.map +0 -1
- package/dist/chunk-G3CEXEW2.js.map +0 -1
- /package/dist/{injector-X5FN7WMR.js.map → injector-7NNSGPGQ.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -1,36 +1,42 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
ErrorCategories,
|
|
4
|
+
ErrorCodes,
|
|
3
5
|
MarketplaceClient,
|
|
4
6
|
PiHarness,
|
|
5
7
|
RECOMMENDATION_ERROR_CODES,
|
|
8
|
+
SkillInstallError,
|
|
9
|
+
buildEnvelope,
|
|
6
10
|
checkSkillUpdate,
|
|
11
|
+
cloneGitLabRepo,
|
|
12
|
+
cloneRepo,
|
|
7
13
|
detectAllProviders,
|
|
8
14
|
detectMcpInstallations,
|
|
9
15
|
detectProjectProviders,
|
|
10
|
-
discoverSkill,
|
|
11
16
|
discoverSkillsMulti,
|
|
12
|
-
dispatchInstallSkillAcrossProviders,
|
|
13
17
|
dispatchRemoveSkillAcrossProviders,
|
|
18
|
+
emitError,
|
|
19
|
+
emitJsonError,
|
|
14
20
|
fetchWithTimeout,
|
|
15
21
|
formatNetworkError,
|
|
16
22
|
formatSkillRecommendations,
|
|
17
23
|
getHarnessFor,
|
|
18
24
|
getInstalledProviders,
|
|
19
|
-
getSkill,
|
|
20
25
|
getSkillDir,
|
|
21
26
|
getTrackedSkills,
|
|
27
|
+
handleFormatError,
|
|
22
28
|
installBatchWithRollback,
|
|
23
29
|
installMcpServer,
|
|
30
|
+
installResolvedSkill,
|
|
31
|
+
installSkillFromSource,
|
|
24
32
|
isCatalogAvailable,
|
|
25
33
|
isHuman,
|
|
26
|
-
isMarketplaceScoped,
|
|
27
|
-
isQuiet,
|
|
28
34
|
isVerbose,
|
|
29
35
|
listAllMcpServers,
|
|
30
36
|
listCanonicalSkills,
|
|
31
37
|
listMcpServers,
|
|
32
38
|
listProfiles,
|
|
33
|
-
|
|
39
|
+
outputSuccess,
|
|
34
40
|
parseSource,
|
|
35
41
|
readConfig,
|
|
36
42
|
readLockFile,
|
|
@@ -40,6 +46,7 @@ import {
|
|
|
40
46
|
removeMcpServerFromAll,
|
|
41
47
|
removeSkillFromLock,
|
|
42
48
|
resolveDefaultTargetProviders,
|
|
49
|
+
resolveFormat,
|
|
43
50
|
resolveProfile,
|
|
44
51
|
scanDirectory,
|
|
45
52
|
scanFile,
|
|
@@ -47,11 +54,12 @@ import {
|
|
|
47
54
|
setHuman,
|
|
48
55
|
setQuiet,
|
|
49
56
|
setVerbose,
|
|
57
|
+
syncGlobalInstructions,
|
|
50
58
|
toSarif,
|
|
51
59
|
tokenizeCriteriaValue,
|
|
52
60
|
updateInstructionsSingleOperation,
|
|
53
61
|
validateSkill
|
|
54
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-QC6CHW72.js";
|
|
55
63
|
import {
|
|
56
64
|
buildSkillsMap,
|
|
57
65
|
checkAllInjections,
|
|
@@ -64,7 +72,7 @@ import {
|
|
|
64
72
|
groupByInstructFile,
|
|
65
73
|
injectAll,
|
|
66
74
|
providerSupports
|
|
67
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-JELNPPLN.js";
|
|
68
76
|
import {
|
|
69
77
|
CANONICAL_HOOK_EVENTS,
|
|
70
78
|
buildHookMatrix,
|
|
@@ -75,7 +83,6 @@ import {
|
|
|
75
83
|
translateToAll
|
|
76
84
|
} from "./chunk-YCAANESR.js";
|
|
77
85
|
import {
|
|
78
|
-
buildSkillSubPathCandidates,
|
|
79
86
|
resolveProviderConfigPath,
|
|
80
87
|
resolveProviderSkillsDir
|
|
81
88
|
} from "./chunk-HDZYZTR2.js";
|
|
@@ -152,7 +159,7 @@ function emitSuccess(operation, result, mvi = "standard") {
|
|
|
152
159
|
};
|
|
153
160
|
console.log(JSON.stringify(envelope, null, 2));
|
|
154
161
|
}
|
|
155
|
-
function
|
|
162
|
+
function emitError2(operation, error, mvi = "standard") {
|
|
156
163
|
let envelope;
|
|
157
164
|
if (error instanceof LAFSCommandError) {
|
|
158
165
|
envelope = {
|
|
@@ -203,7 +210,7 @@ async function runLafsCommand(command, mvi, action) {
|
|
|
203
210
|
const result = await action();
|
|
204
211
|
emitSuccess(command, result, mvi);
|
|
205
212
|
} catch (error) {
|
|
206
|
-
|
|
213
|
+
emitError2(command, error, mvi);
|
|
207
214
|
process.exit(1);
|
|
208
215
|
}
|
|
209
216
|
}
|
|
@@ -498,121 +505,6 @@ function registerAdvancedCommands(program2) {
|
|
|
498
505
|
// src/commands/config.ts
|
|
499
506
|
import { existsSync } from "fs";
|
|
500
507
|
import pc from "picocolors";
|
|
501
|
-
|
|
502
|
-
// src/core/lafs.ts
|
|
503
|
-
import { randomUUID as randomUUID2 } from "crypto";
|
|
504
|
-
import { resolveOutputFormat } from "@cleocode/lafs";
|
|
505
|
-
function resolveFormat(options) {
|
|
506
|
-
return resolveOutputFormat({
|
|
507
|
-
jsonFlag: options.jsonFlag ?? false,
|
|
508
|
-
humanFlag: (options.humanFlag ?? false) || isHuman(),
|
|
509
|
-
projectDefault: options.projectDefault ?? "json"
|
|
510
|
-
}).format;
|
|
511
|
-
}
|
|
512
|
-
function buildEnvelope(operation, mvi, result, error, page = null, sessionId, warnings) {
|
|
513
|
-
return {
|
|
514
|
-
$schema: "https://lafs.dev/schemas/v1/envelope.schema.json",
|
|
515
|
-
_meta: {
|
|
516
|
-
specVersion: "1.0.0",
|
|
517
|
-
schemaVersion: "1.0.0",
|
|
518
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
519
|
-
operation,
|
|
520
|
-
requestId: randomUUID2(),
|
|
521
|
-
transport: "cli",
|
|
522
|
-
strict: true,
|
|
523
|
-
mvi,
|
|
524
|
-
contextVersion: 0,
|
|
525
|
-
...sessionId && { sessionId },
|
|
526
|
-
...warnings && warnings.length > 0 && { warnings }
|
|
527
|
-
},
|
|
528
|
-
success: error === null,
|
|
529
|
-
result,
|
|
530
|
-
error,
|
|
531
|
-
page
|
|
532
|
-
};
|
|
533
|
-
}
|
|
534
|
-
function emitError2(operation, mvi, code, message, category, details = {}, exitCode = 1) {
|
|
535
|
-
const envelope = buildEnvelope(operation, mvi, null, {
|
|
536
|
-
code,
|
|
537
|
-
message,
|
|
538
|
-
category,
|
|
539
|
-
retryable: category === "TRANSIENT" || category === "RATE_LIMIT",
|
|
540
|
-
retryAfterMs: null,
|
|
541
|
-
details
|
|
542
|
-
});
|
|
543
|
-
console.error(JSON.stringify(envelope, null, 2));
|
|
544
|
-
process.exit(exitCode);
|
|
545
|
-
}
|
|
546
|
-
function emitJsonError(operation, mvi, code, message, category, details = {}) {
|
|
547
|
-
const envelope = buildEnvelope(operation, mvi, null, {
|
|
548
|
-
code,
|
|
549
|
-
message,
|
|
550
|
-
category,
|
|
551
|
-
retryable: category === "TRANSIENT" || category === "RATE_LIMIT",
|
|
552
|
-
retryAfterMs: null,
|
|
553
|
-
details
|
|
554
|
-
});
|
|
555
|
-
console.error(JSON.stringify(envelope, null, 2));
|
|
556
|
-
}
|
|
557
|
-
function outputSuccess(operation, mvi, result, page, sessionId, warnings) {
|
|
558
|
-
const envelope = buildEnvelope(operation, mvi, result, null, page ?? null, sessionId, warnings);
|
|
559
|
-
if (isQuiet() && !envelope.error) {
|
|
560
|
-
return;
|
|
561
|
-
}
|
|
562
|
-
console.log(JSON.stringify(envelope, null, 2));
|
|
563
|
-
}
|
|
564
|
-
function handleFormatError(error, operation, mvi, jsonFlag) {
|
|
565
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
566
|
-
if (jsonFlag) {
|
|
567
|
-
emitJsonError(operation, mvi, "E_FORMAT_CONFLICT", message, "VALIDATION");
|
|
568
|
-
} else {
|
|
569
|
-
console.error(message);
|
|
570
|
-
}
|
|
571
|
-
process.exit(1);
|
|
572
|
-
}
|
|
573
|
-
var ErrorCategories = {
|
|
574
|
-
VALIDATION: "VALIDATION",
|
|
575
|
-
AUTH: "AUTH",
|
|
576
|
-
PERMISSION: "PERMISSION",
|
|
577
|
-
NOT_FOUND: "NOT_FOUND",
|
|
578
|
-
CONFLICT: "CONFLICT",
|
|
579
|
-
RATE_LIMIT: "RATE_LIMIT",
|
|
580
|
-
TRANSIENT: "TRANSIENT",
|
|
581
|
-
INTERNAL: "INTERNAL",
|
|
582
|
-
CONTRACT: "CONTRACT",
|
|
583
|
-
MIGRATION: "MIGRATION"
|
|
584
|
-
};
|
|
585
|
-
var ErrorCodes = {
|
|
586
|
-
// Format errors
|
|
587
|
-
FORMAT_CONFLICT: "E_FORMAT_CONFLICT",
|
|
588
|
-
INVALID_JSON: "E_INVALID_JSON",
|
|
589
|
-
// Not found errors
|
|
590
|
-
SKILL_NOT_FOUND: "E_SKILL_NOT_FOUND",
|
|
591
|
-
PROVIDER_NOT_FOUND: "E_PROVIDER_NOT_FOUND",
|
|
592
|
-
MCP_SERVER_NOT_FOUND: "E_MCP_SERVER_NOT_FOUND",
|
|
593
|
-
FILE_NOT_FOUND: "E_FILE_NOT_FOUND",
|
|
594
|
-
// Validation errors
|
|
595
|
-
INVALID_INPUT: "E_INVALID_INPUT",
|
|
596
|
-
INVALID_CONSTRAINT: "E_INVALID_CONSTRAINT",
|
|
597
|
-
INVALID_FORMAT: "E_INVALID_FORMAT",
|
|
598
|
-
// Operation errors
|
|
599
|
-
INSTALL_FAILED: "E_INSTALL_FAILED",
|
|
600
|
-
// Skills federation gates (T9564 — Sphere B)
|
|
601
|
-
SKILL_TRUST_GATE_BLOCKED: "E_SKILL_TRUST_GATE_BLOCKED",
|
|
602
|
-
FEDERATION_UNKNOWN_SOURCE_INTERACTIVE_REQUIRED: "E_FEDERATION_UNKNOWN_SOURCE_INTERACTIVE_REQUIRED",
|
|
603
|
-
FEDERATION_CHECKSUM_MISMATCH: "E_FEDERATION_CHECKSUM_MISMATCH",
|
|
604
|
-
REMOVE_FAILED: "E_REMOVE_FAILED",
|
|
605
|
-
UPDATE_FAILED: "E_UPDATE_FAILED",
|
|
606
|
-
VALIDATION_FAILED: "E_VALIDATION_FAILED",
|
|
607
|
-
AUDIT_FAILED: "E_AUDIT_FAILED",
|
|
608
|
-
// System errors
|
|
609
|
-
NETWORK_ERROR: "E_NETWORK_ERROR",
|
|
610
|
-
FILE_SYSTEM_ERROR: "E_FILE_SYSTEM_ERROR",
|
|
611
|
-
PERMISSION_DENIED: "E_PERMISSION_DENIED",
|
|
612
|
-
INTERNAL_ERROR: "E_INTERNAL_ERROR"
|
|
613
|
-
};
|
|
614
|
-
|
|
615
|
-
// src/commands/config.ts
|
|
616
508
|
function registerConfigCommand(program2) {
|
|
617
509
|
const config = program2.command("config").description("View provider configuration");
|
|
618
510
|
config.command("show").description("Show provider configuration").argument("<provider>", "Provider ID or alias").option("-g, --global", "Show global config").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(
|
|
@@ -1258,6 +1150,8 @@ function registerInstructionsCheck(parent) {
|
|
|
1258
1150
|
providers = getAllProviders();
|
|
1259
1151
|
} else if (opts.agent.length > 0) {
|
|
1260
1152
|
providers = opts.agent.map((a) => getProvider(a)).filter((p) => p !== void 0);
|
|
1153
|
+
} else if (opts.global) {
|
|
1154
|
+
providers = getInstalledProviders();
|
|
1261
1155
|
} else {
|
|
1262
1156
|
providers = resolveDefaultTargetProviders();
|
|
1263
1157
|
}
|
|
@@ -1416,12 +1310,24 @@ function registerInstructionsInject(parent) {
|
|
|
1416
1310
|
}
|
|
1417
1311
|
}
|
|
1418
1312
|
}
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1313
|
+
const failed = [];
|
|
1314
|
+
for (const provider of genericProviders) {
|
|
1315
|
+
try {
|
|
1316
|
+
for (const [file, action] of await injectAll(
|
|
1317
|
+
[provider],
|
|
1318
|
+
process.cwd(),
|
|
1319
|
+
scope,
|
|
1320
|
+
content
|
|
1321
|
+
)) {
|
|
1322
|
+
results.set(file, action);
|
|
1323
|
+
}
|
|
1324
|
+
} catch (err) {
|
|
1325
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
1326
|
+
failed.push({ provider: provider.id, error });
|
|
1327
|
+
if (format === "human") console.log(pc4.red(` x ${provider.id}: ${error}`));
|
|
1423
1328
|
}
|
|
1424
1329
|
}
|
|
1330
|
+
if (failed.length > 0) process.exitCode = 1;
|
|
1425
1331
|
const injected = [];
|
|
1426
1332
|
for (const [file] of results) {
|
|
1427
1333
|
injected.push(file);
|
|
@@ -1430,7 +1336,8 @@ function registerInstructionsInject(parent) {
|
|
|
1430
1336
|
outputSuccess(operation, mvi, {
|
|
1431
1337
|
injected,
|
|
1432
1338
|
providers: providers.map((p) => p.id),
|
|
1433
|
-
count: results.size
|
|
1339
|
+
count: results.size,
|
|
1340
|
+
...failed.length > 0 ? { failed } : {}
|
|
1434
1341
|
});
|
|
1435
1342
|
} else {
|
|
1436
1343
|
for (const [file, action] of results) {
|
|
@@ -1446,6 +1353,44 @@ ${results.size} file(s) processed.`));
|
|
|
1446
1353
|
|
|
1447
1354
|
// src/commands/instructions/update.ts
|
|
1448
1355
|
import pc5 from "picocolors";
|
|
1356
|
+
async function updateGlobal(format) {
|
|
1357
|
+
const operation = "instructions.update";
|
|
1358
|
+
const mvi = "standard";
|
|
1359
|
+
const result = await syncGlobalInstructions();
|
|
1360
|
+
const updated = result.files.filter((file) => file.action !== "intact" && file.action !== "failed").map((file) => file.path);
|
|
1361
|
+
const failed = [
|
|
1362
|
+
...result.files.filter((file) => file.action === "failed").map((file) => ({ provider: file.providers.join(","), error: file.error ?? "unknown" })),
|
|
1363
|
+
...result.findings.map((finding) => ({
|
|
1364
|
+
provider: "hub",
|
|
1365
|
+
error: `${finding.kind}: ${finding.path} (${finding.reason})`
|
|
1366
|
+
}))
|
|
1367
|
+
];
|
|
1368
|
+
if (failed.length > 0) process.exitCode = 1;
|
|
1369
|
+
if (format === "json") {
|
|
1370
|
+
outputSuccess(operation, mvi, {
|
|
1371
|
+
status: result.status,
|
|
1372
|
+
updated,
|
|
1373
|
+
failed,
|
|
1374
|
+
files: result.files,
|
|
1375
|
+
skippedProviders: result.skippedProviders,
|
|
1376
|
+
count: { updated: updated.length, failed: failed.length }
|
|
1377
|
+
});
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1380
|
+
if (result.status === "no-providers") {
|
|
1381
|
+
console.log(pc5.yellow("No provider installations detected."));
|
|
1382
|
+
return;
|
|
1383
|
+
}
|
|
1384
|
+
for (const file of result.files) {
|
|
1385
|
+
const icon = file.action === "failed" ? pc5.red("x") : pc5.green("\u2713");
|
|
1386
|
+
console.log(` ${icon} ${file.path} (${file.action}${file.error ? `: ${file.error}` : ""})`);
|
|
1387
|
+
}
|
|
1388
|
+
for (const finding of result.findings) {
|
|
1389
|
+
console.log(` ${pc5.red("x")} ${finding.kind}: ${finding.path} \u2014 ${finding.reason}`);
|
|
1390
|
+
}
|
|
1391
|
+
console.log(pc5.bold(`
|
|
1392
|
+
${updated.length} file(s) updated.`));
|
|
1393
|
+
}
|
|
1449
1394
|
function registerInstructionsUpdate(parent) {
|
|
1450
1395
|
parent.command("update").description("Update all instruction file injections").option("-g, --global", "Update global instruction files").option("-y, --yes", "Skip confirmation").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (opts) => {
|
|
1451
1396
|
const operation = "instructions.update";
|
|
@@ -1468,8 +1413,12 @@ function registerInstructionsUpdate(parent) {
|
|
|
1468
1413
|
);
|
|
1469
1414
|
process.exit(1);
|
|
1470
1415
|
}
|
|
1416
|
+
if (opts.global) {
|
|
1417
|
+
await updateGlobal(format);
|
|
1418
|
+
return;
|
|
1419
|
+
}
|
|
1471
1420
|
const providers = resolveDefaultTargetProviders();
|
|
1472
|
-
const scope =
|
|
1421
|
+
const scope = "project";
|
|
1473
1422
|
const content = generateInjectionContent();
|
|
1474
1423
|
const harnessProviders = [];
|
|
1475
1424
|
const genericProviders = [];
|
|
@@ -1503,9 +1452,21 @@ function registerInstructionsUpdate(parent) {
|
|
|
1503
1452
|
}
|
|
1504
1453
|
const providerIds = new Set(needsUpdate.map((c) => c.provider));
|
|
1505
1454
|
const toUpdate = genericProviders.filter((p) => providerIds.has(p.id));
|
|
1506
|
-
const
|
|
1507
|
-
const
|
|
1508
|
-
const
|
|
1455
|
+
const failures = [];
|
|
1456
|
+
const results = /* @__PURE__ */ new Map();
|
|
1457
|
+
for (const provider of toUpdate) {
|
|
1458
|
+
try {
|
|
1459
|
+
for (const [file, action] of await injectAll([provider], process.cwd(), scope, content)) {
|
|
1460
|
+
results.set(file, action);
|
|
1461
|
+
}
|
|
1462
|
+
} catch (err) {
|
|
1463
|
+
failures.push({
|
|
1464
|
+
provider: provider.id,
|
|
1465
|
+
error: err instanceof Error ? err.message : String(err)
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
const harnessScope = { kind: "project", projectDir: process.cwd() };
|
|
1509
1470
|
for (const provider of harnessProviders) {
|
|
1510
1471
|
const harness = getHarnessFor(provider);
|
|
1511
1472
|
if (harness === null) continue;
|
|
@@ -1513,22 +1474,19 @@ function registerInstructionsUpdate(parent) {
|
|
|
1513
1474
|
await harness.injectInstructions(content, harnessScope);
|
|
1514
1475
|
results.set(`${provider.id}:AGENTS.md`, "updated");
|
|
1515
1476
|
} catch (err) {
|
|
1516
|
-
|
|
1477
|
+
failures.push({
|
|
1517
1478
|
provider: provider.id,
|
|
1518
1479
|
error: err instanceof Error ? err.message : String(err)
|
|
1519
1480
|
});
|
|
1520
1481
|
}
|
|
1521
1482
|
}
|
|
1522
|
-
const updated = [];
|
|
1523
|
-
for (const [file] of results) {
|
|
1524
|
-
updated.push(file);
|
|
1525
|
-
}
|
|
1483
|
+
const updated = [...results.keys()];
|
|
1526
1484
|
if (format === "human") {
|
|
1527
1485
|
console.log();
|
|
1528
1486
|
for (const [file, action] of results) {
|
|
1529
1487
|
console.log(` ${pc5.green("\u2713")} ${file} (${action})`);
|
|
1530
1488
|
}
|
|
1531
|
-
for (const failure of
|
|
1489
|
+
for (const failure of failures) {
|
|
1532
1490
|
console.log(` ${pc5.red("x")} ${failure.provider}: ${failure.error}`);
|
|
1533
1491
|
}
|
|
1534
1492
|
console.log(pc5.bold(`
|
|
@@ -1537,8 +1495,8 @@ ${results.size} file(s) updated.`));
|
|
|
1537
1495
|
if (format === "json") {
|
|
1538
1496
|
outputSuccess(operation, mvi, {
|
|
1539
1497
|
updated,
|
|
1540
|
-
failed:
|
|
1541
|
-
count: { updated: updated.length, failed:
|
|
1498
|
+
failed: failures,
|
|
1499
|
+
count: { updated: updated.length, failed: failures.length }
|
|
1542
1500
|
});
|
|
1543
1501
|
}
|
|
1544
1502
|
});
|
|
@@ -1883,60 +1841,8 @@ function registerMcpCommands(program2) {
|
|
|
1883
1841
|
// src/commands/pi/cant.ts
|
|
1884
1842
|
import { existsSync as existsSync4 } from "fs";
|
|
1885
1843
|
import { writeFile } from "fs/promises";
|
|
1886
|
-
import { tmpdir as tmpdir3 } from "os";
|
|
1887
|
-
import { isAbsolute, join as join5 } from "path";
|
|
1888
|
-
|
|
1889
|
-
// src/core/sources/github.ts
|
|
1890
|
-
import { mkdtemp, rm } from "fs/promises";
|
|
1891
1844
|
import { tmpdir } from "os";
|
|
1892
|
-
import { join as join3 } from "path";
|
|
1893
|
-
import { simpleGit } from "simple-git";
|
|
1894
|
-
async function cloneRepo(owner, repo, ref, subPath) {
|
|
1895
|
-
const tmpDir = await mkdtemp(join3(tmpdir(), "caamp-"));
|
|
1896
|
-
const repoUrl = `https://github.com/${owner}/${repo}.git`;
|
|
1897
|
-
const git = simpleGit();
|
|
1898
|
-
const cloneOptions = ["--depth", "1"];
|
|
1899
|
-
if (ref) {
|
|
1900
|
-
cloneOptions.push("--branch", ref);
|
|
1901
|
-
}
|
|
1902
|
-
await git.clone(repoUrl, tmpDir, cloneOptions);
|
|
1903
|
-
const localPath = subPath ? join3(tmpDir, subPath) : tmpDir;
|
|
1904
|
-
return {
|
|
1905
|
-
localPath,
|
|
1906
|
-
cleanup: async () => {
|
|
1907
|
-
try {
|
|
1908
|
-
await rm(tmpDir, { recursive: true });
|
|
1909
|
-
} catch {
|
|
1910
|
-
}
|
|
1911
|
-
}
|
|
1912
|
-
};
|
|
1913
|
-
}
|
|
1914
|
-
|
|
1915
|
-
// src/core/sources/gitlab.ts
|
|
1916
|
-
import { mkdtemp as mkdtemp2, rm as rm2 } from "fs/promises";
|
|
1917
|
-
import { tmpdir as tmpdir2 } from "os";
|
|
1918
|
-
import { join as join4 } from "path";
|
|
1919
|
-
import { simpleGit as simpleGit2 } from "simple-git";
|
|
1920
|
-
async function cloneGitLabRepo(owner, repo, ref, subPath) {
|
|
1921
|
-
const tmpDir = await mkdtemp2(join4(tmpdir2(), "caamp-gl-"));
|
|
1922
|
-
const repoUrl = `https://gitlab.com/${owner}/${repo}.git`;
|
|
1923
|
-
const git = simpleGit2();
|
|
1924
|
-
const cloneOptions = ["--depth", "1"];
|
|
1925
|
-
if (ref) {
|
|
1926
|
-
cloneOptions.push("--branch", ref);
|
|
1927
|
-
}
|
|
1928
|
-
await git.clone(repoUrl, tmpDir, cloneOptions);
|
|
1929
|
-
const localPath = subPath ? join4(tmpDir, subPath) : tmpDir;
|
|
1930
|
-
return {
|
|
1931
|
-
localPath,
|
|
1932
|
-
cleanup: async () => {
|
|
1933
|
-
try {
|
|
1934
|
-
await rm2(tmpDir, { recursive: true });
|
|
1935
|
-
} catch {
|
|
1936
|
-
}
|
|
1937
|
-
}
|
|
1938
|
-
};
|
|
1939
|
-
}
|
|
1845
|
+
import { isAbsolute, join as join3 } from "path";
|
|
1940
1846
|
|
|
1941
1847
|
// src/commands/pi/common.ts
|
|
1942
1848
|
var PI_ERROR_CODES = {
|
|
@@ -1999,7 +1905,7 @@ function resolveProjectDir2(tier, explicit) {
|
|
|
1999
1905
|
// src/commands/pi/cant.ts
|
|
2000
1906
|
async function resolveCantSource(source) {
|
|
2001
1907
|
if (isAbsolute(source) || source.startsWith("./") || source.startsWith("../") || source.startsWith("~")) {
|
|
2002
|
-
const expanded = source.startsWith("~/") ?
|
|
1908
|
+
const expanded = source.startsWith("~/") ? join3(process.env["HOME"] ?? "", source.slice(2)) : source;
|
|
2003
1909
|
if (!existsSync4(expanded)) {
|
|
2004
1910
|
throw new LAFSCommandError(
|
|
2005
1911
|
PI_ERROR_CODES.NOT_FOUND,
|
|
@@ -2019,7 +1925,7 @@ async function resolveCantSource(source) {
|
|
|
2019
1925
|
const parsed2 = parseSource(source);
|
|
2020
1926
|
if (parsed2.type === "github" && parsed2.owner !== void 0 && parsed2.repo !== void 0) {
|
|
2021
1927
|
const cloneResult = await cloneRepo(parsed2.owner, parsed2.repo, parsed2.ref);
|
|
2022
|
-
const filePath = parsed2.path !== void 0 ?
|
|
1928
|
+
const filePath = parsed2.path !== void 0 ? join3(cloneResult.localPath, parsed2.path) : cloneResult.localPath;
|
|
2023
1929
|
if (!existsSync4(filePath)) {
|
|
2024
1930
|
await cloneResult.cleanup();
|
|
2025
1931
|
throw new LAFSCommandError(
|
|
@@ -2037,7 +1943,7 @@ async function resolveCantSource(source) {
|
|
|
2037
1943
|
}
|
|
2038
1944
|
if (parsed2.type === "gitlab" && parsed2.owner !== void 0 && parsed2.repo !== void 0) {
|
|
2039
1945
|
const cloneResult = await cloneGitLabRepo(parsed2.owner, parsed2.repo, parsed2.ref);
|
|
2040
|
-
const filePath = parsed2.path !== void 0 ?
|
|
1946
|
+
const filePath = parsed2.path !== void 0 ? join3(cloneResult.localPath, parsed2.path) : cloneResult.localPath;
|
|
2041
1947
|
if (!existsSync4(filePath)) {
|
|
2042
1948
|
await cloneResult.cleanup();
|
|
2043
1949
|
throw new LAFSCommandError(
|
|
@@ -2064,7 +1970,7 @@ async function resolveCantSource(source) {
|
|
|
2064
1970
|
}
|
|
2065
1971
|
const body = await resp.text();
|
|
2066
1972
|
const baseName = inferNameFromUrl(source);
|
|
2067
|
-
const tmp =
|
|
1973
|
+
const tmp = join3(tmpdir(), `caamp-pi-cant-${process.pid}-${Date.now()}-${baseName}.cant`);
|
|
2068
1974
|
await writeFile(tmp, body, "utf8");
|
|
2069
1975
|
return {
|
|
2070
1976
|
localPath: tmp,
|
|
@@ -2080,7 +1986,7 @@ async function resolveCantSource(source) {
|
|
|
2080
1986
|
const parsed = parseSource(source);
|
|
2081
1987
|
if (parsed.type === "github" && parsed.owner !== void 0 && parsed.repo !== void 0) {
|
|
2082
1988
|
const cloneResult = await cloneRepo(parsed.owner, parsed.repo, parsed.ref);
|
|
2083
|
-
const filePath = parsed.path !== void 0 ?
|
|
1989
|
+
const filePath = parsed.path !== void 0 ? join3(cloneResult.localPath, parsed.path) : cloneResult.localPath;
|
|
2084
1990
|
if (!existsSync4(filePath)) {
|
|
2085
1991
|
await cloneResult.cleanup();
|
|
2086
1992
|
throw new LAFSCommandError(
|
|
@@ -2244,11 +2150,11 @@ function registerPiCantCommands(parent) {
|
|
|
2244
2150
|
// src/commands/pi/extensions.ts
|
|
2245
2151
|
import { existsSync as existsSync5 } from "fs";
|
|
2246
2152
|
import { writeFile as writeFile2 } from "fs/promises";
|
|
2247
|
-
import { tmpdir as
|
|
2248
|
-
import { isAbsolute as isAbsolute2, join as
|
|
2153
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
2154
|
+
import { isAbsolute as isAbsolute2, join as join4 } from "path";
|
|
2249
2155
|
async function resolveExtensionSource(source) {
|
|
2250
2156
|
if (isAbsolute2(source) || source.startsWith("./") || source.startsWith("../") || source.startsWith("~")) {
|
|
2251
|
-
const expanded = source.startsWith("~/") ?
|
|
2157
|
+
const expanded = source.startsWith("~/") ? join4(process.env["HOME"] ?? "", source.slice(2)) : source;
|
|
2252
2158
|
if (!existsSync5(expanded)) {
|
|
2253
2159
|
throw new LAFSCommandError(
|
|
2254
2160
|
PI_ERROR_CODES.NOT_FOUND,
|
|
@@ -2269,7 +2175,7 @@ async function resolveExtensionSource(source) {
|
|
|
2269
2175
|
const parsed2 = parseSource(source);
|
|
2270
2176
|
if (parsed2.type === "github" && parsed2.owner !== void 0 && parsed2.repo !== void 0) {
|
|
2271
2177
|
const cloneResult = await cloneRepo(parsed2.owner, parsed2.repo, parsed2.ref);
|
|
2272
|
-
const filePath = parsed2.path !== void 0 ?
|
|
2178
|
+
const filePath = parsed2.path !== void 0 ? join4(cloneResult.localPath, parsed2.path) : cloneResult.localPath;
|
|
2273
2179
|
if (!existsSync5(filePath)) {
|
|
2274
2180
|
await cloneResult.cleanup();
|
|
2275
2181
|
throw new LAFSCommandError(
|
|
@@ -2287,7 +2193,7 @@ async function resolveExtensionSource(source) {
|
|
|
2287
2193
|
}
|
|
2288
2194
|
if (parsed2.type === "gitlab" && parsed2.owner !== void 0 && parsed2.repo !== void 0) {
|
|
2289
2195
|
const cloneResult = await cloneGitLabRepo(parsed2.owner, parsed2.repo, parsed2.ref);
|
|
2290
|
-
const filePath = parsed2.path !== void 0 ?
|
|
2196
|
+
const filePath = parsed2.path !== void 0 ? join4(cloneResult.localPath, parsed2.path) : cloneResult.localPath;
|
|
2291
2197
|
if (!existsSync5(filePath)) {
|
|
2292
2198
|
await cloneResult.cleanup();
|
|
2293
2199
|
throw new LAFSCommandError(
|
|
@@ -2314,7 +2220,7 @@ async function resolveExtensionSource(source) {
|
|
|
2314
2220
|
}
|
|
2315
2221
|
const body = await resp.text();
|
|
2316
2222
|
const baseName = inferNameFromUrl2(source);
|
|
2317
|
-
const tmp =
|
|
2223
|
+
const tmp = join4(tmpdir2(), `caamp-pi-ext-${process.pid}-${Date.now()}-${baseName}.ts`);
|
|
2318
2224
|
await writeFile2(tmp, body, "utf8");
|
|
2319
2225
|
return {
|
|
2320
2226
|
localPath: tmp,
|
|
@@ -2330,7 +2236,7 @@ async function resolveExtensionSource(source) {
|
|
|
2330
2236
|
const parsed = parseSource(source);
|
|
2331
2237
|
if (parsed.type === "github" && parsed.owner !== void 0 && parsed.repo !== void 0) {
|
|
2332
2238
|
const cloneResult = await cloneRepo(parsed.owner, parsed.repo, parsed.ref);
|
|
2333
|
-
const filePath = parsed.path !== void 0 ?
|
|
2239
|
+
const filePath = parsed.path !== void 0 ? join4(cloneResult.localPath, parsed.path) : cloneResult.localPath;
|
|
2334
2240
|
if (!existsSync5(filePath)) {
|
|
2335
2241
|
await cloneResult.cleanup();
|
|
2336
2242
|
throw new LAFSCommandError(
|
|
@@ -2599,7 +2505,7 @@ function registerPiModelsCommands(parent) {
|
|
|
2599
2505
|
|
|
2600
2506
|
// src/commands/pi/prompts.ts
|
|
2601
2507
|
import { existsSync as existsSync6 } from "fs";
|
|
2602
|
-
import { join as
|
|
2508
|
+
import { join as join5, resolve } from "path";
|
|
2603
2509
|
function inferPromptName(sourceDir) {
|
|
2604
2510
|
const normalized = resolve(sourceDir).replace(/[\\/]+$/, "");
|
|
2605
2511
|
const base = normalized.split(/[\\/]/).pop();
|
|
@@ -2629,7 +2535,7 @@ function registerPiPromptsCommands(parent) {
|
|
|
2629
2535
|
false
|
|
2630
2536
|
);
|
|
2631
2537
|
}
|
|
2632
|
-
if (!existsSync6(
|
|
2538
|
+
if (!existsSync6(join5(absSource, "prompt.md"))) {
|
|
2633
2539
|
throw new LAFSCommandError(
|
|
2634
2540
|
PI_ERROR_CODES.VALIDATION,
|
|
2635
2541
|
`Source directory is missing prompt.md: ${absSource}`,
|
|
@@ -2946,8 +2852,8 @@ function registerPiCommands(program2) {
|
|
|
2946
2852
|
}
|
|
2947
2853
|
|
|
2948
2854
|
// src/commands/providers.ts
|
|
2949
|
-
import { randomUUID as
|
|
2950
|
-
import { resolveOutputFormat
|
|
2855
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
2856
|
+
import { resolveOutputFormat } from "@cleocode/lafs";
|
|
2951
2857
|
import pc6 from "picocolors";
|
|
2952
2858
|
function registerProvidersCommand(program2) {
|
|
2953
2859
|
const providers = program2.command("providers").description("Manage AI agent providers");
|
|
@@ -2956,7 +2862,7 @@ function registerProvidersCommand(program2) {
|
|
|
2956
2862
|
const mvi = "standard";
|
|
2957
2863
|
let format;
|
|
2958
2864
|
try {
|
|
2959
|
-
format =
|
|
2865
|
+
format = resolveOutputFormat({
|
|
2960
2866
|
jsonFlag: opts.json ?? false,
|
|
2961
2867
|
humanFlag: (opts.human ?? false) || isHuman(),
|
|
2962
2868
|
projectDefault: "json"
|
|
@@ -3006,7 +2912,7 @@ CAMP Provider Registry v${getRegistryVersion()}`));
|
|
|
3006
2912
|
const mvi = "standard";
|
|
3007
2913
|
let format;
|
|
3008
2914
|
try {
|
|
3009
|
-
format =
|
|
2915
|
+
format = resolveOutputFormat({
|
|
3010
2916
|
jsonFlag: opts.json ?? false,
|
|
3011
2917
|
humanFlag: (opts.human ?? false) || isHuman(),
|
|
3012
2918
|
projectDefault: "json"
|
|
@@ -3062,7 +2968,7 @@ Detected ${installed.length} installed providers:
|
|
|
3062
2968
|
const mvi = "standard";
|
|
3063
2969
|
let format;
|
|
3064
2970
|
try {
|
|
3065
|
-
format =
|
|
2971
|
+
format = resolveOutputFormat({
|
|
3066
2972
|
jsonFlag: opts.json ?? false,
|
|
3067
2973
|
humanFlag: (opts.human ?? false) || isHuman(),
|
|
3068
2974
|
projectDefault: "json"
|
|
@@ -3135,7 +3041,7 @@ ${provider.toolName}`));
|
|
|
3135
3041
|
const mvi = "standard";
|
|
3136
3042
|
let format;
|
|
3137
3043
|
try {
|
|
3138
|
-
format =
|
|
3044
|
+
format = resolveOutputFormat({
|
|
3139
3045
|
jsonFlag: opts.json ?? false,
|
|
3140
3046
|
humanFlag: (opts.human ?? false) || isHuman(),
|
|
3141
3047
|
projectDefault: "json"
|
|
@@ -3193,7 +3099,7 @@ ${provider.toolName}`));
|
|
|
3193
3099
|
const mvi = "standard";
|
|
3194
3100
|
let format;
|
|
3195
3101
|
try {
|
|
3196
|
-
format =
|
|
3102
|
+
format = resolveOutputFormat({
|
|
3197
3103
|
jsonFlag: opts.json ?? false,
|
|
3198
3104
|
humanFlag: (opts.human ?? false) || isHuman(),
|
|
3199
3105
|
projectDefault: "json"
|
|
@@ -3261,7 +3167,7 @@ CAMP Hook Support (mappings v${getHookMappingsVersion()})
|
|
|
3261
3167
|
const mvi = "standard";
|
|
3262
3168
|
let format;
|
|
3263
3169
|
try {
|
|
3264
|
-
format =
|
|
3170
|
+
format = resolveOutputFormat({
|
|
3265
3171
|
jsonFlag: opts.json ?? false,
|
|
3266
3172
|
humanFlag: (opts.human ?? false) || isHuman(),
|
|
3267
3173
|
projectDefault: "json"
|
|
@@ -3308,7 +3214,7 @@ CAMP Hook Support (mappings v${getHookMappingsVersion()})
|
|
|
3308
3214
|
const mvi = "standard";
|
|
3309
3215
|
let format;
|
|
3310
3216
|
try {
|
|
3311
|
-
format =
|
|
3217
|
+
format = resolveOutputFormat({
|
|
3312
3218
|
jsonFlag: opts.json ?? false,
|
|
3313
3219
|
humanFlag: (opts.human ?? false) || isHuman(),
|
|
3314
3220
|
projectDefault: "json"
|
|
@@ -3439,7 +3345,7 @@ CAMP Hook Support (mappings v${getHookMappingsVersion()})
|
|
|
3439
3345
|
const mvi = "standard";
|
|
3440
3346
|
let format;
|
|
3441
3347
|
try {
|
|
3442
|
-
format =
|
|
3348
|
+
format = resolveOutputFormat({
|
|
3443
3349
|
jsonFlag: opts.json ?? false,
|
|
3444
3350
|
humanFlag: (opts.human ?? false) || isHuman(),
|
|
3445
3351
|
projectDefault: "json"
|
|
@@ -3509,7 +3415,7 @@ function buildEnvelope2(operation, mvi, result, error) {
|
|
|
3509
3415
|
schemaVersion: "1.0.0",
|
|
3510
3416
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3511
3417
|
operation,
|
|
3512
|
-
requestId:
|
|
3418
|
+
requestId: randomUUID2(),
|
|
3513
3419
|
transport: "cli",
|
|
3514
3420
|
strict: true,
|
|
3515
3421
|
mvi,
|
|
@@ -3825,8 +3731,8 @@ function registerSkillsCheck(parent) {
|
|
|
3825
3731
|
}
|
|
3826
3732
|
|
|
3827
3733
|
// src/commands/skills/find.ts
|
|
3828
|
-
import { randomUUID as
|
|
3829
|
-
import { resolveOutputFormat as
|
|
3734
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
3735
|
+
import { resolveOutputFormat as resolveOutputFormat2 } from "@cleocode/lafs";
|
|
3830
3736
|
import pc9 from "picocolors";
|
|
3831
3737
|
var SkillsFindValidationError = class extends Error {
|
|
3832
3738
|
code;
|
|
@@ -3858,7 +3764,7 @@ function registerSkillsFind(parent) {
|
|
|
3858
3764
|
const mvi = details ? "full" : "standard";
|
|
3859
3765
|
let format;
|
|
3860
3766
|
try {
|
|
3861
|
-
format =
|
|
3767
|
+
format = resolveOutputFormat2({
|
|
3862
3768
|
jsonFlag: opts.json ?? false,
|
|
3863
3769
|
humanFlag: (opts.human ?? false) || isHuman(),
|
|
3864
3770
|
projectDefault: "json"
|
|
@@ -4087,7 +3993,7 @@ function buildEnvelope3(operation, mvi, result, error) {
|
|
|
4087
3993
|
schemaVersion: "1.0.0",
|
|
4088
3994
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4089
3995
|
operation,
|
|
4090
|
-
requestId:
|
|
3996
|
+
requestId: randomUUID3(),
|
|
4091
3997
|
transport: "cli",
|
|
4092
3998
|
strict: true,
|
|
4093
3999
|
mvi,
|
|
@@ -4114,7 +4020,7 @@ function emitJsonError3(operation, mvi, code, message, category, details = {}) {
|
|
|
4114
4020
|
// src/commands/skills/init.ts
|
|
4115
4021
|
import { existsSync as existsSync10 } from "fs";
|
|
4116
4022
|
import { mkdir, writeFile as writeFile3 } from "fs/promises";
|
|
4117
|
-
import { join as
|
|
4023
|
+
import { join as join6 } from "path";
|
|
4118
4024
|
import pc10 from "picocolors";
|
|
4119
4025
|
function registerSkillsInit(parent) {
|
|
4120
4026
|
parent.command("init").description("Create a new SKILL.md template").argument("[name]", "Skill name").option("-d, --dir <path>", "Output directory", ".").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(
|
|
@@ -4140,7 +4046,7 @@ function registerSkillsInit(parent) {
|
|
|
4140
4046
|
process.exit(1);
|
|
4141
4047
|
}
|
|
4142
4048
|
const skillName = name ?? "my-skill";
|
|
4143
|
-
const skillDir =
|
|
4049
|
+
const skillDir = join6(opts.dir, skillName);
|
|
4144
4050
|
if (existsSync10(skillDir)) {
|
|
4145
4051
|
const message = `Directory already exists: ${skillDir}`;
|
|
4146
4052
|
if (format === "json") {
|
|
@@ -4183,7 +4089,7 @@ Provide detailed instructions for the AI agent here.
|
|
|
4183
4089
|
|
|
4184
4090
|
Show example inputs and expected outputs.
|
|
4185
4091
|
`;
|
|
4186
|
-
await writeFile3(
|
|
4092
|
+
await writeFile3(join6(skillDir, "SKILL.md"), template, "utf-8");
|
|
4187
4093
|
const result = {
|
|
4188
4094
|
name: skillName,
|
|
4189
4095
|
directory: skillDir,
|
|
@@ -4197,95 +4103,88 @@ Show example inputs and expected outputs.
|
|
|
4197
4103
|
console.log(pc10.green(`\u2713 Created skill template: ${skillDir}/SKILL.md`));
|
|
4198
4104
|
console.log(pc10.dim("\nNext steps:"));
|
|
4199
4105
|
console.log(pc10.dim(" 1. Edit SKILL.md with your instructions"));
|
|
4200
|
-
console.log(pc10.dim(` 2. Validate: caamp skills validate ${
|
|
4106
|
+
console.log(pc10.dim(` 2. Validate: caamp skills validate ${join6(skillDir, "SKILL.md")}`));
|
|
4201
4107
|
console.log(pc10.dim(` 3. Install: caamp skills install ${skillDir}`));
|
|
4202
4108
|
}
|
|
4203
4109
|
);
|
|
4204
4110
|
}
|
|
4205
4111
|
|
|
4206
4112
|
// src/commands/skills/install.ts
|
|
4207
|
-
import { existsSync as existsSync11 } from "fs";
|
|
4208
|
-
import { createRequire } from "module";
|
|
4209
|
-
import { pushWarning } from "@cleocode/lafs";
|
|
4210
4113
|
import pc11 from "picocolors";
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
pushWarning({
|
|
4225
|
-
code: "W_CORE_UNAVAILABLE",
|
|
4226
|
-
severity: "warn",
|
|
4227
|
-
message: "caamp running without @cleocode/core \u2014 trust gate skipped (skill installs not security-checked)",
|
|
4228
|
-
context: {
|
|
4229
|
-
error: err instanceof Error ? err.message : String(err)
|
|
4230
|
-
}
|
|
4231
|
-
});
|
|
4114
|
+
function renderProgress(event) {
|
|
4115
|
+
switch (event.kind) {
|
|
4116
|
+
case "marketplace-search":
|
|
4117
|
+
console.log(pc11.dim(`Searching marketplace for ${event.source}...`));
|
|
4118
|
+
return;
|
|
4119
|
+
case "marketplace-found":
|
|
4120
|
+
console.log(` Found: ${pc11.bold(event.name)} by ${event.author} (${pc11.dim(event.repo)})`);
|
|
4121
|
+
return;
|
|
4122
|
+
case "catalog-found":
|
|
4123
|
+
console.log(
|
|
4124
|
+
` Found in catalog: ${pc11.bold(event.name)} v${event.version} (${pc11.dim(event.category)})`
|
|
4125
|
+
);
|
|
4126
|
+
return;
|
|
4232
4127
|
}
|
|
4233
|
-
return cachedCore;
|
|
4234
4128
|
}
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
verdict: "safe",
|
|
4246
|
-
findings: [],
|
|
4247
|
-
scannedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4248
|
-
summary: "core-unavailable"
|
|
4249
|
-
}
|
|
4250
|
-
};
|
|
4129
|
+
function categoryFor(err) {
|
|
4130
|
+
switch (err.code) {
|
|
4131
|
+
case ErrorCodes.NETWORK_ERROR:
|
|
4132
|
+
return ErrorCategories.TRANSIENT;
|
|
4133
|
+
case ErrorCodes.SKILL_NOT_FOUND:
|
|
4134
|
+
return ErrorCategories.NOT_FOUND;
|
|
4135
|
+
case ErrorCodes.SKILL_GATE_UNAVAILABLE:
|
|
4136
|
+
return ErrorCategories.INTERNAL;
|
|
4137
|
+
default:
|
|
4138
|
+
return ErrorCategories.VALIDATION;
|
|
4251
4139
|
}
|
|
4252
|
-
const scan = core.scanSkill(localPath, source);
|
|
4253
|
-
const gate = core.shouldAllowInstall(scan, force);
|
|
4254
|
-
return { decision: gate.decision, reason: gate.reason, scan };
|
|
4255
4140
|
}
|
|
4256
|
-
|
|
4257
|
-
const
|
|
4258
|
-
if (
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4141
|
+
function reportRefusal(err, format, operation, mvi) {
|
|
4142
|
+
const scan = err.details.scan;
|
|
4143
|
+
if (format === "json") {
|
|
4144
|
+
if (scan && err.code === ErrorCodes.SKILL_TRUST_GATE_BLOCKED) {
|
|
4145
|
+
const envelope = buildEnvelope(
|
|
4146
|
+
operation,
|
|
4147
|
+
mvi,
|
|
4148
|
+
{ scan },
|
|
4149
|
+
{
|
|
4150
|
+
code: err.code,
|
|
4151
|
+
message: err.message,
|
|
4152
|
+
category: categoryFor(err),
|
|
4153
|
+
retryable: false,
|
|
4154
|
+
retryAfterMs: null,
|
|
4155
|
+
details: {
|
|
4156
|
+
verdict: scan.verdict,
|
|
4157
|
+
trustLevel: scan.trustLevel,
|
|
4158
|
+
findingsCount: scan.findings.length
|
|
4159
|
+
}
|
|
4160
|
+
}
|
|
4161
|
+
);
|
|
4162
|
+
console.error(JSON.stringify(envelope, null, 2));
|
|
4163
|
+
} else {
|
|
4164
|
+
const details = {};
|
|
4165
|
+
if (err.details.availableSkills) details.availableSkills = err.details.availableSkills;
|
|
4166
|
+
if (err.details.federation) {
|
|
4167
|
+
details.expectedChecksum = err.details.federation.expectedChecksum;
|
|
4168
|
+
details.computedChecksum = err.details.federation.computedChecksum;
|
|
4169
|
+
details.peer = err.details.federation.peer?.url ?? null;
|
|
4170
|
+
}
|
|
4171
|
+
if (err.details.cause) details.cause = err.details.cause;
|
|
4172
|
+
emitJsonError(operation, mvi, err.code, err.message, categoryFor(err), details);
|
|
4173
|
+
}
|
|
4267
4174
|
}
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
}
|
|
4275
|
-
|
|
4276
|
-
const core = await resolveCore();
|
|
4277
|
-
if (!core) return;
|
|
4278
|
-
try {
|
|
4279
|
-
core.recordTrustBypass(scan, reason);
|
|
4280
|
-
} catch (err) {
|
|
4281
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
4282
|
-
pushWarning({
|
|
4283
|
-
code: "W_AUDIT_LOG_FAILED",
|
|
4284
|
-
severity: "warn",
|
|
4285
|
-
message: "trust-bypass audit record failed",
|
|
4286
|
-
context: { error: msg }
|
|
4287
|
-
});
|
|
4175
|
+
console.error(pc11.red(err.message));
|
|
4176
|
+
if (scan && err.code === ErrorCodes.SKILL_TRUST_GATE_BLOCKED && format === "human") {
|
|
4177
|
+
for (const f of scan.findings.slice(0, 5)) {
|
|
4178
|
+
console.error(
|
|
4179
|
+
pc11.dim(` [${f.severity}] ${f.category} ${f.file}:${f.line} \u2014 ${f.description}`)
|
|
4180
|
+
);
|
|
4181
|
+
}
|
|
4182
|
+
console.error(pc11.yellow(" Use --force to override (audited)."));
|
|
4288
4183
|
}
|
|
4184
|
+
if (err.details.availableSkills && format === "human") {
|
|
4185
|
+
console.log(pc11.dim(`Available skills: ${err.details.availableSkills.join(", ")}`));
|
|
4186
|
+
}
|
|
4187
|
+
process.exit(1);
|
|
4289
4188
|
}
|
|
4290
4189
|
function registerSkillsInstall(parent) {
|
|
4291
4190
|
parent.command("install").description("Install a skill from GitHub, URL, marketplace, or registered skill library").argument("[source]", "Skill source (GitHub URL, owner/repo, @author/name, skill-name)").option(
|
|
@@ -4335,7 +4234,7 @@ function registerSkillsInstall(parent) {
|
|
|
4335
4234
|
if (providers.length === 0) {
|
|
4336
4235
|
const message = "No target providers found. Use --agent or --all.";
|
|
4337
4236
|
if (format === "json") {
|
|
4338
|
-
|
|
4237
|
+
emitError(
|
|
4339
4238
|
operation,
|
|
4340
4239
|
mvi,
|
|
4341
4240
|
ErrorCodes.PROVIDER_NOT_FOUND,
|
|
@@ -4360,7 +4259,7 @@ function registerSkillsInstall(parent) {
|
|
|
4360
4259
|
if (!source) {
|
|
4361
4260
|
const message = "Missing required argument: source";
|
|
4362
4261
|
if (format === "json") {
|
|
4363
|
-
|
|
4262
|
+
emitError(
|
|
4364
4263
|
operation,
|
|
4365
4264
|
mvi,
|
|
4366
4265
|
ErrorCodes.INVALID_INPUT,
|
|
@@ -4377,335 +4276,74 @@ function registerSkillsInstall(parent) {
|
|
|
4377
4276
|
if (format === "human") {
|
|
4378
4277
|
console.log(pc11.dim(`Installing to ${providers.length} provider(s)...`));
|
|
4379
4278
|
}
|
|
4380
|
-
let
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
let sourceValue;
|
|
4384
|
-
let sourceType;
|
|
4385
|
-
if (isMarketplaceScoped(source)) {
|
|
4386
|
-
const sourceResult = await handleMarketplaceSource(
|
|
4387
|
-
source,
|
|
4279
|
+
let result;
|
|
4280
|
+
try {
|
|
4281
|
+
result = await installSkillFromSource(source, {
|
|
4388
4282
|
providers,
|
|
4389
|
-
opts.global ?? false,
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
sourceValue = sourceResult.sourceValue;
|
|
4399
|
-
sourceType = sourceResult.sourceType;
|
|
4400
|
-
} else {
|
|
4401
|
-
process.exit(1);
|
|
4402
|
-
}
|
|
4403
|
-
} else {
|
|
4404
|
-
const parsed = parseSource(source);
|
|
4405
|
-
skillName = parsed.inferredName;
|
|
4406
|
-
sourceValue = parsed.value;
|
|
4407
|
-
sourceType = parsed.type;
|
|
4408
|
-
if (parsed.type === "github" && parsed.owner && parsed.repo) {
|
|
4409
|
-
try {
|
|
4410
|
-
const result = await cloneRepo(parsed.owner, parsed.repo, parsed.ref, parsed.path);
|
|
4411
|
-
localPath = result.localPath;
|
|
4412
|
-
cleanup = result.cleanup;
|
|
4413
|
-
} catch (error) {
|
|
4414
|
-
const message = `Failed to clone GitHub repository: ${formatNetworkError(error)}`;
|
|
4415
|
-
if (format === "json") {
|
|
4416
|
-
emitJsonError(
|
|
4417
|
-
operation,
|
|
4418
|
-
mvi,
|
|
4419
|
-
ErrorCodes.NETWORK_ERROR,
|
|
4420
|
-
message,
|
|
4421
|
-
ErrorCategories.TRANSIENT
|
|
4422
|
-
);
|
|
4423
|
-
}
|
|
4424
|
-
console.error(pc11.red(message));
|
|
4425
|
-
process.exit(1);
|
|
4426
|
-
}
|
|
4427
|
-
} else if (parsed.type === "gitlab" && parsed.owner && parsed.repo) {
|
|
4428
|
-
try {
|
|
4429
|
-
const result = await cloneGitLabRepo(
|
|
4430
|
-
parsed.owner,
|
|
4431
|
-
parsed.repo,
|
|
4432
|
-
parsed.ref,
|
|
4433
|
-
parsed.path
|
|
4434
|
-
);
|
|
4435
|
-
localPath = result.localPath;
|
|
4436
|
-
cleanup = result.cleanup;
|
|
4437
|
-
} catch (error) {
|
|
4438
|
-
const message = `Failed to clone GitLab repository: ${formatNetworkError(error)}`;
|
|
4439
|
-
if (format === "json") {
|
|
4440
|
-
emitJsonError(
|
|
4441
|
-
operation,
|
|
4442
|
-
mvi,
|
|
4443
|
-
ErrorCodes.NETWORK_ERROR,
|
|
4444
|
-
message,
|
|
4445
|
-
ErrorCategories.TRANSIENT
|
|
4446
|
-
);
|
|
4447
|
-
}
|
|
4448
|
-
console.error(pc11.red(message));
|
|
4449
|
-
process.exit(1);
|
|
4450
|
-
}
|
|
4451
|
-
} else if (parsed.type === "local") {
|
|
4452
|
-
localPath = parsed.value;
|
|
4453
|
-
const discovered = await discoverSkill(localPath);
|
|
4454
|
-
if (discovered) {
|
|
4455
|
-
skillName = discovered.name;
|
|
4456
|
-
}
|
|
4457
|
-
} else if (parsed.type === "package") {
|
|
4458
|
-
if (!isCatalogAvailable()) {
|
|
4459
|
-
const message = "No skill library registered. Register one with registerSkillLibraryFromPath() or set CAAMP_SKILL_LIBRARY env var.";
|
|
4460
|
-
if (format === "json") {
|
|
4461
|
-
emitJsonError(
|
|
4462
|
-
operation,
|
|
4463
|
-
mvi,
|
|
4464
|
-
ErrorCodes.INVALID_INPUT,
|
|
4465
|
-
message,
|
|
4466
|
-
ErrorCategories.VALIDATION
|
|
4467
|
-
);
|
|
4468
|
-
}
|
|
4469
|
-
console.error(pc11.red(message));
|
|
4470
|
-
process.exit(1);
|
|
4471
|
-
}
|
|
4472
|
-
const catalogSkill = getSkill(parsed.inferredName);
|
|
4473
|
-
if (catalogSkill) {
|
|
4474
|
-
localPath = getSkillDir(catalogSkill.name);
|
|
4475
|
-
skillName = catalogSkill.name;
|
|
4476
|
-
sourceValue = `library:${catalogSkill.name}`;
|
|
4477
|
-
sourceType = "library";
|
|
4478
|
-
if (format === "human") {
|
|
4479
|
-
console.log(
|
|
4480
|
-
` Found in catalog: ${pc11.bold(catalogSkill.name)} v${catalogSkill.version} (${pc11.dim(catalogSkill.category)})`
|
|
4481
|
-
);
|
|
4482
|
-
}
|
|
4483
|
-
} else {
|
|
4484
|
-
const message = `Skill not found in catalog: ${parsed.inferredName}`;
|
|
4485
|
-
if (format === "json") {
|
|
4486
|
-
emitJsonError(
|
|
4487
|
-
operation,
|
|
4488
|
-
mvi,
|
|
4489
|
-
ErrorCodes.SKILL_NOT_FOUND,
|
|
4490
|
-
message,
|
|
4491
|
-
ErrorCategories.NOT_FOUND,
|
|
4492
|
-
{
|
|
4493
|
-
availableSkills: listSkills()
|
|
4494
|
-
}
|
|
4495
|
-
);
|
|
4496
|
-
}
|
|
4497
|
-
console.error(pc11.red(message));
|
|
4498
|
-
console.log(pc11.dim("Available skills: " + listSkills().join(", ")));
|
|
4499
|
-
process.exit(1);
|
|
4500
|
-
}
|
|
4501
|
-
} else {
|
|
4502
|
-
const message = `Unsupported source type: ${parsed.type}`;
|
|
4503
|
-
if (format === "json") {
|
|
4504
|
-
emitJsonError(
|
|
4505
|
-
operation,
|
|
4506
|
-
mvi,
|
|
4507
|
-
ErrorCodes.INVALID_FORMAT,
|
|
4508
|
-
message,
|
|
4509
|
-
ErrorCategories.VALIDATION
|
|
4510
|
-
);
|
|
4511
|
-
}
|
|
4512
|
-
console.error(pc11.red(message));
|
|
4513
|
-
process.exit(1);
|
|
4283
|
+
isGlobal: opts.global ?? false,
|
|
4284
|
+
force: opts.force ?? false,
|
|
4285
|
+
allowNewSource: opts.allowNewSource === true,
|
|
4286
|
+
recordLock: true,
|
|
4287
|
+
onProgress: format === "human" ? renderProgress : void 0
|
|
4288
|
+
});
|
|
4289
|
+
} catch (error) {
|
|
4290
|
+
if (error instanceof SkillInstallError) {
|
|
4291
|
+
reportRefusal(error, format, operation, mvi);
|
|
4514
4292
|
}
|
|
4293
|
+
throw error;
|
|
4515
4294
|
}
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
}
|
|
4531
|
-
if (sourceType !== "library" && sourceType !== "package") {
|
|
4532
|
-
const fedGate = await evaluateFederationGate(sourceValue, {
|
|
4533
|
-
artefactPath: localPath,
|
|
4534
|
-
approveNewSource: opts.allowNewSource === true
|
|
4535
|
-
});
|
|
4536
|
-
if (fedGate.decision === "block-checksum") {
|
|
4537
|
-
const message = `Federation install blocked: ${fedGate.reason}`;
|
|
4538
|
-
if (format === "json") {
|
|
4539
|
-
emitJsonError(
|
|
4540
|
-
operation,
|
|
4541
|
-
mvi,
|
|
4542
|
-
ErrorCodes.FEDERATION_CHECKSUM_MISMATCH,
|
|
4543
|
-
message,
|
|
4544
|
-
ErrorCategories.VALIDATION,
|
|
4545
|
-
{
|
|
4546
|
-
expectedChecksum: fedGate.expectedChecksum,
|
|
4547
|
-
computedChecksum: fedGate.computedChecksum
|
|
4548
|
-
}
|
|
4549
|
-
);
|
|
4550
|
-
}
|
|
4551
|
-
console.error(pc11.red(message));
|
|
4552
|
-
process.exit(1);
|
|
4553
|
-
}
|
|
4554
|
-
if (fedGate.decision === "prompt-first-install") {
|
|
4555
|
-
const message = `${fedGate.reason} Use --allow-new-source to approve in non-interactive contexts.`;
|
|
4556
|
-
if (format === "json") {
|
|
4557
|
-
emitJsonError(
|
|
4558
|
-
operation,
|
|
4559
|
-
mvi,
|
|
4560
|
-
ErrorCodes.FEDERATION_UNKNOWN_SOURCE_INTERACTIVE_REQUIRED,
|
|
4561
|
-
message,
|
|
4562
|
-
ErrorCategories.VALIDATION,
|
|
4563
|
-
{ peer: fedGate.peer?.url ?? null }
|
|
4564
|
-
);
|
|
4565
|
-
}
|
|
4566
|
-
console.error(pc11.yellow(message));
|
|
4567
|
-
process.exit(1);
|
|
4568
|
-
}
|
|
4569
|
-
}
|
|
4570
|
-
if (sourceType !== "library" && sourceType !== "package") {
|
|
4571
|
-
const gate = await evaluateSkillTrustGate(localPath, sourceValue, opts.force ?? false);
|
|
4572
|
-
if (gate.decision === "block") {
|
|
4573
|
-
const message = `Trust gate blocked install: ${gate.reason}`;
|
|
4574
|
-
if (format === "json") {
|
|
4575
|
-
const envelope = buildEnvelope(
|
|
4576
|
-
operation,
|
|
4577
|
-
mvi,
|
|
4578
|
-
{ scan: gate.scan },
|
|
4579
|
-
{
|
|
4580
|
-
code: ErrorCodes.SKILL_TRUST_GATE_BLOCKED,
|
|
4581
|
-
message,
|
|
4582
|
-
category: ErrorCategories.VALIDATION,
|
|
4583
|
-
retryable: false,
|
|
4584
|
-
retryAfterMs: null,
|
|
4585
|
-
details: {
|
|
4586
|
-
verdict: gate.scan.verdict,
|
|
4587
|
-
trustLevel: gate.scan.trustLevel,
|
|
4588
|
-
findingsCount: gate.scan.findings.length
|
|
4589
|
-
}
|
|
4590
|
-
}
|
|
4591
|
-
);
|
|
4592
|
-
console.error(JSON.stringify(envelope, null, 2));
|
|
4593
|
-
} else {
|
|
4594
|
-
console.error(pc11.red(`
|
|
4595
|
-
${message}`));
|
|
4596
|
-
for (const f of gate.scan.findings.slice(0, 5)) {
|
|
4597
|
-
console.error(
|
|
4598
|
-
pc11.dim(
|
|
4599
|
-
` [${f.severity}] ${f.category} ${f.file}:${f.line} \u2014 ${f.description}`
|
|
4600
|
-
)
|
|
4601
|
-
);
|
|
4602
|
-
}
|
|
4603
|
-
console.error(pc11.yellow(" Use --force to override (audited)."));
|
|
4604
|
-
}
|
|
4605
|
-
process.exit(1);
|
|
4606
|
-
}
|
|
4607
|
-
if (gate.decision === "ask") {
|
|
4608
|
-
const message = `Trust gate requires confirmation: ${gate.reason}`;
|
|
4609
|
-
if (format === "json") {
|
|
4610
|
-
emitJsonError(
|
|
4611
|
-
operation,
|
|
4612
|
-
mvi,
|
|
4613
|
-
ErrorCodes.SKILL_TRUST_GATE_BLOCKED,
|
|
4614
|
-
message,
|
|
4615
|
-
ErrorCategories.VALIDATION
|
|
4616
|
-
);
|
|
4617
|
-
}
|
|
4618
|
-
console.error(pc11.red(message));
|
|
4619
|
-
process.exit(1);
|
|
4620
|
-
}
|
|
4621
|
-
if (opts.force === true && gate.scan.verdict !== "safe") {
|
|
4622
|
-
await recordSkillTrustBypass(gate.scan, "operator --force on caamp skills install");
|
|
4623
|
-
}
|
|
4624
|
-
}
|
|
4625
|
-
const result = await dispatchInstallSkillAcrossProviders(
|
|
4626
|
-
localPath,
|
|
4627
|
-
skillName,
|
|
4628
|
-
providers,
|
|
4629
|
-
opts.global ?? false
|
|
4630
|
-
);
|
|
4631
|
-
if (result.success) {
|
|
4632
|
-
const isGlobal = sourceType === "library" || sourceType === "package" ? true : opts.global ?? false;
|
|
4633
|
-
await recordSkillInstall(
|
|
4634
|
-
skillName,
|
|
4635
|
-
sourceValue,
|
|
4636
|
-
sourceValue,
|
|
4637
|
-
sourceType,
|
|
4638
|
-
result.linkedAgents,
|
|
4639
|
-
result.canonicalPath,
|
|
4640
|
-
isGlobal
|
|
4641
|
-
);
|
|
4642
|
-
const installedItem = {
|
|
4643
|
-
name: skillName,
|
|
4644
|
-
scopedName: sourceValue,
|
|
4645
|
-
canonicalPath: result.canonicalPath,
|
|
4646
|
-
providers: result.linkedAgents
|
|
4647
|
-
};
|
|
4648
|
-
const summary = {
|
|
4649
|
-
installed: [installedItem],
|
|
4650
|
-
failed: [],
|
|
4651
|
-
count: {
|
|
4652
|
-
installed: 1,
|
|
4653
|
-
failed: 0,
|
|
4654
|
-
total: 1
|
|
4655
|
-
}
|
|
4656
|
-
};
|
|
4657
|
-
if (format === "json") {
|
|
4658
|
-
outputSuccess(operation, mvi, summary);
|
|
4659
|
-
} else {
|
|
4660
|
-
console.log(pc11.green(`
|
|
4661
|
-
\u2713 Installed ${pc11.bold(skillName)}`));
|
|
4662
|
-
console.log(` Canonical: ${pc11.dim(result.canonicalPath)}`);
|
|
4663
|
-
console.log(` Linked to: ${result.linkedAgents.join(", ")}`);
|
|
4664
|
-
if (result.errors.length > 0) {
|
|
4665
|
-
console.log(pc11.yellow("\nWarnings:"));
|
|
4666
|
-
for (const err of result.errors) {
|
|
4667
|
-
console.log(` ${pc11.yellow("!")} ${err}`);
|
|
4668
|
-
}
|
|
4669
|
-
}
|
|
4670
|
-
}
|
|
4295
|
+
if (result.success) {
|
|
4296
|
+
const installedItem = {
|
|
4297
|
+
name: result.name,
|
|
4298
|
+
scopedName: result.sourceValue,
|
|
4299
|
+
canonicalPath: result.canonicalPath,
|
|
4300
|
+
providers: result.linkedAgents
|
|
4301
|
+
};
|
|
4302
|
+
const summary2 = {
|
|
4303
|
+
installed: [installedItem],
|
|
4304
|
+
failed: [],
|
|
4305
|
+
count: { installed: 1, failed: 0, total: 1 }
|
|
4306
|
+
};
|
|
4307
|
+
if (format === "json") {
|
|
4308
|
+
outputSuccess(operation, mvi, summary2);
|
|
4671
4309
|
} else {
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
}
|
|
4679
|
-
],
|
|
4680
|
-
count: {
|
|
4681
|
-
installed: 0,
|
|
4682
|
-
failed: 1,
|
|
4683
|
-
total: 1
|
|
4684
|
-
}
|
|
4685
|
-
};
|
|
4686
|
-
if (format === "json") {
|
|
4687
|
-
const envelope = buildEnvelope(operation, mvi, summary, {
|
|
4688
|
-
code: ErrorCodes.INSTALL_FAILED,
|
|
4689
|
-
message: result.errors.join(", "),
|
|
4690
|
-
category: ErrorCategories.INTERNAL,
|
|
4691
|
-
retryable: false,
|
|
4692
|
-
retryAfterMs: null,
|
|
4693
|
-
details: { skillName, sourceValue }
|
|
4694
|
-
});
|
|
4695
|
-
console.error(JSON.stringify(envelope, null, 2));
|
|
4696
|
-
} else {
|
|
4697
|
-
console.log(pc11.yellow(`
|
|
4698
|
-
\u2717 Failed to install ${pc11.bold(skillName)}`));
|
|
4699
|
-
console.log(pc11.yellow("Errors:"));
|
|
4310
|
+
console.log(pc11.green(`
|
|
4311
|
+
\u2713 Installed ${pc11.bold(result.name)}`));
|
|
4312
|
+
console.log(` Canonical: ${pc11.dim(result.canonicalPath)}`);
|
|
4313
|
+
console.log(` Linked to: ${result.linkedAgents.join(", ")}`);
|
|
4314
|
+
if (result.errors.length > 0) {
|
|
4315
|
+
console.log(pc11.yellow("\nWarnings:"));
|
|
4700
4316
|
for (const err of result.errors) {
|
|
4701
4317
|
console.log(` ${pc11.yellow("!")} ${err}`);
|
|
4702
4318
|
}
|
|
4703
4319
|
}
|
|
4704
|
-
process.exit(1);
|
|
4705
4320
|
}
|
|
4706
|
-
|
|
4707
|
-
if (cleanup) await cleanup();
|
|
4321
|
+
return;
|
|
4708
4322
|
}
|
|
4323
|
+
const summary = {
|
|
4324
|
+
installed: [],
|
|
4325
|
+
failed: [{ name: result.name, error: result.errors.join(", ") }],
|
|
4326
|
+
count: { installed: 0, failed: 1, total: 1 }
|
|
4327
|
+
};
|
|
4328
|
+
if (format === "json") {
|
|
4329
|
+
const envelope = buildEnvelope(operation, mvi, summary, {
|
|
4330
|
+
code: ErrorCodes.INSTALL_FAILED,
|
|
4331
|
+
message: result.errors.join(", "),
|
|
4332
|
+
category: ErrorCategories.INTERNAL,
|
|
4333
|
+
retryable: false,
|
|
4334
|
+
retryAfterMs: null,
|
|
4335
|
+
details: { skillName: result.name, sourceValue: result.sourceValue }
|
|
4336
|
+
});
|
|
4337
|
+
console.error(JSON.stringify(envelope, null, 2));
|
|
4338
|
+
} else {
|
|
4339
|
+
console.log(pc11.yellow(`
|
|
4340
|
+
\u2717 Failed to install ${pc11.bold(result.name)}`));
|
|
4341
|
+
console.log(pc11.yellow("Errors:"));
|
|
4342
|
+
for (const err of result.errors) {
|
|
4343
|
+
console.log(` ${pc11.yellow("!")} ${err}`);
|
|
4344
|
+
}
|
|
4345
|
+
}
|
|
4346
|
+
process.exit(1);
|
|
4709
4347
|
}
|
|
4710
4348
|
);
|
|
4711
4349
|
}
|
|
@@ -4713,7 +4351,7 @@ async function handleProfileInstall(profileName, providers, isGlobal, format, op
|
|
|
4713
4351
|
if (!isCatalogAvailable()) {
|
|
4714
4352
|
const message = "No skill library registered. Register one with registerSkillLibraryFromPath() or set CAAMP_SKILL_LIBRARY env var.";
|
|
4715
4353
|
if (format === "json") {
|
|
4716
|
-
|
|
4354
|
+
emitError(operation, mvi, ErrorCodes.INVALID_INPUT, message, ErrorCategories.VALIDATION);
|
|
4717
4355
|
}
|
|
4718
4356
|
console.error(pc11.red(message));
|
|
4719
4357
|
process.exit(1);
|
|
@@ -4747,22 +4385,20 @@ async function handleProfileInstall(profileName, providers, isGlobal, format, op
|
|
|
4747
4385
|
const installed = [];
|
|
4748
4386
|
const failed = [];
|
|
4749
4387
|
for (const name of profileSkills) {
|
|
4750
|
-
const skillDir = getSkillDir(name);
|
|
4751
4388
|
try {
|
|
4752
|
-
const result = await
|
|
4389
|
+
const result = await installResolvedSkill(
|
|
4390
|
+
{
|
|
4391
|
+
localPath: getSkillDir(name),
|
|
4392
|
+
skillName: name,
|
|
4393
|
+
sourceValue: `library:${name}`,
|
|
4394
|
+
sourceType: "library"
|
|
4395
|
+
},
|
|
4396
|
+
{ providers, isGlobal, recordLock: true }
|
|
4397
|
+
);
|
|
4753
4398
|
if (result.success) {
|
|
4754
4399
|
if (format === "human") {
|
|
4755
4400
|
console.log(pc11.green(` + ${name}`));
|
|
4756
4401
|
}
|
|
4757
|
-
await recordSkillInstall(
|
|
4758
|
-
name,
|
|
4759
|
-
`library:${name}`,
|
|
4760
|
-
`library:${name}`,
|
|
4761
|
-
"library",
|
|
4762
|
-
result.linkedAgents,
|
|
4763
|
-
result.canonicalPath,
|
|
4764
|
-
true
|
|
4765
|
-
);
|
|
4766
4402
|
installed.push({
|
|
4767
4403
|
name,
|
|
4768
4404
|
scopedName: `library:${name}`,
|
|
@@ -4823,89 +4459,10 @@ ${pc11.green(`${installed.length} installed`)}, ${failed.length > 0 ? pc11.yello
|
|
|
4823
4459
|
}
|
|
4824
4460
|
}
|
|
4825
4461
|
}
|
|
4826
|
-
async function handleMarketplaceSource(source, _providers, _isGlobal, format, operation, mvi) {
|
|
4827
|
-
if (format === "human") {
|
|
4828
|
-
console.log(pc11.dim(`Searching marketplace for ${source}...`));
|
|
4829
|
-
}
|
|
4830
|
-
const client = new MarketplaceClient();
|
|
4831
|
-
let skill;
|
|
4832
|
-
try {
|
|
4833
|
-
skill = await client.getSkill(source);
|
|
4834
|
-
} catch (error) {
|
|
4835
|
-
const message = `Marketplace lookup failed: ${formatNetworkError(error)}`;
|
|
4836
|
-
if (format === "json") {
|
|
4837
|
-
emitJsonError(operation, mvi, ErrorCodes.NETWORK_ERROR, message, ErrorCategories.TRANSIENT);
|
|
4838
|
-
}
|
|
4839
|
-
console.error(pc11.red(message));
|
|
4840
|
-
return { success: false };
|
|
4841
|
-
}
|
|
4842
|
-
if (!skill) {
|
|
4843
|
-
const message = `Skill not found: ${source}`;
|
|
4844
|
-
if (format === "json") {
|
|
4845
|
-
emitJsonError(operation, mvi, ErrorCodes.SKILL_NOT_FOUND, message, ErrorCategories.NOT_FOUND);
|
|
4846
|
-
}
|
|
4847
|
-
console.error(pc11.red(message));
|
|
4848
|
-
return { success: false };
|
|
4849
|
-
}
|
|
4850
|
-
if (format === "human") {
|
|
4851
|
-
console.log(
|
|
4852
|
-
` Found: ${pc11.bold(skill.name)} by ${skill.author} (${pc11.dim(skill.repoFullName)})`
|
|
4853
|
-
);
|
|
4854
|
-
}
|
|
4855
|
-
const parsed = parseSource(skill.githubUrl);
|
|
4856
|
-
if (parsed.type !== "github" || !parsed.owner || !parsed.repo) {
|
|
4857
|
-
const message = "Could not resolve GitHub source";
|
|
4858
|
-
if (format === "json") {
|
|
4859
|
-
emitJsonError(operation, mvi, ErrorCodes.INVALID_FORMAT, message, ErrorCategories.VALIDATION);
|
|
4860
|
-
}
|
|
4861
|
-
console.error(pc11.red(message));
|
|
4862
|
-
return { success: false };
|
|
4863
|
-
}
|
|
4864
|
-
try {
|
|
4865
|
-
const subPathCandidates = buildSkillSubPathCandidates(skill.path, parsed.path);
|
|
4866
|
-
let cloneError;
|
|
4867
|
-
let cloned = false;
|
|
4868
|
-
let localPath;
|
|
4869
|
-
let cleanup;
|
|
4870
|
-
for (const subPath of subPathCandidates) {
|
|
4871
|
-
try {
|
|
4872
|
-
const result = await cloneRepo(parsed.owner, parsed.repo, parsed.ref, subPath);
|
|
4873
|
-
if (subPath && !existsSync11(result.localPath)) {
|
|
4874
|
-
await result.cleanup();
|
|
4875
|
-
continue;
|
|
4876
|
-
}
|
|
4877
|
-
localPath = result.localPath;
|
|
4878
|
-
cleanup = result.cleanup;
|
|
4879
|
-
cloned = true;
|
|
4880
|
-
break;
|
|
4881
|
-
} catch (error) {
|
|
4882
|
-
cloneError = error;
|
|
4883
|
-
}
|
|
4884
|
-
}
|
|
4885
|
-
if (!cloned) {
|
|
4886
|
-
throw cloneError ?? new Error("Unable to resolve skill path from marketplace metadata");
|
|
4887
|
-
}
|
|
4888
|
-
return {
|
|
4889
|
-
success: true,
|
|
4890
|
-
localPath,
|
|
4891
|
-
cleanup,
|
|
4892
|
-
skillName: skill.name,
|
|
4893
|
-
sourceValue: skill.githubUrl,
|
|
4894
|
-
sourceType: parsed.type
|
|
4895
|
-
};
|
|
4896
|
-
} catch (error) {
|
|
4897
|
-
const message = `Failed to fetch source repository: ${formatNetworkError(error)}`;
|
|
4898
|
-
if (format === "json") {
|
|
4899
|
-
emitJsonError(operation, mvi, ErrorCodes.NETWORK_ERROR, message, ErrorCategories.TRANSIENT);
|
|
4900
|
-
}
|
|
4901
|
-
console.error(pc11.red(message));
|
|
4902
|
-
return { success: false };
|
|
4903
|
-
}
|
|
4904
|
-
}
|
|
4905
4462
|
|
|
4906
4463
|
// src/commands/skills/list.ts
|
|
4907
|
-
import { randomUUID as
|
|
4908
|
-
import { resolveOutputFormat as
|
|
4464
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
4465
|
+
import { resolveOutputFormat as resolveOutputFormat3 } from "@cleocode/lafs";
|
|
4909
4466
|
import pc12 from "picocolors";
|
|
4910
4467
|
function registerSkillsList(parent) {
|
|
4911
4468
|
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 (default)").option("--human", "Output in human-readable format").action(async (opts) => {
|
|
@@ -4913,7 +4470,7 @@ function registerSkillsList(parent) {
|
|
|
4913
4470
|
const mvi = "standard";
|
|
4914
4471
|
let format;
|
|
4915
4472
|
try {
|
|
4916
|
-
format =
|
|
4473
|
+
format = resolveOutputFormat3({
|
|
4917
4474
|
jsonFlag: opts.json ?? false,
|
|
4918
4475
|
humanFlag: (opts.human ?? false) || isHuman(),
|
|
4919
4476
|
projectDefault: "json"
|
|
@@ -4986,7 +4543,7 @@ function buildEnvelope4(operation, mvi, result, error) {
|
|
|
4986
4543
|
schemaVersion: "1.0.0",
|
|
4987
4544
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4988
4545
|
operation,
|
|
4989
|
-
requestId:
|
|
4546
|
+
requestId: randomUUID4(),
|
|
4990
4547
|
transport: "cli",
|
|
4991
4548
|
strict: true,
|
|
4992
4549
|
mvi,
|
|
@@ -5243,12 +4800,14 @@ ${outdated.length} skill(s) have updates available:
|
|
|
5243
4800
|
skipped.push(skill.name);
|
|
5244
4801
|
continue;
|
|
5245
4802
|
}
|
|
5246
|
-
const installResult = await
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
4803
|
+
const installResult = await installResolvedSkill(
|
|
4804
|
+
{
|
|
4805
|
+
localPath,
|
|
4806
|
+
skillName: skill.name,
|
|
4807
|
+
sourceValue: entry.source,
|
|
4808
|
+
sourceType: parsed.type
|
|
4809
|
+
},
|
|
4810
|
+
{ providers, isGlobal: entry.isGlobal, projectDir: entry.projectDir }
|
|
5252
4811
|
);
|
|
5253
4812
|
if (installResult.success) {
|
|
5254
4813
|
await recordSkillInstall(
|
|
@@ -5312,7 +4871,7 @@ ${outdated.length} skill(s) have updates available:
|
|
|
5312
4871
|
}
|
|
5313
4872
|
|
|
5314
4873
|
// src/commands/skills/validate.ts
|
|
5315
|
-
import { resolveOutputFormat as
|
|
4874
|
+
import { resolveOutputFormat as resolveOutputFormat4 } from "@cleocode/lafs";
|
|
5316
4875
|
import pc15 from "picocolors";
|
|
5317
4876
|
function registerSkillsValidate(parent) {
|
|
5318
4877
|
parent.command("validate").description("Validate SKILL.md format").argument("[path]", "Path to SKILL.md", "SKILL.md").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(async (path, opts) => {
|
|
@@ -5320,7 +4879,7 @@ function registerSkillsValidate(parent) {
|
|
|
5320
4879
|
const mvi = "standard";
|
|
5321
4880
|
let format;
|
|
5322
4881
|
try {
|
|
5323
|
-
format =
|
|
4882
|
+
format = resolveOutputFormat4({
|
|
5324
4883
|
jsonFlag: opts.json ?? false,
|
|
5325
4884
|
humanFlag: (opts.human ?? false) || isHuman(),
|
|
5326
4885
|
projectDefault: "json"
|