@cleocode/caamp 2026.5.87 → 2026.5.89
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-PGETUTYZ.js → chunk-EH5U4PRC.js} +2 -2
- package/dist/{chunk-H5YXR2DC.js → chunk-HDZYZTR2.js} +1 -34
- package/dist/chunk-HDZYZTR2.js.map +1 -0
- package/dist/{chunk-WXL7RPS4.js → chunk-RTK4A3WY.js} +90 -862
- package/dist/chunk-RTK4A3WY.js.map +1 -0
- package/dist/{chunk-QKC2JRSG.js → chunk-YCAANESR.js} +2 -2
- package/dist/cli.js +259 -458
- package/dist/cli.js.map +1 -1
- package/dist/{hooks-ZN3C4WCK.js → hooks-FHFZZENR.js} +3 -3
- package/dist/index.d.ts +13 -616
- package/dist/index.js +7 -30
- package/dist/index.js.map +1 -1
- package/dist/{injector-QPOIJVOR.js → injector-3TOVIDBO.js} +3 -3
- package/package.json +6 -5
- package/dist/chunk-H5YXR2DC.js.map +0 -1
- package/dist/chunk-WXL7RPS4.js.map +0 -1
- /package/dist/{chunk-PGETUTYZ.js.map → chunk-EH5U4PRC.js.map} +0 -0
- /package/dist/{chunk-QKC2JRSG.js.map → chunk-YCAANESR.js.map} +0 -0
- /package/dist/{hooks-ZN3C4WCK.js.map → hooks-FHFZZENR.js.map} +0 -0
- /package/dist/{injector-QPOIJVOR.js.map → injector-3TOVIDBO.js.map} +0 -0
|
@@ -3,20 +3,19 @@ import {
|
|
|
3
3
|
getPrimaryProvider,
|
|
4
4
|
groupByInstructFile,
|
|
5
5
|
injectAll
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-EH5U4PRC.js";
|
|
7
7
|
import {
|
|
8
8
|
__export,
|
|
9
9
|
getAgentsConfigPath,
|
|
10
10
|
getAgentsHome,
|
|
11
11
|
getAgentsMcpDir,
|
|
12
12
|
getAgentsMcpServersPath,
|
|
13
|
-
getCanonicalSkillsDir,
|
|
14
13
|
getLockFilePath,
|
|
15
14
|
getPlatformLocations,
|
|
16
15
|
resolveProviderConfigPath,
|
|
17
16
|
resolveProviderProjectPath,
|
|
18
17
|
resolveProviderSkillsDirs
|
|
19
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-HDZYZTR2.js";
|
|
20
19
|
|
|
21
20
|
// src/core/logger.ts
|
|
22
21
|
var verboseMode = false;
|
|
@@ -188,12 +187,13 @@ function resetDetectionCache() {
|
|
|
188
187
|
import { existsSync as existsSync2, lstatSync } from "fs";
|
|
189
188
|
import { cp, mkdir, rm, symlink } from "fs/promises";
|
|
190
189
|
import { join as join2 } from "path";
|
|
190
|
+
import { resolveSkillsRoot } from "@cleocode/core/skills/skill-root.js";
|
|
191
191
|
async function ensureCanonicalDir() {
|
|
192
|
-
await mkdir(
|
|
192
|
+
await mkdir(resolveSkillsRoot(), { recursive: true });
|
|
193
193
|
}
|
|
194
194
|
async function installToCanonical(sourcePath, skillName) {
|
|
195
195
|
await ensureCanonicalDir();
|
|
196
|
-
const targetDir = join2(
|
|
196
|
+
const targetDir = join2(resolveSkillsRoot(), skillName);
|
|
197
197
|
await rm(targetDir, { recursive: true, force: true });
|
|
198
198
|
try {
|
|
199
199
|
await cp(sourcePath, targetDir, { recursive: true });
|
|
@@ -308,7 +308,7 @@ async function removeSkill(skillName, providers, isGlobal, projectDir) {
|
|
|
308
308
|
removed.push(provider.id);
|
|
309
309
|
}
|
|
310
310
|
}
|
|
311
|
-
const canonicalPath = join2(
|
|
311
|
+
const canonicalPath = join2(resolveSkillsRoot(), skillName);
|
|
312
312
|
if (existsSync2(canonicalPath)) {
|
|
313
313
|
try {
|
|
314
314
|
await rm(canonicalPath, { recursive: true });
|
|
@@ -319,9 +319,9 @@ async function removeSkill(skillName, providers, isGlobal, projectDir) {
|
|
|
319
319
|
return { removed, errors };
|
|
320
320
|
}
|
|
321
321
|
async function listCanonicalSkills() {
|
|
322
|
-
if (!existsSync2(
|
|
323
|
-
const { readdir:
|
|
324
|
-
const entries = await
|
|
322
|
+
if (!existsSync2(resolveSkillsRoot())) return [];
|
|
323
|
+
const { readdir: readdir3 } = await import("fs/promises");
|
|
324
|
+
const entries = await readdir3(resolveSkillsRoot(), { withFileTypes: true });
|
|
325
325
|
return entries.filter((e) => e.isDirectory() || e.isSymbolicLink()).map((e) => e.name);
|
|
326
326
|
}
|
|
327
327
|
|
|
@@ -330,16 +330,7 @@ import { existsSync as existsSync3, lstatSync as lstatSync2 } from "fs";
|
|
|
330
330
|
import { cp as cp2, mkdir as mkdir2, readlink, rm as rm2, symlink as symlink2 } from "fs/promises";
|
|
331
331
|
import { tmpdir } from "os";
|
|
332
332
|
import { basename, dirname, join as join3 } from "path";
|
|
333
|
-
|
|
334
|
-
// src/core/paths/agents.ts
|
|
335
|
-
var AGENTS_HOME = getAgentsHome();
|
|
336
|
-
var LOCK_FILE_PATH = getLockFilePath();
|
|
337
|
-
var CANONICAL_SKILLS_DIR = getCanonicalSkillsDir();
|
|
338
|
-
var AGENTS_MCP_DIR = getAgentsMcpDir();
|
|
339
|
-
var AGENTS_MCP_SERVERS_PATH = getAgentsMcpServersPath();
|
|
340
|
-
var AGENTS_CONFIG_PATH = getAgentsConfigPath();
|
|
341
|
-
|
|
342
|
-
// src/core/advanced/orchestration.ts
|
|
333
|
+
import { resolveSkillsRoot as resolveSkillsRoot2 } from "@cleocode/core/skills/skill-root.js";
|
|
343
334
|
var PRIORITY_ORDER = {
|
|
344
335
|
primary: -1,
|
|
345
336
|
high: 0,
|
|
@@ -357,7 +348,7 @@ function resolveSkillLinkPath(provider, skillName, isGlobal, projectDir) {
|
|
|
357
348
|
async function snapshotSkillState(providerTargets, operation, projectDir, backupRoot) {
|
|
358
349
|
const skillName = operation.skillName;
|
|
359
350
|
const isGlobal = operation.isGlobal ?? true;
|
|
360
|
-
const canonicalPath = join3(
|
|
351
|
+
const canonicalPath = join3(resolveSkillsRoot2(), skillName);
|
|
361
352
|
const canonicalExisted = existsSync3(canonicalPath);
|
|
362
353
|
const canonicalBackupPath = join3(backupRoot, "canonical", skillName);
|
|
363
354
|
if (canonicalExisted) {
|
|
@@ -1106,7 +1097,7 @@ ${MARKER_END}`;
|
|
|
1106
1097
|
task.signal.addEventListener("abort", onAbort, { once: true });
|
|
1107
1098
|
}
|
|
1108
1099
|
}
|
|
1109
|
-
const exitPromise = new Promise((
|
|
1100
|
+
const exitPromise = new Promise((resolve) => {
|
|
1110
1101
|
child.on("close", (exitCode, signal) => {
|
|
1111
1102
|
flushStdoutBuffer(true);
|
|
1112
1103
|
flushStderrBuffer(true);
|
|
@@ -1128,7 +1119,7 @@ ${MARKER_END}`;
|
|
|
1128
1119
|
};
|
|
1129
1120
|
Promise.allSettled(pendingWrites).then(() => {
|
|
1130
1121
|
safeOnStream({ kind: "exit", subagentId, payload: result2 });
|
|
1131
|
-
|
|
1122
|
+
resolve(result2);
|
|
1132
1123
|
});
|
|
1133
1124
|
});
|
|
1134
1125
|
child.on("error", () => {
|
|
@@ -1857,11 +1848,11 @@ async function terminateSubagent(child, graceMs) {
|
|
|
1857
1848
|
}
|
|
1858
1849
|
const pollInterval = Math.min(25, Math.max(1, graceMs));
|
|
1859
1850
|
const deadline = Date.now() + graceMs;
|
|
1860
|
-
await new Promise((
|
|
1851
|
+
await new Promise((resolve) => {
|
|
1861
1852
|
const timer = setInterval(() => {
|
|
1862
1853
|
if (child.exitCode !== null || child.signalCode !== null) {
|
|
1863
1854
|
clearInterval(timer);
|
|
1864
|
-
|
|
1855
|
+
resolve();
|
|
1865
1856
|
return;
|
|
1866
1857
|
}
|
|
1867
1858
|
if (Date.now() >= deadline) {
|
|
@@ -1870,12 +1861,12 @@ async function terminateSubagent(child, graceMs) {
|
|
|
1870
1861
|
child.kill("SIGKILL");
|
|
1871
1862
|
} catch {
|
|
1872
1863
|
}
|
|
1873
|
-
|
|
1864
|
+
resolve();
|
|
1874
1865
|
}
|
|
1875
1866
|
}, pollInterval);
|
|
1876
1867
|
child.once("close", () => {
|
|
1877
1868
|
clearInterval(timer);
|
|
1878
|
-
|
|
1869
|
+
resolve();
|
|
1879
1870
|
});
|
|
1880
1871
|
});
|
|
1881
1872
|
}
|
|
@@ -2225,9 +2216,9 @@ function getNestedValue(obj, keyPath) {
|
|
|
2225
2216
|
return current;
|
|
2226
2217
|
}
|
|
2227
2218
|
async function ensureDir(filePath) {
|
|
2228
|
-
const { mkdir:
|
|
2229
|
-
const { dirname:
|
|
2230
|
-
await
|
|
2219
|
+
const { mkdir: mkdir5 } = await import("fs/promises");
|
|
2220
|
+
const { dirname: dirname4 } = await import("path");
|
|
2221
|
+
await mkdir5(dirname4(filePath), { recursive: true });
|
|
2231
2222
|
}
|
|
2232
2223
|
|
|
2233
2224
|
// src/core/formats/json.ts
|
|
@@ -2672,11 +2663,11 @@ function parseSource(input) {
|
|
|
2672
2663
|
if (ghUrlMatch) {
|
|
2673
2664
|
const owner = ghUrlMatch[1];
|
|
2674
2665
|
const repo = ghUrlMatch[2];
|
|
2675
|
-
const
|
|
2666
|
+
const path = ghUrlMatch[4];
|
|
2676
2667
|
if (!owner || !repo) {
|
|
2677
2668
|
return { type: "command", value: input, inferredName: inferName(input, "command") };
|
|
2678
2669
|
}
|
|
2679
|
-
const inferredName =
|
|
2670
|
+
const inferredName = path ? path.split("/").pop() ?? repo : repo;
|
|
2680
2671
|
return {
|
|
2681
2672
|
type: "github",
|
|
2682
2673
|
value: input,
|
|
@@ -2684,18 +2675,18 @@ function parseSource(input) {
|
|
|
2684
2675
|
owner,
|
|
2685
2676
|
repo,
|
|
2686
2677
|
ref: ghUrlMatch[3],
|
|
2687
|
-
path
|
|
2678
|
+
path
|
|
2688
2679
|
};
|
|
2689
2680
|
}
|
|
2690
2681
|
const glUrlMatch = input.match(GITLAB_URL);
|
|
2691
2682
|
if (glUrlMatch) {
|
|
2692
2683
|
const owner = glUrlMatch[1];
|
|
2693
2684
|
const repo = glUrlMatch[2];
|
|
2694
|
-
const
|
|
2685
|
+
const path = glUrlMatch[4];
|
|
2695
2686
|
if (!owner || !repo) {
|
|
2696
2687
|
return { type: "command", value: input, inferredName: inferName(input, "command") };
|
|
2697
2688
|
}
|
|
2698
|
-
const inferredName =
|
|
2689
|
+
const inferredName = path ? path.split("/").pop() ?? repo : repo;
|
|
2699
2690
|
return {
|
|
2700
2691
|
type: "gitlab",
|
|
2701
2692
|
value: input,
|
|
@@ -2703,7 +2694,7 @@ function parseSource(input) {
|
|
|
2703
2694
|
owner,
|
|
2704
2695
|
repo,
|
|
2705
2696
|
ref: glUrlMatch[3],
|
|
2706
|
-
path
|
|
2697
|
+
path
|
|
2707
2698
|
};
|
|
2708
2699
|
}
|
|
2709
2700
|
if (HTTP_URL.test(input)) {
|
|
@@ -2724,18 +2715,18 @@ function parseSource(input) {
|
|
|
2724
2715
|
if (ghShorthand && !NPM_SCOPED.test(input)) {
|
|
2725
2716
|
const owner = ghShorthand[1];
|
|
2726
2717
|
const repo = ghShorthand[2];
|
|
2727
|
-
const
|
|
2718
|
+
const path = ghShorthand[3];
|
|
2728
2719
|
if (!owner || !repo) {
|
|
2729
2720
|
return { type: "command", value: input, inferredName: inferName(input, "command") };
|
|
2730
2721
|
}
|
|
2731
|
-
const inferredName =
|
|
2722
|
+
const inferredName = path ? path.split("/").pop() ?? repo : repo;
|
|
2732
2723
|
return {
|
|
2733
2724
|
type: "github",
|
|
2734
2725
|
value: `https://github.com/${owner}/${repo}`,
|
|
2735
2726
|
inferredName,
|
|
2736
2727
|
owner,
|
|
2737
2728
|
repo,
|
|
2738
|
-
path
|
|
2729
|
+
path
|
|
2739
2730
|
};
|
|
2740
2731
|
}
|
|
2741
2732
|
const libraryMatch = input.match(LIBRARY_SKILL);
|
|
@@ -3181,14 +3172,14 @@ async function scanFile(filePath, rules) {
|
|
|
3181
3172
|
return { file: filePath, findings, score, passed };
|
|
3182
3173
|
}
|
|
3183
3174
|
async function scanDirectory(dirPath) {
|
|
3184
|
-
const { readdir:
|
|
3185
|
-
const { join:
|
|
3175
|
+
const { readdir: readdir3 } = await import("fs/promises");
|
|
3176
|
+
const { join: join9 } = await import("path");
|
|
3186
3177
|
if (!existsSync10(dirPath)) return [];
|
|
3187
|
-
const entries = await
|
|
3178
|
+
const entries = await readdir3(dirPath, { withFileTypes: true });
|
|
3188
3179
|
const results = [];
|
|
3189
3180
|
for (const entry of entries) {
|
|
3190
3181
|
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
3191
|
-
const skillFile =
|
|
3182
|
+
const skillFile = join9(dirPath, entry.name, "SKILL.md");
|
|
3192
3183
|
if (existsSync10(skillFile)) {
|
|
3193
3184
|
results.push(await scanFile(skillFile));
|
|
3194
3185
|
}
|
|
@@ -3248,10 +3239,19 @@ import { simpleGit } from "simple-git";
|
|
|
3248
3239
|
// src/core/lock-utils.ts
|
|
3249
3240
|
import { existsSync as existsSync11 } from "fs";
|
|
3250
3241
|
import { mkdir as mkdir4, open as open2, readFile as readFile6, rename as rename2, rm as rm4, stat as stat3, writeFile as writeFile5 } from "fs/promises";
|
|
3242
|
+
|
|
3243
|
+
// src/core/paths/agents.ts
|
|
3244
|
+
var AGENTS_HOME = getAgentsHome();
|
|
3245
|
+
var LOCK_FILE_PATH = getLockFilePath();
|
|
3246
|
+
var AGENTS_MCP_DIR = getAgentsMcpDir();
|
|
3247
|
+
var AGENTS_MCP_SERVERS_PATH = getAgentsMcpServersPath();
|
|
3248
|
+
var AGENTS_CONFIG_PATH = getAgentsConfigPath();
|
|
3249
|
+
|
|
3250
|
+
// src/core/lock-utils.ts
|
|
3251
3251
|
var LOCK_GUARD_PATH = `${LOCK_FILE_PATH}.lock`;
|
|
3252
3252
|
var STALE_LOCK_MS = 5e3;
|
|
3253
3253
|
function sleep(ms) {
|
|
3254
|
-
return new Promise((
|
|
3254
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3255
3255
|
}
|
|
3256
3256
|
async function removeStaleLock() {
|
|
3257
3257
|
try {
|
|
@@ -3449,759 +3449,6 @@ async function checkAllSkillUpdates() {
|
|
|
3449
3449
|
return results;
|
|
3450
3450
|
}
|
|
3451
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
|
-
|
|
4205
3452
|
// src/core/network/fetch.ts
|
|
4206
3453
|
var DEFAULT_FETCH_TIMEOUT_MS = 1e4;
|
|
4207
3454
|
var NetworkError = class extends Error {
|
|
@@ -4778,9 +4025,9 @@ async function recommendSkills2(query, criteria, options = {}) {
|
|
|
4778
4025
|
}
|
|
4779
4026
|
|
|
4780
4027
|
// src/core/skills/library-loader.ts
|
|
4781
|
-
import { existsSync as
|
|
4028
|
+
import { existsSync as existsSync12, readdirSync, readFileSync } from "fs";
|
|
4782
4029
|
import { createRequire } from "module";
|
|
4783
|
-
import { basename as basename3, dirname as
|
|
4030
|
+
import { basename as basename3, dirname as dirname3, join as join6 } from "path";
|
|
4784
4031
|
var require2 = createRequire(import.meta.url);
|
|
4785
4032
|
function loadLibraryFromModule(root) {
|
|
4786
4033
|
let mod;
|
|
@@ -4826,16 +4073,16 @@ function loadLibraryFromModule(root) {
|
|
|
4826
4073
|
return mod;
|
|
4827
4074
|
}
|
|
4828
4075
|
function buildLibraryFromFiles(root) {
|
|
4829
|
-
const catalogPath =
|
|
4830
|
-
if (!
|
|
4076
|
+
const catalogPath = join6(root, "skills.json");
|
|
4077
|
+
if (!existsSync12(catalogPath)) {
|
|
4831
4078
|
throw new Error(`No skills.json found at ${root}`);
|
|
4832
4079
|
}
|
|
4833
4080
|
const catalogData = JSON.parse(readFileSync(catalogPath, "utf-8"));
|
|
4834
4081
|
const entries = catalogData.skills ?? [];
|
|
4835
4082
|
const version = catalogData.version ?? "0.0.0";
|
|
4836
|
-
const manifestPath =
|
|
4083
|
+
const manifestPath = join6(root, "skills", "manifest.json");
|
|
4837
4084
|
let manifest;
|
|
4838
|
-
if (
|
|
4085
|
+
if (existsSync12(manifestPath)) {
|
|
4839
4086
|
manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
4840
4087
|
} else {
|
|
4841
4088
|
manifest = {
|
|
@@ -4845,14 +4092,14 @@ function buildLibraryFromFiles(root) {
|
|
|
4845
4092
|
skills: []
|
|
4846
4093
|
};
|
|
4847
4094
|
}
|
|
4848
|
-
const profilesDir =
|
|
4095
|
+
const profilesDir = join6(root, "profiles");
|
|
4849
4096
|
const profiles = /* @__PURE__ */ new Map();
|
|
4850
|
-
if (
|
|
4851
|
-
for (const file of
|
|
4097
|
+
if (existsSync12(profilesDir)) {
|
|
4098
|
+
for (const file of readdirSync(profilesDir)) {
|
|
4852
4099
|
if (!file.endsWith(".json")) continue;
|
|
4853
4100
|
try {
|
|
4854
4101
|
const profile = JSON.parse(
|
|
4855
|
-
readFileSync(
|
|
4102
|
+
readFileSync(join6(profilesDir, file), "utf-8")
|
|
4856
4103
|
);
|
|
4857
4104
|
profiles.set(profile.name, profile);
|
|
4858
4105
|
} catch {
|
|
@@ -4866,9 +4113,9 @@ function buildLibraryFromFiles(root) {
|
|
|
4866
4113
|
function getSkillDir2(name) {
|
|
4867
4114
|
const entry = skillMap.get(name);
|
|
4868
4115
|
if (entry) {
|
|
4869
|
-
return
|
|
4116
|
+
return dirname3(join6(root, entry.path));
|
|
4870
4117
|
}
|
|
4871
|
-
return
|
|
4118
|
+
return join6(root, "skills", name);
|
|
4872
4119
|
}
|
|
4873
4120
|
function resolveDeps(names, visited = /* @__PURE__ */ new Set()) {
|
|
4874
4121
|
const result = [];
|
|
@@ -4896,8 +4143,8 @@ function buildLibraryFromFiles(root) {
|
|
|
4896
4143
|
return resolveDeps([...new Set(skills)]);
|
|
4897
4144
|
}
|
|
4898
4145
|
function discoverFiles(dir, ext) {
|
|
4899
|
-
if (!
|
|
4900
|
-
return
|
|
4146
|
+
if (!existsSync12(dir)) return [];
|
|
4147
|
+
return readdirSync(dir).filter((f) => f.endsWith(ext)).map((f) => basename3(f, ext));
|
|
4901
4148
|
}
|
|
4902
4149
|
const library = {
|
|
4903
4150
|
version,
|
|
@@ -4913,14 +4160,14 @@ function buildLibraryFromFiles(root) {
|
|
|
4913
4160
|
getSkillPath(name) {
|
|
4914
4161
|
const entry = skillMap.get(name);
|
|
4915
4162
|
if (entry) {
|
|
4916
|
-
return
|
|
4163
|
+
return join6(root, entry.path);
|
|
4917
4164
|
}
|
|
4918
|
-
return
|
|
4165
|
+
return join6(root, "skills", name, "SKILL.md");
|
|
4919
4166
|
},
|
|
4920
4167
|
getSkillDir: getSkillDir2,
|
|
4921
4168
|
readSkillContent(name) {
|
|
4922
4169
|
const skillPath = library.getSkillPath(name);
|
|
4923
|
-
if (!
|
|
4170
|
+
if (!existsSync12(skillPath)) {
|
|
4924
4171
|
throw new Error(`Skill content not found: ${skillPath}`);
|
|
4925
4172
|
}
|
|
4926
4173
|
return readFileSync(skillPath, "utf-8");
|
|
@@ -4947,11 +4194,11 @@ function buildLibraryFromFiles(root) {
|
|
|
4947
4194
|
return resolveProfileByName(name);
|
|
4948
4195
|
},
|
|
4949
4196
|
listSharedResources() {
|
|
4950
|
-
return discoverFiles(
|
|
4197
|
+
return discoverFiles(join6(root, "skills", "_shared"), ".md");
|
|
4951
4198
|
},
|
|
4952
4199
|
getSharedResourcePath(name) {
|
|
4953
|
-
const resourcePath =
|
|
4954
|
-
return
|
|
4200
|
+
const resourcePath = join6(root, "skills", "_shared", `${name}.md`);
|
|
4201
|
+
return existsSync12(resourcePath) ? resourcePath : void 0;
|
|
4955
4202
|
},
|
|
4956
4203
|
readSharedResource(name) {
|
|
4957
4204
|
const resourcePath = library.getSharedResourcePath(name);
|
|
@@ -4959,15 +4206,15 @@ function buildLibraryFromFiles(root) {
|
|
|
4959
4206
|
return readFileSync(resourcePath, "utf-8");
|
|
4960
4207
|
},
|
|
4961
4208
|
listProtocols() {
|
|
4962
|
-
const rootProtocols = discoverFiles(
|
|
4209
|
+
const rootProtocols = discoverFiles(join6(root, "protocols"), ".md");
|
|
4963
4210
|
if (rootProtocols.length > 0) return rootProtocols;
|
|
4964
|
-
return discoverFiles(
|
|
4211
|
+
return discoverFiles(join6(root, "skills", "protocols"), ".md");
|
|
4965
4212
|
},
|
|
4966
4213
|
getProtocolPath(name) {
|
|
4967
|
-
const rootPath =
|
|
4968
|
-
if (
|
|
4969
|
-
const skillsPath =
|
|
4970
|
-
return
|
|
4214
|
+
const rootPath = join6(root, "protocols", `${name}.md`);
|
|
4215
|
+
if (existsSync12(rootPath)) return rootPath;
|
|
4216
|
+
const skillsPath = join6(root, "skills", "protocols", `${name}.md`);
|
|
4217
|
+
return existsSync12(skillsPath) ? skillsPath : void 0;
|
|
4971
4218
|
},
|
|
4972
4219
|
readProtocol(name) {
|
|
4973
4220
|
const protocolPath = library.getProtocolPath(name);
|
|
@@ -4992,8 +4239,8 @@ function buildLibraryFromFiles(root) {
|
|
|
4992
4239
|
if (!entry.version) {
|
|
4993
4240
|
issues.push({ level: "warn", field: "version", message: "Missing version" });
|
|
4994
4241
|
}
|
|
4995
|
-
const skillPath =
|
|
4996
|
-
if (!
|
|
4242
|
+
const skillPath = join6(root, entry.path);
|
|
4243
|
+
if (!existsSync12(skillPath)) {
|
|
4997
4244
|
issues.push({
|
|
4998
4245
|
level: "error",
|
|
4999
4246
|
field: "path",
|
|
@@ -5052,15 +4299,15 @@ __export(catalog_exports, {
|
|
|
5052
4299
|
validateAll: () => validateAll,
|
|
5053
4300
|
validateSkillFrontmatter: () => validateSkillFrontmatter
|
|
5054
4301
|
});
|
|
5055
|
-
import { existsSync as
|
|
5056
|
-
import { join as
|
|
4302
|
+
import { existsSync as existsSync13 } from "fs";
|
|
4303
|
+
import { join as join7 } from "path";
|
|
5057
4304
|
var _library = null;
|
|
5058
4305
|
function registerSkillLibrary(library) {
|
|
5059
4306
|
_library = library;
|
|
5060
4307
|
}
|
|
5061
4308
|
function registerSkillLibraryFromPath(root) {
|
|
5062
|
-
const indexPath =
|
|
5063
|
-
if (
|
|
4309
|
+
const indexPath = join7(root, "index.js");
|
|
4310
|
+
if (existsSync13(indexPath)) {
|
|
5064
4311
|
_library = loadLibraryFromModule(root);
|
|
5065
4312
|
return;
|
|
5066
4313
|
}
|
|
@@ -5071,13 +4318,13 @@ function clearRegisteredLibrary() {
|
|
|
5071
4318
|
}
|
|
5072
4319
|
function discoverLibrary() {
|
|
5073
4320
|
const envPath = process.env["CAAMP_SKILL_LIBRARY"];
|
|
5074
|
-
if (envPath &&
|
|
4321
|
+
if (envPath && existsSync13(envPath)) {
|
|
5075
4322
|
try {
|
|
5076
|
-
const indexPath =
|
|
5077
|
-
if (
|
|
4323
|
+
const indexPath = join7(envPath, "index.js");
|
|
4324
|
+
if (existsSync13(indexPath)) {
|
|
5078
4325
|
return loadLibraryFromModule(envPath);
|
|
5079
4326
|
}
|
|
5080
|
-
if (
|
|
4327
|
+
if (existsSync13(join7(envPath, "skills.json"))) {
|
|
5081
4328
|
return buildLibraryFromFiles(envPath);
|
|
5082
4329
|
}
|
|
5083
4330
|
} catch {
|
|
@@ -5184,9 +4431,9 @@ function getLibraryRoot() {
|
|
|
5184
4431
|
}
|
|
5185
4432
|
|
|
5186
4433
|
// src/core/skills/discovery.ts
|
|
5187
|
-
import { existsSync as
|
|
5188
|
-
import { readdir as
|
|
5189
|
-
import { join as
|
|
4434
|
+
import { existsSync as existsSync14 } from "fs";
|
|
4435
|
+
import { readdir as readdir2, readFile as readFile7 } from "fs/promises";
|
|
4436
|
+
import { join as join8 } from "path";
|
|
5190
4437
|
import matter from "gray-matter";
|
|
5191
4438
|
async function parseSkillFile(filePath) {
|
|
5192
4439
|
try {
|
|
@@ -5210,8 +4457,8 @@ async function parseSkillFile(filePath) {
|
|
|
5210
4457
|
}
|
|
5211
4458
|
}
|
|
5212
4459
|
async function discoverSkill(skillDir) {
|
|
5213
|
-
const skillFile =
|
|
5214
|
-
if (!
|
|
4460
|
+
const skillFile = join8(skillDir, "SKILL.md");
|
|
4461
|
+
if (!existsSync14(skillFile)) return null;
|
|
5215
4462
|
const metadata = await parseSkillFile(skillFile);
|
|
5216
4463
|
if (!metadata) return null;
|
|
5217
4464
|
return {
|
|
@@ -5222,12 +4469,12 @@ async function discoverSkill(skillDir) {
|
|
|
5222
4469
|
};
|
|
5223
4470
|
}
|
|
5224
4471
|
async function discoverSkills(rootDir) {
|
|
5225
|
-
if (!
|
|
5226
|
-
const entries = await
|
|
4472
|
+
if (!existsSync14(rootDir)) return [];
|
|
4473
|
+
const entries = await readdir2(rootDir, { withFileTypes: true });
|
|
5227
4474
|
const skills = [];
|
|
5228
4475
|
for (const entry of entries) {
|
|
5229
4476
|
if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
|
|
5230
|
-
const skillDir =
|
|
4477
|
+
const skillDir = join8(rootDir, entry.name);
|
|
5231
4478
|
const skill = await discoverSkill(skillDir);
|
|
5232
4479
|
if (skill) {
|
|
5233
4480
|
skills.push(skill);
|
|
@@ -5251,7 +4498,7 @@ async function discoverSkillsMulti(dirs) {
|
|
|
5251
4498
|
}
|
|
5252
4499
|
|
|
5253
4500
|
// src/core/skills/validator.ts
|
|
5254
|
-
import { existsSync as
|
|
4501
|
+
import { existsSync as existsSync15 } from "fs";
|
|
5255
4502
|
import { readFile as readFile8 } from "fs/promises";
|
|
5256
4503
|
import matter2 from "gray-matter";
|
|
5257
4504
|
var RESERVED_NAMES = [
|
|
@@ -5273,7 +4520,7 @@ var WARN_BODY_LINES = 500;
|
|
|
5273
4520
|
var WARN_DESCRIPTION_LENGTH = 50;
|
|
5274
4521
|
async function validateSkill(filePath) {
|
|
5275
4522
|
const issues = [];
|
|
5276
|
-
if (!
|
|
4523
|
+
if (!existsSync15(filePath)) {
|
|
5277
4524
|
return {
|
|
5278
4525
|
valid: false,
|
|
5279
4526
|
issues: [{ level: "error", field: "file", message: "File does not exist" }],
|
|
@@ -5390,7 +4637,6 @@ async function validateSkill(filePath) {
|
|
|
5390
4637
|
}
|
|
5391
4638
|
|
|
5392
4639
|
export {
|
|
5393
|
-
CANONICAL_SKILLS_DIR,
|
|
5394
4640
|
setVerbose,
|
|
5395
4641
|
setQuiet,
|
|
5396
4642
|
isVerbose,
|
|
@@ -5429,14 +4675,6 @@ export {
|
|
|
5429
4675
|
readConfig,
|
|
5430
4676
|
writeConfig,
|
|
5431
4677
|
removeConfig,
|
|
5432
|
-
resolveFormat,
|
|
5433
|
-
buildEnvelope,
|
|
5434
|
-
emitError,
|
|
5435
|
-
emitJsonError,
|
|
5436
|
-
outputSuccess,
|
|
5437
|
-
handleFormatError,
|
|
5438
|
-
ErrorCategories,
|
|
5439
|
-
ErrorCodes,
|
|
5440
4678
|
readLockFile,
|
|
5441
4679
|
resolveMcpConfigPath,
|
|
5442
4680
|
listMcpServers,
|
|
@@ -5457,16 +4695,6 @@ export {
|
|
|
5457
4695
|
getTrackedSkills,
|
|
5458
4696
|
checkSkillUpdate,
|
|
5459
4697
|
checkAllSkillUpdates,
|
|
5460
|
-
AgentsSkillsRealDirError,
|
|
5461
|
-
buildBackupTimestamp,
|
|
5462
|
-
runDoctorBridge,
|
|
5463
|
-
registerDoctorBridge,
|
|
5464
|
-
discoverOrphans,
|
|
5465
|
-
applyDecision,
|
|
5466
|
-
writeAuditLog,
|
|
5467
|
-
runDoctorAdopt,
|
|
5468
|
-
caampStandaloneAdapters,
|
|
5469
|
-
registerSkillsDoctorAdopt,
|
|
5470
4698
|
MarketplaceClient,
|
|
5471
4699
|
RECOMMENDATION_ERROR_CODES,
|
|
5472
4700
|
tokenizeCriteriaValue,
|
|
@@ -5495,4 +4723,4 @@ export {
|
|
|
5495
4723
|
discoverSkillsMulti,
|
|
5496
4724
|
validateSkill
|
|
5497
4725
|
};
|
|
5498
|
-
//# sourceMappingURL=chunk-
|
|
4726
|
+
//# sourceMappingURL=chunk-RTK4A3WY.js.map
|