@cleocode/caamp 2026.5.83 → 2026.5.86
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-OCI4RYI5.js → chunk-H5YXR2DC.js} +31 -2
- package/dist/chunk-H5YXR2DC.js.map +1 -0
- package/dist/{chunk-OPUPNLUJ.js → chunk-PGETUTYZ.js} +2 -2
- package/dist/{chunk-SV33CE5X.js → chunk-QKC2JRSG.js} +2 -2
- package/dist/{chunk-4W35AEYA.js → chunk-WXL7RPS4.js} +865 -75
- package/dist/chunk-WXL7RPS4.js.map +1 -0
- package/dist/cli.js +614 -245
- package/dist/cli.js.map +1 -1
- package/dist/{hooks-5EXBKPII.js → hooks-ZN3C4WCK.js} +3 -3
- package/dist/index.d.ts +731 -10
- package/dist/index.js +29 -5
- package/dist/index.js.map +1 -1
- package/dist/{injector-F4EHB3CZ.js → injector-QPOIJVOR.js} +3 -3
- package/package.json +5 -5
- package/dist/chunk-4W35AEYA.js.map +0 -1
- package/dist/chunk-OCI4RYI5.js.map +0 -1
- /package/dist/{chunk-OPUPNLUJ.js.map → chunk-PGETUTYZ.js.map} +0 -0
- /package/dist/{chunk-SV33CE5X.js.map → chunk-QKC2JRSG.js.map} +0 -0
- /package/dist/{hooks-5EXBKPII.js.map → hooks-ZN3C4WCK.js.map} +0 -0
- /package/dist/{injector-F4EHB3CZ.js.map → injector-QPOIJVOR.js.map} +0 -0
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
getPrimaryProvider,
|
|
4
4
|
groupByInstructFile,
|
|
5
5
|
injectAll
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-PGETUTYZ.js";
|
|
7
7
|
import {
|
|
8
8
|
__export,
|
|
9
9
|
getAgentsConfigPath,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
resolveProviderConfigPath,
|
|
17
17
|
resolveProviderProjectPath,
|
|
18
18
|
resolveProviderSkillsDirs
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-H5YXR2DC.js";
|
|
20
20
|
|
|
21
21
|
// src/core/logger.ts
|
|
22
22
|
var verboseMode = false;
|
|
@@ -247,10 +247,28 @@ async function linkToAgent(canonicalPath, provider, skillName, isGlobal, project
|
|
|
247
247
|
error: errors.join("; ") || `Provider ${provider.id} has no skills directory`
|
|
248
248
|
};
|
|
249
249
|
}
|
|
250
|
-
|
|
250
|
+
function inferSkillSourceType(sourceUrl) {
|
|
251
|
+
if (!sourceUrl) return "user";
|
|
252
|
+
if (sourceUrl.startsWith("library:")) return "canonical";
|
|
253
|
+
if (sourceUrl.startsWith("@") || sourceUrl.includes("github.com") || sourceUrl.includes("gitlab.com") || sourceUrl.includes("://")) {
|
|
254
|
+
return "community";
|
|
255
|
+
}
|
|
256
|
+
return "user";
|
|
257
|
+
}
|
|
258
|
+
async function installSkill(sourcePath, skillName, providers, isGlobal, projectDir, options) {
|
|
251
259
|
const errors = [];
|
|
252
260
|
const linkedAgents = [];
|
|
253
261
|
const canonicalPath = await installToCanonical(sourcePath, skillName);
|
|
262
|
+
if (options?.recordRow) {
|
|
263
|
+
const resolvedSourceUrl = options.sourceUrl ?? sourcePath;
|
|
264
|
+
const resolvedSourceType = options.sourceType ?? inferSkillSourceType(resolvedSourceUrl);
|
|
265
|
+
await options.recordRow({
|
|
266
|
+
name: skillName,
|
|
267
|
+
installPath: canonicalPath,
|
|
268
|
+
sourceUrl: resolvedSourceUrl,
|
|
269
|
+
sourceType: resolvedSourceType
|
|
270
|
+
});
|
|
271
|
+
}
|
|
254
272
|
for (const provider of providers) {
|
|
255
273
|
const result = await linkToAgent(canonicalPath, provider, skillName, isGlobal, projectDir);
|
|
256
274
|
if (result.success) {
|
|
@@ -302,8 +320,8 @@ async function removeSkill(skillName, providers, isGlobal, projectDir) {
|
|
|
302
320
|
}
|
|
303
321
|
async function listCanonicalSkills() {
|
|
304
322
|
if (!existsSync2(getCanonicalSkillsDir())) return [];
|
|
305
|
-
const { readdir:
|
|
306
|
-
const entries = await
|
|
323
|
+
const { readdir: readdir4 } = await import("fs/promises");
|
|
324
|
+
const entries = await readdir4(getCanonicalSkillsDir(), { withFileTypes: true });
|
|
307
325
|
return entries.filter((e) => e.isDirectory() || e.isSymbolicLink()).map((e) => e.name);
|
|
308
326
|
}
|
|
309
327
|
|
|
@@ -1088,7 +1106,7 @@ ${MARKER_END}`;
|
|
|
1088
1106
|
task.signal.addEventListener("abort", onAbort, { once: true });
|
|
1089
1107
|
}
|
|
1090
1108
|
}
|
|
1091
|
-
const exitPromise = new Promise((
|
|
1109
|
+
const exitPromise = new Promise((resolve2) => {
|
|
1092
1110
|
child.on("close", (exitCode, signal) => {
|
|
1093
1111
|
flushStdoutBuffer(true);
|
|
1094
1112
|
flushStderrBuffer(true);
|
|
@@ -1110,7 +1128,7 @@ ${MARKER_END}`;
|
|
|
1110
1128
|
};
|
|
1111
1129
|
Promise.allSettled(pendingWrites).then(() => {
|
|
1112
1130
|
safeOnStream({ kind: "exit", subagentId, payload: result2 });
|
|
1113
|
-
|
|
1131
|
+
resolve2(result2);
|
|
1114
1132
|
});
|
|
1115
1133
|
});
|
|
1116
1134
|
child.on("error", () => {
|
|
@@ -1839,11 +1857,11 @@ async function terminateSubagent(child, graceMs) {
|
|
|
1839
1857
|
}
|
|
1840
1858
|
const pollInterval = Math.min(25, Math.max(1, graceMs));
|
|
1841
1859
|
const deadline = Date.now() + graceMs;
|
|
1842
|
-
await new Promise((
|
|
1860
|
+
await new Promise((resolve2) => {
|
|
1843
1861
|
const timer = setInterval(() => {
|
|
1844
1862
|
if (child.exitCode !== null || child.signalCode !== null) {
|
|
1845
1863
|
clearInterval(timer);
|
|
1846
|
-
|
|
1864
|
+
resolve2();
|
|
1847
1865
|
return;
|
|
1848
1866
|
}
|
|
1849
1867
|
if (Date.now() >= deadline) {
|
|
@@ -1852,12 +1870,12 @@ async function terminateSubagent(child, graceMs) {
|
|
|
1852
1870
|
child.kill("SIGKILL");
|
|
1853
1871
|
} catch {
|
|
1854
1872
|
}
|
|
1855
|
-
|
|
1873
|
+
resolve2();
|
|
1856
1874
|
}
|
|
1857
1875
|
}, pollInterval);
|
|
1858
1876
|
child.once("close", () => {
|
|
1859
1877
|
clearInterval(timer);
|
|
1860
|
-
|
|
1878
|
+
resolve2();
|
|
1861
1879
|
});
|
|
1862
1880
|
});
|
|
1863
1881
|
}
|
|
@@ -2207,9 +2225,9 @@ function getNestedValue(obj, keyPath) {
|
|
|
2207
2225
|
return current;
|
|
2208
2226
|
}
|
|
2209
2227
|
async function ensureDir(filePath) {
|
|
2210
|
-
const { mkdir:
|
|
2211
|
-
const { dirname:
|
|
2212
|
-
await
|
|
2228
|
+
const { mkdir: mkdir6 } = await import("fs/promises");
|
|
2229
|
+
const { dirname: dirname5 } = await import("path");
|
|
2230
|
+
await mkdir6(dirname5(filePath), { recursive: true });
|
|
2213
2231
|
}
|
|
2214
2232
|
|
|
2215
2233
|
// src/core/formats/json.ts
|
|
@@ -2654,11 +2672,11 @@ function parseSource(input) {
|
|
|
2654
2672
|
if (ghUrlMatch) {
|
|
2655
2673
|
const owner = ghUrlMatch[1];
|
|
2656
2674
|
const repo = ghUrlMatch[2];
|
|
2657
|
-
const
|
|
2675
|
+
const path2 = ghUrlMatch[4];
|
|
2658
2676
|
if (!owner || !repo) {
|
|
2659
2677
|
return { type: "command", value: input, inferredName: inferName(input, "command") };
|
|
2660
2678
|
}
|
|
2661
|
-
const inferredName =
|
|
2679
|
+
const inferredName = path2 ? path2.split("/").pop() ?? repo : repo;
|
|
2662
2680
|
return {
|
|
2663
2681
|
type: "github",
|
|
2664
2682
|
value: input,
|
|
@@ -2666,18 +2684,18 @@ function parseSource(input) {
|
|
|
2666
2684
|
owner,
|
|
2667
2685
|
repo,
|
|
2668
2686
|
ref: ghUrlMatch[3],
|
|
2669
|
-
path
|
|
2687
|
+
path: path2
|
|
2670
2688
|
};
|
|
2671
2689
|
}
|
|
2672
2690
|
const glUrlMatch = input.match(GITLAB_URL);
|
|
2673
2691
|
if (glUrlMatch) {
|
|
2674
2692
|
const owner = glUrlMatch[1];
|
|
2675
2693
|
const repo = glUrlMatch[2];
|
|
2676
|
-
const
|
|
2694
|
+
const path2 = glUrlMatch[4];
|
|
2677
2695
|
if (!owner || !repo) {
|
|
2678
2696
|
return { type: "command", value: input, inferredName: inferName(input, "command") };
|
|
2679
2697
|
}
|
|
2680
|
-
const inferredName =
|
|
2698
|
+
const inferredName = path2 ? path2.split("/").pop() ?? repo : repo;
|
|
2681
2699
|
return {
|
|
2682
2700
|
type: "gitlab",
|
|
2683
2701
|
value: input,
|
|
@@ -2685,7 +2703,7 @@ function parseSource(input) {
|
|
|
2685
2703
|
owner,
|
|
2686
2704
|
repo,
|
|
2687
2705
|
ref: glUrlMatch[3],
|
|
2688
|
-
path
|
|
2706
|
+
path: path2
|
|
2689
2707
|
};
|
|
2690
2708
|
}
|
|
2691
2709
|
if (HTTP_URL.test(input)) {
|
|
@@ -2706,18 +2724,18 @@ function parseSource(input) {
|
|
|
2706
2724
|
if (ghShorthand && !NPM_SCOPED.test(input)) {
|
|
2707
2725
|
const owner = ghShorthand[1];
|
|
2708
2726
|
const repo = ghShorthand[2];
|
|
2709
|
-
const
|
|
2727
|
+
const path2 = ghShorthand[3];
|
|
2710
2728
|
if (!owner || !repo) {
|
|
2711
2729
|
return { type: "command", value: input, inferredName: inferName(input, "command") };
|
|
2712
2730
|
}
|
|
2713
|
-
const inferredName =
|
|
2731
|
+
const inferredName = path2 ? path2.split("/").pop() ?? repo : repo;
|
|
2714
2732
|
return {
|
|
2715
2733
|
type: "github",
|
|
2716
2734
|
value: `https://github.com/${owner}/${repo}`,
|
|
2717
2735
|
inferredName,
|
|
2718
2736
|
owner,
|
|
2719
2737
|
repo,
|
|
2720
|
-
path
|
|
2738
|
+
path: path2
|
|
2721
2739
|
};
|
|
2722
2740
|
}
|
|
2723
2741
|
const libraryMatch = input.match(LIBRARY_SKILL);
|
|
@@ -3163,14 +3181,14 @@ async function scanFile(filePath, rules) {
|
|
|
3163
3181
|
return { file: filePath, findings, score, passed };
|
|
3164
3182
|
}
|
|
3165
3183
|
async function scanDirectory(dirPath) {
|
|
3166
|
-
const { readdir:
|
|
3167
|
-
const { join:
|
|
3184
|
+
const { readdir: readdir4 } = await import("fs/promises");
|
|
3185
|
+
const { join: join11 } = await import("path");
|
|
3168
3186
|
if (!existsSync10(dirPath)) return [];
|
|
3169
|
-
const entries = await
|
|
3187
|
+
const entries = await readdir4(dirPath, { withFileTypes: true });
|
|
3170
3188
|
const results = [];
|
|
3171
3189
|
for (const entry of entries) {
|
|
3172
3190
|
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
3173
|
-
const skillFile =
|
|
3191
|
+
const skillFile = join11(dirPath, entry.name, "SKILL.md");
|
|
3174
3192
|
if (existsSync10(skillFile)) {
|
|
3175
3193
|
results.push(await scanFile(skillFile));
|
|
3176
3194
|
}
|
|
@@ -3233,7 +3251,7 @@ import { mkdir as mkdir4, open as open2, readFile as readFile6, rename as rename
|
|
|
3233
3251
|
var LOCK_GUARD_PATH = `${LOCK_FILE_PATH}.lock`;
|
|
3234
3252
|
var STALE_LOCK_MS = 5e3;
|
|
3235
3253
|
function sleep(ms) {
|
|
3236
|
-
return new Promise((
|
|
3254
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
3237
3255
|
}
|
|
3238
3256
|
async function removeStaleLock() {
|
|
3239
3257
|
try {
|
|
@@ -3431,6 +3449,759 @@ async function checkAllSkillUpdates() {
|
|
|
3431
3449
|
return results;
|
|
3432
3450
|
}
|
|
3433
3451
|
|
|
3452
|
+
// src/commands/skills/doctor-bridge.ts
|
|
3453
|
+
import { existsSync as existsSync12, lstatSync as lstatSync3, readdirSync, readlinkSync, realpathSync } from "fs";
|
|
3454
|
+
import { cp as cp4, mkdir as mkdir5, readdir as readdir2, rm as rm5, symlink as symlink3, unlink } from "fs/promises";
|
|
3455
|
+
import { homedir as homedir3 } from "os";
|
|
3456
|
+
import * as path from "path";
|
|
3457
|
+
import pc from "picocolors";
|
|
3458
|
+
|
|
3459
|
+
// src/core/lafs.ts
|
|
3460
|
+
import { randomUUID } from "crypto";
|
|
3461
|
+
import { resolveOutputFormat } from "@cleocode/lafs";
|
|
3462
|
+
function resolveFormat(options) {
|
|
3463
|
+
return resolveOutputFormat({
|
|
3464
|
+
jsonFlag: options.jsonFlag ?? false,
|
|
3465
|
+
humanFlag: (options.humanFlag ?? false) || isHuman(),
|
|
3466
|
+
projectDefault: options.projectDefault ?? "json"
|
|
3467
|
+
}).format;
|
|
3468
|
+
}
|
|
3469
|
+
function buildEnvelope(operation, mvi, result, error, page = null, sessionId, warnings) {
|
|
3470
|
+
return {
|
|
3471
|
+
$schema: "https://lafs.dev/schemas/v1/envelope.schema.json",
|
|
3472
|
+
_meta: {
|
|
3473
|
+
specVersion: "1.0.0",
|
|
3474
|
+
schemaVersion: "1.0.0",
|
|
3475
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3476
|
+
operation,
|
|
3477
|
+
requestId: randomUUID(),
|
|
3478
|
+
transport: "cli",
|
|
3479
|
+
strict: true,
|
|
3480
|
+
mvi,
|
|
3481
|
+
contextVersion: 0,
|
|
3482
|
+
...sessionId && { sessionId },
|
|
3483
|
+
...warnings && warnings.length > 0 && { warnings }
|
|
3484
|
+
},
|
|
3485
|
+
success: error === null,
|
|
3486
|
+
result,
|
|
3487
|
+
error,
|
|
3488
|
+
page
|
|
3489
|
+
};
|
|
3490
|
+
}
|
|
3491
|
+
function emitError(operation, mvi, code, message, category, details = {}, exitCode = 1) {
|
|
3492
|
+
const envelope = buildEnvelope(operation, mvi, null, {
|
|
3493
|
+
code,
|
|
3494
|
+
message,
|
|
3495
|
+
category,
|
|
3496
|
+
retryable: category === "TRANSIENT" || category === "RATE_LIMIT",
|
|
3497
|
+
retryAfterMs: null,
|
|
3498
|
+
details
|
|
3499
|
+
});
|
|
3500
|
+
console.error(JSON.stringify(envelope, null, 2));
|
|
3501
|
+
process.exit(exitCode);
|
|
3502
|
+
}
|
|
3503
|
+
function emitJsonError(operation, mvi, code, message, category, details = {}) {
|
|
3504
|
+
const envelope = buildEnvelope(operation, mvi, null, {
|
|
3505
|
+
code,
|
|
3506
|
+
message,
|
|
3507
|
+
category,
|
|
3508
|
+
retryable: category === "TRANSIENT" || category === "RATE_LIMIT",
|
|
3509
|
+
retryAfterMs: null,
|
|
3510
|
+
details
|
|
3511
|
+
});
|
|
3512
|
+
console.error(JSON.stringify(envelope, null, 2));
|
|
3513
|
+
}
|
|
3514
|
+
function outputSuccess(operation, mvi, result, page, sessionId, warnings) {
|
|
3515
|
+
const envelope = buildEnvelope(operation, mvi, result, null, page ?? null, sessionId, warnings);
|
|
3516
|
+
if (isQuiet() && !envelope.error) {
|
|
3517
|
+
return;
|
|
3518
|
+
}
|
|
3519
|
+
console.log(JSON.stringify(envelope, null, 2));
|
|
3520
|
+
}
|
|
3521
|
+
function handleFormatError(error, operation, mvi, jsonFlag) {
|
|
3522
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3523
|
+
if (jsonFlag) {
|
|
3524
|
+
emitJsonError(operation, mvi, "E_FORMAT_CONFLICT", message, "VALIDATION");
|
|
3525
|
+
} else {
|
|
3526
|
+
console.error(message);
|
|
3527
|
+
}
|
|
3528
|
+
process.exit(1);
|
|
3529
|
+
}
|
|
3530
|
+
var ErrorCategories = {
|
|
3531
|
+
VALIDATION: "VALIDATION",
|
|
3532
|
+
AUTH: "AUTH",
|
|
3533
|
+
PERMISSION: "PERMISSION",
|
|
3534
|
+
NOT_FOUND: "NOT_FOUND",
|
|
3535
|
+
CONFLICT: "CONFLICT",
|
|
3536
|
+
RATE_LIMIT: "RATE_LIMIT",
|
|
3537
|
+
TRANSIENT: "TRANSIENT",
|
|
3538
|
+
INTERNAL: "INTERNAL",
|
|
3539
|
+
CONTRACT: "CONTRACT",
|
|
3540
|
+
MIGRATION: "MIGRATION"
|
|
3541
|
+
};
|
|
3542
|
+
var ErrorCodes = {
|
|
3543
|
+
// Format errors
|
|
3544
|
+
FORMAT_CONFLICT: "E_FORMAT_CONFLICT",
|
|
3545
|
+
INVALID_JSON: "E_INVALID_JSON",
|
|
3546
|
+
// Not found errors
|
|
3547
|
+
SKILL_NOT_FOUND: "E_SKILL_NOT_FOUND",
|
|
3548
|
+
PROVIDER_NOT_FOUND: "E_PROVIDER_NOT_FOUND",
|
|
3549
|
+
MCP_SERVER_NOT_FOUND: "E_MCP_SERVER_NOT_FOUND",
|
|
3550
|
+
FILE_NOT_FOUND: "E_FILE_NOT_FOUND",
|
|
3551
|
+
// Validation errors
|
|
3552
|
+
INVALID_INPUT: "E_INVALID_INPUT",
|
|
3553
|
+
INVALID_CONSTRAINT: "E_INVALID_CONSTRAINT",
|
|
3554
|
+
INVALID_FORMAT: "E_INVALID_FORMAT",
|
|
3555
|
+
// Operation errors
|
|
3556
|
+
INSTALL_FAILED: "E_INSTALL_FAILED",
|
|
3557
|
+
// Skills federation gates (T9564 — Sphere B)
|
|
3558
|
+
SKILL_TRUST_GATE_BLOCKED: "E_SKILL_TRUST_GATE_BLOCKED",
|
|
3559
|
+
FEDERATION_UNKNOWN_SOURCE_INTERACTIVE_REQUIRED: "E_FEDERATION_UNKNOWN_SOURCE_INTERACTIVE_REQUIRED",
|
|
3560
|
+
FEDERATION_CHECKSUM_MISMATCH: "E_FEDERATION_CHECKSUM_MISMATCH",
|
|
3561
|
+
REMOVE_FAILED: "E_REMOVE_FAILED",
|
|
3562
|
+
UPDATE_FAILED: "E_UPDATE_FAILED",
|
|
3563
|
+
VALIDATION_FAILED: "E_VALIDATION_FAILED",
|
|
3564
|
+
AUDIT_FAILED: "E_AUDIT_FAILED",
|
|
3565
|
+
// System errors
|
|
3566
|
+
NETWORK_ERROR: "E_NETWORK_ERROR",
|
|
3567
|
+
FILE_SYSTEM_ERROR: "E_FILE_SYSTEM_ERROR",
|
|
3568
|
+
PERMISSION_DENIED: "E_PERMISSION_DENIED",
|
|
3569
|
+
INTERNAL_ERROR: "E_INTERNAL_ERROR"
|
|
3570
|
+
};
|
|
3571
|
+
|
|
3572
|
+
// src/commands/skills/doctor-bridge.ts
|
|
3573
|
+
var AgentsSkillsRealDirError = class extends Error {
|
|
3574
|
+
/** LAFS error code surfaced by the CLI. */
|
|
3575
|
+
code = "E_AGENTS_SKILLS_REAL_DIR";
|
|
3576
|
+
/** Resolved path of the offending real directory. */
|
|
3577
|
+
agentsSkillsPath;
|
|
3578
|
+
/** Number of immediate entries in the offending directory. */
|
|
3579
|
+
entryCount;
|
|
3580
|
+
/**
|
|
3581
|
+
* Construct an `AgentsSkillsRealDirError`.
|
|
3582
|
+
*
|
|
3583
|
+
* @param agentsSkillsPath - Path to the real `~/.agents/skills` directory.
|
|
3584
|
+
* @param entryCount - Number of entries inside the directory.
|
|
3585
|
+
*/
|
|
3586
|
+
constructor(agentsSkillsPath, entryCount) {
|
|
3587
|
+
super(
|
|
3588
|
+
`Refusing to replace real directory at ${agentsSkillsPath} (${entryCount} entries). Pass --force to back up and bridge.`
|
|
3589
|
+
);
|
|
3590
|
+
this.name = "AgentsSkillsRealDirError";
|
|
3591
|
+
this.agentsSkillsPath = agentsSkillsPath;
|
|
3592
|
+
this.entryCount = entryCount;
|
|
3593
|
+
}
|
|
3594
|
+
};
|
|
3595
|
+
function buildBackupTimestamp() {
|
|
3596
|
+
const d = /* @__PURE__ */ new Date();
|
|
3597
|
+
const pad = (n) => n.toString().padStart(2, "0");
|
|
3598
|
+
return `${d.getUTCFullYear()}${pad(d.getUTCMonth() + 1)}${pad(d.getUTCDate())}-${pad(d.getUTCHours())}${pad(d.getUTCMinutes())}${pad(d.getUTCSeconds())}`;
|
|
3599
|
+
}
|
|
3600
|
+
function resolveBridgePaths(homeRoot) {
|
|
3601
|
+
return {
|
|
3602
|
+
skillsRoot: path.join(homeRoot, ".cleo", "skills"),
|
|
3603
|
+
bridgeTarget: path.join(homeRoot, ".claude", "skills", "agents-shared"),
|
|
3604
|
+
bridgePath: path.join(homeRoot, ".agents", "skills"),
|
|
3605
|
+
backupsRoot: path.join(homeRoot, ".cleo", "backups"),
|
|
3606
|
+
claudeSkillsRoot: path.join(homeRoot, ".claude", "skills")
|
|
3607
|
+
};
|
|
3608
|
+
}
|
|
3609
|
+
function listSkillDirs(skillsRoot) {
|
|
3610
|
+
if (!existsSync12(skillsRoot)) return [];
|
|
3611
|
+
const entries = readdirSync(skillsRoot, { withFileTypes: true });
|
|
3612
|
+
return entries.filter((e) => e.isDirectory() || e.isSymbolicLink()).map((e) => e.name).filter((n) => !n.startsWith(".")).sort();
|
|
3613
|
+
}
|
|
3614
|
+
function symlinkPointsAt(linkPath, target) {
|
|
3615
|
+
try {
|
|
3616
|
+
const stat4 = lstatSync3(linkPath);
|
|
3617
|
+
if (!stat4.isSymbolicLink()) return false;
|
|
3618
|
+
const current = readlinkSync(linkPath);
|
|
3619
|
+
const resolved = path.isAbsolute(current) ? current : path.resolve(path.dirname(linkPath), current);
|
|
3620
|
+
return path.resolve(resolved) === path.resolve(target);
|
|
3621
|
+
} catch {
|
|
3622
|
+
return false;
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3625
|
+
async function ensureSymlink(linkPath, target, dryRun) {
|
|
3626
|
+
if (dryRun) return;
|
|
3627
|
+
await mkdir5(path.dirname(linkPath), { recursive: true });
|
|
3628
|
+
if (existsSync12(linkPath)) {
|
|
3629
|
+
try {
|
|
3630
|
+
await unlink(linkPath);
|
|
3631
|
+
} catch {
|
|
3632
|
+
}
|
|
3633
|
+
}
|
|
3634
|
+
await symlink3(target, linkPath, "dir");
|
|
3635
|
+
}
|
|
3636
|
+
async function countEntries(dir) {
|
|
3637
|
+
try {
|
|
3638
|
+
const entries = await readdir2(dir);
|
|
3639
|
+
return entries.length;
|
|
3640
|
+
} catch {
|
|
3641
|
+
return 0;
|
|
3642
|
+
}
|
|
3643
|
+
}
|
|
3644
|
+
async function runDoctorBridge(options = {}) {
|
|
3645
|
+
const homeRoot = options.homeDir ?? homedir3();
|
|
3646
|
+
const force = options.force ?? false;
|
|
3647
|
+
const dryRun = options.dryRun ?? false;
|
|
3648
|
+
const { skillsRoot, bridgeTarget, bridgePath, backupsRoot, claudeSkillsRoot } = resolveBridgePaths(homeRoot);
|
|
3649
|
+
if (!dryRun) {
|
|
3650
|
+
await mkdir5(bridgeTarget, { recursive: true });
|
|
3651
|
+
}
|
|
3652
|
+
const skillNames = listSkillDirs(skillsRoot);
|
|
3653
|
+
const created = [];
|
|
3654
|
+
for (const name of skillNames) {
|
|
3655
|
+
const linkPath = path.join(bridgeTarget, name);
|
|
3656
|
+
const target = path.join(skillsRoot, name);
|
|
3657
|
+
if (symlinkPointsAt(linkPath, target)) continue;
|
|
3658
|
+
await ensureSymlink(linkPath, target, dryRun);
|
|
3659
|
+
created.push({ name, linkPath, target });
|
|
3660
|
+
}
|
|
3661
|
+
const removed = [];
|
|
3662
|
+
if (existsSync12(claudeSkillsRoot)) {
|
|
3663
|
+
const entries = readdirSync(claudeSkillsRoot, { withFileTypes: true });
|
|
3664
|
+
for (const entry of entries) {
|
|
3665
|
+
if (entry.name === "agents-shared") continue;
|
|
3666
|
+
const entryPath = path.join(claudeSkillsRoot, entry.name);
|
|
3667
|
+
let stat4;
|
|
3668
|
+
try {
|
|
3669
|
+
stat4 = lstatSync3(entryPath);
|
|
3670
|
+
} catch {
|
|
3671
|
+
continue;
|
|
3672
|
+
}
|
|
3673
|
+
if (!stat4.isSymbolicLink()) continue;
|
|
3674
|
+
let resolvedTarget = null;
|
|
3675
|
+
try {
|
|
3676
|
+
const raw = readlinkSync(entryPath);
|
|
3677
|
+
resolvedTarget = path.isAbsolute(raw) ? raw : path.resolve(path.dirname(entryPath), raw);
|
|
3678
|
+
} catch {
|
|
3679
|
+
resolvedTarget = null;
|
|
3680
|
+
}
|
|
3681
|
+
if (resolvedTarget !== null) {
|
|
3682
|
+
const realResolved = (() => {
|
|
3683
|
+
try {
|
|
3684
|
+
return realpathSync(resolvedTarget);
|
|
3685
|
+
} catch {
|
|
3686
|
+
return resolvedTarget;
|
|
3687
|
+
}
|
|
3688
|
+
})();
|
|
3689
|
+
if (realResolved === bridgeTarget || realResolved.startsWith(`${bridgeTarget}${path.sep}`)) {
|
|
3690
|
+
continue;
|
|
3691
|
+
}
|
|
3692
|
+
}
|
|
3693
|
+
if (!dryRun) {
|
|
3694
|
+
await unlink(entryPath);
|
|
3695
|
+
}
|
|
3696
|
+
removed.push({ linkPath: entryPath, previousTarget: resolvedTarget });
|
|
3697
|
+
}
|
|
3698
|
+
}
|
|
3699
|
+
let backupPath = null;
|
|
3700
|
+
const bridgeAlreadyCorrect = symlinkPointsAt(bridgePath, bridgeTarget);
|
|
3701
|
+
let bridgeSymlinkActive = bridgeAlreadyCorrect;
|
|
3702
|
+
if (!bridgeAlreadyCorrect) {
|
|
3703
|
+
if (existsSync12(bridgePath)) {
|
|
3704
|
+
const lstat = lstatSync3(bridgePath);
|
|
3705
|
+
if (lstat.isSymbolicLink()) {
|
|
3706
|
+
if (!dryRun) await unlink(bridgePath);
|
|
3707
|
+
} else if (lstat.isDirectory()) {
|
|
3708
|
+
const entryCount = await countEntries(bridgePath);
|
|
3709
|
+
if (entryCount > 0 && !force) {
|
|
3710
|
+
throw new AgentsSkillsRealDirError(bridgePath, entryCount);
|
|
3711
|
+
}
|
|
3712
|
+
if (entryCount > 0) {
|
|
3713
|
+
backupPath = path.join(backupsRoot, `agents-skills-pre-bridge-${buildBackupTimestamp()}`);
|
|
3714
|
+
if (!dryRun) {
|
|
3715
|
+
await mkdir5(backupsRoot, { recursive: true });
|
|
3716
|
+
await cp4(bridgePath, backupPath, { recursive: true, dereference: false });
|
|
3717
|
+
await rm5(bridgePath, { recursive: true, force: true });
|
|
3718
|
+
}
|
|
3719
|
+
} else if (!dryRun) {
|
|
3720
|
+
await rm5(bridgePath, { recursive: true, force: true });
|
|
3721
|
+
}
|
|
3722
|
+
} else if (!dryRun) {
|
|
3723
|
+
await unlink(bridgePath);
|
|
3724
|
+
}
|
|
3725
|
+
}
|
|
3726
|
+
if (!dryRun) {
|
|
3727
|
+
await mkdir5(path.dirname(bridgePath), { recursive: true });
|
|
3728
|
+
await symlink3(bridgeTarget, bridgePath, "dir");
|
|
3729
|
+
bridgeSymlinkActive = true;
|
|
3730
|
+
}
|
|
3731
|
+
}
|
|
3732
|
+
return {
|
|
3733
|
+
bridgeCreated: !bridgeAlreadyCorrect,
|
|
3734
|
+
bridgeSymlinkActive,
|
|
3735
|
+
perSkillSymlinksCreated: created,
|
|
3736
|
+
perSkillSymlinksRemoved: removed,
|
|
3737
|
+
backupPath,
|
|
3738
|
+
dryRun,
|
|
3739
|
+
skillsRoot,
|
|
3740
|
+
bridgeTarget,
|
|
3741
|
+
bridgePath
|
|
3742
|
+
};
|
|
3743
|
+
}
|
|
3744
|
+
function printHumanSummary(result) {
|
|
3745
|
+
if (result.dryRun) {
|
|
3746
|
+
console.log(pc.dim("(dry-run \u2014 no disk state mutated)"));
|
|
3747
|
+
}
|
|
3748
|
+
if (!result.bridgeCreated && result.perSkillSymlinksCreated.length === 0) {
|
|
3749
|
+
console.log(pc.green("Bridge already correct \u2014 nothing to do."));
|
|
3750
|
+
} else {
|
|
3751
|
+
console.log(pc.green("Bridge configured."));
|
|
3752
|
+
}
|
|
3753
|
+
console.log(` ${pc.dim("bridge:")} ${result.bridgePath} -> ${result.bridgeTarget}`);
|
|
3754
|
+
console.log(
|
|
3755
|
+
` ${pc.dim("per-skill symlinks created:")} ${result.perSkillSymlinksCreated.length}`
|
|
3756
|
+
);
|
|
3757
|
+
console.log(
|
|
3758
|
+
` ${pc.dim("per-skill symlinks removed:")} ${result.perSkillSymlinksRemoved.length}`
|
|
3759
|
+
);
|
|
3760
|
+
if (result.backupPath) {
|
|
3761
|
+
console.log(` ${pc.yellow("backup:")} ${result.backupPath}`);
|
|
3762
|
+
}
|
|
3763
|
+
}
|
|
3764
|
+
function registerDoctorBridge(parent) {
|
|
3765
|
+
parent.command("bridge").description("Create the single ~/.agents/skills bridge symlink and rip per-skill symlinks").option("--force", "Back up and replace a real ~/.agents/skills directory if present").option("--dry-run", "Print planned actions without mutating disk state").option("--json", "Output as JSON (default)").option("--human", "Output in human-readable format").action(
|
|
3766
|
+
async (opts) => {
|
|
3767
|
+
const operation = "skills.doctor.bridge";
|
|
3768
|
+
const mvi = "standard";
|
|
3769
|
+
let format;
|
|
3770
|
+
try {
|
|
3771
|
+
format = resolveFormat({
|
|
3772
|
+
jsonFlag: opts.json ?? false,
|
|
3773
|
+
humanFlag: opts.human ?? false,
|
|
3774
|
+
projectDefault: "json"
|
|
3775
|
+
});
|
|
3776
|
+
} catch (error) {
|
|
3777
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3778
|
+
emitJsonError(
|
|
3779
|
+
operation,
|
|
3780
|
+
mvi,
|
|
3781
|
+
ErrorCodes.FORMAT_CONFLICT,
|
|
3782
|
+
message,
|
|
3783
|
+
ErrorCategories.VALIDATION
|
|
3784
|
+
);
|
|
3785
|
+
process.exit(1);
|
|
3786
|
+
}
|
|
3787
|
+
try {
|
|
3788
|
+
const result = await runDoctorBridge({
|
|
3789
|
+
force: opts.force ?? false,
|
|
3790
|
+
dryRun: opts.dryRun ?? false
|
|
3791
|
+
});
|
|
3792
|
+
if (format === "json") {
|
|
3793
|
+
outputSuccess(operation, mvi, result);
|
|
3794
|
+
} else {
|
|
3795
|
+
printHumanSummary(result);
|
|
3796
|
+
}
|
|
3797
|
+
} catch (error) {
|
|
3798
|
+
if (error instanceof AgentsSkillsRealDirError) {
|
|
3799
|
+
if (format === "json") {
|
|
3800
|
+
emitJsonError(operation, mvi, error.code, error.message, ErrorCategories.CONFLICT, {
|
|
3801
|
+
agentsSkillsPath: error.agentsSkillsPath,
|
|
3802
|
+
entryCount: error.entryCount
|
|
3803
|
+
});
|
|
3804
|
+
} else {
|
|
3805
|
+
console.error(pc.red(error.message));
|
|
3806
|
+
}
|
|
3807
|
+
process.exit(1);
|
|
3808
|
+
}
|
|
3809
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3810
|
+
if (format === "json") {
|
|
3811
|
+
emitJsonError(
|
|
3812
|
+
operation,
|
|
3813
|
+
mvi,
|
|
3814
|
+
ErrorCodes.INTERNAL_ERROR,
|
|
3815
|
+
message,
|
|
3816
|
+
ErrorCategories.INTERNAL
|
|
3817
|
+
);
|
|
3818
|
+
} else {
|
|
3819
|
+
console.error(pc.red(message));
|
|
3820
|
+
}
|
|
3821
|
+
process.exit(1);
|
|
3822
|
+
}
|
|
3823
|
+
}
|
|
3824
|
+
);
|
|
3825
|
+
}
|
|
3826
|
+
|
|
3827
|
+
// src/commands/skills/doctor-adopt.ts
|
|
3828
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
3829
|
+
import {
|
|
3830
|
+
cpSync,
|
|
3831
|
+
existsSync as existsSync13,
|
|
3832
|
+
lstatSync as lstatSync4,
|
|
3833
|
+
mkdirSync,
|
|
3834
|
+
readdirSync as readdirSync2,
|
|
3835
|
+
realpathSync as realpathSync2,
|
|
3836
|
+
renameSync,
|
|
3837
|
+
rmSync,
|
|
3838
|
+
statSync,
|
|
3839
|
+
writeFileSync
|
|
3840
|
+
} from "fs";
|
|
3841
|
+
import { homedir as homedir4 } from "os";
|
|
3842
|
+
import { join as join7 } from "path";
|
|
3843
|
+
import { createInterface } from "readline/promises";
|
|
3844
|
+
import pc2 from "picocolors";
|
|
3845
|
+
function cleoSkillsRoot() {
|
|
3846
|
+
return join7(homedir4(), ".cleo", "skills");
|
|
3847
|
+
}
|
|
3848
|
+
function legacyAgentsSkillsRoot() {
|
|
3849
|
+
return join7(homedir4(), ".local", "share", "agents", "skills");
|
|
3850
|
+
}
|
|
3851
|
+
function homeAgentsSkillsRoot() {
|
|
3852
|
+
return join7(homedir4(), ".agents", "skills");
|
|
3853
|
+
}
|
|
3854
|
+
function archiveRoot() {
|
|
3855
|
+
return join7(cleoSkillsRoot(), ".archive");
|
|
3856
|
+
}
|
|
3857
|
+
function auditLogRoot() {
|
|
3858
|
+
return join7(cleoSkillsRoot(), ".audit-log");
|
|
3859
|
+
}
|
|
3860
|
+
function listCandidates(root) {
|
|
3861
|
+
if (!existsSync13(root)) return [];
|
|
3862
|
+
let entries;
|
|
3863
|
+
try {
|
|
3864
|
+
entries = readdirSync2(root);
|
|
3865
|
+
} catch {
|
|
3866
|
+
return [];
|
|
3867
|
+
}
|
|
3868
|
+
const out = [];
|
|
3869
|
+
for (const name of entries) {
|
|
3870
|
+
if (name.startsWith(".")) continue;
|
|
3871
|
+
const full = join7(root, name);
|
|
3872
|
+
let isDirLike = false;
|
|
3873
|
+
try {
|
|
3874
|
+
const stat4 = lstatSync4(full);
|
|
3875
|
+
if (stat4.isDirectory()) {
|
|
3876
|
+
isDirLike = true;
|
|
3877
|
+
} else if (stat4.isSymbolicLink()) {
|
|
3878
|
+
try {
|
|
3879
|
+
const real = statSync(full);
|
|
3880
|
+
isDirLike = real.isDirectory();
|
|
3881
|
+
} catch {
|
|
3882
|
+
isDirLike = false;
|
|
3883
|
+
}
|
|
3884
|
+
}
|
|
3885
|
+
} catch {
|
|
3886
|
+
isDirLike = false;
|
|
3887
|
+
}
|
|
3888
|
+
if (isDirLike) {
|
|
3889
|
+
out.push({ name, path: full });
|
|
3890
|
+
}
|
|
3891
|
+
}
|
|
3892
|
+
return out;
|
|
3893
|
+
}
|
|
3894
|
+
function approxDirSize(dir) {
|
|
3895
|
+
let total = 0;
|
|
3896
|
+
try {
|
|
3897
|
+
const entries = readdirSync2(dir);
|
|
3898
|
+
for (const entry of entries) {
|
|
3899
|
+
try {
|
|
3900
|
+
const stat4 = statSync(join7(dir, entry));
|
|
3901
|
+
if (stat4.isFile()) total += stat4.size;
|
|
3902
|
+
} catch {
|
|
3903
|
+
}
|
|
3904
|
+
}
|
|
3905
|
+
} catch {
|
|
3906
|
+
return 0;
|
|
3907
|
+
}
|
|
3908
|
+
return total;
|
|
3909
|
+
}
|
|
3910
|
+
function discoverOrphans(registeredNames) {
|
|
3911
|
+
const cleoRoot = cleoSkillsRoot();
|
|
3912
|
+
const legacyRoot = legacyAgentsSkillsRoot();
|
|
3913
|
+
const homeRoot = homeAgentsSkillsRoot();
|
|
3914
|
+
const seen = /* @__PURE__ */ new Map();
|
|
3915
|
+
const visit = (root, via, filter) => {
|
|
3916
|
+
for (const candidate of listCandidates(root)) {
|
|
3917
|
+
if (seen.has(candidate.name)) continue;
|
|
3918
|
+
if (registeredNames.has(candidate.name)) continue;
|
|
3919
|
+
if (filter && !filter(candidate.path)) continue;
|
|
3920
|
+
seen.set(candidate.name, {
|
|
3921
|
+
name: candidate.name,
|
|
3922
|
+
path: candidate.path,
|
|
3923
|
+
discoveredVia: via,
|
|
3924
|
+
hasSkillMd: existsSync13(join7(candidate.path, "SKILL.md")),
|
|
3925
|
+
sizeBytes: approxDirSize(candidate.path)
|
|
3926
|
+
});
|
|
3927
|
+
}
|
|
3928
|
+
};
|
|
3929
|
+
visit(cleoRoot, "cleo");
|
|
3930
|
+
visit(legacyRoot, "legacy-agents");
|
|
3931
|
+
visit(homeRoot, "home-agents", (path2) => {
|
|
3932
|
+
try {
|
|
3933
|
+
const real = realpathSync2(path2);
|
|
3934
|
+
return !real.startsWith(`${cleoRoot}/`);
|
|
3935
|
+
} catch {
|
|
3936
|
+
return true;
|
|
3937
|
+
}
|
|
3938
|
+
});
|
|
3939
|
+
return Array.from(seen.values()).sort((a, b) => a.name.localeCompare(b.name));
|
|
3940
|
+
}
|
|
3941
|
+
function canonicalAdoptRefusal() {
|
|
3942
|
+
return {
|
|
3943
|
+
code: "E_CANONICAL_ADOPT_REFUSED",
|
|
3944
|
+
message: "Canonical adoption is refused on user machines. Canonical skills are owned by the CLEO core team and ONLY the owner-CI workflow may write them (architecture-v3 \xA76 invariant).",
|
|
3945
|
+
remediation: "To contribute this skill to canonical: clone https://github.com/kryptobaseddev/cleo, place the skill under packages/skills/skills/<name>/, and open a PR. Local user-machine canonical writes are blocked by design."
|
|
3946
|
+
};
|
|
3947
|
+
}
|
|
3948
|
+
function buildAdoptedRow(orphan, now) {
|
|
3949
|
+
return {
|
|
3950
|
+
name: orphan.name,
|
|
3951
|
+
installPath: orphan.path,
|
|
3952
|
+
installedAt: now,
|
|
3953
|
+
sourceType: "user",
|
|
3954
|
+
lifecycleState: "active"
|
|
3955
|
+
};
|
|
3956
|
+
}
|
|
3957
|
+
function archiveAndDelete(orphan, now) {
|
|
3958
|
+
const tsToken = now.replace(/[:.]/g, "-");
|
|
3959
|
+
const archiveDir = join7(archiveRoot(), `${orphan.name}-${tsToken}`);
|
|
3960
|
+
mkdirSync(archiveRoot(), { recursive: true });
|
|
3961
|
+
cpSync(orphan.path, archiveDir, { recursive: true, dereference: false });
|
|
3962
|
+
rmSync(orphan.path, { recursive: true, force: true });
|
|
3963
|
+
return archiveDir;
|
|
3964
|
+
}
|
|
3965
|
+
async function applyDecision(orphan, decision, now, recordRow) {
|
|
3966
|
+
const base = {
|
|
3967
|
+
orphan,
|
|
3968
|
+
decidedAt: now
|
|
3969
|
+
};
|
|
3970
|
+
if (decision === "canonical-adopt") {
|
|
3971
|
+
return {
|
|
3972
|
+
...base,
|
|
3973
|
+
decision,
|
|
3974
|
+
applied: false,
|
|
3975
|
+
refusal: canonicalAdoptRefusal(),
|
|
3976
|
+
archivedTo: null
|
|
3977
|
+
};
|
|
3978
|
+
}
|
|
3979
|
+
if (decision === "skip") {
|
|
3980
|
+
return { ...base, decision, applied: true, refusal: null, archivedTo: null };
|
|
3981
|
+
}
|
|
3982
|
+
if (decision === "user-adopt") {
|
|
3983
|
+
try {
|
|
3984
|
+
await recordRow(buildAdoptedRow(orphan, now));
|
|
3985
|
+
return { ...base, decision, applied: true, refusal: null, archivedTo: null };
|
|
3986
|
+
} catch (err) {
|
|
3987
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
3988
|
+
return {
|
|
3989
|
+
...base,
|
|
3990
|
+
decision,
|
|
3991
|
+
applied: false,
|
|
3992
|
+
refusal: {
|
|
3993
|
+
code: "E_CANONICAL_ADOPT_REFUSED",
|
|
3994
|
+
message: `user-adopt failed: ${message}`,
|
|
3995
|
+
remediation: "Initialise the registry with `cleo skills list` then re-run."
|
|
3996
|
+
},
|
|
3997
|
+
archivedTo: null
|
|
3998
|
+
};
|
|
3999
|
+
}
|
|
4000
|
+
}
|
|
4001
|
+
try {
|
|
4002
|
+
const archived = archiveAndDelete(orphan, now);
|
|
4003
|
+
return { ...base, decision, applied: true, refusal: null, archivedTo: archived };
|
|
4004
|
+
} catch (err) {
|
|
4005
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
4006
|
+
return {
|
|
4007
|
+
...base,
|
|
4008
|
+
decision,
|
|
4009
|
+
applied: false,
|
|
4010
|
+
refusal: {
|
|
4011
|
+
code: "E_CANONICAL_ADOPT_REFUSED",
|
|
4012
|
+
message: `delete failed: ${message}`,
|
|
4013
|
+
remediation: "Inspect filesystem permissions and rerun with --non-interactive to verify."
|
|
4014
|
+
},
|
|
4015
|
+
archivedTo: null
|
|
4016
|
+
};
|
|
4017
|
+
}
|
|
4018
|
+
}
|
|
4019
|
+
function writeAuditLog(result) {
|
|
4020
|
+
const dir = auditLogRoot();
|
|
4021
|
+
mkdirSync(dir, { recursive: true });
|
|
4022
|
+
const tsToken = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
4023
|
+
const path2 = join7(dir, `adopt-${tsToken}.json`);
|
|
4024
|
+
const tmp = `${path2}.tmp`;
|
|
4025
|
+
const payload = {
|
|
4026
|
+
runId: randomUUID2(),
|
|
4027
|
+
writtenAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4028
|
+
...result
|
|
4029
|
+
};
|
|
4030
|
+
writeFileSync(tmp, `${JSON.stringify(payload, null, 2)}
|
|
4031
|
+
`, "utf8");
|
|
4032
|
+
renameSync(tmp, path2);
|
|
4033
|
+
return path2;
|
|
4034
|
+
}
|
|
4035
|
+
async function promptDecision(rl, orphan) {
|
|
4036
|
+
const kb = Math.round(orphan.sizeBytes / 1024);
|
|
4037
|
+
process.stderr.write(
|
|
4038
|
+
`
|
|
4039
|
+
${pc2.bold(orphan.name)}
|
|
4040
|
+
path: ${orphan.path}
|
|
4041
|
+
via: ${orphan.discoveredVia}
|
|
4042
|
+
size: ~${kb} KiB
|
|
4043
|
+
SKILL.md: ${orphan.hasSkillMd ? "yes" : "no"}
|
|
4044
|
+
`
|
|
4045
|
+
);
|
|
4046
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
4047
|
+
const answer = (await rl.question(" [c]anonical-adopt | [u]ser-adopt | [d]elete | [s]kip: ")).trim().toLowerCase();
|
|
4048
|
+
if (answer === "c" || answer === "canonical" || answer === "canonical-adopt") {
|
|
4049
|
+
return "canonical-adopt";
|
|
4050
|
+
}
|
|
4051
|
+
if (answer === "u" || answer === "user" || answer === "user-adopt") {
|
|
4052
|
+
return "user-adopt";
|
|
4053
|
+
}
|
|
4054
|
+
if (answer === "d" || answer === "delete") return "delete";
|
|
4055
|
+
if (answer === "s" || answer === "skip" || answer === "") return "skip";
|
|
4056
|
+
process.stderr.write(` ${pc2.yellow("unrecognised input \u2014 try one of c/u/d/s")}
|
|
4057
|
+
`);
|
|
4058
|
+
}
|
|
4059
|
+
return "skip";
|
|
4060
|
+
}
|
|
4061
|
+
async function runDoctorAdopt(options) {
|
|
4062
|
+
const discover = options.discoverFn ?? discoverOrphans;
|
|
4063
|
+
const registeredNames = await options.loadRegisteredNames();
|
|
4064
|
+
const orphans = discover(registeredNames);
|
|
4065
|
+
const results = [];
|
|
4066
|
+
const mode = options.nonInteractive ? "non-interactive" : options.autoUserAdopt ? "auto-user-adopt" : "interactive";
|
|
4067
|
+
if (orphans.length === 0) {
|
|
4068
|
+
const empty = {
|
|
4069
|
+
totalOrphans: 0,
|
|
4070
|
+
results: [],
|
|
4071
|
+
auditLogPath: "",
|
|
4072
|
+
mode
|
|
4073
|
+
};
|
|
4074
|
+
if (!options.skipAuditLog) empty.auditLogPath = writeAuditLog(empty);
|
|
4075
|
+
return empty;
|
|
4076
|
+
}
|
|
4077
|
+
if (mode === "non-interactive") {
|
|
4078
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4079
|
+
for (const orphan of orphans) {
|
|
4080
|
+
results.push({
|
|
4081
|
+
orphan,
|
|
4082
|
+
decision: "skip",
|
|
4083
|
+
applied: true,
|
|
4084
|
+
refusal: null,
|
|
4085
|
+
archivedTo: null,
|
|
4086
|
+
decidedAt: now
|
|
4087
|
+
});
|
|
4088
|
+
}
|
|
4089
|
+
} else if (mode === "auto-user-adopt") {
|
|
4090
|
+
for (const orphan of orphans) {
|
|
4091
|
+
results.push(
|
|
4092
|
+
await applyDecision(orphan, "user-adopt", (/* @__PURE__ */ new Date()).toISOString(), options.recordRow)
|
|
4093
|
+
);
|
|
4094
|
+
}
|
|
4095
|
+
} else {
|
|
4096
|
+
const promptFn = options.prompt ?? (async (orphan) => {
|
|
4097
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
4098
|
+
try {
|
|
4099
|
+
return await promptDecision(rl, orphan);
|
|
4100
|
+
} finally {
|
|
4101
|
+
rl.close();
|
|
4102
|
+
}
|
|
4103
|
+
});
|
|
4104
|
+
for (const orphan of orphans) {
|
|
4105
|
+
const decision = await promptFn(orphan);
|
|
4106
|
+
results.push(
|
|
4107
|
+
await applyDecision(orphan, decision, (/* @__PURE__ */ new Date()).toISOString(), options.recordRow)
|
|
4108
|
+
);
|
|
4109
|
+
}
|
|
4110
|
+
}
|
|
4111
|
+
const result = {
|
|
4112
|
+
totalOrphans: orphans.length,
|
|
4113
|
+
results,
|
|
4114
|
+
auditLogPath: "",
|
|
4115
|
+
mode
|
|
4116
|
+
};
|
|
4117
|
+
if (!options.skipAuditLog) result.auditLogPath = writeAuditLog(result);
|
|
4118
|
+
return result;
|
|
4119
|
+
}
|
|
4120
|
+
var caampStandaloneAdapters = {
|
|
4121
|
+
loadRegisteredNames: () => /* @__PURE__ */ new Set(),
|
|
4122
|
+
recordRow: () => {
|
|
4123
|
+
throw new Error(
|
|
4124
|
+
"caamp standalone CLI cannot write to skills.db. Use `cleo skills doctor adopt-orphans` instead."
|
|
4125
|
+
);
|
|
4126
|
+
}
|
|
4127
|
+
};
|
|
4128
|
+
function registerSkillsDoctorAdopt(parent, adapters = caampStandaloneAdapters) {
|
|
4129
|
+
const existing = parent.commands.find((c) => c.name() === "doctor");
|
|
4130
|
+
const doctor = existing ?? parent.command("doctor").description("Diagnostics + repair for the skill system");
|
|
4131
|
+
doctor.command("adopt-orphans").description(
|
|
4132
|
+
"Interactive audit of on-disk skill dirs not tracked in skills.db (canonical/user/delete/skip)"
|
|
4133
|
+
).option("--json", "Output as LAFS JSON envelope (default)").option("--human", "Output a colorised human-readable summary").option("--non-interactive", "List orphans + exit without action").option("--auto-user-adopt", "Bulk-mark all orphans as source_type=user without prompting").action(
|
|
4134
|
+
async (opts) => {
|
|
4135
|
+
const operation = "skills.doctor.adopt-orphans";
|
|
4136
|
+
const mvi = "standard";
|
|
4137
|
+
let format;
|
|
4138
|
+
try {
|
|
4139
|
+
format = resolveFormat({
|
|
4140
|
+
jsonFlag: opts.json ?? false,
|
|
4141
|
+
humanFlag: opts.human ?? false,
|
|
4142
|
+
projectDefault: "json"
|
|
4143
|
+
});
|
|
4144
|
+
} catch (error) {
|
|
4145
|
+
handleFormatError(error, operation, mvi, opts.json);
|
|
4146
|
+
}
|
|
4147
|
+
try {
|
|
4148
|
+
const result = await runDoctorAdopt({
|
|
4149
|
+
nonInteractive: opts.nonInteractive ?? false,
|
|
4150
|
+
autoUserAdopt: opts.autoUserAdopt ?? false,
|
|
4151
|
+
loadRegisteredNames: adapters.loadRegisteredNames,
|
|
4152
|
+
recordRow: adapters.recordRow
|
|
4153
|
+
});
|
|
4154
|
+
if (format === "json") {
|
|
4155
|
+
outputSuccess(operation, mvi, result);
|
|
4156
|
+
return;
|
|
4157
|
+
}
|
|
4158
|
+
const ok = result.results.filter((r) => r.applied);
|
|
4159
|
+
const blocked = result.results.filter((r) => !r.applied);
|
|
4160
|
+
console.log(pc2.bold(`
|
|
4161
|
+
skills doctor adopt-orphans (${result.mode})
|
|
4162
|
+
`));
|
|
4163
|
+
console.log(
|
|
4164
|
+
` ${pc2.bold("Discovered")}: ${result.totalOrphans} orphan${result.totalOrphans === 1 ? "" : "s"}`
|
|
4165
|
+
);
|
|
4166
|
+
for (const r of result.results) {
|
|
4167
|
+
const icon = r.decision === "skip" ? pc2.dim("\xB7") : r.applied ? pc2.green("\u2713") : pc2.red("\u2717");
|
|
4168
|
+
const verb = r.applied ? r.decision : `${r.decision} (refused)`;
|
|
4169
|
+
console.log(` ${icon} ${r.orphan.name.padEnd(32)} ${pc2.dim(verb)}`);
|
|
4170
|
+
if (r.refusal) {
|
|
4171
|
+
console.log(` ${pc2.yellow(r.refusal.message)}`);
|
|
4172
|
+
console.log(` ${pc2.dim(r.refusal.remediation)}`);
|
|
4173
|
+
}
|
|
4174
|
+
if (r.archivedTo) {
|
|
4175
|
+
console.log(` ${pc2.dim(`archived \u2192 ${r.archivedTo}`)}`);
|
|
4176
|
+
}
|
|
4177
|
+
}
|
|
4178
|
+
console.log(
|
|
4179
|
+
`
|
|
4180
|
+
${pc2.bold("Summary")}: ${pc2.green(`${ok.length} applied`)}, ${pc2.red(`${blocked.length} blocked`)}`
|
|
4181
|
+
);
|
|
4182
|
+
if (result.auditLogPath) {
|
|
4183
|
+
console.log(` ${pc2.dim(`audit log \u2192 ${result.auditLogPath}`)}`);
|
|
4184
|
+
}
|
|
4185
|
+
console.log();
|
|
4186
|
+
} catch (error) {
|
|
4187
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4188
|
+
if (format === "json") {
|
|
4189
|
+
emitJsonError(
|
|
4190
|
+
operation,
|
|
4191
|
+
mvi,
|
|
4192
|
+
ErrorCodes.INTERNAL_ERROR,
|
|
4193
|
+
message,
|
|
4194
|
+
ErrorCategories.INTERNAL
|
|
4195
|
+
);
|
|
4196
|
+
} else {
|
|
4197
|
+
console.error(pc2.red(`Error: ${message}`));
|
|
4198
|
+
}
|
|
4199
|
+
process.exit(1);
|
|
4200
|
+
}
|
|
4201
|
+
}
|
|
4202
|
+
);
|
|
4203
|
+
}
|
|
4204
|
+
|
|
3434
4205
|
// src/core/network/fetch.ts
|
|
3435
4206
|
var DEFAULT_FETCH_TIMEOUT_MS = 1e4;
|
|
3436
4207
|
var NetworkError = class extends Error {
|
|
@@ -4007,9 +4778,9 @@ async function recommendSkills2(query, criteria, options = {}) {
|
|
|
4007
4778
|
}
|
|
4008
4779
|
|
|
4009
4780
|
// src/core/skills/library-loader.ts
|
|
4010
|
-
import { existsSync as
|
|
4781
|
+
import { existsSync as existsSync14, readdirSync as readdirSync3, readFileSync } from "fs";
|
|
4011
4782
|
import { createRequire } from "module";
|
|
4012
|
-
import { basename as basename3, dirname as
|
|
4783
|
+
import { basename as basename3, dirname as dirname4, join as join8 } from "path";
|
|
4013
4784
|
var require2 = createRequire(import.meta.url);
|
|
4014
4785
|
function loadLibraryFromModule(root) {
|
|
4015
4786
|
let mod;
|
|
@@ -4055,16 +4826,16 @@ function loadLibraryFromModule(root) {
|
|
|
4055
4826
|
return mod;
|
|
4056
4827
|
}
|
|
4057
4828
|
function buildLibraryFromFiles(root) {
|
|
4058
|
-
const catalogPath =
|
|
4059
|
-
if (!
|
|
4829
|
+
const catalogPath = join8(root, "skills.json");
|
|
4830
|
+
if (!existsSync14(catalogPath)) {
|
|
4060
4831
|
throw new Error(`No skills.json found at ${root}`);
|
|
4061
4832
|
}
|
|
4062
4833
|
const catalogData = JSON.parse(readFileSync(catalogPath, "utf-8"));
|
|
4063
4834
|
const entries = catalogData.skills ?? [];
|
|
4064
4835
|
const version = catalogData.version ?? "0.0.0";
|
|
4065
|
-
const manifestPath =
|
|
4836
|
+
const manifestPath = join8(root, "skills", "manifest.json");
|
|
4066
4837
|
let manifest;
|
|
4067
|
-
if (
|
|
4838
|
+
if (existsSync14(manifestPath)) {
|
|
4068
4839
|
manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
4069
4840
|
} else {
|
|
4070
4841
|
manifest = {
|
|
@@ -4074,14 +4845,14 @@ function buildLibraryFromFiles(root) {
|
|
|
4074
4845
|
skills: []
|
|
4075
4846
|
};
|
|
4076
4847
|
}
|
|
4077
|
-
const profilesDir =
|
|
4848
|
+
const profilesDir = join8(root, "profiles");
|
|
4078
4849
|
const profiles = /* @__PURE__ */ new Map();
|
|
4079
|
-
if (
|
|
4080
|
-
for (const file of
|
|
4850
|
+
if (existsSync14(profilesDir)) {
|
|
4851
|
+
for (const file of readdirSync3(profilesDir)) {
|
|
4081
4852
|
if (!file.endsWith(".json")) continue;
|
|
4082
4853
|
try {
|
|
4083
4854
|
const profile = JSON.parse(
|
|
4084
|
-
readFileSync(
|
|
4855
|
+
readFileSync(join8(profilesDir, file), "utf-8")
|
|
4085
4856
|
);
|
|
4086
4857
|
profiles.set(profile.name, profile);
|
|
4087
4858
|
} catch {
|
|
@@ -4095,9 +4866,9 @@ function buildLibraryFromFiles(root) {
|
|
|
4095
4866
|
function getSkillDir2(name) {
|
|
4096
4867
|
const entry = skillMap.get(name);
|
|
4097
4868
|
if (entry) {
|
|
4098
|
-
return
|
|
4869
|
+
return dirname4(join8(root, entry.path));
|
|
4099
4870
|
}
|
|
4100
|
-
return
|
|
4871
|
+
return join8(root, "skills", name);
|
|
4101
4872
|
}
|
|
4102
4873
|
function resolveDeps(names, visited = /* @__PURE__ */ new Set()) {
|
|
4103
4874
|
const result = [];
|
|
@@ -4125,8 +4896,8 @@ function buildLibraryFromFiles(root) {
|
|
|
4125
4896
|
return resolveDeps([...new Set(skills)]);
|
|
4126
4897
|
}
|
|
4127
4898
|
function discoverFiles(dir, ext) {
|
|
4128
|
-
if (!
|
|
4129
|
-
return
|
|
4899
|
+
if (!existsSync14(dir)) return [];
|
|
4900
|
+
return readdirSync3(dir).filter((f) => f.endsWith(ext)).map((f) => basename3(f, ext));
|
|
4130
4901
|
}
|
|
4131
4902
|
const library = {
|
|
4132
4903
|
version,
|
|
@@ -4142,14 +4913,14 @@ function buildLibraryFromFiles(root) {
|
|
|
4142
4913
|
getSkillPath(name) {
|
|
4143
4914
|
const entry = skillMap.get(name);
|
|
4144
4915
|
if (entry) {
|
|
4145
|
-
return
|
|
4916
|
+
return join8(root, entry.path);
|
|
4146
4917
|
}
|
|
4147
|
-
return
|
|
4918
|
+
return join8(root, "skills", name, "SKILL.md");
|
|
4148
4919
|
},
|
|
4149
4920
|
getSkillDir: getSkillDir2,
|
|
4150
4921
|
readSkillContent(name) {
|
|
4151
4922
|
const skillPath = library.getSkillPath(name);
|
|
4152
|
-
if (!
|
|
4923
|
+
if (!existsSync14(skillPath)) {
|
|
4153
4924
|
throw new Error(`Skill content not found: ${skillPath}`);
|
|
4154
4925
|
}
|
|
4155
4926
|
return readFileSync(skillPath, "utf-8");
|
|
@@ -4176,11 +4947,11 @@ function buildLibraryFromFiles(root) {
|
|
|
4176
4947
|
return resolveProfileByName(name);
|
|
4177
4948
|
},
|
|
4178
4949
|
listSharedResources() {
|
|
4179
|
-
return discoverFiles(
|
|
4950
|
+
return discoverFiles(join8(root, "skills", "_shared"), ".md");
|
|
4180
4951
|
},
|
|
4181
4952
|
getSharedResourcePath(name) {
|
|
4182
|
-
const resourcePath =
|
|
4183
|
-
return
|
|
4953
|
+
const resourcePath = join8(root, "skills", "_shared", `${name}.md`);
|
|
4954
|
+
return existsSync14(resourcePath) ? resourcePath : void 0;
|
|
4184
4955
|
},
|
|
4185
4956
|
readSharedResource(name) {
|
|
4186
4957
|
const resourcePath = library.getSharedResourcePath(name);
|
|
@@ -4188,15 +4959,15 @@ function buildLibraryFromFiles(root) {
|
|
|
4188
4959
|
return readFileSync(resourcePath, "utf-8");
|
|
4189
4960
|
},
|
|
4190
4961
|
listProtocols() {
|
|
4191
|
-
const rootProtocols = discoverFiles(
|
|
4962
|
+
const rootProtocols = discoverFiles(join8(root, "protocols"), ".md");
|
|
4192
4963
|
if (rootProtocols.length > 0) return rootProtocols;
|
|
4193
|
-
return discoverFiles(
|
|
4964
|
+
return discoverFiles(join8(root, "skills", "protocols"), ".md");
|
|
4194
4965
|
},
|
|
4195
4966
|
getProtocolPath(name) {
|
|
4196
|
-
const rootPath =
|
|
4197
|
-
if (
|
|
4198
|
-
const skillsPath =
|
|
4199
|
-
return
|
|
4967
|
+
const rootPath = join8(root, "protocols", `${name}.md`);
|
|
4968
|
+
if (existsSync14(rootPath)) return rootPath;
|
|
4969
|
+
const skillsPath = join8(root, "skills", "protocols", `${name}.md`);
|
|
4970
|
+
return existsSync14(skillsPath) ? skillsPath : void 0;
|
|
4200
4971
|
},
|
|
4201
4972
|
readProtocol(name) {
|
|
4202
4973
|
const protocolPath = library.getProtocolPath(name);
|
|
@@ -4221,8 +4992,8 @@ function buildLibraryFromFiles(root) {
|
|
|
4221
4992
|
if (!entry.version) {
|
|
4222
4993
|
issues.push({ level: "warn", field: "version", message: "Missing version" });
|
|
4223
4994
|
}
|
|
4224
|
-
const skillPath =
|
|
4225
|
-
if (!
|
|
4995
|
+
const skillPath = join8(root, entry.path);
|
|
4996
|
+
if (!existsSync14(skillPath)) {
|
|
4226
4997
|
issues.push({
|
|
4227
4998
|
level: "error",
|
|
4228
4999
|
field: "path",
|
|
@@ -4281,15 +5052,15 @@ __export(catalog_exports, {
|
|
|
4281
5052
|
validateAll: () => validateAll,
|
|
4282
5053
|
validateSkillFrontmatter: () => validateSkillFrontmatter
|
|
4283
5054
|
});
|
|
4284
|
-
import { existsSync as
|
|
4285
|
-
import { join as
|
|
5055
|
+
import { existsSync as existsSync15 } from "fs";
|
|
5056
|
+
import { join as join9 } from "path";
|
|
4286
5057
|
var _library = null;
|
|
4287
5058
|
function registerSkillLibrary(library) {
|
|
4288
5059
|
_library = library;
|
|
4289
5060
|
}
|
|
4290
5061
|
function registerSkillLibraryFromPath(root) {
|
|
4291
|
-
const indexPath =
|
|
4292
|
-
if (
|
|
5062
|
+
const indexPath = join9(root, "index.js");
|
|
5063
|
+
if (existsSync15(indexPath)) {
|
|
4293
5064
|
_library = loadLibraryFromModule(root);
|
|
4294
5065
|
return;
|
|
4295
5066
|
}
|
|
@@ -4300,13 +5071,13 @@ function clearRegisteredLibrary() {
|
|
|
4300
5071
|
}
|
|
4301
5072
|
function discoverLibrary() {
|
|
4302
5073
|
const envPath = process.env["CAAMP_SKILL_LIBRARY"];
|
|
4303
|
-
if (envPath &&
|
|
5074
|
+
if (envPath && existsSync15(envPath)) {
|
|
4304
5075
|
try {
|
|
4305
|
-
const indexPath =
|
|
4306
|
-
if (
|
|
5076
|
+
const indexPath = join9(envPath, "index.js");
|
|
5077
|
+
if (existsSync15(indexPath)) {
|
|
4307
5078
|
return loadLibraryFromModule(envPath);
|
|
4308
5079
|
}
|
|
4309
|
-
if (
|
|
5080
|
+
if (existsSync15(join9(envPath, "skills.json"))) {
|
|
4310
5081
|
return buildLibraryFromFiles(envPath);
|
|
4311
5082
|
}
|
|
4312
5083
|
} catch {
|
|
@@ -4413,9 +5184,9 @@ function getLibraryRoot() {
|
|
|
4413
5184
|
}
|
|
4414
5185
|
|
|
4415
5186
|
// src/core/skills/discovery.ts
|
|
4416
|
-
import { existsSync as
|
|
4417
|
-
import { readdir as
|
|
4418
|
-
import { join as
|
|
5187
|
+
import { existsSync as existsSync16 } from "fs";
|
|
5188
|
+
import { readdir as readdir3, readFile as readFile7 } from "fs/promises";
|
|
5189
|
+
import { join as join10 } from "path";
|
|
4419
5190
|
import matter from "gray-matter";
|
|
4420
5191
|
async function parseSkillFile(filePath) {
|
|
4421
5192
|
try {
|
|
@@ -4439,8 +5210,8 @@ async function parseSkillFile(filePath) {
|
|
|
4439
5210
|
}
|
|
4440
5211
|
}
|
|
4441
5212
|
async function discoverSkill(skillDir) {
|
|
4442
|
-
const skillFile =
|
|
4443
|
-
if (!
|
|
5213
|
+
const skillFile = join10(skillDir, "SKILL.md");
|
|
5214
|
+
if (!existsSync16(skillFile)) return null;
|
|
4444
5215
|
const metadata = await parseSkillFile(skillFile);
|
|
4445
5216
|
if (!metadata) return null;
|
|
4446
5217
|
return {
|
|
@@ -4451,12 +5222,12 @@ async function discoverSkill(skillDir) {
|
|
|
4451
5222
|
};
|
|
4452
5223
|
}
|
|
4453
5224
|
async function discoverSkills(rootDir) {
|
|
4454
|
-
if (!
|
|
4455
|
-
const entries = await
|
|
5225
|
+
if (!existsSync16(rootDir)) return [];
|
|
5226
|
+
const entries = await readdir3(rootDir, { withFileTypes: true });
|
|
4456
5227
|
const skills = [];
|
|
4457
5228
|
for (const entry of entries) {
|
|
4458
5229
|
if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
|
|
4459
|
-
const skillDir =
|
|
5230
|
+
const skillDir = join10(rootDir, entry.name);
|
|
4460
5231
|
const skill = await discoverSkill(skillDir);
|
|
4461
5232
|
if (skill) {
|
|
4462
5233
|
skills.push(skill);
|
|
@@ -4480,7 +5251,7 @@ async function discoverSkillsMulti(dirs) {
|
|
|
4480
5251
|
}
|
|
4481
5252
|
|
|
4482
5253
|
// src/core/skills/validator.ts
|
|
4483
|
-
import { existsSync as
|
|
5254
|
+
import { existsSync as existsSync17 } from "fs";
|
|
4484
5255
|
import { readFile as readFile8 } from "fs/promises";
|
|
4485
5256
|
import matter2 from "gray-matter";
|
|
4486
5257
|
var RESERVED_NAMES = [
|
|
@@ -4502,7 +5273,7 @@ var WARN_BODY_LINES = 500;
|
|
|
4502
5273
|
var WARN_DESCRIPTION_LENGTH = 50;
|
|
4503
5274
|
async function validateSkill(filePath) {
|
|
4504
5275
|
const issues = [];
|
|
4505
|
-
if (!
|
|
5276
|
+
if (!existsSync17(filePath)) {
|
|
4506
5277
|
return {
|
|
4507
5278
|
valid: false,
|
|
4508
5279
|
issues: [{ level: "error", field: "file", message: "File does not exist" }],
|
|
@@ -4631,6 +5402,7 @@ export {
|
|
|
4631
5402
|
getInstalledProviders,
|
|
4632
5403
|
detectProjectProviders,
|
|
4633
5404
|
resetDetectionCache,
|
|
5405
|
+
inferSkillSourceType,
|
|
4634
5406
|
installSkill,
|
|
4635
5407
|
removeSkill,
|
|
4636
5408
|
listCanonicalSkills,
|
|
@@ -4657,6 +5429,14 @@ export {
|
|
|
4657
5429
|
readConfig,
|
|
4658
5430
|
writeConfig,
|
|
4659
5431
|
removeConfig,
|
|
5432
|
+
resolveFormat,
|
|
5433
|
+
buildEnvelope,
|
|
5434
|
+
emitError,
|
|
5435
|
+
emitJsonError,
|
|
5436
|
+
outputSuccess,
|
|
5437
|
+
handleFormatError,
|
|
5438
|
+
ErrorCategories,
|
|
5439
|
+
ErrorCodes,
|
|
4660
5440
|
readLockFile,
|
|
4661
5441
|
resolveMcpConfigPath,
|
|
4662
5442
|
listMcpServers,
|
|
@@ -4677,6 +5457,16 @@ export {
|
|
|
4677
5457
|
getTrackedSkills,
|
|
4678
5458
|
checkSkillUpdate,
|
|
4679
5459
|
checkAllSkillUpdates,
|
|
5460
|
+
AgentsSkillsRealDirError,
|
|
5461
|
+
buildBackupTimestamp,
|
|
5462
|
+
runDoctorBridge,
|
|
5463
|
+
registerDoctorBridge,
|
|
5464
|
+
discoverOrphans,
|
|
5465
|
+
applyDecision,
|
|
5466
|
+
writeAuditLog,
|
|
5467
|
+
runDoctorAdopt,
|
|
5468
|
+
caampStandaloneAdapters,
|
|
5469
|
+
registerSkillsDoctorAdopt,
|
|
4680
5470
|
MarketplaceClient,
|
|
4681
5471
|
RECOMMENDATION_ERROR_CODES,
|
|
4682
5472
|
tokenizeCriteriaValue,
|
|
@@ -4705,4 +5495,4 @@ export {
|
|
|
4705
5495
|
discoverSkillsMulti,
|
|
4706
5496
|
validateSkill
|
|
4707
5497
|
};
|
|
4708
|
-
//# sourceMappingURL=chunk-
|
|
5498
|
+
//# sourceMappingURL=chunk-WXL7RPS4.js.map
|