@cleocode/caamp 2026.5.82 → 2026.5.84

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: join10 } = 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 = join10(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,377 @@ 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
+ REMOVE_FAILED: "E_REMOVE_FAILED",
3558
+ UPDATE_FAILED: "E_UPDATE_FAILED",
3559
+ VALIDATION_FAILED: "E_VALIDATION_FAILED",
3560
+ AUDIT_FAILED: "E_AUDIT_FAILED",
3561
+ // System errors
3562
+ NETWORK_ERROR: "E_NETWORK_ERROR",
3563
+ FILE_SYSTEM_ERROR: "E_FILE_SYSTEM_ERROR",
3564
+ PERMISSION_DENIED: "E_PERMISSION_DENIED",
3565
+ INTERNAL_ERROR: "E_INTERNAL_ERROR"
3566
+ };
3567
+
3568
+ // src/commands/skills/doctor-bridge.ts
3569
+ var AgentsSkillsRealDirError = class extends Error {
3570
+ /** LAFS error code surfaced by the CLI. */
3571
+ code = "E_AGENTS_SKILLS_REAL_DIR";
3572
+ /** Resolved path of the offending real directory. */
3573
+ agentsSkillsPath;
3574
+ /** Number of immediate entries in the offending directory. */
3575
+ entryCount;
3576
+ /**
3577
+ * Construct an `AgentsSkillsRealDirError`.
3578
+ *
3579
+ * @param agentsSkillsPath - Path to the real `~/.agents/skills` directory.
3580
+ * @param entryCount - Number of entries inside the directory.
3581
+ */
3582
+ constructor(agentsSkillsPath, entryCount) {
3583
+ super(
3584
+ `Refusing to replace real directory at ${agentsSkillsPath} (${entryCount} entries). Pass --force to back up and bridge.`
3585
+ );
3586
+ this.name = "AgentsSkillsRealDirError";
3587
+ this.agentsSkillsPath = agentsSkillsPath;
3588
+ this.entryCount = entryCount;
3589
+ }
3590
+ };
3591
+ function buildBackupTimestamp() {
3592
+ const d = /* @__PURE__ */ new Date();
3593
+ const pad = (n) => n.toString().padStart(2, "0");
3594
+ return `${d.getUTCFullYear()}${pad(d.getUTCMonth() + 1)}${pad(d.getUTCDate())}-${pad(d.getUTCHours())}${pad(d.getUTCMinutes())}${pad(d.getUTCSeconds())}`;
3595
+ }
3596
+ function resolveBridgePaths(homeRoot) {
3597
+ return {
3598
+ skillsRoot: path.join(homeRoot, ".cleo", "skills"),
3599
+ bridgeTarget: path.join(homeRoot, ".claude", "skills", "agents-shared"),
3600
+ bridgePath: path.join(homeRoot, ".agents", "skills"),
3601
+ backupsRoot: path.join(homeRoot, ".cleo", "backups"),
3602
+ claudeSkillsRoot: path.join(homeRoot, ".claude", "skills")
3603
+ };
3604
+ }
3605
+ function listSkillDirs(skillsRoot) {
3606
+ if (!existsSync12(skillsRoot)) return [];
3607
+ const entries = readdirSync(skillsRoot, { withFileTypes: true });
3608
+ return entries.filter((e) => e.isDirectory() || e.isSymbolicLink()).map((e) => e.name).filter((n) => !n.startsWith(".")).sort();
3609
+ }
3610
+ function symlinkPointsAt(linkPath, target) {
3611
+ try {
3612
+ const stat4 = lstatSync3(linkPath);
3613
+ if (!stat4.isSymbolicLink()) return false;
3614
+ const current = readlinkSync(linkPath);
3615
+ const resolved = path.isAbsolute(current) ? current : path.resolve(path.dirname(linkPath), current);
3616
+ return path.resolve(resolved) === path.resolve(target);
3617
+ } catch {
3618
+ return false;
3619
+ }
3620
+ }
3621
+ async function ensureSymlink(linkPath, target, dryRun) {
3622
+ if (dryRun) return;
3623
+ await mkdir5(path.dirname(linkPath), { recursive: true });
3624
+ if (existsSync12(linkPath)) {
3625
+ try {
3626
+ await unlink(linkPath);
3627
+ } catch {
3628
+ }
3629
+ }
3630
+ await symlink3(target, linkPath, "dir");
3631
+ }
3632
+ async function countEntries(dir) {
3633
+ try {
3634
+ const entries = await readdir2(dir);
3635
+ return entries.length;
3636
+ } catch {
3637
+ return 0;
3638
+ }
3639
+ }
3640
+ async function runDoctorBridge(options = {}) {
3641
+ const homeRoot = options.homeDir ?? homedir3();
3642
+ const force = options.force ?? false;
3643
+ const dryRun = options.dryRun ?? false;
3644
+ const { skillsRoot, bridgeTarget, bridgePath, backupsRoot, claudeSkillsRoot } = resolveBridgePaths(homeRoot);
3645
+ if (!dryRun) {
3646
+ await mkdir5(bridgeTarget, { recursive: true });
3647
+ }
3648
+ const skillNames = listSkillDirs(skillsRoot);
3649
+ const created = [];
3650
+ for (const name of skillNames) {
3651
+ const linkPath = path.join(bridgeTarget, name);
3652
+ const target = path.join(skillsRoot, name);
3653
+ if (symlinkPointsAt(linkPath, target)) continue;
3654
+ await ensureSymlink(linkPath, target, dryRun);
3655
+ created.push({ name, linkPath, target });
3656
+ }
3657
+ const removed = [];
3658
+ if (existsSync12(claudeSkillsRoot)) {
3659
+ const entries = readdirSync(claudeSkillsRoot, { withFileTypes: true });
3660
+ for (const entry of entries) {
3661
+ if (entry.name === "agents-shared") continue;
3662
+ const entryPath = path.join(claudeSkillsRoot, entry.name);
3663
+ let stat4;
3664
+ try {
3665
+ stat4 = lstatSync3(entryPath);
3666
+ } catch {
3667
+ continue;
3668
+ }
3669
+ if (!stat4.isSymbolicLink()) continue;
3670
+ let resolvedTarget = null;
3671
+ try {
3672
+ const raw = readlinkSync(entryPath);
3673
+ resolvedTarget = path.isAbsolute(raw) ? raw : path.resolve(path.dirname(entryPath), raw);
3674
+ } catch {
3675
+ resolvedTarget = null;
3676
+ }
3677
+ if (resolvedTarget !== null) {
3678
+ const realResolved = (() => {
3679
+ try {
3680
+ return realpathSync(resolvedTarget);
3681
+ } catch {
3682
+ return resolvedTarget;
3683
+ }
3684
+ })();
3685
+ if (realResolved === bridgeTarget || realResolved.startsWith(`${bridgeTarget}${path.sep}`)) {
3686
+ continue;
3687
+ }
3688
+ }
3689
+ if (!dryRun) {
3690
+ await unlink(entryPath);
3691
+ }
3692
+ removed.push({ linkPath: entryPath, previousTarget: resolvedTarget });
3693
+ }
3694
+ }
3695
+ let backupPath = null;
3696
+ const bridgeAlreadyCorrect = symlinkPointsAt(bridgePath, bridgeTarget);
3697
+ let bridgeSymlinkActive = bridgeAlreadyCorrect;
3698
+ if (!bridgeAlreadyCorrect) {
3699
+ if (existsSync12(bridgePath)) {
3700
+ const lstat = lstatSync3(bridgePath);
3701
+ if (lstat.isSymbolicLink()) {
3702
+ if (!dryRun) await unlink(bridgePath);
3703
+ } else if (lstat.isDirectory()) {
3704
+ const entryCount = await countEntries(bridgePath);
3705
+ if (entryCount > 0 && !force) {
3706
+ throw new AgentsSkillsRealDirError(bridgePath, entryCount);
3707
+ }
3708
+ if (entryCount > 0) {
3709
+ backupPath = path.join(backupsRoot, `agents-skills-pre-bridge-${buildBackupTimestamp()}`);
3710
+ if (!dryRun) {
3711
+ await mkdir5(backupsRoot, { recursive: true });
3712
+ await cp4(bridgePath, backupPath, { recursive: true, dereference: false });
3713
+ await rm5(bridgePath, { recursive: true, force: true });
3714
+ }
3715
+ } else if (!dryRun) {
3716
+ await rm5(bridgePath, { recursive: true, force: true });
3717
+ }
3718
+ } else if (!dryRun) {
3719
+ await unlink(bridgePath);
3720
+ }
3721
+ }
3722
+ if (!dryRun) {
3723
+ await mkdir5(path.dirname(bridgePath), { recursive: true });
3724
+ await symlink3(bridgeTarget, bridgePath, "dir");
3725
+ bridgeSymlinkActive = true;
3726
+ }
3727
+ }
3728
+ return {
3729
+ bridgeCreated: !bridgeAlreadyCorrect,
3730
+ bridgeSymlinkActive,
3731
+ perSkillSymlinksCreated: created,
3732
+ perSkillSymlinksRemoved: removed,
3733
+ backupPath,
3734
+ dryRun,
3735
+ skillsRoot,
3736
+ bridgeTarget,
3737
+ bridgePath
3738
+ };
3739
+ }
3740
+ function printHumanSummary(result) {
3741
+ if (result.dryRun) {
3742
+ console.log(pc.dim("(dry-run \u2014 no disk state mutated)"));
3743
+ }
3744
+ if (!result.bridgeCreated && result.perSkillSymlinksCreated.length === 0) {
3745
+ console.log(pc.green("Bridge already correct \u2014 nothing to do."));
3746
+ } else {
3747
+ console.log(pc.green("Bridge configured."));
3748
+ }
3749
+ console.log(` ${pc.dim("bridge:")} ${result.bridgePath} -> ${result.bridgeTarget}`);
3750
+ console.log(
3751
+ ` ${pc.dim("per-skill symlinks created:")} ${result.perSkillSymlinksCreated.length}`
3752
+ );
3753
+ console.log(
3754
+ ` ${pc.dim("per-skill symlinks removed:")} ${result.perSkillSymlinksRemoved.length}`
3755
+ );
3756
+ if (result.backupPath) {
3757
+ console.log(` ${pc.yellow("backup:")} ${result.backupPath}`);
3758
+ }
3759
+ }
3760
+ function registerDoctorBridge(parent) {
3761
+ 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(
3762
+ async (opts) => {
3763
+ const operation = "skills.doctor.bridge";
3764
+ const mvi = "standard";
3765
+ let format;
3766
+ try {
3767
+ format = resolveFormat({
3768
+ jsonFlag: opts.json ?? false,
3769
+ humanFlag: opts.human ?? false,
3770
+ projectDefault: "json"
3771
+ });
3772
+ } catch (error) {
3773
+ const message = error instanceof Error ? error.message : String(error);
3774
+ emitJsonError(
3775
+ operation,
3776
+ mvi,
3777
+ ErrorCodes.FORMAT_CONFLICT,
3778
+ message,
3779
+ ErrorCategories.VALIDATION
3780
+ );
3781
+ process.exit(1);
3782
+ }
3783
+ try {
3784
+ const result = await runDoctorBridge({
3785
+ force: opts.force ?? false,
3786
+ dryRun: opts.dryRun ?? false
3787
+ });
3788
+ if (format === "json") {
3789
+ outputSuccess(operation, mvi, result);
3790
+ } else {
3791
+ printHumanSummary(result);
3792
+ }
3793
+ } catch (error) {
3794
+ if (error instanceof AgentsSkillsRealDirError) {
3795
+ if (format === "json") {
3796
+ emitJsonError(operation, mvi, error.code, error.message, ErrorCategories.CONFLICT, {
3797
+ agentsSkillsPath: error.agentsSkillsPath,
3798
+ entryCount: error.entryCount
3799
+ });
3800
+ } else {
3801
+ console.error(pc.red(error.message));
3802
+ }
3803
+ process.exit(1);
3804
+ }
3805
+ const message = error instanceof Error ? error.message : String(error);
3806
+ if (format === "json") {
3807
+ emitJsonError(
3808
+ operation,
3809
+ mvi,
3810
+ ErrorCodes.INTERNAL_ERROR,
3811
+ message,
3812
+ ErrorCategories.INTERNAL
3813
+ );
3814
+ } else {
3815
+ console.error(pc.red(message));
3816
+ }
3817
+ process.exit(1);
3818
+ }
3819
+ }
3820
+ );
3821
+ }
3822
+
3434
3823
  // src/core/network/fetch.ts
3435
3824
  var DEFAULT_FETCH_TIMEOUT_MS = 1e4;
3436
3825
  var NetworkError = class extends Error {
@@ -4007,9 +4396,9 @@ async function recommendSkills2(query, criteria, options = {}) {
4007
4396
  }
4008
4397
 
4009
4398
  // src/core/skills/library-loader.ts
4010
- import { existsSync as existsSync12, readdirSync, readFileSync } from "fs";
4399
+ import { existsSync as existsSync13, readdirSync as readdirSync2, readFileSync } from "fs";
4011
4400
  import { createRequire } from "module";
4012
- import { basename as basename3, dirname as dirname3, join as join6 } from "path";
4401
+ import { basename as basename3, dirname as dirname4, join as join7 } from "path";
4013
4402
  var require2 = createRequire(import.meta.url);
4014
4403
  function loadLibraryFromModule(root) {
4015
4404
  let mod;
@@ -4055,16 +4444,16 @@ function loadLibraryFromModule(root) {
4055
4444
  return mod;
4056
4445
  }
4057
4446
  function buildLibraryFromFiles(root) {
4058
- const catalogPath = join6(root, "skills.json");
4059
- if (!existsSync12(catalogPath)) {
4447
+ const catalogPath = join7(root, "skills.json");
4448
+ if (!existsSync13(catalogPath)) {
4060
4449
  throw new Error(`No skills.json found at ${root}`);
4061
4450
  }
4062
4451
  const catalogData = JSON.parse(readFileSync(catalogPath, "utf-8"));
4063
4452
  const entries = catalogData.skills ?? [];
4064
4453
  const version = catalogData.version ?? "0.0.0";
4065
- const manifestPath = join6(root, "skills", "manifest.json");
4454
+ const manifestPath = join7(root, "skills", "manifest.json");
4066
4455
  let manifest;
4067
- if (existsSync12(manifestPath)) {
4456
+ if (existsSync13(manifestPath)) {
4068
4457
  manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
4069
4458
  } else {
4070
4459
  manifest = {
@@ -4074,14 +4463,14 @@ function buildLibraryFromFiles(root) {
4074
4463
  skills: []
4075
4464
  };
4076
4465
  }
4077
- const profilesDir = join6(root, "profiles");
4466
+ const profilesDir = join7(root, "profiles");
4078
4467
  const profiles = /* @__PURE__ */ new Map();
4079
- if (existsSync12(profilesDir)) {
4080
- for (const file of readdirSync(profilesDir)) {
4468
+ if (existsSync13(profilesDir)) {
4469
+ for (const file of readdirSync2(profilesDir)) {
4081
4470
  if (!file.endsWith(".json")) continue;
4082
4471
  try {
4083
4472
  const profile = JSON.parse(
4084
- readFileSync(join6(profilesDir, file), "utf-8")
4473
+ readFileSync(join7(profilesDir, file), "utf-8")
4085
4474
  );
4086
4475
  profiles.set(profile.name, profile);
4087
4476
  } catch {
@@ -4095,9 +4484,9 @@ function buildLibraryFromFiles(root) {
4095
4484
  function getSkillDir2(name) {
4096
4485
  const entry = skillMap.get(name);
4097
4486
  if (entry) {
4098
- return dirname3(join6(root, entry.path));
4487
+ return dirname4(join7(root, entry.path));
4099
4488
  }
4100
- return join6(root, "skills", name);
4489
+ return join7(root, "skills", name);
4101
4490
  }
4102
4491
  function resolveDeps(names, visited = /* @__PURE__ */ new Set()) {
4103
4492
  const result = [];
@@ -4125,8 +4514,8 @@ function buildLibraryFromFiles(root) {
4125
4514
  return resolveDeps([...new Set(skills)]);
4126
4515
  }
4127
4516
  function discoverFiles(dir, ext) {
4128
- if (!existsSync12(dir)) return [];
4129
- return readdirSync(dir).filter((f) => f.endsWith(ext)).map((f) => basename3(f, ext));
4517
+ if (!existsSync13(dir)) return [];
4518
+ return readdirSync2(dir).filter((f) => f.endsWith(ext)).map((f) => basename3(f, ext));
4130
4519
  }
4131
4520
  const library = {
4132
4521
  version,
@@ -4142,14 +4531,14 @@ function buildLibraryFromFiles(root) {
4142
4531
  getSkillPath(name) {
4143
4532
  const entry = skillMap.get(name);
4144
4533
  if (entry) {
4145
- return join6(root, entry.path);
4534
+ return join7(root, entry.path);
4146
4535
  }
4147
- return join6(root, "skills", name, "SKILL.md");
4536
+ return join7(root, "skills", name, "SKILL.md");
4148
4537
  },
4149
4538
  getSkillDir: getSkillDir2,
4150
4539
  readSkillContent(name) {
4151
4540
  const skillPath = library.getSkillPath(name);
4152
- if (!existsSync12(skillPath)) {
4541
+ if (!existsSync13(skillPath)) {
4153
4542
  throw new Error(`Skill content not found: ${skillPath}`);
4154
4543
  }
4155
4544
  return readFileSync(skillPath, "utf-8");
@@ -4176,11 +4565,11 @@ function buildLibraryFromFiles(root) {
4176
4565
  return resolveProfileByName(name);
4177
4566
  },
4178
4567
  listSharedResources() {
4179
- return discoverFiles(join6(root, "skills", "_shared"), ".md");
4568
+ return discoverFiles(join7(root, "skills", "_shared"), ".md");
4180
4569
  },
4181
4570
  getSharedResourcePath(name) {
4182
- const resourcePath = join6(root, "skills", "_shared", `${name}.md`);
4183
- return existsSync12(resourcePath) ? resourcePath : void 0;
4571
+ const resourcePath = join7(root, "skills", "_shared", `${name}.md`);
4572
+ return existsSync13(resourcePath) ? resourcePath : void 0;
4184
4573
  },
4185
4574
  readSharedResource(name) {
4186
4575
  const resourcePath = library.getSharedResourcePath(name);
@@ -4188,15 +4577,15 @@ function buildLibraryFromFiles(root) {
4188
4577
  return readFileSync(resourcePath, "utf-8");
4189
4578
  },
4190
4579
  listProtocols() {
4191
- const rootProtocols = discoverFiles(join6(root, "protocols"), ".md");
4580
+ const rootProtocols = discoverFiles(join7(root, "protocols"), ".md");
4192
4581
  if (rootProtocols.length > 0) return rootProtocols;
4193
- return discoverFiles(join6(root, "skills", "protocols"), ".md");
4582
+ return discoverFiles(join7(root, "skills", "protocols"), ".md");
4194
4583
  },
4195
4584
  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;
4585
+ const rootPath = join7(root, "protocols", `${name}.md`);
4586
+ if (existsSync13(rootPath)) return rootPath;
4587
+ const skillsPath = join7(root, "skills", "protocols", `${name}.md`);
4588
+ return existsSync13(skillsPath) ? skillsPath : void 0;
4200
4589
  },
4201
4590
  readProtocol(name) {
4202
4591
  const protocolPath = library.getProtocolPath(name);
@@ -4221,8 +4610,8 @@ function buildLibraryFromFiles(root) {
4221
4610
  if (!entry.version) {
4222
4611
  issues.push({ level: "warn", field: "version", message: "Missing version" });
4223
4612
  }
4224
- const skillPath = join6(root, entry.path);
4225
- if (!existsSync12(skillPath)) {
4613
+ const skillPath = join7(root, entry.path);
4614
+ if (!existsSync13(skillPath)) {
4226
4615
  issues.push({
4227
4616
  level: "error",
4228
4617
  field: "path",
@@ -4281,15 +4670,15 @@ __export(catalog_exports, {
4281
4670
  validateAll: () => validateAll,
4282
4671
  validateSkillFrontmatter: () => validateSkillFrontmatter
4283
4672
  });
4284
- import { existsSync as existsSync13 } from "fs";
4285
- import { join as join7 } from "path";
4673
+ import { existsSync as existsSync14 } from "fs";
4674
+ import { join as join8 } from "path";
4286
4675
  var _library = null;
4287
4676
  function registerSkillLibrary(library) {
4288
4677
  _library = library;
4289
4678
  }
4290
4679
  function registerSkillLibraryFromPath(root) {
4291
- const indexPath = join7(root, "index.js");
4292
- if (existsSync13(indexPath)) {
4680
+ const indexPath = join8(root, "index.js");
4681
+ if (existsSync14(indexPath)) {
4293
4682
  _library = loadLibraryFromModule(root);
4294
4683
  return;
4295
4684
  }
@@ -4300,13 +4689,13 @@ function clearRegisteredLibrary() {
4300
4689
  }
4301
4690
  function discoverLibrary() {
4302
4691
  const envPath = process.env["CAAMP_SKILL_LIBRARY"];
4303
- if (envPath && existsSync13(envPath)) {
4692
+ if (envPath && existsSync14(envPath)) {
4304
4693
  try {
4305
- const indexPath = join7(envPath, "index.js");
4306
- if (existsSync13(indexPath)) {
4694
+ const indexPath = join8(envPath, "index.js");
4695
+ if (existsSync14(indexPath)) {
4307
4696
  return loadLibraryFromModule(envPath);
4308
4697
  }
4309
- if (existsSync13(join7(envPath, "skills.json"))) {
4698
+ if (existsSync14(join8(envPath, "skills.json"))) {
4310
4699
  return buildLibraryFromFiles(envPath);
4311
4700
  }
4312
4701
  } catch {
@@ -4413,9 +4802,9 @@ function getLibraryRoot() {
4413
4802
  }
4414
4803
 
4415
4804
  // 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";
4805
+ import { existsSync as existsSync15 } from "fs";
4806
+ import { readdir as readdir3, readFile as readFile7 } from "fs/promises";
4807
+ import { join as join9 } from "path";
4419
4808
  import matter from "gray-matter";
4420
4809
  async function parseSkillFile(filePath) {
4421
4810
  try {
@@ -4439,8 +4828,8 @@ async function parseSkillFile(filePath) {
4439
4828
  }
4440
4829
  }
4441
4830
  async function discoverSkill(skillDir) {
4442
- const skillFile = join8(skillDir, "SKILL.md");
4443
- if (!existsSync14(skillFile)) return null;
4831
+ const skillFile = join9(skillDir, "SKILL.md");
4832
+ if (!existsSync15(skillFile)) return null;
4444
4833
  const metadata = await parseSkillFile(skillFile);
4445
4834
  if (!metadata) return null;
4446
4835
  return {
@@ -4451,12 +4840,12 @@ async function discoverSkill(skillDir) {
4451
4840
  };
4452
4841
  }
4453
4842
  async function discoverSkills(rootDir) {
4454
- if (!existsSync14(rootDir)) return [];
4455
- const entries = await readdir2(rootDir, { withFileTypes: true });
4843
+ if (!existsSync15(rootDir)) return [];
4844
+ const entries = await readdir3(rootDir, { withFileTypes: true });
4456
4845
  const skills = [];
4457
4846
  for (const entry of entries) {
4458
4847
  if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
4459
- const skillDir = join8(rootDir, entry.name);
4848
+ const skillDir = join9(rootDir, entry.name);
4460
4849
  const skill = await discoverSkill(skillDir);
4461
4850
  if (skill) {
4462
4851
  skills.push(skill);
@@ -4480,7 +4869,7 @@ async function discoverSkillsMulti(dirs) {
4480
4869
  }
4481
4870
 
4482
4871
  // src/core/skills/validator.ts
4483
- import { existsSync as existsSync15 } from "fs";
4872
+ import { existsSync as existsSync16 } from "fs";
4484
4873
  import { readFile as readFile8 } from "fs/promises";
4485
4874
  import matter2 from "gray-matter";
4486
4875
  var RESERVED_NAMES = [
@@ -4502,7 +4891,7 @@ var WARN_BODY_LINES = 500;
4502
4891
  var WARN_DESCRIPTION_LENGTH = 50;
4503
4892
  async function validateSkill(filePath) {
4504
4893
  const issues = [];
4505
- if (!existsSync15(filePath)) {
4894
+ if (!existsSync16(filePath)) {
4506
4895
  return {
4507
4896
  valid: false,
4508
4897
  issues: [{ level: "error", field: "file", message: "File does not exist" }],
@@ -4631,6 +5020,7 @@ export {
4631
5020
  getInstalledProviders,
4632
5021
  detectProjectProviders,
4633
5022
  resetDetectionCache,
5023
+ inferSkillSourceType,
4634
5024
  installSkill,
4635
5025
  removeSkill,
4636
5026
  listCanonicalSkills,
@@ -4657,6 +5047,14 @@ export {
4657
5047
  readConfig,
4658
5048
  writeConfig,
4659
5049
  removeConfig,
5050
+ resolveFormat,
5051
+ buildEnvelope,
5052
+ emitError,
5053
+ emitJsonError,
5054
+ outputSuccess,
5055
+ handleFormatError,
5056
+ ErrorCategories,
5057
+ ErrorCodes,
4660
5058
  readLockFile,
4661
5059
  resolveMcpConfigPath,
4662
5060
  listMcpServers,
@@ -4677,6 +5075,10 @@ export {
4677
5075
  getTrackedSkills,
4678
5076
  checkSkillUpdate,
4679
5077
  checkAllSkillUpdates,
5078
+ AgentsSkillsRealDirError,
5079
+ buildBackupTimestamp,
5080
+ runDoctorBridge,
5081
+ registerDoctorBridge,
4680
5082
  MarketplaceClient,
4681
5083
  RECOMMENDATION_ERROR_CODES,
4682
5084
  tokenizeCriteriaValue,
@@ -4705,4 +5107,4 @@ export {
4705
5107
  discoverSkillsMulti,
4706
5108
  validateSkill
4707
5109
  };
4708
- //# sourceMappingURL=chunk-4W35AEYA.js.map
5110
+ //# sourceMappingURL=chunk-QSJSM57K.js.map