@cleocode/caamp 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/{chunk-RW745KDU.js → chunk-PCWTRJV2.js} +154 -87
- package/dist/chunk-PCWTRJV2.js.map +1 -0
- package/dist/cli.js +267 -3
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1490 -60
- package/dist/index.js +9 -1
- package/package.json +13 -10
- package/dist/chunk-RW745KDU.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
listMcpServers,
|
|
25
25
|
parseSource,
|
|
26
26
|
readConfig,
|
|
27
|
+
readLockFile,
|
|
27
28
|
recordMcpInstall,
|
|
28
29
|
recordSkillInstall,
|
|
29
30
|
removeMcpFromLock,
|
|
@@ -33,9 +34,11 @@ import {
|
|
|
33
34
|
resolveConfigPath,
|
|
34
35
|
scanDirectory,
|
|
35
36
|
scanFile,
|
|
37
|
+
setQuiet,
|
|
38
|
+
setVerbose,
|
|
36
39
|
toSarif,
|
|
37
40
|
validateSkill
|
|
38
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-PCWTRJV2.js";
|
|
39
42
|
|
|
40
43
|
// src/cli.ts
|
|
41
44
|
import { Command } from "commander";
|
|
@@ -208,7 +211,7 @@ function registerSkillsInstall(parent) {
|
|
|
208
211
|
let cleanup;
|
|
209
212
|
let skillName;
|
|
210
213
|
let sourceValue;
|
|
211
|
-
let sourceType
|
|
214
|
+
let sourceType;
|
|
212
215
|
if (isMarketplaceScoped(source)) {
|
|
213
216
|
console.log(pc2.dim(`Searching marketplace for ${source}...`));
|
|
214
217
|
const client = new MarketplaceClient();
|
|
@@ -228,10 +231,12 @@ function registerSkillsInstall(parent) {
|
|
|
228
231
|
cleanup = result.cleanup;
|
|
229
232
|
skillName = skill.name;
|
|
230
233
|
sourceValue = skill.githubUrl;
|
|
234
|
+
sourceType = parsed.type;
|
|
231
235
|
} else {
|
|
232
236
|
const parsed = parseSource(source);
|
|
233
237
|
skillName = parsed.inferredName;
|
|
234
238
|
sourceValue = parsed.value;
|
|
239
|
+
sourceType = parsed.type;
|
|
235
240
|
if (parsed.type === "github" && parsed.owner && parsed.repo) {
|
|
236
241
|
const result = await cloneRepo(parsed.owner, parsed.repo, parsed.ref, parsed.path);
|
|
237
242
|
localPath = result.localPath;
|
|
@@ -1059,13 +1064,272 @@ ${provider.toolName} config (${configPath}):
|
|
|
1059
1064
|
});
|
|
1060
1065
|
}
|
|
1061
1066
|
|
|
1067
|
+
// src/commands/doctor.ts
|
|
1068
|
+
import pc19 from "picocolors";
|
|
1069
|
+
import { execFileSync } from "child_process";
|
|
1070
|
+
import { existsSync as existsSync5, readdirSync, lstatSync } from "fs";
|
|
1071
|
+
import { homedir } from "os";
|
|
1072
|
+
import { join as join6 } from "path";
|
|
1073
|
+
var CAAMP_VERSION = "0.2.0";
|
|
1074
|
+
function getNodeVersion() {
|
|
1075
|
+
return process.version;
|
|
1076
|
+
}
|
|
1077
|
+
function getNpmVersion() {
|
|
1078
|
+
try {
|
|
1079
|
+
return execFileSync("npm", ["--version"], { stdio: "pipe", encoding: "utf-8" }).trim();
|
|
1080
|
+
} catch {
|
|
1081
|
+
return null;
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
function checkEnvironment() {
|
|
1085
|
+
const checks = [];
|
|
1086
|
+
checks.push({ label: `Node.js ${getNodeVersion()}`, status: "pass" });
|
|
1087
|
+
const npmVersion = getNpmVersion();
|
|
1088
|
+
if (npmVersion) {
|
|
1089
|
+
checks.push({ label: `npm ${npmVersion}`, status: "pass" });
|
|
1090
|
+
} else {
|
|
1091
|
+
checks.push({ label: "npm not found", status: "warn" });
|
|
1092
|
+
}
|
|
1093
|
+
checks.push({ label: `CAAMP v${CAAMP_VERSION}`, status: "pass" });
|
|
1094
|
+
checks.push({ label: `${process.platform} ${process.arch}`, status: "pass" });
|
|
1095
|
+
return { name: "Environment", checks };
|
|
1096
|
+
}
|
|
1097
|
+
function checkRegistry() {
|
|
1098
|
+
const checks = [];
|
|
1099
|
+
try {
|
|
1100
|
+
const providers = getAllProviders();
|
|
1101
|
+
const count = getProviderCount();
|
|
1102
|
+
checks.push({ label: `${count} providers loaded`, status: "pass" });
|
|
1103
|
+
const malformed = [];
|
|
1104
|
+
for (const p of providers) {
|
|
1105
|
+
if (!p.id || !p.toolName || !p.configKey || !p.configFormat) {
|
|
1106
|
+
malformed.push(p.id || "(unknown)");
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
if (malformed.length === 0) {
|
|
1110
|
+
checks.push({ label: "All entries valid", status: "pass" });
|
|
1111
|
+
} else {
|
|
1112
|
+
checks.push({
|
|
1113
|
+
label: `${malformed.length} malformed entries`,
|
|
1114
|
+
status: "fail",
|
|
1115
|
+
detail: malformed.join(", ")
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
} catch (err) {
|
|
1119
|
+
checks.push({
|
|
1120
|
+
label: "Failed to load registry",
|
|
1121
|
+
status: "fail",
|
|
1122
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
1123
|
+
});
|
|
1124
|
+
}
|
|
1125
|
+
return { name: "Registry", checks };
|
|
1126
|
+
}
|
|
1127
|
+
function checkInstalledProviders() {
|
|
1128
|
+
const checks = [];
|
|
1129
|
+
try {
|
|
1130
|
+
const results = detectAllProviders();
|
|
1131
|
+
const installed = results.filter((r) => r.installed);
|
|
1132
|
+
checks.push({ label: `${installed.length} found`, status: "pass" });
|
|
1133
|
+
for (const r of installed) {
|
|
1134
|
+
const methods = r.methods.join(", ");
|
|
1135
|
+
checks.push({ label: `${r.provider.toolName} (${methods})`, status: "pass" });
|
|
1136
|
+
}
|
|
1137
|
+
} catch (err) {
|
|
1138
|
+
checks.push({
|
|
1139
|
+
label: "Detection failed",
|
|
1140
|
+
status: "fail",
|
|
1141
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
1142
|
+
});
|
|
1143
|
+
}
|
|
1144
|
+
return { name: "Installed Providers", checks };
|
|
1145
|
+
}
|
|
1146
|
+
function checkSkillSymlinks() {
|
|
1147
|
+
const checks = [];
|
|
1148
|
+
const canonicalDir = join6(homedir(), ".agents", "skills");
|
|
1149
|
+
if (!existsSync5(canonicalDir)) {
|
|
1150
|
+
checks.push({ label: "0 canonical skills", status: "pass" });
|
|
1151
|
+
checks.push({ label: "No broken symlinks", status: "pass" });
|
|
1152
|
+
return { name: "Skills", checks };
|
|
1153
|
+
}
|
|
1154
|
+
let canonicalCount = 0;
|
|
1155
|
+
try {
|
|
1156
|
+
const entries = readdirSync(canonicalDir);
|
|
1157
|
+
canonicalCount = entries.length;
|
|
1158
|
+
checks.push({ label: `${canonicalCount} canonical skills`, status: "pass" });
|
|
1159
|
+
} catch {
|
|
1160
|
+
checks.push({ label: "Cannot read skills directory", status: "warn" });
|
|
1161
|
+
return { name: "Skills", checks };
|
|
1162
|
+
}
|
|
1163
|
+
const broken = [];
|
|
1164
|
+
const providers = getAllProviders();
|
|
1165
|
+
for (const provider of providers) {
|
|
1166
|
+
const skillDir = provider.pathSkills;
|
|
1167
|
+
if (!existsSync5(skillDir)) continue;
|
|
1168
|
+
try {
|
|
1169
|
+
const entries = readdirSync(skillDir);
|
|
1170
|
+
for (const entry of entries) {
|
|
1171
|
+
const fullPath = join6(skillDir, entry);
|
|
1172
|
+
try {
|
|
1173
|
+
const stat = lstatSync(fullPath);
|
|
1174
|
+
if (stat.isSymbolicLink()) {
|
|
1175
|
+
if (!existsSync5(fullPath)) {
|
|
1176
|
+
broken.push(`${provider.id}/${entry}`);
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
} catch {
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
} catch {
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
if (broken.length === 0) {
|
|
1186
|
+
checks.push({ label: "No broken symlinks", status: "pass" });
|
|
1187
|
+
} else {
|
|
1188
|
+
checks.push({
|
|
1189
|
+
label: `${broken.length} broken symlinks`,
|
|
1190
|
+
status: "warn",
|
|
1191
|
+
detail: broken.join(", ")
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
return { name: "Skills", checks };
|
|
1195
|
+
}
|
|
1196
|
+
async function checkLockFile() {
|
|
1197
|
+
const checks = [];
|
|
1198
|
+
try {
|
|
1199
|
+
const lock = await readLockFile();
|
|
1200
|
+
checks.push({ label: "Lock file valid", status: "pass" });
|
|
1201
|
+
let orphaned = 0;
|
|
1202
|
+
for (const [name, entry] of Object.entries(lock.skills)) {
|
|
1203
|
+
if (entry.canonicalPath && !existsSync5(entry.canonicalPath)) {
|
|
1204
|
+
orphaned++;
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
if (orphaned === 0) {
|
|
1208
|
+
checks.push({ label: `0 orphaned entries`, status: "pass" });
|
|
1209
|
+
} else {
|
|
1210
|
+
checks.push({
|
|
1211
|
+
label: `${orphaned} orphaned skill entries`,
|
|
1212
|
+
status: "warn",
|
|
1213
|
+
detail: "Skills tracked in lock file but missing from disk"
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
} catch (err) {
|
|
1217
|
+
checks.push({
|
|
1218
|
+
label: "Failed to read lock file",
|
|
1219
|
+
status: "fail",
|
|
1220
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1223
|
+
return { name: "Lock File", checks };
|
|
1224
|
+
}
|
|
1225
|
+
async function checkConfigFiles() {
|
|
1226
|
+
const checks = [];
|
|
1227
|
+
const results = detectAllProviders();
|
|
1228
|
+
const installed = results.filter((r) => r.installed);
|
|
1229
|
+
for (const r of installed) {
|
|
1230
|
+
const provider = r.provider;
|
|
1231
|
+
const configPath = provider.configPathGlobal;
|
|
1232
|
+
if (!existsSync5(configPath)) {
|
|
1233
|
+
checks.push({
|
|
1234
|
+
label: `${provider.id}: no config file found`,
|
|
1235
|
+
status: "warn",
|
|
1236
|
+
detail: configPath
|
|
1237
|
+
});
|
|
1238
|
+
continue;
|
|
1239
|
+
}
|
|
1240
|
+
try {
|
|
1241
|
+
await readConfig(configPath, provider.configFormat);
|
|
1242
|
+
const relPath = configPath.replace(homedir(), "~");
|
|
1243
|
+
checks.push({
|
|
1244
|
+
label: `${provider.id}: ${relPath} readable`,
|
|
1245
|
+
status: "pass"
|
|
1246
|
+
});
|
|
1247
|
+
} catch (err) {
|
|
1248
|
+
checks.push({
|
|
1249
|
+
label: `${provider.id}: config parse error`,
|
|
1250
|
+
status: "fail",
|
|
1251
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
if (installed.length === 0) {
|
|
1256
|
+
checks.push({ label: "No installed providers to check", status: "pass" });
|
|
1257
|
+
}
|
|
1258
|
+
return { name: "Config Files", checks };
|
|
1259
|
+
}
|
|
1260
|
+
function formatSection(section) {
|
|
1261
|
+
const lines = [];
|
|
1262
|
+
lines.push(` ${pc19.bold(section.name)}`);
|
|
1263
|
+
for (const check of section.checks) {
|
|
1264
|
+
const icon = check.status === "pass" ? pc19.green("\u2713") : check.status === "warn" ? pc19.yellow("\u26A0") : pc19.red("\u2717");
|
|
1265
|
+
lines.push(` ${icon} ${check.label}`);
|
|
1266
|
+
if (check.detail) {
|
|
1267
|
+
lines.push(` ${pc19.dim(check.detail)}`);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
return lines.join("\n");
|
|
1271
|
+
}
|
|
1272
|
+
function registerDoctorCommand(program2) {
|
|
1273
|
+
program2.command("doctor").description("Diagnose configuration issues and health").option("--json", "Output as JSON").action(async (opts) => {
|
|
1274
|
+
const sections = [];
|
|
1275
|
+
sections.push(checkEnvironment());
|
|
1276
|
+
sections.push(checkRegistry());
|
|
1277
|
+
sections.push(checkInstalledProviders());
|
|
1278
|
+
sections.push(checkSkillSymlinks());
|
|
1279
|
+
sections.push(await checkLockFile());
|
|
1280
|
+
sections.push(await checkConfigFiles());
|
|
1281
|
+
let passed = 0;
|
|
1282
|
+
let warnings = 0;
|
|
1283
|
+
let errors = 0;
|
|
1284
|
+
for (const section of sections) {
|
|
1285
|
+
for (const check of section.checks) {
|
|
1286
|
+
if (check.status === "pass") passed++;
|
|
1287
|
+
else if (check.status === "warn") warnings++;
|
|
1288
|
+
else errors++;
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
if (opts.json) {
|
|
1292
|
+
const output = {
|
|
1293
|
+
version: CAAMP_VERSION,
|
|
1294
|
+
sections: sections.map((s) => ({
|
|
1295
|
+
name: s.name,
|
|
1296
|
+
checks: s.checks
|
|
1297
|
+
})),
|
|
1298
|
+
summary: { passed, warnings, errors }
|
|
1299
|
+
};
|
|
1300
|
+
console.log(JSON.stringify(output, null, 2));
|
|
1301
|
+
return;
|
|
1302
|
+
}
|
|
1303
|
+
console.log(pc19.bold("\ncaamp doctor\n"));
|
|
1304
|
+
for (const section of sections) {
|
|
1305
|
+
console.log(formatSection(section));
|
|
1306
|
+
console.log();
|
|
1307
|
+
}
|
|
1308
|
+
const parts = [];
|
|
1309
|
+
parts.push(pc19.green(`${passed} checks passed`));
|
|
1310
|
+
if (warnings > 0) parts.push(pc19.yellow(`${warnings} warning${warnings !== 1 ? "s" : ""}`));
|
|
1311
|
+
if (errors > 0) parts.push(pc19.red(`${errors} error${errors !== 1 ? "s" : ""}`));
|
|
1312
|
+
console.log(` ${pc19.bold("Summary")}: ${parts.join(", ")}`);
|
|
1313
|
+
console.log();
|
|
1314
|
+
if (errors > 0) {
|
|
1315
|
+
process.exit(1);
|
|
1316
|
+
}
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1062
1320
|
// src/cli.ts
|
|
1063
1321
|
var program = new Command();
|
|
1064
|
-
program.name("caamp").description("Central AI Agent Managed Packages - unified provider registry and package manager").version("0.
|
|
1322
|
+
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");
|
|
1323
|
+
program.hook("preAction", (thisCommand) => {
|
|
1324
|
+
const opts = thisCommand.optsWithGlobals();
|
|
1325
|
+
if (opts.verbose) setVerbose(true);
|
|
1326
|
+
if (opts.quiet) setQuiet(true);
|
|
1327
|
+
});
|
|
1065
1328
|
registerProvidersCommand(program);
|
|
1066
1329
|
registerSkillsCommands(program);
|
|
1067
1330
|
registerMcpCommands(program);
|
|
1068
1331
|
registerInstructionsCommands(program);
|
|
1069
1332
|
registerConfigCommand(program);
|
|
1333
|
+
registerDoctorCommand(program);
|
|
1070
1334
|
program.parse();
|
|
1071
1335
|
//# sourceMappingURL=cli.js.map
|