@cleocode/caamp 1.8.1 → 1.9.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,265 +1,18 @@
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
- };
1
+ import {
2
+ resolveProviderSkillsDir,
3
+ resolveProvidersRegistryPath,
4
+ resolveRegistryTemplatePath
5
+ } from "./chunk-TI6WOJDG.js";
6
6
 
7
7
  // src/core/instructions/injector.ts
8
- import { existsSync as existsSync2 } from "fs";
8
+ import { existsSync } from "fs";
9
9
  import { mkdir, readFile, writeFile } from "fs/promises";
10
- import { dirname as dirname3, join as join4 } from "path";
10
+ import { dirname as dirname2, join as join2 } from "path";
11
11
 
12
12
  // src/core/registry/providers.ts
13
13
  import { readFileSync } from "fs";
14
- import { dirname as dirname2, join as join3 } from "path";
14
+ import { dirname, join } from "path";
15
15
  import { fileURLToPath } from "url";
16
-
17
- // src/core/paths/standard.ts
18
- import { existsSync } from "fs";
19
- import { homedir as homedir2 } from "os";
20
- import { dirname, join as join2 } from "path";
21
-
22
- // src/core/platform-paths.ts
23
- import envPaths from "env-paths";
24
- import { arch, homedir, hostname, platform, release } from "os";
25
- import { isAbsolute, join, resolve } from "path";
26
- var APP_NAME = "agents";
27
- function resolveAgentsHomeOverride(value) {
28
- if (value === void 0) return void 0;
29
- const trimmed = value.trim();
30
- if (trimmed.length === 0) return void 0;
31
- if (trimmed === "~") return homedir();
32
- if (trimmed.startsWith("~/")) return join(homedir(), trimmed.slice(2));
33
- if (isAbsolute(trimmed)) return resolve(trimmed);
34
- return resolve(homedir(), trimmed);
35
- }
36
- var _paths = null;
37
- var _sysInfo = null;
38
- var _lastAgentsHome = void 0;
39
- function getPlatformPaths() {
40
- const currentAgentsHome = process.env["AGENTS_HOME"];
41
- if (_paths && currentAgentsHome !== _lastAgentsHome) {
42
- _paths = null;
43
- _sysInfo = null;
44
- }
45
- if (_paths) return _paths;
46
- const ep = envPaths(APP_NAME, { suffix: "" });
47
- _lastAgentsHome = currentAgentsHome;
48
- _paths = {
49
- data: resolveAgentsHomeOverride(currentAgentsHome) ?? ep.data,
50
- config: ep.config,
51
- cache: ep.cache,
52
- log: ep.log,
53
- temp: ep.temp
54
- };
55
- return _paths;
56
- }
57
- function getSystemInfo() {
58
- if (_sysInfo) return _sysInfo;
59
- const paths = getPlatformPaths();
60
- _sysInfo = {
61
- platform: platform(),
62
- arch: arch(),
63
- release: release(),
64
- hostname: hostname(),
65
- nodeVersion: process.version,
66
- paths
67
- };
68
- return _sysInfo;
69
- }
70
- function _resetPlatformPathsCache() {
71
- _paths = null;
72
- _sysInfo = null;
73
- _lastAgentsHome = void 0;
74
- }
75
-
76
- // src/core/paths/standard.ts
77
- function getPlatformLocations() {
78
- const home = homedir2();
79
- const platform2 = process.platform;
80
- if (platform2 === "win32") {
81
- const appData = process.env["APPDATA"] ?? join2(home, "AppData", "Roaming");
82
- return {
83
- home,
84
- config: appData,
85
- vscodeConfig: join2(appData, "Code", "User"),
86
- zedConfig: join2(appData, "Zed"),
87
- claudeDesktopConfig: join2(appData, "Claude"),
88
- applications: []
89
- };
90
- }
91
- if (platform2 === "darwin") {
92
- const config2 = process.env["XDG_CONFIG_HOME"] ?? join2(home, ".config");
93
- return {
94
- home,
95
- config: config2,
96
- vscodeConfig: join2(home, "Library", "Application Support", "Code", "User"),
97
- zedConfig: join2(home, "Library", "Application Support", "Zed"),
98
- claudeDesktopConfig: join2(home, "Library", "Application Support", "Claude"),
99
- applications: ["/Applications", join2(home, "Applications")]
100
- };
101
- }
102
- const config = process.env["XDG_CONFIG_HOME"] ?? join2(home, ".config");
103
- return {
104
- home,
105
- config,
106
- vscodeConfig: join2(config, "Code", "User"),
107
- zedConfig: join2(config, "zed"),
108
- claudeDesktopConfig: join2(config, "Claude"),
109
- applications: []
110
- };
111
- }
112
- function getAgentsHome() {
113
- return getPlatformPaths().data;
114
- }
115
- function getProjectAgentsDir(projectRoot = process.cwd()) {
116
- return join2(projectRoot, ".agents");
117
- }
118
- function resolveProjectPath(relativePath, projectDir = process.cwd()) {
119
- return join2(projectDir, relativePath);
120
- }
121
- function getCanonicalSkillsDir() {
122
- return join2(getAgentsHome(), "skills");
123
- }
124
- function getLockFilePath() {
125
- return join2(getAgentsHome(), ".caamp-lock.json");
126
- }
127
- function getAgentsMcpDir(scope = "global", projectDir) {
128
- if (scope === "global") return join2(getAgentsHome(), "mcp");
129
- return join2(projectDir ?? process.cwd(), ".agents", "mcp");
130
- }
131
- function getAgentsMcpServersPath(scope = "global", projectDir) {
132
- return join2(getAgentsMcpDir(scope, projectDir), "servers.json");
133
- }
134
- function getAgentsInstructFile(scope = "global", projectDir) {
135
- if (scope === "global") return join2(getAgentsHome(), "AGENTS.md");
136
- return join2(projectDir ?? process.cwd(), ".agents", "AGENTS.md");
137
- }
138
- function getAgentsConfigPath(scope = "global", projectDir) {
139
- if (scope === "global") return join2(getAgentsHome(), "config.toml");
140
- return join2(projectDir ?? process.cwd(), ".agents", "config.toml");
141
- }
142
- function getAgentsWikiDir(scope = "global", projectDir) {
143
- if (scope === "global") return join2(getAgentsHome(), "wiki");
144
- return join2(projectDir ?? process.cwd(), ".agents", "wiki");
145
- }
146
- function getAgentsSpecDir(scope = "global", projectDir) {
147
- if (scope === "global") return join2(getAgentsHome(), "spec");
148
- return join2(projectDir ?? process.cwd(), ".agents", "spec");
149
- }
150
- function getAgentsLinksDir(scope = "global", projectDir) {
151
- if (scope === "global") return join2(getAgentsHome(), "links");
152
- return join2(projectDir ?? process.cwd(), ".agents", "links");
153
- }
154
- function resolveRegistryTemplatePath(template) {
155
- const locations = getPlatformLocations();
156
- 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());
157
- }
158
- function resolveProviderConfigPath(provider, scope, projectDir = process.cwd()) {
159
- if (scope === "global") {
160
- return provider.configPathGlobal;
161
- }
162
- if (!provider.configPathProject) {
163
- return null;
164
- }
165
- return resolveProjectPath(provider.configPathProject, projectDir);
166
- }
167
- function resolvePreferredConfigScope(provider, useGlobalFlag) {
168
- if (useGlobalFlag) {
169
- return "global";
170
- }
171
- return provider.configPathProject ? "project" : "global";
172
- }
173
- function resolveProviderSkillsDir(provider, scope, projectDir = process.cwd()) {
174
- if (scope === "global") {
175
- return provider.pathSkills;
176
- }
177
- return resolveProjectPath(provider.pathProjectSkills, projectDir);
178
- }
179
- function resolveProviderSkillsDirs(provider, scope, projectDir = process.cwd()) {
180
- const vendorPath = resolveProviderSkillsDir(provider, scope, projectDir);
181
- const precedence = provider.capabilities?.skills?.precedence ?? "vendor-only";
182
- const resolveAgentsPath = () => {
183
- if (scope === "global") {
184
- return provider.capabilities?.skills?.agentsGlobalPath ?? null;
185
- }
186
- const projectRelative = provider.capabilities?.skills?.agentsProjectPath ?? null;
187
- return projectRelative ? join2(projectDir, projectRelative) : null;
188
- };
189
- switch (precedence) {
190
- case "vendor-only":
191
- return [vendorPath];
192
- case "agents-canonical": {
193
- const agentsPath = resolveAgentsPath();
194
- return agentsPath ? [agentsPath] : [vendorPath];
195
- }
196
- case "agents-first": {
197
- const agentsPath = resolveAgentsPath();
198
- return agentsPath ? [agentsPath, vendorPath] : [vendorPath];
199
- }
200
- case "agents-supported": {
201
- const agentsPath = resolveAgentsPath();
202
- return agentsPath ? [vendorPath, agentsPath] : [vendorPath];
203
- }
204
- case "vendor-global-agents-project": {
205
- if (scope === "global") {
206
- return [vendorPath];
207
- }
208
- const agentsPath = resolveAgentsPath();
209
- return agentsPath ? [agentsPath, vendorPath] : [vendorPath];
210
- }
211
- default:
212
- return [vendorPath];
213
- }
214
- }
215
- function resolveProviderProjectPath(provider, projectDir = process.cwd()) {
216
- return resolveProjectPath(provider.pathProject, projectDir);
217
- }
218
- function resolveProvidersRegistryPath(startDir) {
219
- const candidates = [
220
- join2(startDir, "..", "..", "..", "providers", "registry.json"),
221
- join2(startDir, "..", "providers", "registry.json")
222
- ];
223
- for (const candidate of candidates) {
224
- if (existsSync(candidate)) {
225
- return candidate;
226
- }
227
- }
228
- let current = startDir;
229
- for (let i = 0; i < 8; i += 1) {
230
- const candidate = join2(current, "providers", "registry.json");
231
- if (existsSync(candidate)) {
232
- return candidate;
233
- }
234
- current = dirname(current);
235
- }
236
- throw new Error(`Cannot find providers/registry.json (searched from ${startDir})`);
237
- }
238
- function normalizeSkillSubPath(path) {
239
- if (!path) return void 0;
240
- const normalized = path.replace(/\\/g, "/").replace(/^\/+/, "").replace(/\/SKILL\.md$/i, "").trim();
241
- return normalized.length > 0 ? normalized : void 0;
242
- }
243
- function buildSkillSubPathCandidates(marketplacePath, parsedPath) {
244
- const candidates = [];
245
- const base = normalizeSkillSubPath(marketplacePath);
246
- const parsed = normalizeSkillSubPath(parsedPath);
247
- if (base) candidates.push(base);
248
- if (parsed) candidates.push(parsed);
249
- const knownPrefixes = [".agents", ".claude"];
250
- for (const value of [base, parsed]) {
251
- if (!value || !value.startsWith("skills/")) continue;
252
- for (const prefix of knownPrefixes) {
253
- candidates.push(`${prefix}/${value}`);
254
- }
255
- }
256
- if (candidates.length === 0) {
257
- candidates.push(void 0);
258
- }
259
- return Array.from(new Set(candidates));
260
- }
261
-
262
- // src/core/registry/providers.ts
263
16
  var DEFAULT_SKILLS_CAPABILITY = {
264
17
  agentsGlobalPath: null,
265
18
  agentsProjectPath: null,
@@ -298,7 +51,7 @@ function resolveCapabilities(raw) {
298
51
  return { skills, hooks, spawn };
299
52
  }
300
53
  function findRegistryPath() {
301
- const thisDir = dirname2(fileURLToPath(import.meta.url));
54
+ const thisDir = dirname(fileURLToPath(import.meta.url));
302
55
  return resolveProvidersRegistryPath(thisDir);
303
56
  }
304
57
  var _registry = null;
@@ -429,7 +182,7 @@ function getEffectiveSkillsPaths(provider, scope, projectDir) {
429
182
  const resolveAgentsPath = () => {
430
183
  if (scope === "global" && agentsGlobalPath) return agentsGlobalPath;
431
184
  if (scope === "project" && agentsProjectPath && projectDir) {
432
- return join3(projectDir, agentsProjectPath);
185
+ return join(projectDir, agentsProjectPath);
433
186
  }
434
187
  return null;
435
188
  };
@@ -560,7 +313,7 @@ var MARKER_END = "<!-- CAAMP:END -->";
560
313
  var MARKER_PATTERN = /<!-- CAAMP:START -->[\s\S]*?<!-- CAAMP:END -->/g;
561
314
  var MARKER_PATTERN_SINGLE = /<!-- CAAMP:START -->[\s\S]*?<!-- CAAMP:END -->/;
562
315
  async function checkInjection(filePath, expectedContent) {
563
- if (!existsSync2(filePath)) return "missing";
316
+ if (!existsSync(filePath)) return "missing";
564
317
  const content = await readFile(filePath, "utf-8");
565
318
  if (!MARKER_PATTERN_SINGLE.test(content)) return "none";
566
319
  if (expectedContent) {
@@ -584,8 +337,8 @@ ${MARKER_END}`;
584
337
  }
585
338
  async function inject(filePath, content) {
586
339
  const block = buildBlock(content);
587
- await mkdir(dirname3(filePath), { recursive: true });
588
- if (!existsSync2(filePath)) {
340
+ await mkdir(dirname2(filePath), { recursive: true });
341
+ if (!existsSync(filePath)) {
589
342
  await writeFile(filePath, `${block}
590
343
  `, "utf-8");
591
344
  return "created";
@@ -617,7 +370,7 @@ ${existing}`;
617
370
  return "added";
618
371
  }
619
372
  async function removeInjection(filePath) {
620
- if (!existsSync2(filePath)) return false;
373
+ if (!existsSync(filePath)) return false;
621
374
  const content = await readFile(filePath, "utf-8");
622
375
  if (!MARKER_PATTERN.test(content)) return false;
623
376
  const cleaned = content.replace(MARKER_PATTERN, "").replace(/^\n{2,}/, "\n").trim();
@@ -634,7 +387,7 @@ async function checkAllInjections(providers, projectDir, scope, expectedContent)
634
387
  const results = [];
635
388
  const checked = /* @__PURE__ */ new Set();
636
389
  for (const provider of providers) {
637
- const filePath = scope === "global" ? join4(provider.pathGlobal, provider.instructFile) : join4(projectDir, provider.instructFile);
390
+ const filePath = scope === "global" ? join2(provider.pathGlobal, provider.instructFile) : join2(projectDir, provider.instructFile);
638
391
  if (checked.has(filePath)) continue;
639
392
  checked.add(filePath);
640
393
  const status = await checkInjection(filePath, expectedContent);
@@ -642,7 +395,7 @@ async function checkAllInjections(providers, projectDir, scope, expectedContent)
642
395
  file: filePath,
643
396
  provider: provider.id,
644
397
  status,
645
- fileExists: existsSync2(filePath)
398
+ fileExists: existsSync(filePath)
646
399
  });
647
400
  }
648
401
  return results;
@@ -651,7 +404,7 @@ async function injectAll(providers, projectDir, scope, content) {
651
404
  const results = /* @__PURE__ */ new Map();
652
405
  const injected = /* @__PURE__ */ new Set();
653
406
  for (const provider of providers) {
654
- const filePath = scope === "global" ? join4(provider.pathGlobal, provider.instructFile) : join4(projectDir, provider.instructFile);
407
+ const filePath = scope === "global" ? join2(provider.pathGlobal, provider.instructFile) : join2(projectDir, provider.instructFile);
655
408
  if (injected.has(filePath)) continue;
656
409
  injected.add(filePath);
657
410
  const action = await inject(filePath, content);
@@ -665,7 +418,7 @@ async function ensureProviderInstructionFile(providerId, projectDir, options) {
665
418
  throw new Error(`Unknown provider: "${providerId}". Check CAAMP provider registry.`);
666
419
  }
667
420
  const scope = options.scope ?? "project";
668
- const filePath = scope === "global" ? join4(provider.pathGlobal, provider.instructFile) : join4(projectDir, provider.instructFile);
421
+ const filePath = scope === "global" ? join2(provider.pathGlobal, provider.instructFile) : join2(projectDir, provider.instructFile);
669
422
  const template = {
670
423
  references: options.references,
671
424
  content: options.content
@@ -688,7 +441,7 @@ async function ensureAllProviderInstructionFiles(providerIds, projectDir, option
688
441
  throw new Error(`Unknown provider: "${providerId}". Check CAAMP provider registry.`);
689
442
  }
690
443
  const scope = options.scope ?? "project";
691
- const filePath = scope === "global" ? join4(provider.pathGlobal, provider.instructFile) : join4(projectDir, provider.instructFile);
444
+ const filePath = scope === "global" ? join2(provider.pathGlobal, provider.instructFile) : join2(projectDir, provider.instructFile);
692
445
  if (processed.has(filePath)) continue;
693
446
  processed.add(filePath);
694
447
  const template = {
@@ -708,29 +461,6 @@ async function ensureAllProviderInstructionFiles(providerIds, projectDir, option
708
461
  }
709
462
 
710
463
  export {
711
- __export,
712
- getPlatformPaths,
713
- getSystemInfo,
714
- _resetPlatformPathsCache,
715
- getPlatformLocations,
716
- getAgentsHome,
717
- getProjectAgentsDir,
718
- getCanonicalSkillsDir,
719
- getLockFilePath,
720
- getAgentsMcpDir,
721
- getAgentsMcpServersPath,
722
- getAgentsInstructFile,
723
- getAgentsConfigPath,
724
- getAgentsWikiDir,
725
- getAgentsSpecDir,
726
- getAgentsLinksDir,
727
- resolveRegistryTemplatePath,
728
- resolveProviderConfigPath,
729
- resolvePreferredConfigScope,
730
- resolveProviderSkillsDir,
731
- resolveProviderSkillsDirs,
732
- resolveProviderProjectPath,
733
- buildSkillSubPathCandidates,
734
464
  getAllProviders,
735
465
  getProvider,
736
466
  resolveAlias,
@@ -763,4 +493,4 @@ export {
763
493
  ensureProviderInstructionFile,
764
494
  ensureAllProviderInstructionFiles
765
495
  };
766
- //# sourceMappingURL=chunk-CPHF5IM4.js.map
496
+ //# sourceMappingURL=chunk-O7IVK5JY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/instructions/injector.ts","../src/core/registry/providers.ts","../src/core/instructions/templates.ts"],"sourcesContent":["/**\n * Marker-based instruction file injection\n *\n * Injects content blocks between CAAMP markers in instruction files\n * (CLAUDE.md, AGENTS.md, GEMINI.md).\n */\n\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport type { InjectionCheckResult, InjectionStatus, Provider } from \"../../types.js\";\nimport { getProvider } from \"../registry/providers.js\";\nimport { buildInjectionContent, type InjectionTemplate } from \"./templates.js\";\n\nconst MARKER_START = \"<!-- CAAMP:START -->\";\nconst MARKER_END = \"<!-- CAAMP:END -->\";\nconst MARKER_PATTERN = /<!-- CAAMP:START -->[\\s\\S]*?<!-- CAAMP:END -->/g;\nconst MARKER_PATTERN_SINGLE = /<!-- CAAMP:START -->[\\s\\S]*?<!-- CAAMP:END -->/;\n\n/**\n * Check the status of a CAAMP injection block in an instruction file.\n *\n * Returns the injection status:\n * - `\"missing\"` - File does not exist\n * - `\"none\"` - File exists but has no CAAMP markers\n * - `\"current\"` - CAAMP block exists and matches expected content (or no expected content given)\n * - `\"outdated\"` - CAAMP block exists but differs from expected content\n *\n * @param filePath - Absolute path to the instruction file\n * @param expectedContent - Optional expected content to compare against\n * @returns The injection status\n *\n * @remarks\n * Does not modify the file. Safe to call repeatedly for status checks.\n *\n * @example\n * ```typescript\n * const status = await checkInjection(\"/project/CLAUDE.md\", expectedContent);\n * if (status === \"outdated\") {\n * console.log(\"CAAMP injection needs updating\");\n * }\n * ```\n *\n * @public\n */\nexport async function checkInjection(\n filePath: string,\n expectedContent?: string,\n): Promise<InjectionStatus> {\n if (!existsSync(filePath)) return \"missing\";\n\n const content = await readFile(filePath, \"utf-8\");\n\n if (!MARKER_PATTERN_SINGLE.test(content)) return \"none\";\n\n if (expectedContent) {\n const blockContent = extractBlock(content);\n if (blockContent && blockContent.trim() === expectedContent.trim()) {\n return \"current\";\n }\n return \"outdated\";\n }\n\n return \"current\";\n}\n\n/** Extract the content between CAAMP markers */\nfunction extractBlock(content: string): string | null {\n const match = content.match(MARKER_PATTERN_SINGLE);\n if (!match) return null;\n\n return match[0]\n .replace(MARKER_START, \"\")\n .replace(MARKER_END, \"\")\n .trim();\n}\n\n/** Build the injection block */\nfunction buildBlock(content: string): string {\n return `${MARKER_START}\\n${content}\\n${MARKER_END}`;\n}\n\n/**\n * Inject content into an instruction file between CAAMP markers.\n *\n * Behavior depends on the file state:\n * - File does not exist: creates the file with the injection block → `\"created\"`\n * - File exists without markers: prepends the injection block → `\"added\"`\n * - File exists with multiple markers (duplicates): consolidates into single block → `\"consolidated\"`\n * - File exists with markers, content differs: replaces the block → `\"updated\"`\n * - File exists with markers, content matches: no-op → `\"intact\"`\n *\n * This function is **idempotent** — calling it multiple times with the same\n * content will not modify the file after the first write.\n *\n * @param filePath - Absolute path to the instruction file\n * @param content - Content to inject between CAAMP markers\n * @returns Action taken: `\"created\"`, `\"added\"`, `\"consolidated\"`, `\"updated\"`, or `\"intact\"`\n *\n * @remarks\n * Handles duplicate marker consolidation automatically. When multiple CAAMP\n * blocks are detected (from manual edits or bugs), they are merged into one.\n *\n * @example\n * ```typescript\n * const action = await inject(\"/project/CLAUDE.md\", \"## My Config\\nSome content\");\n * console.log(`File ${action}`); // \"created\" on first call, \"intact\" on subsequent\n * ```\n *\n * @public\n */\nexport async function inject(\n filePath: string,\n content: string,\n): Promise<\"created\" | \"added\" | \"consolidated\" | \"updated\" | \"intact\"> {\n const block = buildBlock(content);\n\n // Ensure parent directory exists\n await mkdir(dirname(filePath), { recursive: true });\n\n if (!existsSync(filePath)) {\n // Create new file with injection block\n await writeFile(filePath, `${block}\\n`, \"utf-8\");\n return \"created\";\n }\n\n const existing = await readFile(filePath, \"utf-8\");\n\n // Find all CAAMP blocks in the file\n const matches = existing.match(MARKER_PATTERN);\n\n if (matches && matches.length > 0) {\n // Check if there are multiple duplicate blocks\n if (matches.length > 1) {\n // Consolidate all blocks into a single clean block\n const updated = existing\n .replace(MARKER_PATTERN, \"\")\n .replace(/^\\n{2,}/, \"\\n\")\n .trim();\n \n // Write the clean content with a single block\n const finalContent = updated \n ? `${block}\\n\\n${updated}`\n : `${block}\\n`;\n await writeFile(filePath, finalContent, \"utf-8\");\n return \"consolidated\";\n }\n\n // Check if existing content already matches (idempotency)\n const existingBlock = extractBlock(existing);\n if (existingBlock !== null && existingBlock.trim() === content.trim()) {\n return \"intact\";\n }\n\n // Replace existing block with new content\n const updated = existing.replace(MARKER_PATTERN_SINGLE, block);\n await writeFile(filePath, updated, \"utf-8\");\n return \"updated\";\n }\n\n // Prepend block to existing content\n const updated = `${block}\\n\\n${existing}`;\n await writeFile(filePath, updated, \"utf-8\");\n return \"added\";\n}\n\n/**\n * Remove the CAAMP injection block from an instruction file.\n *\n * If removing the block would leave the file empty, the file is deleted entirely.\n *\n * @param filePath - Absolute path to the instruction file\n * @returns `true` if a CAAMP block was found and removed, `false` otherwise\n *\n * @remarks\n * Cleans up any leftover blank lines after removing the block. If the file\n * would be entirely empty after removal, the file itself is deleted.\n *\n * @example\n * ```typescript\n * const removed = await removeInjection(\"/project/CLAUDE.md\");\n * ```\n *\n * @public\n */\nexport async function removeInjection(filePath: string): Promise<boolean> {\n if (!existsSync(filePath)) return false;\n\n const content = await readFile(filePath, \"utf-8\");\n if (!MARKER_PATTERN.test(content)) return false;\n\n const cleaned = content\n .replace(MARKER_PATTERN, \"\")\n .replace(/^\\n{2,}/, \"\\n\")\n .trim();\n\n if (!cleaned) {\n // File would be empty - remove it entirely\n const { rm } = await import(\"node:fs/promises\");\n await rm(filePath);\n } else {\n await writeFile(filePath, `${cleaned}\\n`, \"utf-8\");\n }\n\n return true;\n}\n\n/**\n * Check injection status across all providers' instruction files.\n *\n * Deduplicates by file path since multiple providers may share the same\n * instruction file (e.g. many providers use `AGENTS.md`).\n *\n * @param providers - Array of providers to check\n * @param projectDir - Absolute path to the project directory\n * @param scope - Whether to check project or global instruction files\n * @param expectedContent - Optional expected content to compare against\n * @returns Array of injection check results, one per unique instruction file\n *\n * @remarks\n * Multiple providers may share the same instruction file (e.g. many use\n * `AGENTS.md`). This function deduplicates to avoid redundant file reads.\n *\n * @example\n * ```typescript\n * const results = await checkAllInjections(providers, \"/project\", \"project\", expected);\n * const outdated = results.filter(r => r.status === \"outdated\");\n * ```\n *\n * @public\n */\nexport async function checkAllInjections(\n providers: Provider[],\n projectDir: string,\n scope: \"project\" | \"global\",\n expectedContent?: string,\n): Promise<InjectionCheckResult[]> {\n const results: InjectionCheckResult[] = [];\n const checked = new Set<string>();\n\n for (const provider of providers) {\n const filePath = scope === \"global\"\n ? join(provider.pathGlobal, provider.instructFile)\n : join(projectDir, provider.instructFile);\n\n // Skip duplicates (multiple providers share same instruction file)\n if (checked.has(filePath)) continue;\n checked.add(filePath);\n\n const status = await checkInjection(filePath, expectedContent);\n\n results.push({\n file: filePath,\n provider: provider.id,\n status,\n fileExists: existsSync(filePath),\n });\n }\n\n return results;\n}\n\n/**\n * Inject content into all providers' instruction files.\n *\n * Deduplicates by file path to avoid injecting the same file multiple times.\n *\n * @param providers - Array of providers to inject into\n * @param projectDir - Absolute path to the project directory\n * @param scope - Whether to target project or global instruction files\n * @param content - Content to inject between CAAMP markers\n * @returns Map of file path to action taken (`\"created\"`, `\"added\"`, `\"consolidated\"`, `\"updated\"`, or `\"intact\"`)\n *\n * @remarks\n * Providers sharing the same instruction file are only written once to avoid\n * conflicting concurrent writes.\n *\n * @example\n * ```typescript\n * const results = await injectAll(providers, \"/project\", \"project\", content);\n * for (const [file, action] of results) {\n * console.log(`${file}: ${action}`);\n * }\n * ```\n *\n * @public\n */\nexport async function injectAll(\n providers: Provider[],\n projectDir: string,\n scope: \"project\" | \"global\",\n content: string,\n): Promise<Map<string, \"created\" | \"added\" | \"consolidated\" | \"updated\" | \"intact\">> {\n const results = new Map<string, \"created\" | \"added\" | \"consolidated\" | \"updated\" | \"intact\">();\n const injected = new Set<string>();\n\n for (const provider of providers) {\n const filePath = scope === \"global\"\n ? join(provider.pathGlobal, provider.instructFile)\n : join(projectDir, provider.instructFile);\n\n // Skip duplicates\n if (injected.has(filePath)) continue;\n injected.add(filePath);\n\n const action = await inject(filePath, content);\n results.set(filePath, action);\n }\n\n return results;\n}\n\n// ── Provider Instruction File API ─────────────────────────────────\n\n/**\n * Options for ensuring a provider instruction file.\n *\n * @public\n */\nexport interface EnsureProviderInstructionFileOptions {\n /** `\\@` references to inject (e.g. `[\"\\@AGENTS.md\"]`). */\n references: string[];\n /** Optional inline content blocks. @defaultValue `undefined` */\n content?: string[];\n /** Whether this is a global or project-level file. @defaultValue `\"project\"` */\n scope?: \"project\" | \"global\";\n}\n\n/**\n * Result of ensuring a provider instruction file.\n *\n * @public\n */\nexport interface EnsureProviderInstructionFileResult {\n /** Absolute path to the instruction file. */\n filePath: string;\n /** Instruction file name from the provider registry. */\n instructFile: string;\n /** Action taken. */\n action: \"created\" | \"added\" | \"consolidated\" | \"updated\" | \"intact\";\n /** Provider ID. */\n providerId: string;\n}\n\n/**\n * Ensure a provider's instruction file exists with the correct CAAMP block.\n *\n * This is the canonical API for adapters and external packages to manage\n * provider instruction files. Instead of directly creating/modifying\n * CLAUDE.md, GEMINI.md, etc., callers should use this function to\n * delegate instruction file management to CAAMP.\n *\n * The instruction file name is resolved from CAAMP's provider registry\n * (single source of truth), not hardcoded by the caller.\n *\n * @remarks\n * The instruction file name is resolved from CAAMP's provider registry\n * (single source of truth), not hardcoded by the caller.\n *\n * @param providerId - Provider ID from the registry (e.g. `\"claude-code\"`, `\"gemini-cli\"`)\n * @param projectDir - Absolute path to the project directory\n * @param options - References, content, and scope configuration\n * @returns Result with file path, action taken, and provider metadata\n * @throws Error if the provider ID is not found in the registry\n *\n * @example\n * ```typescript\n * const result = await ensureProviderInstructionFile(\"claude-code\", \"/project\", {\n * references: [\"\\@AGENTS.md\"],\n * });\n * ```\n *\n * @public\n */\nexport async function ensureProviderInstructionFile(\n providerId: string,\n projectDir: string,\n options: EnsureProviderInstructionFileOptions,\n): Promise<EnsureProviderInstructionFileResult> {\n const provider = getProvider(providerId);\n if (!provider) {\n throw new Error(`Unknown provider: \"${providerId}\". Check CAAMP provider registry.`);\n }\n\n const scope = options.scope ?? \"project\";\n const filePath = scope === \"global\"\n ? join(provider.pathGlobal, provider.instructFile)\n : join(projectDir, provider.instructFile);\n\n const template: InjectionTemplate = {\n references: options.references,\n content: options.content,\n };\n\n const injectionContent = buildInjectionContent(template);\n const action = await inject(filePath, injectionContent);\n\n return {\n filePath,\n instructFile: provider.instructFile,\n action,\n providerId: provider.id,\n };\n}\n\n/**\n * Ensure instruction files for multiple providers at once.\n *\n * Deduplicates by file path — providers sharing the same instruction file\n * (e.g. many providers use AGENTS.md) are only written once.\n *\n * @remarks\n * Providers sharing the same instruction file (e.g. many use `AGENTS.md`)\n * are only written once, avoiding duplicate blocks.\n *\n * @param providerIds - Array of provider IDs from the registry\n * @param projectDir - Absolute path to the project directory\n * @param options - References, content, and scope configuration\n * @returns Array of results, one per unique instruction file\n * @throws Error if any provider ID is not found in the registry\n *\n * @example\n * ```typescript\n * const results = await ensureAllProviderInstructionFiles(\n * [\"claude-code\", \"cursor\", \"gemini-cli\"],\n * \"/project\",\n * { references: [\"\\@AGENTS.md\"] },\n * );\n * ```\n *\n * @public\n */\nexport async function ensureAllProviderInstructionFiles(\n providerIds: string[],\n projectDir: string,\n options: EnsureProviderInstructionFileOptions,\n): Promise<EnsureProviderInstructionFileResult[]> {\n const results: EnsureProviderInstructionFileResult[] = [];\n const processed = new Set<string>();\n\n for (const providerId of providerIds) {\n const provider = getProvider(providerId);\n if (!provider) {\n throw new Error(`Unknown provider: \"${providerId}\". Check CAAMP provider registry.`);\n }\n\n const scope = options.scope ?? \"project\";\n const filePath = scope === \"global\"\n ? join(provider.pathGlobal, provider.instructFile)\n : join(projectDir, provider.instructFile);\n\n // Skip duplicates (multiple providers may share the same instruction file)\n if (processed.has(filePath)) continue;\n processed.add(filePath);\n\n const template: InjectionTemplate = {\n references: options.references,\n content: options.content,\n };\n\n const injectionContent = buildInjectionContent(template);\n const action = await inject(filePath, injectionContent);\n\n results.push({\n filePath,\n instructFile: provider.instructFile,\n action,\n providerId: provider.id,\n });\n }\n\n return results;\n}\n","/**\n * Provider registry loader\n *\n * Loads providers from providers/registry.json and resolves\n * platform-specific paths at runtime.\n */\n\nimport { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type {\n ConfigFormat,\n DetectionMethod,\n Provider,\n ProviderCapabilities,\n ProviderHooksCapability,\n ProviderPriority,\n ProviderSkillsCapability,\n ProviderSpawnCapability,\n ProviderStatus,\n TransportType,\n} from \"../../types.js\";\nimport { type PathScope, resolveProvidersRegistryPath, resolveProviderSkillsDir, resolveRegistryTemplatePath } from \"../paths/standard.js\";\nimport type { HookEvent, ProviderRegistry, RegistryCapabilities, RegistryProvider, SkillsPrecedence, SpawnMechanism } from \"./types.js\";\n\n// ── Capability Defaults ──────────────────────────────────────────────\n\nconst DEFAULT_SKILLS_CAPABILITY: ProviderSkillsCapability = {\n agentsGlobalPath: null,\n agentsProjectPath: null,\n precedence: \"vendor-only\",\n};\n\nconst DEFAULT_HOOKS_CAPABILITY: ProviderHooksCapability = {\n supported: [],\n hookConfigPath: null,\n hookFormat: null,\n};\n\nconst DEFAULT_SPAWN_CAPABILITY: ProviderSpawnCapability = {\n supportsSubagents: false,\n supportsProgrammaticSpawn: false,\n supportsInterAgentComms: false,\n supportsParallelSpawn: false,\n spawnMechanism: null,\n};\n\nfunction resolveCapabilities(raw?: RegistryCapabilities): ProviderCapabilities {\n const skills: ProviderSkillsCapability = raw?.skills\n ? {\n agentsGlobalPath: raw.skills.agentsGlobalPath\n ? resolveRegistryTemplatePath(raw.skills.agentsGlobalPath)\n : null,\n agentsProjectPath: raw.skills.agentsProjectPath,\n precedence: raw.skills.precedence,\n }\n : { ...DEFAULT_SKILLS_CAPABILITY };\n\n const hooks: ProviderHooksCapability = raw?.hooks\n ? {\n supported: raw.hooks.supported as HookEvent[],\n hookConfigPath: raw.hooks.hookConfigPath\n ? resolveRegistryTemplatePath(raw.hooks.hookConfigPath)\n : null,\n hookFormat: raw.hooks.hookFormat as ProviderHooksCapability[\"hookFormat\"],\n }\n : { ...DEFAULT_HOOKS_CAPABILITY, supported: [] };\n\n const spawn: ProviderSpawnCapability = raw?.spawn\n ? {\n supportsSubagents: raw.spawn.supportsSubagents,\n supportsProgrammaticSpawn: raw.spawn.supportsProgrammaticSpawn,\n supportsInterAgentComms: raw.spawn.supportsInterAgentComms,\n supportsParallelSpawn: raw.spawn.supportsParallelSpawn,\n spawnMechanism: raw.spawn.spawnMechanism as SpawnMechanism | null,\n }\n : { ...DEFAULT_SPAWN_CAPABILITY };\n\n return { skills, hooks, spawn };\n}\n\nfunction findRegistryPath(): string {\n const thisDir = dirname(fileURLToPath(import.meta.url));\n return resolveProvidersRegistryPath(thisDir);\n}\n\nlet _registry: ProviderRegistry | null = null;\nlet _providers: Map<string, Provider> | null = null;\nlet _aliasMap: Map<string, string> | null = null;\n\nfunction resolveProvider(raw: RegistryProvider): Provider {\n return {\n id: raw.id,\n toolName: raw.toolName,\n vendor: raw.vendor,\n agentFlag: raw.agentFlag,\n aliases: raw.aliases,\n pathGlobal: resolveRegistryTemplatePath(raw.pathGlobal),\n pathProject: raw.pathProject,\n instructFile: raw.instructFile,\n configKey: raw.configKey,\n configFormat: raw.configFormat as ConfigFormat,\n configPathGlobal: resolveRegistryTemplatePath(raw.configPathGlobal),\n configPathProject: raw.configPathProject,\n pathSkills: resolveRegistryTemplatePath(raw.pathSkills),\n pathProjectSkills: raw.pathProjectSkills,\n detection: {\n methods: raw.detection.methods as DetectionMethod[],\n binary: raw.detection.binary,\n directories: raw.detection.directories?.map(resolveRegistryTemplatePath),\n appBundle: raw.detection.appBundle,\n flatpakId: raw.detection.flatpakId,\n },\n supportedTransports: raw.supportedTransports as TransportType[],\n supportsHeaders: raw.supportsHeaders,\n priority: raw.priority as ProviderPriority,\n status: raw.status as ProviderStatus,\n agentSkillsCompatible: raw.agentSkillsCompatible,\n capabilities: resolveCapabilities(raw.capabilities),\n };\n}\n\nfunction loadRegistry(): ProviderRegistry {\n if (_registry) return _registry;\n\n const registryPath = findRegistryPath();\n const raw = readFileSync(registryPath, \"utf-8\");\n _registry = JSON.parse(raw) as ProviderRegistry;\n return _registry;\n}\n\nfunction ensureProviders(): void {\n if (_providers) return;\n\n const registry = loadRegistry();\n _providers = new Map<string, Provider>();\n _aliasMap = new Map<string, string>();\n\n for (const [id, raw] of Object.entries(registry.providers)) {\n const provider = resolveProvider(raw);\n _providers.set(id, provider);\n\n // Build alias map\n for (const alias of provider.aliases) {\n _aliasMap.set(alias, id);\n }\n }\n}\n\n/**\n * Retrieve all registered providers with resolved platform paths.\n *\n * Providers are lazily loaded from `providers/registry.json` on first call\n * and cached for subsequent calls.\n *\n * @remarks\n * The registry is parsed once and cached in-module state. Platform-specific\n * template paths (e.g. `~/.config/...`) are resolved at load time via\n * {@link resolveRegistryTemplatePath}. Call {@link resetRegistry} to force\n * a reload.\n *\n * @returns Array of all provider definitions\n *\n * @example\n * ```typescript\n * const providers = getAllProviders();\n * console.log(`${providers.length} providers registered`);\n * ```\n *\n * @public\n */\nexport function getAllProviders(): Provider[] {\n ensureProviders();\n if (!_providers) return [];\n return Array.from(_providers.values());\n}\n\n/**\n * Look up a provider by its ID or any of its aliases.\n *\n * @remarks\n * Alias resolution is performed via an internal map built during registry loading.\n * If the input matches an alias, it is resolved to the canonical provider ID before\n * lookup. If it matches neither an alias nor a canonical ID, `undefined` is returned.\n *\n * @param idOrAlias - Provider ID (e.g. `\"claude-code\"`) or alias (e.g. `\"claude\"`)\n * @returns The matching provider, or `undefined` if not found\n *\n * @example\n * ```typescript\n * const provider = getProvider(\"claude\");\n * // Returns the claude-code provider via alias resolution\n * ```\n *\n * @public\n */\nexport function getProvider(idOrAlias: string): Provider | undefined {\n ensureProviders();\n const resolved = _aliasMap?.get(idOrAlias) ?? idOrAlias;\n return _providers?.get(resolved);\n}\n\n/**\n * Resolve an alias to its canonical provider ID.\n *\n * If the input is already a canonical ID (or unrecognized), it is returned as-is.\n *\n * @remarks\n * Alias mappings are built from the `aliases` array in each provider's registry\n * entry. This function is safe to call with canonical IDs -- they pass through unchanged.\n *\n * @param idOrAlias - Provider ID or alias to resolve\n * @returns The canonical provider ID\n *\n * @example\n * ```typescript\n * resolveAlias(\"claude\"); // \"claude-code\"\n * resolveAlias(\"claude-code\"); // \"claude-code\"\n * resolveAlias(\"unknown\"); // \"unknown\"\n * ```\n *\n * @public\n */\nexport function resolveAlias(idOrAlias: string): string {\n ensureProviders();\n return _aliasMap?.get(idOrAlias) ?? idOrAlias;\n}\n\n/**\n * Filter providers by their priority tier.\n *\n * @remarks\n * Provider priority is assigned in `providers/registry.json` and indicates the\n * relative importance of a provider for detection ordering and display.\n *\n * @param priority - Priority level to filter by (`\"high\"`, `\"medium\"`, or `\"low\"`)\n * @returns Array of providers matching the given priority\n *\n * @example\n * ```typescript\n * const highPriority = getProvidersByPriority(\"high\");\n * console.log(highPriority.map(p => p.toolName));\n * ```\n *\n * @public\n */\nexport function getProvidersByPriority(priority: ProviderPriority): Provider[] {\n return getAllProviders().filter((p) => p.priority === priority);\n}\n\n/**\n * Filter providers by their lifecycle status.\n *\n * @remarks\n * Lifecycle status is maintained per-provider in the registry and reflects\n * the provider's stability and support level within CAAMP.\n *\n * @param status - Status to filter by (`\"active\"`, `\"beta\"`, `\"deprecated\"`, or `\"planned\"`)\n * @returns Array of providers matching the given status\n *\n * @example\n * ```typescript\n * const active = getProvidersByStatus(\"active\");\n * console.log(`${active.length} active providers`);\n * ```\n *\n * @public\n */\nexport function getProvidersByStatus(status: ProviderStatus): Provider[] {\n return getAllProviders().filter((p) => p.status === status);\n}\n\n/**\n * Filter providers that use a specific instruction file.\n *\n * Multiple providers often share the same instruction file (e.g. many use `\"AGENTS.md\"`).\n *\n * @remarks\n * CAAMP supports three instruction file types: `CLAUDE.md`, `AGENTS.md`, and `GEMINI.md`.\n * Most providers read from `AGENTS.md` as the universal standard, while a few\n * have vendor-specific files.\n *\n * @param file - Instruction file name (e.g. `\"CLAUDE.md\"`, `\"AGENTS.md\"`)\n * @returns Array of providers that use the given instruction file\n *\n * @example\n * ```typescript\n * const claudeProviders = getProvidersByInstructFile(\"CLAUDE.md\");\n * console.log(claudeProviders.map(p => p.id));\n * ```\n *\n * @public\n */\nexport function getProvidersByInstructFile(file: string): Provider[] {\n return getAllProviders().filter((p) => p.instructFile === file);\n}\n\n/**\n * Get the set of all unique instruction file names across all providers.\n *\n * @remarks\n * Iterates over all registered providers and collects the distinct\n * `instructFile` values. The result is deduplicated via a `Set`.\n *\n * @returns Array of unique instruction file names (e.g. `[\"CLAUDE.md\", \"AGENTS.md\", \"GEMINI.md\"]`)\n *\n * @example\n * ```typescript\n * const files = getInstructionFiles();\n * // [\"CLAUDE.md\", \"AGENTS.md\", \"GEMINI.md\"]\n * ```\n *\n * @public\n */\nexport function getInstructionFiles(): string[] {\n const files = new Set<string>();\n for (const p of getAllProviders()) {\n files.add(p.instructFile);\n }\n return Array.from(files);\n}\n\n/**\n * Get the total number of registered providers.\n *\n * @remarks\n * Triggers lazy loading of the registry if not already loaded.\n * The count reflects the number of entries in `providers/registry.json`.\n *\n * @returns Count of providers in the registry\n *\n * @example\n * ```typescript\n * console.log(`Registry has ${getProviderCount()} providers`);\n * ```\n *\n * @public\n */\nexport function getProviderCount(): number {\n ensureProviders();\n return _providers?.size ?? 0;\n}\n\n/**\n * Get the semantic version string of the provider registry.\n *\n * @remarks\n * The version is read from the top-level `version` field in `providers/registry.json`\n * and follows semver conventions. It is bumped when provider definitions change.\n *\n * @returns Version string from `providers/registry.json` (e.g. `\"1.0.0\"`)\n *\n * @example\n * ```typescript\n * console.log(`Registry version: ${getRegistryVersion()}`);\n * ```\n *\n * @public\n */\nexport function getRegistryVersion(): string {\n return loadRegistry().version;\n}\n\n/**\n * Filter providers that support a specific hook event.\n *\n * @remarks\n * Hook events are declared per-provider in the `capabilities.hooks.supported`\n * array within the registry. Only providers that explicitly list the event\n * are returned.\n *\n * @param event - Hook event to filter by (e.g. `\"onToolComplete\"`)\n * @returns Array of providers whose hooks capability includes the given event\n *\n * @example\n * ```typescript\n * const providers = getProvidersByHookEvent(\"onToolComplete\");\n * console.log(providers.map(p => p.id));\n * ```\n *\n * @public\n */\nexport function getProvidersByHookEvent(event: HookEvent): Provider[] {\n return getAllProviders().filter((p) => p.capabilities.hooks.supported.includes(event));\n}\n\n/**\n * Get hook events common to all specified providers.\n *\n * If providerIds is provided, returns the intersection of their supported events.\n * If providerIds is undefined or empty, uses all providers.\n *\n * @remarks\n * Computes the set intersection of `capabilities.hooks.supported` across the\n * target providers. Useful for determining which hook events can be reliably\n * used across a multi-agent installation.\n *\n * @param providerIds - Optional array of provider IDs to intersect\n * @returns Array of hook events supported by ALL specified providers\n *\n * @example\n * ```typescript\n * const common = getCommonHookEvents([\"claude-code\", \"gemini-cli\"]);\n * console.log(`${common.length} common hook events`);\n * ```\n *\n * @public\n */\nexport function getCommonHookEvents(providerIds?: string[]): HookEvent[] {\n const providers = providerIds && providerIds.length > 0\n ? providerIds.map((id) => getProvider(id)).filter((p): p is Provider => p !== undefined)\n : getAllProviders();\n\n if (providers.length === 0) return [];\n\n const first = providers[0]!.capabilities.hooks.supported as HookEvent[];\n return first.filter((event) =>\n providers.every((p) => p.capabilities.hooks.supported.includes(event)),\n );\n}\n\n/**\n * Check whether a provider supports a specific capability via dot-path query.\n *\n * The dot-path addresses a value inside `provider.capabilities`. For boolean\n * fields the provider \"supports\" the capability when the value is `true`.\n * For non-boolean fields the provider \"supports\" it when the value is neither\n * `null` nor `undefined` (and, for arrays, non-empty).\n *\n * @remarks\n * This function traverses the capabilities object using dot-delimited path\n * segments. It handles three value types: booleans (must be `true`), arrays\n * (must be non-empty), and all other values (must be non-null/undefined).\n * Invalid paths return `false`.\n *\n * @param provider - Provider to inspect\n * @param dotPath - Dot-delimited capability path (e.g. `\"spawn.supportsSubagents\"`, `\"hooks.supported\"`)\n * @returns `true` when the provider has the specified capability\n *\n * @example\n * ```typescript\n * const claude = getProvider(\"claude-code\");\n * providerSupports(claude!, \"spawn.supportsSubagents\"); // true\n * providerSupports(claude!, \"hooks.supported\"); // true (non-empty array)\n * ```\n *\n * @public\n */\nexport function providerSupports(provider: Provider, dotPath: string): boolean {\n const parts = dotPath.split(\".\");\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let current: any = provider.capabilities;\n for (const part of parts) {\n if (current == null || typeof current !== \"object\") return false;\n current = current[part];\n }\n if (typeof current === \"boolean\") return current;\n if (Array.isArray(current)) return current.length > 0;\n return current != null;\n}\n\n/**\n * Filter providers that support spawning subagents.\n *\n * @remarks\n * This is a convenience wrapper that checks the `capabilities.spawn.supportsSubagents`\n * boolean flag. For more granular spawn capability filtering, use\n * {@link getProvidersBySpawnCapability}.\n *\n * @returns Array of providers where `capabilities.spawn.supportsSubagents === true`\n *\n * @example\n * ```typescript\n * const spawnCapable = getSpawnCapableProviders();\n * console.log(spawnCapable.map(p => p.id));\n * ```\n *\n * @public\n */\nexport function getSpawnCapableProviders(): Provider[] {\n return getAllProviders().filter((p) => p.capabilities.spawn.supportsSubagents);\n}\n\n/**\n * Filter providers by a specific boolean spawn capability flag.\n *\n * @remarks\n * The spawn capability has four boolean flags that can be queried independently.\n * The `spawnMechanism` string field is excluded from the flag type since it is\n * not a boolean check.\n *\n * @param flag - One of the four boolean flags on {@link ProviderSpawnCapability}\n * (`\"supportsSubagents\"`, `\"supportsProgrammaticSpawn\"`,\n * `\"supportsInterAgentComms\"`, `\"supportsParallelSpawn\"`)\n * @returns Array of providers where the specified flag is `true`\n *\n * @example\n * ```typescript\n * const parallel = getProvidersBySpawnCapability(\"supportsParallelSpawn\");\n * console.log(parallel.map(p => p.id));\n * ```\n *\n * @see {@link getSpawnCapableProviders}\n *\n * @public\n */\nexport function getProvidersBySpawnCapability(\n flag: keyof Omit<ProviderSpawnCapability, \"spawnMechanism\">,\n): Provider[] {\n return getAllProviders().filter((p) => p.capabilities.spawn[flag] === true);\n}\n\n/**\n * Reset cached registry data, forcing a reload on next access.\n *\n * @remarks\n * Clears the in-memory provider map, alias map, and raw registry cache.\n * Primarily used in test suites to ensure a clean state between test cases.\n *\n * @example\n * ```typescript\n * resetRegistry();\n * // Next call to getAllProviders() will re-read registry.json\n * ```\n *\n * @public\n */\nexport function resetRegistry(): void {\n _registry = null;\n _providers = null;\n _aliasMap = null;\n}\n\n// ── Skills Query Functions ──────────────────────────────────────────\n\n/**\n * Filter providers by their skills precedence value.\n *\n * @remarks\n * Skills precedence controls how a provider resolves skill files when both\n * vendor-specific and `.agents/` standard paths exist. Values include\n * `\"vendor-only\"`, `\"agents-canonical\"`, `\"agents-first\"`, `\"agents-supported\"`,\n * and `\"vendor-global-agents-project\"`.\n *\n * @param precedence - Skills precedence to filter by\n * @returns Array of providers matching the given precedence\n *\n * @example\n * ```typescript\n * const vendorOnly = getProvidersBySkillsPrecedence(\"vendor-only\");\n * console.log(vendorOnly.map(p => p.id));\n * ```\n *\n * @public\n */\nexport function getProvidersBySkillsPrecedence(precedence: SkillsPrecedence): Provider[] {\n return getAllProviders().filter((p) => p.capabilities.skills.precedence === precedence);\n}\n\n/**\n * Get the effective skills paths for a provider, ordered by precedence.\n *\n * @remarks\n * The returned array is ordered by precedence priority. For example, with\n * `\"agents-first\"` precedence the `.agents/` path appears before the vendor\n * path. The `source` field indicates whether the path comes from the vendor\n * directory or the `.agents/` standard directory.\n *\n * @param provider - Provider to resolve paths for\n * @param scope - Whether to resolve global or project paths\n * @param projectDir - Project directory for project-scope resolution\n * @returns Ordered array of paths with source and scope metadata\n *\n * @example\n * ```typescript\n * const provider = getProvider(\"claude-code\")!;\n * const paths = getEffectiveSkillsPaths(provider, \"global\");\n * for (const p of paths) {\n * console.log(`${p.source} (${p.scope}): ${p.path}`);\n * }\n * ```\n *\n * @public\n */\nexport function getEffectiveSkillsPaths(\n provider: Provider,\n scope: PathScope,\n projectDir?: string,\n): Array<{ path: string; source: string; scope: string }> {\n const vendorPath = resolveProviderSkillsDir(provider, scope, projectDir);\n const { precedence, agentsGlobalPath, agentsProjectPath } = provider.capabilities.skills;\n\n const resolveAgentsPath = (): string | null => {\n if (scope === \"global\" && agentsGlobalPath) return agentsGlobalPath;\n if (scope === \"project\" && agentsProjectPath && projectDir) {\n return join(projectDir, agentsProjectPath);\n }\n return null;\n };\n\n const agentsPath = resolveAgentsPath();\n const scopeLabel = scope === \"global\" ? \"global\" : \"project\";\n\n switch (precedence) {\n case \"vendor-only\":\n return [{ path: vendorPath, source: \"vendor\", scope: scopeLabel }];\n case \"agents-canonical\":\n return agentsPath ? [{ path: agentsPath, source: \"agents\", scope: scopeLabel }] : [];\n case \"agents-first\":\n return [\n ...(agentsPath ? [{ path: agentsPath, source: \"agents\", scope: scopeLabel }] : []),\n { path: vendorPath, source: \"vendor\", scope: scopeLabel },\n ];\n case \"agents-supported\":\n return [\n { path: vendorPath, source: \"vendor\", scope: scopeLabel },\n ...(agentsPath ? [{ path: agentsPath, source: \"agents\", scope: scopeLabel }] : []),\n ];\n case \"vendor-global-agents-project\":\n if (scope === \"global\") {\n return [{ path: vendorPath, source: \"vendor\", scope: \"global\" }];\n }\n return [\n ...(agentsPath ? [{ path: agentsPath, source: \"agents\", scope: \"project\" }] : []),\n { path: vendorPath, source: \"vendor\", scope: \"project\" },\n ];\n default:\n return [{ path: vendorPath, source: \"vendor\", scope: scopeLabel }];\n }\n}\n\n/**\n * Build a full skills map for all providers.\n *\n * @remarks\n * Produces a summary of each provider's skills configuration including\n * the precedence mode and resolved global/project paths. For `\"vendor-only\"`\n * providers the paths point to the vendor skills directory; for others they\n * point to the `.agents/` standard paths.\n *\n * @returns Array of skills map entries with provider ID, tool name, precedence, and paths\n *\n * @example\n * ```typescript\n * const skillsMap = buildSkillsMap();\n * for (const entry of skillsMap) {\n * console.log(`${entry.providerId}: ${entry.precedence}`);\n * }\n * ```\n *\n * @public\n */\nexport function buildSkillsMap(): Array<{\n providerId: string;\n toolName: string;\n precedence: SkillsPrecedence;\n paths: { global: string | null; project: string | null };\n}> {\n return getAllProviders().map((p) => {\n const { precedence, agentsGlobalPath, agentsProjectPath } = p.capabilities.skills;\n const isVendorOnly = precedence === \"vendor-only\";\n return {\n providerId: p.id,\n toolName: p.toolName,\n precedence,\n paths: {\n global: isVendorOnly ? p.pathSkills : (agentsGlobalPath ?? null),\n project: isVendorOnly ? p.pathProjectSkills : (agentsProjectPath ?? null),\n },\n };\n });\n}\n\n/**\n * Get capabilities for a provider by ID or alias.\n *\n * @remarks\n * Shorthand for `getProvider(idOrAlias)?.capabilities`. Returns the full\n * capabilities object containing skills, hooks, and spawn sub-objects.\n *\n * @param idOrAlias - Provider ID or alias\n * @returns The provider's capabilities, or undefined if not found\n *\n * @example\n * ```typescript\n * const caps = getProviderCapabilities(\"claude-code\");\n * if (caps?.spawn.supportsSubagents) {\n * console.log(\"Supports subagent spawning\");\n * }\n * ```\n *\n * @public\n */\nexport function getProviderCapabilities(idOrAlias: string): ProviderCapabilities | undefined {\n return getProvider(idOrAlias)?.capabilities;\n}\n\n/**\n * Check if a provider supports a capability using ID/alias lookup.\n *\n * Convenience wrapper that resolves the provider first, then delegates\n * to the provider-level {@link providerSupports}.\n *\n * @remarks\n * Returns `false` both when the provider is not found and when the capability\n * is not supported. Use {@link getProvider} first if you need to distinguish\n * between these cases.\n *\n * @param idOrAlias - Provider ID or alias\n * @param capabilityPath - Dot-path into capabilities (e.g. \"spawn.supportsSubagents\")\n * @returns true if the provider supports the capability, false otherwise\n *\n * @example\n * ```typescript\n * if (providerSupportsById(\"claude-code\", \"spawn.supportsSubagents\")) {\n * console.log(\"Claude Code supports subagent spawning\");\n * }\n * ```\n *\n * @see {@link providerSupports}\n *\n * @public\n */\nexport function providerSupportsById(idOrAlias: string, capabilityPath: string): boolean {\n const provider = getProvider(idOrAlias);\n if (!provider) return false;\n return providerSupports(provider, capabilityPath);\n}\n","/**\n * Instruction template management\n *\n * Generates injection content based on provider capabilities.\n * Includes structured InjectionTemplate API for project-level customization.\n */\n\nimport type { Provider } from \"../../types.js\";\n\n// ── InjectionTemplate API ───────────────────────────────────────────\n\n/**\n * Structured template for injection content.\n *\n * @remarks\n * Projects use this to define what goes between CAAMP markers in\n * instruction files, rather than passing ad-hoc strings.\n *\n * @public\n */\nexport interface InjectionTemplate {\n /** References to include (e.g. `\"\\@AGENTS.md\"`, `\"\\@.cleo/project-context.json\"`). */\n references: string[];\n /** Inline content blocks (raw markdown/text). @defaultValue `undefined` */\n content?: string[];\n}\n\n/**\n * Build injection content from a structured template.\n *\n * Produces a string suitable for injection between CAAMP markers.\n * References are output as `@` lines, content blocks are appended as-is.\n *\n * @param template - Template defining references and content\n * @returns Formatted injection content string\n *\n * @remarks\n * References are output one per line. Content blocks are appended after a\n * blank separator line when references are present.\n *\n * @example\n * ```typescript\n * const content = buildInjectionContent({\n * references: [\"\\@AGENTS.md\"],\n * });\n * ```\n *\n * @public\n */\nexport function buildInjectionContent(template: InjectionTemplate): string {\n const lines: string[] = [];\n\n for (const ref of template.references) {\n lines.push(ref);\n }\n\n if (template.content && template.content.length > 0) {\n if (lines.length > 0) {\n lines.push(\"\");\n }\n lines.push(...template.content);\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Parse injection content back into template form.\n *\n * Lines starting with `@` are treated as references.\n * All other non-empty lines are treated as content blocks.\n *\n * @param content - Raw injection content string\n * @returns Parsed InjectionTemplate\n *\n * @remarks\n * Inverse of {@link buildInjectionContent}. Empty lines are ignored.\n *\n * @example\n * ```typescript\n * const template = parseInjectionContent(\"\\@AGENTS.md\\n\\@.cleo/config.json\");\n * ```\n *\n * @public\n */\nexport function parseInjectionContent(content: string): InjectionTemplate {\n const references: string[] = [];\n const contentLines: string[] = [];\n\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n\n if (trimmed.startsWith(\"@\")) {\n references.push(trimmed);\n } else {\n contentLines.push(line);\n }\n }\n\n return {\n references,\n content: contentLines.length > 0 ? contentLines : undefined,\n };\n}\n\n// ── Legacy API (preserved) ──────────────────────────────────────────\n\n/**\n * Generate a standard CAAMP injection block for instruction files.\n *\n * Produces markdown content suitable for injection between CAAMP markers.\n * Optionally includes MCP server and custom content sections.\n *\n * @remarks\n * This is the legacy API preserved for backward compatibility. New code\n * should prefer {@link buildInjectionContent} with an `InjectionTemplate`.\n *\n * @param options - Optional configuration for the generated content\n * @returns Generated markdown string\n *\n * @example\n * ```typescript\n * const content = generateInjectionContent({ mcpServerName: \"filesystem\" });\n * ```\n *\n * @public\n */\nexport function generateInjectionContent(options?: {\n mcpServerName?: string;\n customContent?: string;\n}): string {\n const lines: string[] = [];\n\n lines.push(\"## CAAMP Managed Configuration\");\n lines.push(\"\");\n lines.push(\"This section is managed by [CAAMP](https://github.com/caamp/caamp).\");\n lines.push(\"Do not edit between the CAAMP markers manually.\");\n\n if (options?.mcpServerName) {\n lines.push(\"\");\n lines.push(`### MCP Server: ${options.mcpServerName}`);\n lines.push(`Configured via \\`caamp mcp install\\`.`);\n }\n\n if (options?.customContent) {\n lines.push(\"\");\n lines.push(options.customContent);\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Generate a skills discovery section for instruction files.\n *\n * @remarks\n * Produces a markdown list of installed skill names. Returns an empty string\n * when no skills are provided.\n *\n * @param skillNames - Array of skill names to list\n * @returns Markdown string listing installed skills\n *\n * @example\n * ```typescript\n * const section = generateSkillsSection([\"code-review\", \"testing\"]);\n * ```\n *\n * @public\n */\nexport function generateSkillsSection(skillNames: string[]): string {\n if (skillNames.length === 0) return \"\";\n\n const lines: string[] = [];\n lines.push(\"### Installed Skills\");\n lines.push(\"\");\n\n for (const name of skillNames) {\n lines.push(`- \\`${name}\\` - Available via SKILL.md`);\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Get the correct instruction file name for a provider.\n *\n * @remarks\n * Simple accessor that returns the `instructFile` property from the provider\n * registry entry (e.g. `\"CLAUDE.md\"`, `\"AGENTS.md\"`, `\"GEMINI.md\"`).\n *\n * @param provider - Provider registry entry\n * @returns Instruction file name\n *\n * @example\n * ```typescript\n * const fileName = getInstructFile(provider);\n * // \"CLAUDE.md\"\n * ```\n *\n * @public\n */\nexport function getInstructFile(provider: Provider): string {\n return provider.instructFile;\n}\n\n/**\n * Group providers by their instruction file name.\n *\n * Useful for determining which providers share the same instruction file\n * (e.g. multiple providers using `AGENTS.md`).\n *\n * @param providers - Array of providers to group\n * @returns Map from instruction file name to array of providers using that file\n *\n * @remarks\n * Useful for determining which providers share the same instruction file\n * to avoid duplicate file operations.\n *\n * @example\n * ```typescript\n * const groups = groupByInstructFile(getAllProviders());\n * for (const [file, providers] of groups) {\n * console.log(`${file}: ${providers.map(p => p.id).join(\", \")}`);\n * }\n * ```\n *\n * @public\n */\nexport function groupByInstructFile(providers: Provider[]): Map<string, Provider[]> {\n const groups = new Map<string, Provider[]>();\n\n for (const provider of providers) {\n const existing = groups.get(provider.instructFile) ?? [];\n existing.push(provider);\n groups.set(provider.instructFile, existing);\n }\n\n return groups;\n}\n"],"mappings":"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","names":["dirname","join","dirname","updated","join"]}