@cleocode/caamp 0.4.0 → 0.5.1

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.
@@ -1,58 +1,191 @@
1
- // src/core/registry/providers.ts
2
- import { readFileSync, existsSync } from "fs";
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/core/paths/standard.ts
8
+ import { existsSync } from "fs";
3
9
  import { homedir } from "os";
4
- import { join, dirname } from "path";
5
- import { fileURLToPath } from "url";
6
- function findRegistryPath() {
7
- const thisDir = dirname(fileURLToPath(import.meta.url));
8
- const devPath = join(thisDir, "..", "..", "..", "providers", "registry.json");
9
- if (existsSync(devPath)) return devPath;
10
- const distPath = join(thisDir, "..", "providers", "registry.json");
11
- if (existsSync(distPath)) return distPath;
12
- let dir = thisDir;
13
- for (let i = 0; i < 5; i++) {
14
- const candidate = join(dir, "providers", "registry.json");
15
- if (existsSync(candidate)) return candidate;
16
- dir = dirname(dir);
17
- }
18
- throw new Error(`Cannot find providers/registry.json (searched from ${thisDir})`);
19
- }
20
- var _registry = null;
21
- var _providers = null;
22
- var _aliasMap = null;
23
- function getPlatformPaths() {
10
+ import { dirname, isAbsolute, join, resolve } from "path";
11
+ function getPlatformLocations() {
24
12
  const home = homedir();
25
13
  const platform = process.platform;
26
14
  if (platform === "win32") {
27
15
  const appData = process.env["APPDATA"] ?? join(home, "AppData", "Roaming");
28
16
  return {
17
+ home,
29
18
  config: appData,
30
19
  vscodeConfig: join(appData, "Code", "User"),
31
20
  zedConfig: join(appData, "Zed"),
32
- claudeDesktopConfig: join(appData, "Claude")
21
+ claudeDesktopConfig: join(appData, "Claude"),
22
+ applications: []
33
23
  };
34
- } else if (platform === "darwin") {
24
+ }
25
+ if (platform === "darwin") {
26
+ const config2 = process.env["XDG_CONFIG_HOME"] ?? join(home, ".config");
35
27
  return {
36
- config: process.env["XDG_CONFIG_HOME"] ?? join(home, ".config"),
28
+ home,
29
+ config: config2,
37
30
  vscodeConfig: join(home, "Library", "Application Support", "Code", "User"),
38
31
  zedConfig: join(home, "Library", "Application Support", "Zed"),
39
- claudeDesktopConfig: join(home, "Library", "Application Support", "Claude")
40
- };
41
- } else {
42
- const config = process.env["XDG_CONFIG_HOME"] ?? join(home, ".config");
43
- return {
44
- config,
45
- vscodeConfig: join(config, "Code", "User"),
46
- zedConfig: join(config, "zed"),
47
- claudeDesktopConfig: join(config, "Claude")
32
+ claudeDesktopConfig: join(home, "Library", "Application Support", "Claude"),
33
+ applications: ["/Applications", join(home, "Applications")]
48
34
  };
49
35
  }
36
+ const config = process.env["XDG_CONFIG_HOME"] ?? join(home, ".config");
37
+ return {
38
+ home,
39
+ config,
40
+ vscodeConfig: join(config, "Code", "User"),
41
+ zedConfig: join(config, "zed"),
42
+ claudeDesktopConfig: join(config, "Claude"),
43
+ applications: []
44
+ };
50
45
  }
51
- function resolvePath(template) {
46
+ function normalizeHomeOverride(value) {
52
47
  const home = homedir();
53
- const paths = getPlatformPaths();
54
- return template.replace(/\$HOME/g, home).replace(/\$CONFIG/g, paths.config).replace(/\$VSCODE_CONFIG/g, paths.vscodeConfig).replace(/\$ZED_CONFIG/g, paths.zedConfig).replace(/\$CLAUDE_DESKTOP_CONFIG/g, paths.claudeDesktopConfig);
48
+ const trimmed = value.trim();
49
+ if (trimmed.startsWith("~/")) {
50
+ return join(home, trimmed.slice(2));
51
+ }
52
+ if (trimmed === "~") {
53
+ return home;
54
+ }
55
+ if (isAbsolute(trimmed)) {
56
+ return resolve(trimmed);
57
+ }
58
+ return resolve(home, trimmed);
55
59
  }
60
+ function getAgentsHome() {
61
+ const override = process.env["AGENTS_HOME"];
62
+ if (override && override.trim().length > 0) {
63
+ return normalizeHomeOverride(override);
64
+ }
65
+ return join(homedir(), ".agents");
66
+ }
67
+ function getProjectAgentsDir(projectRoot = process.cwd()) {
68
+ return join(projectRoot, ".agents");
69
+ }
70
+ function resolveProjectPath(relativePath, projectDir = process.cwd()) {
71
+ return join(projectDir, relativePath);
72
+ }
73
+ function getCanonicalSkillsDir() {
74
+ return join(getAgentsHome(), "skills");
75
+ }
76
+ function getLockFilePath() {
77
+ return join(getAgentsHome(), ".caamp-lock.json");
78
+ }
79
+ function getAgentsMcpDir(scope = "global", projectDir) {
80
+ if (scope === "global") return join(getAgentsHome(), "mcp");
81
+ return join(projectDir ?? process.cwd(), ".agents", "mcp");
82
+ }
83
+ function getAgentsMcpServersPath(scope = "global", projectDir) {
84
+ return join(getAgentsMcpDir(scope, projectDir), "servers.json");
85
+ }
86
+ function getAgentsInstructFile(scope = "global", projectDir) {
87
+ if (scope === "global") return join(getAgentsHome(), "AGENTS.md");
88
+ return join(projectDir ?? process.cwd(), ".agents", "AGENTS.md");
89
+ }
90
+ function getAgentsConfigPath(scope = "global", projectDir) {
91
+ if (scope === "global") return join(getAgentsHome(), "config.toml");
92
+ return join(projectDir ?? process.cwd(), ".agents", "config.toml");
93
+ }
94
+ function getAgentsWikiDir(scope = "global", projectDir) {
95
+ if (scope === "global") return join(getAgentsHome(), "wiki");
96
+ return join(projectDir ?? process.cwd(), ".agents", "wiki");
97
+ }
98
+ function getAgentsSpecDir(scope = "global", projectDir) {
99
+ if (scope === "global") return join(getAgentsHome(), "spec");
100
+ return join(projectDir ?? process.cwd(), ".agents", "spec");
101
+ }
102
+ function getAgentsLinksDir(scope = "global", projectDir) {
103
+ if (scope === "global") return join(getAgentsHome(), "links");
104
+ return join(projectDir ?? process.cwd(), ".agents", "links");
105
+ }
106
+ function resolveRegistryTemplatePath(template) {
107
+ const locations = getPlatformLocations();
108
+ return template.replace(/\$HOME/g, locations.home).replace(/\$CONFIG/g, locations.config).replace(/\$VSCODE_CONFIG/g, locations.vscodeConfig).replace(/\$ZED_CONFIG/g, locations.zedConfig).replace(/\$CLAUDE_DESKTOP_CONFIG/g, locations.claudeDesktopConfig).replace(/\$AGENTS_HOME/g, getAgentsHome());
109
+ }
110
+ function resolveProviderConfigPath(provider, scope, projectDir = process.cwd()) {
111
+ if (scope === "global") {
112
+ return provider.configPathGlobal;
113
+ }
114
+ if (!provider.configPathProject) {
115
+ return null;
116
+ }
117
+ return resolveProjectPath(provider.configPathProject, projectDir);
118
+ }
119
+ function resolvePreferredConfigScope(provider, useGlobalFlag) {
120
+ if (useGlobalFlag) {
121
+ return "global";
122
+ }
123
+ return provider.configPathProject ? "project" : "global";
124
+ }
125
+ function resolveProviderSkillsDir(provider, scope, projectDir = process.cwd()) {
126
+ if (scope === "global") {
127
+ return provider.pathSkills;
128
+ }
129
+ return resolveProjectPath(provider.pathProjectSkills, projectDir);
130
+ }
131
+ function resolveProviderProjectPath(provider, projectDir = process.cwd()) {
132
+ return resolveProjectPath(provider.pathProject, projectDir);
133
+ }
134
+ function resolveProvidersRegistryPath(startDir) {
135
+ const candidates = [
136
+ join(startDir, "..", "..", "..", "providers", "registry.json"),
137
+ join(startDir, "..", "providers", "registry.json")
138
+ ];
139
+ for (const candidate of candidates) {
140
+ if (existsSync(candidate)) {
141
+ return candidate;
142
+ }
143
+ }
144
+ let current = startDir;
145
+ for (let i = 0; i < 8; i += 1) {
146
+ const candidate = join(current, "providers", "registry.json");
147
+ if (existsSync(candidate)) {
148
+ return candidate;
149
+ }
150
+ current = dirname(current);
151
+ }
152
+ throw new Error(`Cannot find providers/registry.json (searched from ${startDir})`);
153
+ }
154
+ function normalizeSkillSubPath(path) {
155
+ if (!path) return void 0;
156
+ const normalized = path.replace(/\\/g, "/").replace(/^\/+/, "").replace(/\/SKILL\.md$/i, "").trim();
157
+ return normalized.length > 0 ? normalized : void 0;
158
+ }
159
+ function buildSkillSubPathCandidates(marketplacePath, parsedPath) {
160
+ const candidates = [];
161
+ const base = normalizeSkillSubPath(marketplacePath);
162
+ const parsed = normalizeSkillSubPath(parsedPath);
163
+ if (base) candidates.push(base);
164
+ if (parsed) candidates.push(parsed);
165
+ const knownPrefixes = [".agents", ".claude"];
166
+ for (const value of [base, parsed]) {
167
+ if (!value || !value.startsWith("skills/")) continue;
168
+ for (const prefix of knownPrefixes) {
169
+ candidates.push(`${prefix}/${value}`);
170
+ }
171
+ }
172
+ if (candidates.length === 0) {
173
+ candidates.push(void 0);
174
+ }
175
+ return Array.from(new Set(candidates));
176
+ }
177
+
178
+ // src/core/registry/providers.ts
179
+ import { readFileSync } from "fs";
180
+ import { dirname as dirname2 } from "path";
181
+ import { fileURLToPath } from "url";
182
+ function findRegistryPath() {
183
+ const thisDir = dirname2(fileURLToPath(import.meta.url));
184
+ return resolveProvidersRegistryPath(thisDir);
185
+ }
186
+ var _registry = null;
187
+ var _providers = null;
188
+ var _aliasMap = null;
56
189
  function resolveProvider(raw) {
57
190
  return {
58
191
  id: raw.id,
@@ -60,19 +193,19 @@ function resolveProvider(raw) {
60
193
  vendor: raw.vendor,
61
194
  agentFlag: raw.agentFlag,
62
195
  aliases: raw.aliases,
63
- pathGlobal: resolvePath(raw.pathGlobal),
196
+ pathGlobal: resolveRegistryTemplatePath(raw.pathGlobal),
64
197
  pathProject: raw.pathProject,
65
198
  instructFile: raw.instructFile,
66
199
  configKey: raw.configKey,
67
200
  configFormat: raw.configFormat,
68
- configPathGlobal: resolvePath(raw.configPathGlobal),
201
+ configPathGlobal: resolveRegistryTemplatePath(raw.configPathGlobal),
69
202
  configPathProject: raw.configPathProject,
70
- pathSkills: resolvePath(raw.pathSkills),
203
+ pathSkills: resolveRegistryTemplatePath(raw.pathSkills),
71
204
  pathProjectSkills: raw.pathProjectSkills,
72
205
  detection: {
73
206
  methods: raw.detection.methods,
74
207
  binary: raw.detection.binary,
75
- directories: raw.detection.directories?.map(resolvePath),
208
+ directories: raw.detection.directories?.map(resolveRegistryTemplatePath),
76
209
  appBundle: raw.detection.appBundle,
77
210
  flatpakId: raw.detection.flatpakId
78
211
  },
@@ -105,16 +238,17 @@ function ensureProviders() {
105
238
  }
106
239
  function getAllProviders() {
107
240
  ensureProviders();
241
+ if (!_providers) return [];
108
242
  return Array.from(_providers.values());
109
243
  }
110
244
  function getProvider(idOrAlias) {
111
245
  ensureProviders();
112
- const resolved = _aliasMap.get(idOrAlias) ?? idOrAlias;
113
- return _providers.get(resolved);
246
+ const resolved = _aliasMap?.get(idOrAlias) ?? idOrAlias;
247
+ return _providers?.get(resolved);
114
248
  }
115
249
  function resolveAlias(idOrAlias) {
116
250
  ensureProviders();
117
- return _aliasMap.get(idOrAlias) ?? idOrAlias;
251
+ return _aliasMap?.get(idOrAlias) ?? idOrAlias;
118
252
  }
119
253
  function getProvidersByPriority(priority) {
120
254
  return getAllProviders().filter((p) => p.priority === priority);
@@ -134,7 +268,7 @@ function getInstructionFiles() {
134
268
  }
135
269
  function getProviderCount() {
136
270
  ensureProviders();
137
- return _providers.size;
271
+ return _providers?.size ?? 0;
138
272
  }
139
273
  function getRegistryVersion() {
140
274
  return loadRegistry().version;
@@ -163,6 +297,8 @@ function isQuiet() {
163
297
  import { existsSync as existsSync2 } from "fs";
164
298
  import { execFileSync } from "child_process";
165
299
  import { join as join2 } from "path";
300
+ var DEFAULT_DETECTION_CACHE_TTL_MS = 3e4;
301
+ var detectionCache = null;
166
302
  function checkBinary(binary) {
167
303
  try {
168
304
  const cmd = process.platform === "win32" ? "where" : "which";
@@ -177,7 +313,8 @@ function checkDirectory(dir) {
177
313
  }
178
314
  function checkAppBundle(appName) {
179
315
  if (process.platform !== "darwin") return false;
180
- return existsSync2(join2("/Applications", appName));
316
+ const applications = getPlatformLocations().applications;
317
+ return applications.some((base) => existsSync2(join2(base, appName)));
181
318
  }
182
319
  function checkFlatpak(flatpakId) {
183
320
  if (process.platform !== "linux") return false;
@@ -229,24 +366,71 @@ function detectProvider(provider) {
229
366
  projectDetected: false
230
367
  };
231
368
  }
369
+ function providerSignature(provider) {
370
+ return JSON.stringify({
371
+ id: provider.id,
372
+ methods: provider.detection.methods,
373
+ binary: provider.detection.binary,
374
+ directories: provider.detection.directories,
375
+ appBundle: provider.detection.appBundle,
376
+ flatpakId: provider.detection.flatpakId
377
+ });
378
+ }
379
+ function buildProvidersSignature(providers) {
380
+ return providers.map(providerSignature).join("|");
381
+ }
382
+ function cloneDetectionResults(results) {
383
+ return results.map((result) => ({
384
+ provider: result.provider,
385
+ installed: result.installed,
386
+ methods: [...result.methods],
387
+ projectDetected: result.projectDetected
388
+ }));
389
+ }
390
+ function getCachedResults(signature, options) {
391
+ if (!detectionCache || options.forceRefresh) return null;
392
+ if (detectionCache.signature !== signature) return null;
393
+ const ttlMs = options.ttlMs ?? DEFAULT_DETECTION_CACHE_TTL_MS;
394
+ if (ttlMs <= 0) return null;
395
+ if (Date.now() - detectionCache.createdAt > ttlMs) return null;
396
+ return cloneDetectionResults(detectionCache.results);
397
+ }
398
+ function setCachedResults(signature, results) {
399
+ detectionCache = {
400
+ createdAt: Date.now(),
401
+ signature,
402
+ results: cloneDetectionResults(results)
403
+ };
404
+ }
232
405
  function detectProjectProvider(provider, projectDir) {
233
406
  if (!provider.pathProject) return false;
234
- return existsSync2(join2(projectDir, provider.pathProject));
407
+ return existsSync2(resolveProviderProjectPath(provider, projectDir));
235
408
  }
236
- function detectAllProviders() {
409
+ function detectAllProviders(options = {}) {
237
410
  const providers = getAllProviders();
238
- return providers.map(detectProvider);
411
+ const signature = buildProvidersSignature(providers);
412
+ const cached = getCachedResults(signature, options);
413
+ if (cached) {
414
+ debug(`detection cache hit for ${providers.length} providers`);
415
+ return cached;
416
+ }
417
+ const results = providers.map(detectProvider);
418
+ setCachedResults(signature, results);
419
+ return cloneDetectionResults(results);
239
420
  }
240
- function getInstalledProviders() {
241
- return detectAllProviders().filter((r) => r.installed).map((r) => r.provider);
421
+ function getInstalledProviders(options = {}) {
422
+ return detectAllProviders(options).filter((r) => r.installed).map((r) => r.provider);
242
423
  }
243
- function detectProjectProviders(projectDir) {
244
- const results = detectAllProviders();
424
+ function detectProjectProviders(projectDir, options = {}) {
425
+ const results = detectAllProviders(options);
245
426
  return results.map((r) => ({
246
427
  ...r,
247
428
  projectDetected: detectProjectProvider(r.provider, projectDir)
248
429
  }));
249
430
  }
431
+ function resetDetectionCache() {
432
+ detectionCache = null;
433
+ }
250
434
 
251
435
  // src/core/sources/parser.ts
252
436
  var GITHUB_SHORTHAND = /^([a-zA-Z0-9_.-]+)\/([a-zA-Z0-9_.-]+)(?:\/(.+))?$/;
@@ -261,13 +445,15 @@ function inferName(source, type) {
261
445
  const url = new URL(source);
262
446
  const parts = url.hostname.split(".");
263
447
  if (parts.length >= 2) {
264
- const brand = parts.length === 3 ? parts[parts.length - 2] : parts[0];
448
+ const fallback = parts[0] ?? source;
449
+ const secondLevel = parts[parts.length - 2] ?? fallback;
450
+ const brand = parts.length === 3 ? secondLevel : fallback;
265
451
  if (brand !== "www" && brand !== "api" && brand !== "mcp") {
266
452
  return brand;
267
453
  }
268
- return parts[parts.length - 2] ?? parts[0];
454
+ return secondLevel;
269
455
  }
270
- return parts[0];
456
+ return parts[0] ?? source;
271
457
  } catch {
272
458
  return source;
273
459
  }
@@ -284,6 +470,11 @@ function inferName(source, type) {
284
470
  const match = source.match(/\/([^/]+?)(?:\.git)?$/);
285
471
  return match?.[1] ?? source;
286
472
  }
473
+ if (type === "local") {
474
+ const normalized = source.replace(/\\/g, "/").replace(/\/+$/, "");
475
+ const lastSegment = normalized.split("/").pop();
476
+ return lastSegment ?? source;
477
+ }
287
478
  if (type === "command") {
288
479
  const parts = source.split(/\s+/);
289
480
  const command = parts.find((p) => !p.startsWith("-") && p !== "npx" && p !== "node" && p !== "python" && p !== "python3");
@@ -294,24 +485,34 @@ function inferName(source, type) {
294
485
  function parseSource(input) {
295
486
  const ghUrlMatch = input.match(GITHUB_URL);
296
487
  if (ghUrlMatch) {
488
+ const owner = ghUrlMatch[1];
489
+ const repo = ghUrlMatch[2];
490
+ if (!owner || !repo) {
491
+ return { type: "command", value: input, inferredName: inferName(input, "command") };
492
+ }
297
493
  return {
298
494
  type: "github",
299
495
  value: input,
300
- inferredName: ghUrlMatch[2],
301
- owner: ghUrlMatch[1],
302
- repo: ghUrlMatch[2],
496
+ inferredName: repo,
497
+ owner,
498
+ repo,
303
499
  ref: ghUrlMatch[3],
304
500
  path: ghUrlMatch[4]
305
501
  };
306
502
  }
307
503
  const glUrlMatch = input.match(GITLAB_URL);
308
504
  if (glUrlMatch) {
505
+ const owner = glUrlMatch[1];
506
+ const repo = glUrlMatch[2];
507
+ if (!owner || !repo) {
508
+ return { type: "command", value: input, inferredName: inferName(input, "command") };
509
+ }
309
510
  return {
310
511
  type: "gitlab",
311
512
  value: input,
312
- inferredName: glUrlMatch[2],
313
- owner: glUrlMatch[1],
314
- repo: glUrlMatch[2],
513
+ inferredName: repo,
514
+ owner,
515
+ repo,
315
516
  ref: glUrlMatch[3],
316
517
  path: glUrlMatch[4]
317
518
  };
@@ -332,12 +533,17 @@ function parseSource(input) {
332
533
  }
333
534
  const ghShorthand = input.match(GITHUB_SHORTHAND);
334
535
  if (ghShorthand && !NPM_SCOPED.test(input)) {
536
+ const owner = ghShorthand[1];
537
+ const repo = ghShorthand[2];
538
+ if (!owner || !repo) {
539
+ return { type: "command", value: input, inferredName: inferName(input, "command") };
540
+ }
335
541
  return {
336
542
  type: "github",
337
- value: `https://github.com/${ghShorthand[1]}/${ghShorthand[2]}`,
338
- inferredName: ghShorthand[2],
339
- owner: ghShorthand[1],
340
- repo: ghShorthand[2],
543
+ value: `https://github.com/${owner}/${repo}`,
544
+ inferredName: repo,
545
+ owner,
546
+ repo,
341
547
  path: ghShorthand[3]
342
548
  };
343
549
  }
@@ -368,15 +574,23 @@ function isMarketplaceScoped(input) {
368
574
  // src/core/skills/installer.ts
369
575
  import { mkdir, symlink, rm, cp } from "fs/promises";
370
576
  import { existsSync as existsSync3, lstatSync } from "fs";
371
- import { homedir as homedir2 } from "os";
372
577
  import { join as join3 } from "path";
373
- var CANONICAL_DIR = join3(homedir2(), ".agents", "skills");
578
+
579
+ // src/core/paths/agents.ts
580
+ var AGENTS_HOME = getAgentsHome();
581
+ var LOCK_FILE_PATH = getLockFilePath();
582
+ var CANONICAL_SKILLS_DIR = getCanonicalSkillsDir();
583
+ var AGENTS_MCP_DIR = getAgentsMcpDir();
584
+ var AGENTS_MCP_SERVERS_PATH = getAgentsMcpServersPath();
585
+ var AGENTS_CONFIG_PATH = getAgentsConfigPath();
586
+
587
+ // src/core/skills/installer.ts
374
588
  async function ensureCanonicalDir() {
375
- await mkdir(CANONICAL_DIR, { recursive: true });
589
+ await mkdir(CANONICAL_SKILLS_DIR, { recursive: true });
376
590
  }
377
591
  async function installToCanonical(sourcePath, skillName) {
378
592
  await ensureCanonicalDir();
379
- const targetDir = join3(CANONICAL_DIR, skillName);
593
+ const targetDir = join3(CANONICAL_SKILLS_DIR, skillName);
380
594
  if (existsSync3(targetDir)) {
381
595
  await rm(targetDir, { recursive: true });
382
596
  }
@@ -384,7 +598,11 @@ async function installToCanonical(sourcePath, skillName) {
384
598
  return targetDir;
385
599
  }
386
600
  async function linkToAgent(canonicalPath, provider, skillName, isGlobal, projectDir) {
387
- const targetSkillsDir = isGlobal ? provider.pathSkills : join3(projectDir ?? process.cwd(), provider.pathProjectSkills);
601
+ const targetSkillsDir = resolveProviderSkillsDir(
602
+ provider,
603
+ isGlobal ? "global" : "project",
604
+ projectDir
605
+ );
388
606
  if (!targetSkillsDir) {
389
607
  return { success: false, error: `Provider ${provider.id} has no skills directory` };
390
608
  }
@@ -437,7 +655,11 @@ async function removeSkill(skillName, providers, isGlobal, projectDir) {
437
655
  const removed = [];
438
656
  const errors = [];
439
657
  for (const provider of providers) {
440
- const skillsDir = isGlobal ? provider.pathSkills : join3(projectDir ?? process.cwd(), provider.pathProjectSkills);
658
+ const skillsDir = resolveProviderSkillsDir(
659
+ provider,
660
+ isGlobal ? "global" : "project",
661
+ projectDir
662
+ );
441
663
  if (!skillsDir) continue;
442
664
  const linkPath = join3(skillsDir, skillName);
443
665
  if (existsSync3(linkPath)) {
@@ -449,7 +671,7 @@ async function removeSkill(skillName, providers, isGlobal, projectDir) {
449
671
  }
450
672
  }
451
673
  }
452
- const canonicalPath = join3(CANONICAL_DIR, skillName);
674
+ const canonicalPath = join3(CANONICAL_SKILLS_DIR, skillName);
453
675
  if (existsSync3(canonicalPath)) {
454
676
  try {
455
677
  await rm(canonicalPath, { recursive: true });
@@ -460,62 +682,95 @@ async function removeSkill(skillName, providers, isGlobal, projectDir) {
460
682
  return { removed, errors };
461
683
  }
462
684
  async function listCanonicalSkills() {
463
- if (!existsSync3(CANONICAL_DIR)) return [];
685
+ if (!existsSync3(CANONICAL_SKILLS_DIR)) return [];
464
686
  const { readdir: readdir2 } = await import("fs/promises");
465
- const entries = await readdir2(CANONICAL_DIR, { withFileTypes: true });
687
+ const entries = await readdir2(CANONICAL_SKILLS_DIR, { withFileTypes: true });
466
688
  return entries.filter((e) => e.isDirectory() || e.isSymbolicLink()).map((e) => e.name);
467
689
  }
468
690
 
469
691
  // src/core/lock-utils.ts
470
- import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
692
+ import { open, readFile, writeFile, mkdir as mkdir2, rm as rm2, rename } from "fs/promises";
471
693
  import { existsSync as existsSync4 } from "fs";
472
- import { homedir as homedir3 } from "os";
473
- import { join as join4 } from "path";
474
- var LOCK_DIR = join4(homedir3(), ".agents");
475
- var LOCK_FILE = join4(LOCK_DIR, ".caamp-lock.json");
694
+ var LOCK_GUARD_PATH = `${LOCK_FILE_PATH}.lock`;
695
+ function sleep(ms) {
696
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
697
+ }
698
+ async function acquireLockGuard(retries = 40, delayMs = 25) {
699
+ await mkdir2(AGENTS_HOME, { recursive: true });
700
+ for (let attempt = 0; attempt < retries; attempt += 1) {
701
+ try {
702
+ const handle = await open(LOCK_GUARD_PATH, "wx");
703
+ await handle.close();
704
+ return;
705
+ } catch (error) {
706
+ if (!(error instanceof Error) || !("code" in error) || error.code !== "EEXIST") {
707
+ throw error;
708
+ }
709
+ await sleep(delayMs);
710
+ }
711
+ }
712
+ throw new Error("Timed out waiting for lock file guard");
713
+ }
714
+ async function releaseLockGuard() {
715
+ await rm2(LOCK_GUARD_PATH, { force: true });
716
+ }
717
+ async function writeLockFileUnsafe(lock) {
718
+ const tmpPath = `${LOCK_FILE_PATH}.tmp-${process.pid}-${Date.now()}`;
719
+ await writeFile(tmpPath, JSON.stringify(lock, null, 2) + "\n", "utf-8");
720
+ await rename(tmpPath, LOCK_FILE_PATH);
721
+ }
476
722
  async function readLockFile() {
477
723
  try {
478
- if (!existsSync4(LOCK_FILE)) {
724
+ if (!existsSync4(LOCK_FILE_PATH)) {
479
725
  return { version: 1, skills: {}, mcpServers: {} };
480
726
  }
481
- const content = await readFile2(LOCK_FILE, "utf-8");
727
+ const content = await readFile(LOCK_FILE_PATH, "utf-8");
482
728
  return JSON.parse(content);
483
729
  } catch {
484
730
  return { version: 1, skills: {}, mcpServers: {} };
485
731
  }
486
732
  }
487
- async function writeLockFile(lock) {
488
- await mkdir2(LOCK_DIR, { recursive: true });
489
- await writeFile2(LOCK_FILE, JSON.stringify(lock, null, 2) + "\n", "utf-8");
733
+ async function updateLockFile(updater) {
734
+ await acquireLockGuard();
735
+ try {
736
+ const lock = await readLockFile();
737
+ await updater(lock);
738
+ await writeLockFileUnsafe(lock);
739
+ return lock;
740
+ } finally {
741
+ await releaseLockGuard();
742
+ }
490
743
  }
491
744
 
492
745
  // src/core/skills/lock.ts
493
746
  import { simpleGit } from "simple-git";
494
747
  async function recordSkillInstall(skillName, scopedName, source, sourceType, agents, canonicalPath, isGlobal, projectDir, version) {
495
- const lock = await readLockFile();
496
- const now = (/* @__PURE__ */ new Date()).toISOString();
497
- const existing = lock.skills[skillName];
498
- lock.skills[skillName] = {
499
- name: skillName,
500
- scopedName,
501
- source,
502
- sourceType,
503
- version,
504
- installedAt: existing?.installedAt ?? now,
505
- updatedAt: now,
506
- agents: [.../* @__PURE__ */ new Set([...existing?.agents ?? [], ...agents])],
507
- canonicalPath,
508
- isGlobal,
509
- projectDir
510
- };
511
- await writeLockFile(lock);
748
+ await updateLockFile((lock) => {
749
+ const now = (/* @__PURE__ */ new Date()).toISOString();
750
+ const existing = lock.skills[skillName];
751
+ lock.skills[skillName] = {
752
+ name: skillName,
753
+ scopedName: existing?.scopedName ?? scopedName,
754
+ source: existing?.source ?? source,
755
+ sourceType: existing?.sourceType ?? sourceType,
756
+ version: version ?? existing?.version,
757
+ installedAt: existing?.installedAt ?? now,
758
+ updatedAt: now,
759
+ agents: [.../* @__PURE__ */ new Set([...existing?.agents ?? [], ...agents])],
760
+ canonicalPath,
761
+ isGlobal: existing?.isGlobal ?? isGlobal,
762
+ projectDir: existing?.projectDir ?? projectDir
763
+ };
764
+ });
512
765
  }
513
766
  async function removeSkillFromLock(skillName) {
514
- const lock = await readLockFile();
515
- if (!(skillName in lock.skills)) return false;
516
- delete lock.skills[skillName];
517
- await writeLockFile(lock);
518
- return true;
767
+ let removed = false;
768
+ await updateLockFile((lock) => {
769
+ if (!(skillName in lock.skills)) return;
770
+ delete lock.skills[skillName];
771
+ removed = true;
772
+ });
773
+ return removed;
519
774
  }
520
775
  async function getTrackedSkills() {
521
776
  const lock = await readLockFile();
@@ -827,33 +1082,33 @@ var MarketplaceClient = class {
827
1082
  };
828
1083
 
829
1084
  // src/core/skills/discovery.ts
830
- import { readFile as readFile3, readdir } from "fs/promises";
1085
+ import { readFile as readFile2, readdir } from "fs/promises";
831
1086
  import { existsSync as existsSync5 } from "fs";
832
- import { join as join5 } from "path";
1087
+ import { join as join4 } from "path";
833
1088
  import matter from "gray-matter";
834
1089
  async function parseSkillFile(filePath) {
835
1090
  try {
836
- const content = await readFile3(filePath, "utf-8");
1091
+ const content = await readFile2(filePath, "utf-8");
837
1092
  const { data } = matter(content);
838
- if (!data["name"] || !data["description"]) {
1093
+ if (!data.name || !data.description) {
839
1094
  return null;
840
1095
  }
841
- const allowedTools = data["allowed-tools"] ?? data["allowedTools"];
1096
+ const allowedTools = data["allowed-tools"] ?? data.allowedTools;
842
1097
  return {
843
- name: String(data["name"]),
844
- description: String(data["description"]),
845
- license: data["license"] ? String(data["license"]) : void 0,
846
- compatibility: data["compatibility"] ? String(data["compatibility"]) : void 0,
847
- metadata: data["metadata"],
1098
+ name: String(data.name),
1099
+ description: String(data.description),
1100
+ license: data.license ? String(data.license) : void 0,
1101
+ compatibility: data.compatibility ? String(data.compatibility) : void 0,
1102
+ metadata: data.metadata,
848
1103
  allowedTools: typeof allowedTools === "string" ? allowedTools.split(/\s+/) : Array.isArray(allowedTools) ? allowedTools.map(String) : void 0,
849
- version: data["version"] ? String(data["version"]) : void 0
1104
+ version: data.version ? String(data.version) : void 0
850
1105
  };
851
1106
  } catch {
852
1107
  return null;
853
1108
  }
854
1109
  }
855
1110
  async function discoverSkill(skillDir) {
856
- const skillFile = join5(skillDir, "SKILL.md");
1111
+ const skillFile = join4(skillDir, "SKILL.md");
857
1112
  if (!existsSync5(skillFile)) return null;
858
1113
  const metadata = await parseSkillFile(skillFile);
859
1114
  if (!metadata) return null;
@@ -870,7 +1125,7 @@ async function discoverSkills(rootDir) {
870
1125
  const skills = [];
871
1126
  for (const entry of entries) {
872
1127
  if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
873
- const skillDir = join5(rootDir, entry.name);
1128
+ const skillDir = join4(rootDir, entry.name);
874
1129
  const skill = await discoverSkill(skillDir);
875
1130
  if (skill) {
876
1131
  skills.push(skill);
@@ -893,6 +1148,135 @@ async function discoverSkillsMulti(dirs) {
893
1148
  return all;
894
1149
  }
895
1150
 
1151
+ // src/core/skills/catalog.ts
1152
+ var catalog_exports = {};
1153
+ __export(catalog_exports, {
1154
+ getCoreSkills: () => getCoreSkills,
1155
+ getDispatchMatrix: () => getDispatchMatrix,
1156
+ getLibraryRoot: () => getLibraryRoot,
1157
+ getManifest: () => getManifest,
1158
+ getProfile: () => getProfile,
1159
+ getProtocolPath: () => getProtocolPath,
1160
+ getSharedResourcePath: () => getSharedResourcePath,
1161
+ getSkill: () => getSkill,
1162
+ getSkillDependencies: () => getSkillDependencies,
1163
+ getSkillDir: () => getSkillDir,
1164
+ getSkillPath: () => getSkillPath,
1165
+ getSkills: () => getSkills,
1166
+ getSkillsByCategory: () => getSkillsByCategory,
1167
+ getVersion: () => getVersion,
1168
+ isCatalogAvailable: () => isCatalogAvailable,
1169
+ listProfiles: () => listProfiles,
1170
+ listProtocols: () => listProtocols,
1171
+ listSharedResources: () => listSharedResources,
1172
+ listSkills: () => listSkills,
1173
+ readProtocol: () => readProtocol,
1174
+ readSharedResource: () => readSharedResource,
1175
+ readSkillContent: () => readSkillContent,
1176
+ resolveDependencyTree: () => resolveDependencyTree,
1177
+ resolveProfile: () => resolveProfile,
1178
+ validateAll: () => validateAll,
1179
+ validateSkillFrontmatter: () => validateSkillFrontmatter
1180
+ });
1181
+ import { createRequire } from "module";
1182
+ var require2 = createRequire(import.meta.url);
1183
+ var _ctSkills;
1184
+ function getCtSkills() {
1185
+ if (!_ctSkills) {
1186
+ try {
1187
+ _ctSkills = require2("@cleocode/ct-skills");
1188
+ } catch {
1189
+ throw new Error(
1190
+ "@cleocode/ct-skills is not installed. Run: npm install @cleocode/ct-skills"
1191
+ );
1192
+ }
1193
+ }
1194
+ return _ctSkills;
1195
+ }
1196
+ function getSkills() {
1197
+ return getCtSkills().skills;
1198
+ }
1199
+ function getManifest() {
1200
+ return getCtSkills().manifest;
1201
+ }
1202
+ function listSkills() {
1203
+ return getCtSkills().listSkills();
1204
+ }
1205
+ function getSkill(name) {
1206
+ return getCtSkills().getSkill(name);
1207
+ }
1208
+ function getSkillPath(name) {
1209
+ return getCtSkills().getSkillPath(name);
1210
+ }
1211
+ function getSkillDir(name) {
1212
+ return getCtSkills().getSkillDir(name);
1213
+ }
1214
+ function readSkillContent(name) {
1215
+ return getCtSkills().readSkillContent(name);
1216
+ }
1217
+ function getCoreSkills() {
1218
+ return getCtSkills().getCoreSkills();
1219
+ }
1220
+ function getSkillsByCategory(category) {
1221
+ return getCtSkills().getSkillsByCategory(category);
1222
+ }
1223
+ function getSkillDependencies(name) {
1224
+ return getCtSkills().getSkillDependencies(name);
1225
+ }
1226
+ function resolveDependencyTree(names) {
1227
+ return getCtSkills().resolveDependencyTree(names);
1228
+ }
1229
+ function listProfiles() {
1230
+ return getCtSkills().listProfiles();
1231
+ }
1232
+ function getProfile(name) {
1233
+ return getCtSkills().getProfile(name);
1234
+ }
1235
+ function resolveProfile(name) {
1236
+ return getCtSkills().resolveProfile(name);
1237
+ }
1238
+ function listSharedResources() {
1239
+ return getCtSkills().listSharedResources();
1240
+ }
1241
+ function getSharedResourcePath(name) {
1242
+ return getCtSkills().getSharedResourcePath(name);
1243
+ }
1244
+ function readSharedResource(name) {
1245
+ return getCtSkills().readSharedResource(name);
1246
+ }
1247
+ function listProtocols() {
1248
+ return getCtSkills().listProtocols();
1249
+ }
1250
+ function getProtocolPath(name) {
1251
+ return getCtSkills().getProtocolPath(name);
1252
+ }
1253
+ function readProtocol(name) {
1254
+ return getCtSkills().readProtocol(name);
1255
+ }
1256
+ function validateSkillFrontmatter(name) {
1257
+ return getCtSkills().validateSkillFrontmatter(name);
1258
+ }
1259
+ function validateAll() {
1260
+ return getCtSkills().validateAll();
1261
+ }
1262
+ function getDispatchMatrix() {
1263
+ return getCtSkills().getDispatchMatrix();
1264
+ }
1265
+ function getVersion() {
1266
+ return getCtSkills().version;
1267
+ }
1268
+ function getLibraryRoot() {
1269
+ return getCtSkills().libraryRoot;
1270
+ }
1271
+ function isCatalogAvailable() {
1272
+ try {
1273
+ getCtSkills();
1274
+ return true;
1275
+ } catch {
1276
+ return false;
1277
+ }
1278
+ }
1279
+
896
1280
  // src/core/skills/recommendation.ts
897
1281
  var RECOMMENDATION_ERROR_CODES = {
898
1282
  QUERY_INVALID: "E_SKILLS_QUERY_INVALID",
@@ -1161,8 +1545,8 @@ async function recommendSkills2(query, criteria, options = {}) {
1161
1545
  }
1162
1546
 
1163
1547
  // src/core/skills/audit/scanner.ts
1164
- import { readFile as readFile4 } from "fs/promises";
1165
1548
  import { existsSync as existsSync6 } from "fs";
1549
+ import { readFile as readFile3 } from "fs/promises";
1166
1550
 
1167
1551
  // src/core/skills/audit/rules.ts
1168
1552
  function rule(id, name, description, severity, category, pattern) {
@@ -1232,7 +1616,7 @@ var AUDIT_RULES = [
1232
1616
  "Invisible characters or zero-width spaces",
1233
1617
  "medium",
1234
1618
  "prompt-injection",
1235
- /[\u200B\u200C\u200D\u2060\uFEFF]/
1619
+ /(?:\u200B|\u200C|\u200D|\u2060|\uFEFF)/
1236
1620
  ),
1237
1621
  // ── Command Injection ───────────────────────────────────────
1238
1622
  rule(
@@ -1544,13 +1928,13 @@ async function scanFile(filePath, rules) {
1544
1928
  if (!existsSync6(filePath)) {
1545
1929
  return { file: filePath, findings: [], score: 100, passed: true };
1546
1930
  }
1547
- const content = await readFile4(filePath, "utf-8");
1931
+ const content = await readFile3(filePath, "utf-8");
1548
1932
  const lines = content.split("\n");
1549
1933
  const activeRules = rules ?? AUDIT_RULES;
1550
1934
  const findings = [];
1551
1935
  for (const rule2 of activeRules) {
1552
1936
  for (let i = 0; i < lines.length; i++) {
1553
- const line = lines[i];
1937
+ const line = lines[i] ?? "";
1554
1938
  const match = line.match(rule2.pattern);
1555
1939
  if (match) {
1556
1940
  findings.push({
@@ -1573,13 +1957,13 @@ async function scanFile(filePath, rules) {
1573
1957
  }
1574
1958
  async function scanDirectory(dirPath) {
1575
1959
  const { readdir: readdir2 } = await import("fs/promises");
1576
- const { join: join9 } = await import("path");
1960
+ const { join: join7 } = await import("path");
1577
1961
  if (!existsSync6(dirPath)) return [];
1578
1962
  const entries = await readdir2(dirPath, { withFileTypes: true });
1579
1963
  const results = [];
1580
1964
  for (const entry of entries) {
1581
1965
  if (entry.isDirectory() || entry.isSymbolicLink()) {
1582
- const skillFile = join9(dirPath, entry.name, "SKILL.md");
1966
+ const skillFile = join7(dirPath, entry.name, "SKILL.md");
1583
1967
  if (existsSync6(skillFile)) {
1584
1968
  results.push(await scanFile(skillFile));
1585
1969
  }
@@ -1632,7 +2016,7 @@ function toSarif(results) {
1632
2016
  }
1633
2017
 
1634
2018
  // src/core/skills/validator.ts
1635
- import { readFile as readFile5 } from "fs/promises";
2019
+ import { readFile as readFile4 } from "fs/promises";
1636
2020
  import { existsSync as existsSync7 } from "fs";
1637
2021
  import matter2 from "gray-matter";
1638
2022
  var RESERVED_NAMES = [
@@ -1661,7 +2045,7 @@ async function validateSkill(filePath) {
1661
2045
  metadata: null
1662
2046
  };
1663
2047
  }
1664
- const content = await readFile5(filePath, "utf-8");
2048
+ const content = await readFile4(filePath, "utf-8");
1665
2049
  if (!content.startsWith("---")) {
1666
2050
  issues.push({
1667
2051
  level: "error",
@@ -1684,10 +2068,10 @@ async function validateSkill(filePath) {
1684
2068
  });
1685
2069
  return { valid: false, issues, metadata: null };
1686
2070
  }
1687
- if (!data["name"]) {
2071
+ if (!data.name) {
1688
2072
  issues.push({ level: "error", field: "name", message: "Missing required field: name" });
1689
2073
  } else {
1690
- const name = String(data["name"]);
2074
+ const name = String(data.name);
1691
2075
  if (name.length > MAX_NAME_LENGTH) {
1692
2076
  issues.push({
1693
2077
  level: "error",
@@ -1717,10 +2101,10 @@ async function validateSkill(filePath) {
1717
2101
  });
1718
2102
  }
1719
2103
  }
1720
- if (!data["description"]) {
2104
+ if (!data.description) {
1721
2105
  issues.push({ level: "error", field: "description", message: "Missing required field: description" });
1722
2106
  } else {
1723
- const desc = String(data["description"]);
2107
+ const desc = String(data.description);
1724
2108
  if (desc.length > MAX_DESCRIPTION_LENGTH) {
1725
2109
  issues.push({
1726
2110
  level: "error",
@@ -1799,12 +2183,12 @@ async function ensureDir(filePath) {
1799
2183
  }
1800
2184
 
1801
2185
  // src/core/formats/json.ts
1802
- import { readFile as readFile6, writeFile as writeFile3 } from "fs/promises";
2186
+ import { readFile as readFile5, writeFile as writeFile2 } from "fs/promises";
1803
2187
  import { existsSync as existsSync8 } from "fs";
1804
2188
  import * as jsonc from "jsonc-parser";
1805
2189
  async function readJsonConfig(filePath) {
1806
2190
  if (!existsSync8(filePath)) return {};
1807
- const content = await readFile6(filePath, "utf-8");
2191
+ const content = await readFile5(filePath, "utf-8");
1808
2192
  if (!content.trim()) return {};
1809
2193
  const errors = [];
1810
2194
  const result = jsonc.parse(content, errors);
@@ -1831,7 +2215,7 @@ async function writeJsonConfig(filePath, configKey, serverName, serverConfig) {
1831
2215
  await ensureDir(filePath);
1832
2216
  let content;
1833
2217
  if (existsSync8(filePath)) {
1834
- content = await readFile6(filePath, "utf-8");
2218
+ content = await readFile5(filePath, "utf-8");
1835
2219
  if (!content.trim()) {
1836
2220
  content = "{}";
1837
2221
  }
@@ -1853,11 +2237,11 @@ async function writeJsonConfig(filePath, configKey, serverName, serverConfig) {
1853
2237
  if (!content.endsWith("\n")) {
1854
2238
  content += "\n";
1855
2239
  }
1856
- await writeFile3(filePath, content, "utf-8");
2240
+ await writeFile2(filePath, content, "utf-8");
1857
2241
  }
1858
2242
  async function removeJsonConfig(filePath, configKey, serverName) {
1859
2243
  if (!existsSync8(filePath)) return false;
1860
- let content = await readFile6(filePath, "utf-8");
2244
+ let content = await readFile5(filePath, "utf-8");
1861
2245
  if (!content.trim()) return false;
1862
2246
  const { tabSize, insertSpaces } = detectIndent(content);
1863
2247
  const formatOptions = {
@@ -1873,17 +2257,17 @@ async function removeJsonConfig(filePath, configKey, serverName) {
1873
2257
  if (!content.endsWith("\n")) {
1874
2258
  content += "\n";
1875
2259
  }
1876
- await writeFile3(filePath, content, "utf-8");
2260
+ await writeFile2(filePath, content, "utf-8");
1877
2261
  return true;
1878
2262
  }
1879
2263
 
1880
2264
  // src/core/formats/yaml.ts
1881
- import { readFile as readFile7, writeFile as writeFile4 } from "fs/promises";
1882
2265
  import { existsSync as existsSync9 } from "fs";
2266
+ import { readFile as readFile6, writeFile as writeFile3 } from "fs/promises";
1883
2267
  import yaml from "js-yaml";
1884
2268
  async function readYamlConfig(filePath) {
1885
2269
  if (!existsSync9(filePath)) return {};
1886
- const content = await readFile7(filePath, "utf-8");
2270
+ const content = await readFile6(filePath, "utf-8");
1887
2271
  if (!content.trim()) return {};
1888
2272
  const result = yaml.load(content);
1889
2273
  return result ?? {};
@@ -1893,8 +2277,8 @@ async function writeYamlConfig(filePath, configKey, serverName, serverConfig) {
1893
2277
  const existing = await readYamlConfig(filePath);
1894
2278
  const keyParts = configKey.split(".");
1895
2279
  let newEntry = { [serverName]: serverConfig };
1896
- for (let i = keyParts.length - 1; i >= 0; i--) {
1897
- newEntry = { [keyParts[i]]: newEntry };
2280
+ for (const part of [...keyParts].reverse()) {
2281
+ newEntry = { [part]: newEntry };
1898
2282
  }
1899
2283
  const merged = deepMerge(existing, newEntry);
1900
2284
  const content = yaml.dump(merged, {
@@ -1903,7 +2287,7 @@ async function writeYamlConfig(filePath, configKey, serverName, serverConfig) {
1903
2287
  noRefs: true,
1904
2288
  sortKeys: false
1905
2289
  });
1906
- await writeFile4(filePath, content, "utf-8");
2290
+ await writeFile3(filePath, content, "utf-8");
1907
2291
  }
1908
2292
  async function removeYamlConfig(filePath, configKey, serverName) {
1909
2293
  if (!existsSync9(filePath)) return false;
@@ -1923,17 +2307,17 @@ async function removeYamlConfig(filePath, configKey, serverName) {
1923
2307
  noRefs: true,
1924
2308
  sortKeys: false
1925
2309
  });
1926
- await writeFile4(filePath, content, "utf-8");
2310
+ await writeFile3(filePath, content, "utf-8");
1927
2311
  return true;
1928
2312
  }
1929
2313
 
1930
2314
  // src/core/formats/toml.ts
1931
- import { readFile as readFile8, writeFile as writeFile5 } from "fs/promises";
1932
2315
  import { existsSync as existsSync10 } from "fs";
2316
+ import { readFile as readFile7, writeFile as writeFile4 } from "fs/promises";
1933
2317
  import TOML from "@iarna/toml";
1934
2318
  async function readTomlConfig(filePath) {
1935
2319
  if (!existsSync10(filePath)) return {};
1936
- const content = await readFile8(filePath, "utf-8");
2320
+ const content = await readFile7(filePath, "utf-8");
1937
2321
  if (!content.trim()) return {};
1938
2322
  const result = TOML.parse(content);
1939
2323
  return result;
@@ -1943,12 +2327,12 @@ async function writeTomlConfig(filePath, configKey, serverName, serverConfig) {
1943
2327
  const existing = await readTomlConfig(filePath);
1944
2328
  const keyParts = configKey.split(".");
1945
2329
  let newEntry = { [serverName]: serverConfig };
1946
- for (let i = keyParts.length - 1; i >= 0; i--) {
1947
- newEntry = { [keyParts[i]]: newEntry };
2330
+ for (const part of [...keyParts].reverse()) {
2331
+ newEntry = { [part]: newEntry };
1948
2332
  }
1949
2333
  const merged = deepMerge(existing, newEntry);
1950
2334
  const content = TOML.stringify(merged);
1951
- await writeFile5(filePath, content, "utf-8");
2335
+ await writeFile4(filePath, content, "utf-8");
1952
2336
  }
1953
2337
  async function removeTomlConfig(filePath, configKey, serverName) {
1954
2338
  if (!existsSync10(filePath)) return false;
@@ -1963,7 +2347,7 @@ async function removeTomlConfig(filePath, configKey, serverName) {
1963
2347
  if (!(serverName in current)) return false;
1964
2348
  delete current[serverName];
1965
2349
  const content = TOML.stringify(existing);
1966
- await writeFile5(filePath, content, "utf-8");
2350
+ await writeFile4(filePath, content, "utf-8");
1967
2351
  return true;
1968
2352
  }
1969
2353
 
@@ -2010,6 +2394,83 @@ async function removeConfig(filePath, format, key, serverName) {
2010
2394
  }
2011
2395
  }
2012
2396
 
2397
+ // src/core/mcp/reader.ts
2398
+ import { existsSync as existsSync11 } from "fs";
2399
+ function resolveConfigPath(provider, scope, projectDir) {
2400
+ return resolveProviderConfigPath(provider, scope, projectDir ?? process.cwd());
2401
+ }
2402
+ async function listMcpServers(provider, scope, projectDir) {
2403
+ const configPath = resolveConfigPath(provider, scope, projectDir);
2404
+ debug(`listing MCP servers for ${provider.id} (${scope}) at ${configPath ?? "(none)"}`);
2405
+ if (!configPath || !existsSync11(configPath)) return [];
2406
+ try {
2407
+ const config = await readConfig(configPath, provider.configFormat);
2408
+ const servers = getNestedValue(config, provider.configKey);
2409
+ if (!servers || typeof servers !== "object") return [];
2410
+ const entries = [];
2411
+ for (const [name, cfg] of Object.entries(servers)) {
2412
+ entries.push({
2413
+ name,
2414
+ providerId: provider.id,
2415
+ providerName: provider.toolName,
2416
+ scope,
2417
+ configPath,
2418
+ config: cfg ?? {}
2419
+ });
2420
+ }
2421
+ return entries;
2422
+ } catch {
2423
+ return [];
2424
+ }
2425
+ }
2426
+ async function listAgentsMcpServers(scope, projectDir) {
2427
+ const serversPath = getAgentsMcpServersPath(scope, projectDir);
2428
+ debug(`listing .agents/ MCP servers (${scope}) at ${serversPath}`);
2429
+ if (!existsSync11(serversPath)) return [];
2430
+ try {
2431
+ const config = await readConfig(serversPath, "json");
2432
+ const servers = config["servers"];
2433
+ if (!servers || typeof servers !== "object") return [];
2434
+ const entries = [];
2435
+ for (const [name, cfg] of Object.entries(servers)) {
2436
+ entries.push({
2437
+ name,
2438
+ providerId: ".agents",
2439
+ providerName: ".agents/ standard",
2440
+ scope,
2441
+ configPath: serversPath,
2442
+ config: cfg ?? {}
2443
+ });
2444
+ }
2445
+ return entries;
2446
+ } catch {
2447
+ return [];
2448
+ }
2449
+ }
2450
+ async function listAllMcpServers(providers, scope, projectDir) {
2451
+ const seen = /* @__PURE__ */ new Set();
2452
+ const allEntries = [];
2453
+ const agentsServersPath = getAgentsMcpServersPath(scope, projectDir);
2454
+ const agentsEntries = await listAgentsMcpServers(scope, projectDir);
2455
+ if (agentsEntries.length > 0) {
2456
+ allEntries.push(...agentsEntries);
2457
+ seen.add(agentsServersPath);
2458
+ }
2459
+ for (const provider of providers) {
2460
+ const configPath = resolveConfigPath(provider, scope, projectDir);
2461
+ if (!configPath || seen.has(configPath)) continue;
2462
+ seen.add(configPath);
2463
+ const entries = await listMcpServers(provider, scope, projectDir);
2464
+ allEntries.push(...entries);
2465
+ }
2466
+ return allEntries;
2467
+ }
2468
+ async function removeMcpServer(provider, serverName, scope, projectDir) {
2469
+ const configPath = resolveConfigPath(provider, scope, projectDir);
2470
+ if (!configPath) return false;
2471
+ return removeConfig(configPath, provider.configFormat, provider.configKey, serverName);
2472
+ }
2473
+
2013
2474
  // src/core/mcp/transforms.ts
2014
2475
  function transformGoose(serverName, config) {
2015
2476
  if (config.url) {
@@ -2033,7 +2494,7 @@ function transformGoose(serverName, config) {
2033
2494
  timeout: 300
2034
2495
  };
2035
2496
  }
2036
- function transformZed(serverName, config) {
2497
+ function transformZed(_serverName, config) {
2037
2498
  if (config.url) {
2038
2499
  return {
2039
2500
  source: "custom",
@@ -2049,7 +2510,7 @@ function transformZed(serverName, config) {
2049
2510
  ...config.env ? { env: config.env } : {}
2050
2511
  };
2051
2512
  }
2052
- function transformOpenCode(serverName, config) {
2513
+ function transformOpenCode(_serverName, config) {
2053
2514
  if (config.url) {
2054
2515
  return {
2055
2516
  type: "remote",
@@ -2066,7 +2527,7 @@ function transformOpenCode(serverName, config) {
2066
2527
  ...config.env ? { environment: config.env } : {}
2067
2528
  };
2068
2529
  }
2069
- function transformCodex(serverName, config) {
2530
+ function transformCodex(_serverName, config) {
2070
2531
  if (config.url) {
2071
2532
  return {
2072
2533
  type: config.type ?? "http",
@@ -2080,7 +2541,7 @@ function transformCodex(serverName, config) {
2080
2541
  ...config.env ? { env: config.env } : {}
2081
2542
  };
2082
2543
  }
2083
- function transformCursor(serverName, config) {
2544
+ function transformCursor(_serverName, config) {
2084
2545
  if (config.url) {
2085
2546
  return {
2086
2547
  url: config.url,
@@ -2106,58 +2567,6 @@ function getTransform(providerId) {
2106
2567
  }
2107
2568
  }
2108
2569
 
2109
- // src/core/mcp/reader.ts
2110
- import { join as join6 } from "path";
2111
- import { existsSync as existsSync11 } from "fs";
2112
- function resolveConfigPath(provider, scope, projectDir) {
2113
- if (scope === "project") {
2114
- if (!provider.configPathProject) return null;
2115
- return join6(projectDir ?? process.cwd(), provider.configPathProject);
2116
- }
2117
- return provider.configPathGlobal;
2118
- }
2119
- async function listMcpServers(provider, scope, projectDir) {
2120
- const configPath = resolveConfigPath(provider, scope, projectDir);
2121
- debug(`listing MCP servers for ${provider.id} (${scope}) at ${configPath ?? "(none)"}`);
2122
- if (!configPath || !existsSync11(configPath)) return [];
2123
- try {
2124
- const config = await readConfig(configPath, provider.configFormat);
2125
- const servers = getNestedValue(config, provider.configKey);
2126
- if (!servers || typeof servers !== "object") return [];
2127
- const entries = [];
2128
- for (const [name, cfg] of Object.entries(servers)) {
2129
- entries.push({
2130
- name,
2131
- providerId: provider.id,
2132
- providerName: provider.toolName,
2133
- scope,
2134
- configPath,
2135
- config: cfg ?? {}
2136
- });
2137
- }
2138
- return entries;
2139
- } catch {
2140
- return [];
2141
- }
2142
- }
2143
- async function listAllMcpServers(providers, scope, projectDir) {
2144
- const seen = /* @__PURE__ */ new Set();
2145
- const allEntries = [];
2146
- for (const provider of providers) {
2147
- const configPath = resolveConfigPath(provider, scope, projectDir);
2148
- if (!configPath || seen.has(configPath)) continue;
2149
- seen.add(configPath);
2150
- const entries = await listMcpServers(provider, scope, projectDir);
2151
- allEntries.push(...entries);
2152
- }
2153
- return allEntries;
2154
- }
2155
- async function removeMcpServer(provider, serverName, scope, projectDir) {
2156
- const configPath = resolveConfigPath(provider, scope, projectDir);
2157
- if (!configPath) return false;
2158
- return removeConfig(configPath, provider.configFormat, provider.configKey, serverName);
2159
- }
2160
-
2161
2570
  // src/core/mcp/installer.ts
2162
2571
  function buildConfig(provider, serverName, config) {
2163
2572
  const transform = getTransform(provider.id);
@@ -2228,46 +2637,49 @@ function buildServerConfig(source, transport, headers) {
2228
2637
  args: ["-y", source.value]
2229
2638
  };
2230
2639
  }
2231
- const parts = source.value.split(/\s+/);
2640
+ const parts = source.value.trim().split(/\s+/);
2641
+ const command = parts[0] ?? source.value;
2232
2642
  return {
2233
- command: parts[0],
2643
+ command,
2234
2644
  args: parts.slice(1)
2235
2645
  };
2236
2646
  }
2237
2647
 
2238
2648
  // src/core/mcp/lock.ts
2239
2649
  async function recordMcpInstall(serverName, source, sourceType, agents, isGlobal) {
2240
- const lock = await readLockFile();
2241
- const now = (/* @__PURE__ */ new Date()).toISOString();
2242
- const existing = lock.mcpServers[serverName];
2243
- lock.mcpServers[serverName] = {
2244
- name: serverName,
2245
- scopedName: serverName,
2246
- source,
2247
- sourceType,
2248
- installedAt: existing?.installedAt ?? now,
2249
- updatedAt: now,
2250
- agents: [.../* @__PURE__ */ new Set([...existing?.agents ?? [], ...agents])],
2251
- canonicalPath: "",
2252
- isGlobal
2253
- };
2254
- await writeLockFile(lock);
2650
+ await updateLockFile((lock) => {
2651
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2652
+ const existing = lock.mcpServers[serverName];
2653
+ lock.mcpServers[serverName] = {
2654
+ name: serverName,
2655
+ scopedName: serverName,
2656
+ source,
2657
+ sourceType,
2658
+ installedAt: existing?.installedAt ?? now,
2659
+ updatedAt: now,
2660
+ agents: [.../* @__PURE__ */ new Set([...existing?.agents ?? [], ...agents])],
2661
+ canonicalPath: "",
2662
+ isGlobal
2663
+ };
2664
+ });
2255
2665
  }
2256
2666
  async function removeMcpFromLock(serverName) {
2257
- const lock = await readLockFile();
2258
- if (!(serverName in lock.mcpServers)) return false;
2259
- delete lock.mcpServers[serverName];
2260
- await writeLockFile(lock);
2261
- return true;
2667
+ let removed = false;
2668
+ await updateLockFile((lock) => {
2669
+ if (!(serverName in lock.mcpServers)) return;
2670
+ delete lock.mcpServers[serverName];
2671
+ removed = true;
2672
+ });
2673
+ return removed;
2262
2674
  }
2263
2675
  async function getTrackedMcpServers() {
2264
2676
  const lock = await readLockFile();
2265
2677
  return lock.mcpServers;
2266
2678
  }
2267
2679
  async function saveLastSelectedAgents(agents) {
2268
- const lock = await readLockFile();
2269
- lock.lastSelectedAgents = agents;
2270
- await writeLockFile(lock);
2680
+ await updateLockFile((lock) => {
2681
+ lock.lastSelectedAgents = agents;
2682
+ });
2271
2683
  }
2272
2684
  async function getLastSelectedAgents() {
2273
2685
  const lock = await readLockFile();
@@ -2275,16 +2687,16 @@ async function getLastSelectedAgents() {
2275
2687
  }
2276
2688
 
2277
2689
  // src/core/instructions/injector.ts
2278
- import { readFile as readFile9, writeFile as writeFile6 } from "fs/promises";
2690
+ import { readFile as readFile8, writeFile as writeFile5 } from "fs/promises";
2279
2691
  import { existsSync as existsSync12 } from "fs";
2280
- import { join as join7, dirname as dirname3 } from "path";
2692
+ import { join as join5, dirname as dirname3 } from "path";
2281
2693
  import { mkdir as mkdir3 } from "fs/promises";
2282
2694
  var MARKER_START = "<!-- CAAMP:START -->";
2283
2695
  var MARKER_END = "<!-- CAAMP:END -->";
2284
2696
  var MARKER_PATTERN = /<!-- CAAMP:START -->[\s\S]*?<!-- CAAMP:END -->/;
2285
2697
  async function checkInjection(filePath, expectedContent) {
2286
2698
  if (!existsSync12(filePath)) return "missing";
2287
- const content = await readFile9(filePath, "utf-8");
2699
+ const content = await readFile8(filePath, "utf-8");
2288
2700
  if (!MARKER_PATTERN.test(content)) return "none";
2289
2701
  if (expectedContent) {
2290
2702
  const blockContent = extractBlock(content);
@@ -2309,29 +2721,33 @@ async function inject(filePath, content) {
2309
2721
  const block = buildBlock(content);
2310
2722
  await mkdir3(dirname3(filePath), { recursive: true });
2311
2723
  if (!existsSync12(filePath)) {
2312
- await writeFile6(filePath, block + "\n", "utf-8");
2724
+ await writeFile5(filePath, `${block}
2725
+ `, "utf-8");
2313
2726
  return "created";
2314
2727
  }
2315
- const existing = await readFile9(filePath, "utf-8");
2728
+ const existing = await readFile8(filePath, "utf-8");
2316
2729
  if (MARKER_PATTERN.test(existing)) {
2317
2730
  const updated2 = existing.replace(MARKER_PATTERN, block);
2318
- await writeFile6(filePath, updated2, "utf-8");
2731
+ await writeFile5(filePath, updated2, "utf-8");
2319
2732
  return "updated";
2320
2733
  }
2321
- const updated = block + "\n\n" + existing;
2322
- await writeFile6(filePath, updated, "utf-8");
2734
+ const updated = `${block}
2735
+
2736
+ ${existing}`;
2737
+ await writeFile5(filePath, updated, "utf-8");
2323
2738
  return "added";
2324
2739
  }
2325
2740
  async function removeInjection(filePath) {
2326
2741
  if (!existsSync12(filePath)) return false;
2327
- const content = await readFile9(filePath, "utf-8");
2742
+ const content = await readFile8(filePath, "utf-8");
2328
2743
  if (!MARKER_PATTERN.test(content)) return false;
2329
2744
  const cleaned = content.replace(MARKER_PATTERN, "").replace(/^\n{2,}/, "\n").trim();
2330
2745
  if (!cleaned) {
2331
- const { rm: rm3 } = await import("fs/promises");
2332
- await rm3(filePath);
2746
+ const { rm: rm4 } = await import("fs/promises");
2747
+ await rm4(filePath);
2333
2748
  } else {
2334
- await writeFile6(filePath, cleaned + "\n", "utf-8");
2749
+ await writeFile5(filePath, `${cleaned}
2750
+ `, "utf-8");
2335
2751
  }
2336
2752
  return true;
2337
2753
  }
@@ -2339,7 +2755,7 @@ async function checkAllInjections(providers, projectDir, scope, expectedContent)
2339
2755
  const results = [];
2340
2756
  const checked = /* @__PURE__ */ new Set();
2341
2757
  for (const provider of providers) {
2342
- const filePath = scope === "global" ? join7(provider.pathGlobal, provider.instructFile) : join7(projectDir, provider.instructFile);
2758
+ const filePath = scope === "global" ? join5(provider.pathGlobal, provider.instructFile) : join5(projectDir, provider.instructFile);
2343
2759
  if (checked.has(filePath)) continue;
2344
2760
  checked.add(filePath);
2345
2761
  const status = await checkInjection(filePath, expectedContent);
@@ -2356,7 +2772,7 @@ async function injectAll(providers, projectDir, scope, content) {
2356
2772
  const results = /* @__PURE__ */ new Map();
2357
2773
  const injected = /* @__PURE__ */ new Set();
2358
2774
  for (const provider of providers) {
2359
- const filePath = scope === "global" ? join7(provider.pathGlobal, provider.instructFile) : join7(projectDir, provider.instructFile);
2775
+ const filePath = scope === "global" ? join5(provider.pathGlobal, provider.instructFile) : join5(projectDir, provider.instructFile);
2360
2776
  if (injected.has(filePath)) continue;
2361
2777
  injected.add(filePath);
2362
2778
  const action = await inject(filePath, content);
@@ -2398,27 +2814,26 @@ import { existsSync as existsSync13, lstatSync as lstatSync2 } from "fs";
2398
2814
  import {
2399
2815
  cp as cp2,
2400
2816
  mkdir as mkdir4,
2401
- readFile as readFile10,
2402
- readlink as readlink2,
2403
- rm as rm2,
2817
+ readFile as readFile9,
2818
+ readlink,
2819
+ rm as rm3,
2404
2820
  symlink as symlink2,
2405
- writeFile as writeFile7
2821
+ writeFile as writeFile6
2406
2822
  } from "fs/promises";
2407
- import { homedir as homedir4, tmpdir } from "os";
2408
- import { basename as basename2, dirname as dirname4, join as join8 } from "path";
2823
+ import { tmpdir } from "os";
2824
+ import { basename, dirname as dirname4, join as join6 } from "path";
2409
2825
  var PRIORITY_ORDER = {
2410
2826
  high: 0,
2411
2827
  medium: 1,
2412
2828
  low: 2
2413
2829
  };
2414
- var CANONICAL_SKILLS_DIR = join8(homedir4(), ".agents", "skills");
2415
2830
  function selectProvidersByMinimumPriority(providers, minimumPriority = "low") {
2416
2831
  const maxRank = PRIORITY_ORDER[minimumPriority];
2417
2832
  return [...providers].filter((provider) => PRIORITY_ORDER[provider.priority] <= maxRank).sort((a, b) => PRIORITY_ORDER[a.priority] - PRIORITY_ORDER[b.priority]);
2418
2833
  }
2419
2834
  function resolveSkillLinkPath(provider, skillName, isGlobal, projectDir) {
2420
- const skillDir = isGlobal ? provider.pathSkills : join8(projectDir, provider.pathProjectSkills);
2421
- return join8(skillDir, skillName);
2835
+ const skillDir = isGlobal ? provider.pathSkills : join6(projectDir, provider.pathProjectSkills);
2836
+ return join6(skillDir, skillName);
2422
2837
  }
2423
2838
  async function snapshotConfigs(paths) {
2424
2839
  const snapshots = /* @__PURE__ */ new Map();
@@ -2428,26 +2843,26 @@ async function snapshotConfigs(paths) {
2428
2843
  snapshots.set(path, null);
2429
2844
  continue;
2430
2845
  }
2431
- snapshots.set(path, await readFile10(path, "utf-8"));
2846
+ snapshots.set(path, await readFile9(path, "utf-8"));
2432
2847
  }
2433
2848
  return snapshots;
2434
2849
  }
2435
2850
  async function restoreConfigSnapshots(snapshots) {
2436
2851
  for (const [path, content] of snapshots) {
2437
2852
  if (content === null) {
2438
- await rm2(path, { force: true });
2853
+ await rm3(path, { force: true });
2439
2854
  continue;
2440
2855
  }
2441
2856
  await mkdir4(dirname4(path), { recursive: true });
2442
- await writeFile7(path, content, "utf-8");
2857
+ await writeFile6(path, content, "utf-8");
2443
2858
  }
2444
2859
  }
2445
2860
  async function snapshotSkillState(providerTargets, operation, projectDir, backupRoot) {
2446
2861
  const skillName = operation.skillName;
2447
2862
  const isGlobal = operation.isGlobal ?? true;
2448
- const canonicalPath = join8(CANONICAL_SKILLS_DIR, skillName);
2863
+ const canonicalPath = join6(CANONICAL_SKILLS_DIR, skillName);
2449
2864
  const canonicalExisted = existsSync13(canonicalPath);
2450
- const canonicalBackupPath = join8(backupRoot, "canonical", skillName);
2865
+ const canonicalBackupPath = join6(backupRoot, "canonical", skillName);
2451
2866
  if (canonicalExisted) {
2452
2867
  await mkdir4(dirname4(canonicalBackupPath), { recursive: true });
2453
2868
  await cp2(canonicalPath, canonicalBackupPath, { recursive: true });
@@ -2464,11 +2879,11 @@ async function snapshotSkillState(providerTargets, operation, projectDir, backup
2464
2879
  pathSnapshots.push({
2465
2880
  linkPath,
2466
2881
  state: "symlink",
2467
- symlinkTarget: await readlink2(linkPath)
2882
+ symlinkTarget: await readlink(linkPath)
2468
2883
  });
2469
2884
  continue;
2470
2885
  }
2471
- const backupPath = join8(backupRoot, "links", provider.id, `${skillName}-${basename2(linkPath)}`);
2886
+ const backupPath = join6(backupRoot, "links", provider.id, `${skillName}-${basename(linkPath)}`);
2472
2887
  await mkdir4(dirname4(backupPath), { recursive: true });
2473
2888
  if (stat.isDirectory()) {
2474
2889
  await cp2(linkPath, backupPath, { recursive: true });
@@ -2489,14 +2904,14 @@ async function snapshotSkillState(providerTargets, operation, projectDir, backup
2489
2904
  }
2490
2905
  async function restoreSkillSnapshot(snapshot) {
2491
2906
  if (existsSync13(snapshot.canonicalPath)) {
2492
- await rm2(snapshot.canonicalPath, { recursive: true, force: true });
2907
+ await rm3(snapshot.canonicalPath, { recursive: true, force: true });
2493
2908
  }
2494
2909
  if (snapshot.canonicalExisted && snapshot.canonicalBackupPath && existsSync13(snapshot.canonicalBackupPath)) {
2495
2910
  await mkdir4(dirname4(snapshot.canonicalPath), { recursive: true });
2496
2911
  await cp2(snapshot.canonicalBackupPath, snapshot.canonicalPath, { recursive: true });
2497
2912
  }
2498
2913
  for (const pathSnapshot of snapshot.pathSnapshots) {
2499
- await rm2(pathSnapshot.linkPath, { recursive: true, force: true });
2914
+ await rm3(pathSnapshot.linkPath, { recursive: true, force: true });
2500
2915
  if (pathSnapshot.state === "missing") continue;
2501
2916
  await mkdir4(dirname4(pathSnapshot.linkPath), { recursive: true });
2502
2917
  if (pathSnapshot.state === "symlink" && pathSnapshot.symlinkTarget) {
@@ -2529,7 +2944,7 @@ async function installBatchWithRollback(options) {
2529
2944
  return paths;
2530
2945
  });
2531
2946
  const configSnapshots = await snapshotConfigs(configPaths);
2532
- const backupRoot = join8(
2947
+ const backupRoot = join6(
2533
2948
  tmpdir(),
2534
2949
  `caamp-skill-backup-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
2535
2950
  );
@@ -2578,7 +2993,7 @@ async function installBatchWithRollback(options) {
2578
2993
  }
2579
2994
  skillsApplied += 1;
2580
2995
  }
2581
- await rm2(backupRoot, { recursive: true, force: true });
2996
+ await rm3(backupRoot, { recursive: true, force: true });
2582
2997
  return {
2583
2998
  success: true,
2584
2999
  providerIds: providers.map((provider) => provider.id),
@@ -2608,7 +3023,7 @@ async function installBatchWithRollback(options) {
2608
3023
  rollbackErrors.push(err instanceof Error ? err.message : String(err));
2609
3024
  }
2610
3025
  }
2611
- await rm2(backupRoot, { recursive: true, force: true });
3026
+ await rm3(backupRoot, { recursive: true, force: true });
2612
3027
  return {
2613
3028
  success: false,
2614
3029
  providerIds: providers.map((provider) => provider.id),
@@ -2720,10 +3135,10 @@ async function updateInstructionsSingleOperation(providers, content, scope = "pr
2720
3135
  };
2721
3136
  for (const [filePath, action] of actions.entries()) {
2722
3137
  const providersForFile = providers.filter((provider) => {
2723
- const expectedPath = scope === "global" ? join8(provider.pathGlobal, provider.instructFile) : join8(projectDir, provider.instructFile);
3138
+ const expectedPath = scope === "global" ? join6(provider.pathGlobal, provider.instructFile) : join6(projectDir, provider.instructFile);
2724
3139
  return expectedPath === filePath;
2725
3140
  });
2726
- const fallback = groupedByFile.get(basename2(filePath)) ?? [];
3141
+ const fallback = groupedByFile.get(basename(filePath)) ?? [];
2727
3142
  const selected = providersForFile.length > 0 ? providersForFile : fallback;
2728
3143
  summary.actions.push({
2729
3144
  file: filePath,
@@ -2786,6 +3201,23 @@ async function configureProviderGlobalAndProject(provider, options) {
2786
3201
  }
2787
3202
 
2788
3203
  export {
3204
+ getPlatformLocations,
3205
+ getAgentsHome,
3206
+ getProjectAgentsDir,
3207
+ getCanonicalSkillsDir,
3208
+ getLockFilePath,
3209
+ getAgentsMcpDir,
3210
+ getAgentsMcpServersPath,
3211
+ getAgentsInstructFile,
3212
+ getAgentsConfigPath,
3213
+ getAgentsWikiDir,
3214
+ getAgentsSpecDir,
3215
+ getAgentsLinksDir,
3216
+ resolveRegistryTemplatePath,
3217
+ resolveProviderConfigPath,
3218
+ resolvePreferredConfigScope,
3219
+ resolveProviderSkillsDir,
3220
+ buildSkillSubPathCandidates,
2789
3221
  getAllProviders,
2790
3222
  getProvider,
2791
3223
  resolveAlias,
@@ -2803,8 +3235,10 @@ export {
2803
3235
  detectAllProviders,
2804
3236
  getInstalledProviders,
2805
3237
  detectProjectProviders,
3238
+ resetDetectionCache,
2806
3239
  parseSource,
2807
3240
  isMarketplaceScoped,
3241
+ CANONICAL_SKILLS_DIR,
2808
3242
  installSkill,
2809
3243
  removeSkill,
2810
3244
  listCanonicalSkills,
@@ -2819,6 +3253,13 @@ export {
2819
3253
  discoverSkill,
2820
3254
  discoverSkills,
2821
3255
  discoverSkillsMulti,
3256
+ listSkills,
3257
+ getSkill,
3258
+ getSkillDir,
3259
+ listProfiles,
3260
+ resolveProfile,
3261
+ isCatalogAvailable,
3262
+ catalog_exports,
2822
3263
  RECOMMENDATION_ERROR_CODES,
2823
3264
  tokenizeCriteriaValue,
2824
3265
  validateRecommendationCriteria,
@@ -2838,11 +3279,12 @@ export {
2838
3279
  readConfig,
2839
3280
  writeConfig,
2840
3281
  removeConfig,
2841
- getTransform,
2842
3282
  resolveConfigPath,
2843
3283
  listMcpServers,
3284
+ listAgentsMcpServers,
2844
3285
  listAllMcpServers,
2845
3286
  removeMcpServer,
3287
+ getTransform,
2846
3288
  installMcpServer,
2847
3289
  installMcpServerToAll,
2848
3290
  buildServerConfig,
@@ -2865,4 +3307,4 @@ export {
2865
3307
  updateInstructionsSingleOperation,
2866
3308
  configureProviderGlobalAndProject
2867
3309
  };
2868
- //# sourceMappingURL=chunk-ZYINKJDE.js.map
3310
+ //# sourceMappingURL=chunk-YCSZGZ5W.js.map