@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.
@@ -3,7 +3,7 @@ import {
3
3
  getPrimaryProvider,
4
4
  groupByInstructFile,
5
5
  injectAll
6
- } from "./chunk-OPUPNLUJ.js";
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-OCI4RYI5.js";
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
- async function installSkill(sourcePath, skillName, providers, isGlobal, projectDir) {
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: readdir3 } = await import("fs/promises");
306
- const entries = await readdir3(getCanonicalSkillsDir(), { withFileTypes: true });
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((resolve) => {
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
- resolve(result2);
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((resolve) => {
1860
+ await new Promise((resolve2) => {
1843
1861
  const timer = setInterval(() => {
1844
1862
  if (child.exitCode !== null || child.signalCode !== null) {
1845
1863
  clearInterval(timer);
1846
- resolve();
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
- resolve();
1873
+ resolve2();
1856
1874
  }
1857
1875
  }, pollInterval);
1858
1876
  child.once("close", () => {
1859
1877
  clearInterval(timer);
1860
- resolve();
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: mkdir5 } = await import("fs/promises");
2211
- const { dirname: dirname4 } = await import("path");
2212
- await mkdir5(dirname4(filePath), { recursive: true });
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 path = ghUrlMatch[4];
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 = path ? path.split("/").pop() ?? repo : repo;
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 path = glUrlMatch[4];
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 = path ? path.split("/").pop() ?? repo : repo;
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 path = ghShorthand[3];
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 = path ? path.split("/").pop() ?? repo : repo;
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: readdir3 } = await import("fs/promises");
3167
- const { join: join9 } = await import("path");
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 readdir3(dirPath, { withFileTypes: true });
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 = join9(dirPath, entry.name, "SKILL.md");
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((resolve) => setTimeout(resolve, ms));
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 existsSync12, readdirSync, readFileSync } from "fs";
4781
+ import { existsSync as existsSync14, readdirSync as readdirSync3, readFileSync } from "fs";
4011
4782
  import { createRequire } from "module";
4012
- import { basename as basename3, dirname as dirname3, join as join6 } from "path";
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 = join6(root, "skills.json");
4059
- if (!existsSync12(catalogPath)) {
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 = join6(root, "skills", "manifest.json");
4836
+ const manifestPath = join8(root, "skills", "manifest.json");
4066
4837
  let manifest;
4067
- if (existsSync12(manifestPath)) {
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 = join6(root, "profiles");
4848
+ const profilesDir = join8(root, "profiles");
4078
4849
  const profiles = /* @__PURE__ */ new Map();
4079
- if (existsSync12(profilesDir)) {
4080
- for (const file of readdirSync(profilesDir)) {
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(join6(profilesDir, file), "utf-8")
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 dirname3(join6(root, entry.path));
4869
+ return dirname4(join8(root, entry.path));
4099
4870
  }
4100
- return join6(root, "skills", name);
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 (!existsSync12(dir)) return [];
4129
- return readdirSync(dir).filter((f) => f.endsWith(ext)).map((f) => basename3(f, ext));
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 join6(root, entry.path);
4916
+ return join8(root, entry.path);
4146
4917
  }
4147
- return join6(root, "skills", name, "SKILL.md");
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 (!existsSync12(skillPath)) {
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(join6(root, "skills", "_shared"), ".md");
4950
+ return discoverFiles(join8(root, "skills", "_shared"), ".md");
4180
4951
  },
4181
4952
  getSharedResourcePath(name) {
4182
- const resourcePath = join6(root, "skills", "_shared", `${name}.md`);
4183
- return existsSync12(resourcePath) ? resourcePath : void 0;
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(join6(root, "protocols"), ".md");
4962
+ const rootProtocols = discoverFiles(join8(root, "protocols"), ".md");
4192
4963
  if (rootProtocols.length > 0) return rootProtocols;
4193
- return discoverFiles(join6(root, "skills", "protocols"), ".md");
4964
+ return discoverFiles(join8(root, "skills", "protocols"), ".md");
4194
4965
  },
4195
4966
  getProtocolPath(name) {
4196
- const rootPath = join6(root, "protocols", `${name}.md`);
4197
- if (existsSync12(rootPath)) return rootPath;
4198
- const skillsPath = join6(root, "skills", "protocols", `${name}.md`);
4199
- return existsSync12(skillsPath) ? skillsPath : void 0;
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 = join6(root, entry.path);
4225
- if (!existsSync12(skillPath)) {
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 existsSync13 } from "fs";
4285
- import { join as join7 } from "path";
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 = join7(root, "index.js");
4292
- if (existsSync13(indexPath)) {
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 && existsSync13(envPath)) {
5074
+ if (envPath && existsSync15(envPath)) {
4304
5075
  try {
4305
- const indexPath = join7(envPath, "index.js");
4306
- if (existsSync13(indexPath)) {
5076
+ const indexPath = join9(envPath, "index.js");
5077
+ if (existsSync15(indexPath)) {
4307
5078
  return loadLibraryFromModule(envPath);
4308
5079
  }
4309
- if (existsSync13(join7(envPath, "skills.json"))) {
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 existsSync14 } from "fs";
4417
- import { readdir as readdir2, readFile as readFile7 } from "fs/promises";
4418
- import { join as join8 } from "path";
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 = join8(skillDir, "SKILL.md");
4443
- if (!existsSync14(skillFile)) return null;
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 (!existsSync14(rootDir)) return [];
4455
- const entries = await readdir2(rootDir, { withFileTypes: true });
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 = join8(rootDir, entry.name);
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 existsSync15 } from "fs";
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 (!existsSync15(filePath)) {
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-4W35AEYA.js.map
5498
+ //# sourceMappingURL=chunk-WXL7RPS4.js.map