@cleocode/caamp 2026.8.1 → 2026.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/skills/integrity.ts"],"sourcesContent":["/**\n * Skill integrity checking\n *\n * Validates that installed skills have intact symlinks, correct canonical paths,\n * and enforces ct-* prefix priority for CAAMP-shipped skills.\n */\n\nimport { existsSync, lstatSync, readlinkSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { resolveSkillsRoot } from '@cleocode/core/skills/skill-root.js';\nimport type { LockEntry, Provider } from '../../types.js';\nimport { readLockFile } from '../lock-utils.js';\nimport { resolveProviderSkillsDirs } from '../paths/standard.js';\n\n/** CAAMP-reserved skill prefix. Skills with this prefix are owned by CAAMP. */\nconst CAAMP_SKILL_PREFIX = 'ct-';\n\n/**\n * Status of a single skill's integrity check.\n *\n * @public\n */\nexport type SkillIntegrityStatus =\n | 'intact'\n | 'broken-symlink'\n | 'missing-canonical'\n | 'missing-link'\n | 'not-tracked'\n | 'tampered';\n\n/**\n * Result of checking a single skill's integrity.\n *\n * @public\n */\nexport interface SkillIntegrityResult {\n /** Skill name. */\n name: string;\n /** Overall integrity status. */\n status: SkillIntegrityStatus;\n /** Whether the canonical directory exists. */\n canonicalExists: boolean;\n /** Expected canonical path from lock file. */\n canonicalPath: string | null;\n /** Provider link statuses — which agents have valid symlinks. */\n linkStatuses: Array<{\n providerId: string;\n linkPath: string;\n exists: boolean;\n isSymlink: boolean;\n pointsToCanonical: boolean;\n }>;\n /** Whether this is a CAAMP-reserved (ct-*) skill. */\n isCaampOwned: boolean;\n /** Human-readable issue description, if any. */\n issue?: string;\n}\n\n/**\n * Check whether a skill name is reserved by CAAMP (ct-* prefix).\n *\n * @remarks\n * Skills with the `ct-` prefix are considered CAAMP-owned and receive\n * special treatment during installation conflict resolution.\n *\n * @param skillName - Skill name to check\n * @returns `true` if the skill name starts with `ct-`\n *\n * @example\n * ```typescript\n * isCaampOwnedSkill(\"ct-research-agent\"); // true\n * isCaampOwnedSkill(\"my-custom-skill\"); // false\n * ```\n *\n * @public\n */\nexport function isCaampOwnedSkill(skillName: string): boolean {\n return skillName.startsWith(CAAMP_SKILL_PREFIX);\n}\n\n/**\n * Check the integrity of a single installed skill.\n *\n * @remarks\n * Validates that the canonical directory exists on disk, the lock file entry\n * matches the actual state, and symlinks from provider skill directories\n * point to the canonical path.\n *\n * @param skillName - Name of the skill to check\n * @param providers - Providers to check symlinks for\n * @param scope - Whether to check global or project links\n * @param projectDir - Project directory (for project scope)\n * @returns Integrity check result\n *\n * @example\n * ```typescript\n * const result = await checkSkillIntegrity(\"ct-research-agent\", providers, \"global\");\n * if (result.status !== \"intact\") {\n * console.log(`Issue: ${result.issue}`);\n * }\n * ```\n *\n * @public\n */\nexport async function checkSkillIntegrity(\n skillName: string,\n providers: Provider[],\n scope: 'global' | 'project' = 'global',\n projectDir?: string,\n): Promise<SkillIntegrityResult> {\n const lock = await readLockFile();\n const entry = lock.skills[skillName];\n const isCaampOwned = isCaampOwnedSkill(skillName);\n\n // Not tracked in lock file\n if (!entry) {\n const canonicalPath = join(resolveSkillsRoot(), skillName);\n return {\n name: skillName,\n status: 'not-tracked',\n canonicalExists: existsSync(canonicalPath),\n canonicalPath: null,\n linkStatuses: [],\n isCaampOwned,\n issue: 'Skill is not tracked in the CAAMP lock file',\n };\n }\n\n const canonicalPath = entry.canonicalPath;\n const canonicalExists = existsSync(canonicalPath);\n\n // Check symlinks for each provider\n const linkStatuses: SkillIntegrityResult['linkStatuses'] = [];\n\n for (const provider of providers) {\n const targetDirs = resolveProviderSkillsDirs(provider, scope, projectDir);\n for (const skillsDir of targetDirs) {\n if (!skillsDir) continue;\n\n const linkPath = join(skillsDir, skillName);\n const exists = existsSync(linkPath);\n let isSymlink = false;\n let pointsToCanonical = false;\n\n if (exists) {\n try {\n const stat = lstatSync(linkPath);\n isSymlink = stat.isSymbolicLink();\n if (isSymlink) {\n const target = resolve(readlinkSync(linkPath));\n pointsToCanonical = target === resolve(canonicalPath);\n }\n } catch {\n // Can't stat — treat as broken\n }\n }\n\n linkStatuses.push({\n providerId: provider.id,\n linkPath,\n exists,\n isSymlink,\n pointsToCanonical,\n });\n }\n }\n\n // Determine overall status\n if (!canonicalExists) {\n return {\n name: skillName,\n status: 'missing-canonical',\n canonicalExists,\n canonicalPath,\n linkStatuses,\n isCaampOwned,\n issue: `Canonical directory missing: ${canonicalPath}`,\n };\n }\n\n const brokenLinks = linkStatuses.filter((l) => !l.exists);\n const tamperedLinks = linkStatuses.filter((l) => l.exists && !l.pointsToCanonical);\n\n if (tamperedLinks.length > 0) {\n return {\n name: skillName,\n status: 'tampered',\n canonicalExists,\n canonicalPath,\n linkStatuses,\n isCaampOwned,\n issue: `${tamperedLinks.length} link(s) do not point to canonical path`,\n };\n }\n\n if (brokenLinks.length > 0) {\n return {\n name: skillName,\n status: 'broken-symlink',\n canonicalExists,\n canonicalPath,\n linkStatuses,\n isCaampOwned,\n issue: `${brokenLinks.length} symlink(s) missing`,\n };\n }\n\n return {\n name: skillName,\n status: 'intact',\n canonicalExists,\n canonicalPath,\n linkStatuses,\n isCaampOwned,\n };\n}\n\n/**\n * Check integrity of all tracked skills.\n *\n * @remarks\n * Iterates over every skill in the lock file and runs\n * {@link checkSkillIntegrity} on each.\n *\n * @param providers - Providers to check symlinks for\n * @param scope - Whether to check global or project links\n * @param projectDir - Project directory (for project scope)\n * @returns Map of skill name to integrity result\n *\n * @example\n * ```typescript\n * const results = await checkAllSkillIntegrity(providers);\n * for (const [name, result] of results) {\n * console.log(`${name}: ${result.status}`);\n * }\n * ```\n *\n * @public\n */\nexport async function checkAllSkillIntegrity(\n providers: Provider[],\n scope: 'global' | 'project' = 'global',\n projectDir?: string,\n): Promise<Map<string, SkillIntegrityResult>> {\n const lock = await readLockFile();\n const results = new Map<string, SkillIntegrityResult>();\n\n for (const skillName of Object.keys(lock.skills)) {\n const result = await checkSkillIntegrity(skillName, providers, scope, projectDir);\n results.set(skillName, result);\n }\n\n return results;\n}\n\n/**\n * Resolve a skill name conflict where a user-installed skill collides\n * with a CAAMP-owned (ct-*) skill.\n *\n * @remarks\n * CAAMP-owned skills always win. Returns `true` if the incoming skill\n * should take precedence over the existing installation.\n *\n * @param skillName - Skill name to check\n * @param incomingSource - Source of the incoming skill installation\n * @param existingEntry - Existing lock entry, if any\n * @returns `true` if the incoming installation should proceed\n *\n * @example\n * ```typescript\n * const proceed = shouldOverrideSkill(\"ct-research-agent\", \"library\", existingEntry);\n * if (proceed) {\n * // Safe to install/override\n * }\n * ```\n *\n * @public\n */\nexport function shouldOverrideSkill(\n skillName: string,\n incomingSource: string,\n existingEntry: LockEntry | undefined,\n): boolean {\n // No existing entry — always allow\n if (!existingEntry) return true;\n\n // For ct-* skills, CAAMP package source always wins\n if (isCaampOwnedSkill(skillName)) {\n // If incoming is from CAAMP package (library source), it always wins\n if (existingEntry.sourceType === 'library') return true;\n // If existing is from CAAMP but incoming is user, CAAMP wins (block user)\n return true;\n }\n\n // Non-ct-* skills: user always wins\n return true;\n}\n\n/**\n * Validate instruction file injection status across all providers.\n *\n * @remarks\n * Checks that CAAMP blocks exist and are current in all relevant\n * instruction files (CLAUDE.md, AGENTS.md, GEMINI.md).\n *\n * @param providers - Providers to check\n * @param projectDir - Project directory\n * @param scope - Whether to check global or project files\n * @param expectedContent - Expected CAAMP block content\n * @returns Array of file paths with issues\n *\n * @example\n * ```typescript\n * const issues = await validateInstructionIntegrity(providers, process.cwd(), \"project\");\n * for (const issue of issues) {\n * console.log(`${issue.providerId}: ${issue.issue} (${issue.file})`);\n * }\n * ```\n *\n * @public\n */\nexport async function validateInstructionIntegrity(\n providers: Provider[],\n projectDir: string,\n scope: 'project' | 'global',\n expectedContent?: string,\n): Promise<Array<{ file: string; providerId: string; issue: string }>> {\n const { checkAllInjections } = await import('../instructions/injector.js');\n const results = await checkAllInjections(providers, projectDir, scope, expectedContent);\n const issues: Array<{ file: string; providerId: string; issue: string }> = [];\n\n for (const result of results) {\n if (result.status === 'missing') {\n issues.push({\n file: result.file,\n providerId: result.provider,\n issue: 'Instruction file does not exist',\n });\n } else if (result.status === 'none') {\n issues.push({\n file: result.file,\n providerId: result.provider,\n issue: 'No CAAMP injection block found',\n });\n } else if (result.status === 'outdated') {\n issues.push({\n file: result.file,\n providerId: result.provider,\n issue: 'CAAMP injection block is outdated',\n });\n }\n }\n\n return issues;\n}\n"],"mappings":"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","names":["canonicalPath","checkAllInjections"]}
1
+ {"version":3,"sources":["../src/core/skills/integrity.ts"],"sourcesContent":["/**\n * Skill integrity checking\n *\n * Validates that installed skills have intact symlinks, correct canonical paths,\n * and enforces ct-* prefix priority for CAAMP-shipped skills.\n */\n\nimport { existsSync, lstatSync, readlinkSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { resolveSkillsRoot } from '@cleocode/core/skills/skill-root.js';\nimport type { LockEntry, Provider } from '../../types.js';\nimport { readLockFile } from '../lock-utils.js';\nimport { resolveProviderSkillsDirs } from '../paths/standard.js';\n\n/** CAAMP-reserved skill prefix. Skills with this prefix are owned by CAAMP. */\nconst CAAMP_SKILL_PREFIX = 'ct-';\n\n/**\n * Status of a single skill's integrity check.\n *\n * @public\n */\nexport type SkillIntegrityStatus =\n | 'intact'\n | 'broken-symlink'\n | 'missing-canonical'\n | 'missing-link'\n | 'not-tracked'\n | 'tampered';\n\n/**\n * Result of checking a single skill's integrity.\n *\n * @public\n */\nexport interface SkillIntegrityResult {\n /** Skill name. */\n name: string;\n /** Overall integrity status. */\n status: SkillIntegrityStatus;\n /** Whether the canonical directory exists. */\n canonicalExists: boolean;\n /** Expected canonical path from lock file. */\n canonicalPath: string | null;\n /** Provider link statuses — which agents have valid symlinks. */\n linkStatuses: Array<{\n providerId: string;\n linkPath: string;\n exists: boolean;\n isSymlink: boolean;\n pointsToCanonical: boolean;\n }>;\n /** Whether this is a CAAMP-reserved (ct-*) skill. */\n isCaampOwned: boolean;\n /** Human-readable issue description, if any. */\n issue?: string;\n}\n\n/**\n * Check whether a skill name is reserved by CAAMP (ct-* prefix).\n *\n * @remarks\n * Skills with the `ct-` prefix are considered CAAMP-owned and receive\n * special treatment during installation conflict resolution.\n *\n * @param skillName - Skill name to check\n * @returns `true` if the skill name starts with `ct-`\n *\n * @example\n * ```typescript\n * isCaampOwnedSkill(\"ct-research-agent\"); // true\n * isCaampOwnedSkill(\"my-custom-skill\"); // false\n * ```\n *\n * @public\n */\nexport function isCaampOwnedSkill(skillName: string): boolean {\n return skillName.startsWith(CAAMP_SKILL_PREFIX);\n}\n\n/**\n * Check the integrity of a single installed skill.\n *\n * @remarks\n * Validates that the canonical directory exists on disk, the lock file entry\n * matches the actual state, and symlinks from provider skill directories\n * point to the canonical path.\n *\n * @param skillName - Name of the skill to check\n * @param providers - Providers to check symlinks for\n * @param scope - Whether to check global or project links\n * @param projectDir - Project directory (for project scope)\n * @returns Integrity check result\n *\n * @example\n * ```typescript\n * const result = await checkSkillIntegrity(\"ct-research-agent\", providers, \"global\");\n * if (result.status !== \"intact\") {\n * console.log(`Issue: ${result.issue}`);\n * }\n * ```\n *\n * @public\n */\nexport async function checkSkillIntegrity(\n skillName: string,\n providers: Provider[],\n scope: 'global' | 'project' = 'global',\n projectDir?: string,\n): Promise<SkillIntegrityResult> {\n const lock = await readLockFile();\n const entry = lock.skills[skillName];\n const isCaampOwned = isCaampOwnedSkill(skillName);\n\n // Not tracked in lock file\n if (!entry) {\n const canonicalPath = join(resolveSkillsRoot(), skillName);\n return {\n name: skillName,\n status: 'not-tracked',\n canonicalExists: existsSync(canonicalPath),\n canonicalPath: null,\n linkStatuses: [],\n isCaampOwned,\n issue: 'Skill is not tracked in the CAAMP lock file',\n };\n }\n\n const canonicalPath = entry.canonicalPath;\n const canonicalExists = existsSync(canonicalPath);\n\n // Check symlinks for each provider\n const linkStatuses: SkillIntegrityResult['linkStatuses'] = [];\n\n for (const provider of providers) {\n const targetDirs = resolveProviderSkillsDirs(provider, scope, projectDir);\n for (const skillsDir of targetDirs) {\n if (!skillsDir) continue;\n\n const linkPath = join(skillsDir, skillName);\n const exists = existsSync(linkPath);\n let isSymlink = false;\n let pointsToCanonical = false;\n\n if (exists) {\n try {\n const stat = lstatSync(linkPath);\n isSymlink = stat.isSymbolicLink();\n if (isSymlink) {\n const target = resolve(readlinkSync(linkPath));\n pointsToCanonical = target === resolve(canonicalPath);\n }\n } catch {\n // Can't stat — treat as broken\n }\n }\n\n linkStatuses.push({\n providerId: provider.id,\n linkPath,\n exists,\n isSymlink,\n pointsToCanonical,\n });\n }\n }\n\n // Determine overall status\n if (!canonicalExists) {\n return {\n name: skillName,\n status: 'missing-canonical',\n canonicalExists,\n canonicalPath,\n linkStatuses,\n isCaampOwned,\n issue: `Canonical directory missing: ${canonicalPath}`,\n };\n }\n\n const brokenLinks = linkStatuses.filter((l) => !l.exists);\n const tamperedLinks = linkStatuses.filter((l) => l.exists && !l.pointsToCanonical);\n\n if (tamperedLinks.length > 0) {\n return {\n name: skillName,\n status: 'tampered',\n canonicalExists,\n canonicalPath,\n linkStatuses,\n isCaampOwned,\n issue: `${tamperedLinks.length} link(s) do not point to canonical path`,\n };\n }\n\n if (brokenLinks.length > 0) {\n return {\n name: skillName,\n status: 'broken-symlink',\n canonicalExists,\n canonicalPath,\n linkStatuses,\n isCaampOwned,\n issue: `${brokenLinks.length} symlink(s) missing`,\n };\n }\n\n return {\n name: skillName,\n status: 'intact',\n canonicalExists,\n canonicalPath,\n linkStatuses,\n isCaampOwned,\n };\n}\n\n/**\n * Check integrity of all tracked skills.\n *\n * @remarks\n * Iterates over every skill in the lock file and runs\n * {@link checkSkillIntegrity} on each.\n *\n * @param providers - Providers to check symlinks for\n * @param scope - Whether to check global or project links\n * @param projectDir - Project directory (for project scope)\n * @returns Map of skill name to integrity result\n *\n * @example\n * ```typescript\n * const results = await checkAllSkillIntegrity(providers);\n * for (const [name, result] of results) {\n * console.log(`${name}: ${result.status}`);\n * }\n * ```\n *\n * @public\n */\nexport async function checkAllSkillIntegrity(\n providers: Provider[],\n scope: 'global' | 'project' = 'global',\n projectDir?: string,\n): Promise<Map<string, SkillIntegrityResult>> {\n const lock = await readLockFile();\n const results = new Map<string, SkillIntegrityResult>();\n\n for (const skillName of Object.keys(lock.skills)) {\n const result = await checkSkillIntegrity(skillName, providers, scope, projectDir);\n results.set(skillName, result);\n }\n\n return results;\n}\n\n/**\n * Resolve a skill name conflict where a user-installed skill collides\n * with a CAAMP-owned (ct-*) skill.\n *\n * @remarks\n * CAAMP-owned skills always win. Returns `true` if the incoming skill\n * should take precedence over the existing installation.\n *\n * @param skillName - Skill name to check\n * @param incomingSource - Source of the incoming skill installation\n * @param existingEntry - Existing lock entry, if any\n * @returns `true` if the incoming installation should proceed\n *\n * @example\n * ```typescript\n * const proceed = shouldOverrideSkill(\"ct-research-agent\", \"library\", existingEntry);\n * if (proceed) {\n * // Safe to install/override\n * }\n * ```\n *\n * @public\n */\nexport function shouldOverrideSkill(\n skillName: string,\n incomingSource: string,\n existingEntry: LockEntry | undefined,\n): boolean {\n // No existing entry — always allow\n if (!existingEntry) return true;\n\n // For ct-* skills, CAAMP package source always wins\n if (isCaampOwnedSkill(skillName)) {\n // If incoming is from CAAMP package (library source), it always wins\n if (existingEntry.sourceType === 'library') return true;\n // If existing is from CAAMP but incoming is user, CAAMP wins (block user)\n return true;\n }\n\n // Non-ct-* skills: user always wins\n return true;\n}\n\n/**\n * Validate instruction file injection status across all providers.\n *\n * @remarks\n * Checks that CAAMP blocks exist and are current in all relevant\n * instruction files (CLAUDE.md, AGENTS.md, GEMINI.md).\n *\n * @param providers - Providers to check\n * @param projectDir - Project directory\n * @param scope - Whether to check global or project files\n * @param expectedContent - Expected CAAMP block content\n * @returns Array of file paths with issues\n *\n * @example\n * ```typescript\n * const issues = await validateInstructionIntegrity(providers, process.cwd(), \"project\");\n * for (const issue of issues) {\n * console.log(`${issue.providerId}: ${issue.issue} (${issue.file})`);\n * }\n * ```\n *\n * @public\n */\nexport async function validateInstructionIntegrity(\n providers: Provider[],\n projectDir: string,\n scope: 'project' | 'global',\n expectedContent?: string,\n): Promise<Array<{ file: string; providerId: string; issue: string }>> {\n const { checkAllInjections } = await import('../instructions/injector.js');\n const results = await checkAllInjections(providers, projectDir, scope, expectedContent);\n const issues: Array<{ file: string; providerId: string; issue: string }> = [];\n\n for (const result of results) {\n if (result.status === 'missing') {\n issues.push({\n file: result.file,\n providerId: result.provider,\n issue: 'Instruction file does not exist',\n });\n } else if (result.status === 'none') {\n issues.push({\n file: result.file,\n providerId: result.provider,\n issue: 'No CAAMP injection block found',\n });\n } else if (result.status === 'outdated') {\n issues.push({\n file: result.file,\n providerId: result.provider,\n issue: 'CAAMP injection block is outdated',\n });\n }\n }\n\n return issues;\n}\n"],"mappings":"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","names":["canonicalPath","checkAllInjections"]}
@@ -8,10 +8,12 @@ import {
8
8
  getProviderAgentFolder,
9
9
  inject,
10
10
  injectAll,
11
+ instructionFileCascade,
11
12
  parseCaampBlocks,
12
13
  removeInjection,
14
+ repairInstructionFiles,
13
15
  writeAgentFileToAllProviders
14
- } from "./chunk-EH5U4PRC.js";
16
+ } from "./chunk-3IQUGSIV.js";
15
17
  import "./chunk-HDZYZTR2.js";
16
18
  export {
17
19
  checkAllInjections,
@@ -23,8 +25,10 @@ export {
23
25
  getProviderAgentFolder,
24
26
  inject,
25
27
  injectAll,
28
+ instructionFileCascade,
26
29
  parseCaampBlocks,
27
30
  removeInjection,
31
+ repairInstructionFiles,
28
32
  writeAgentFileToAllProviders
29
33
  };
30
- //# sourceMappingURL=injector-3TOVIDBO.js.map
34
+ //# sourceMappingURL=injector-6YGSK3B6.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cleocode/caamp",
3
- "version": "2026.8.1",
3
+ "version": "2026.8.2",
4
4
  "description": "Central AI Agent Managed Packages - unified provider registry and package manager for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -50,14 +50,14 @@
50
50
  "jsonc-parser": "^3.3.1",
51
51
  "picocolors": "^1.1.1",
52
52
  "simple-git": "3.33.0",
53
- "@cleocode/contracts": "2026.8.1",
54
- "@cleocode/core": "2026.8.1",
55
- "@cleocode/cant": "2026.8.1",
56
- "@cleocode/paths": "2026.8.1",
57
- "@cleocode/lafs": "2026.8.1"
53
+ "@cleocode/cant": "2026.8.2",
54
+ "@cleocode/lafs": "2026.8.2",
55
+ "@cleocode/paths": "2026.8.2",
56
+ "@cleocode/contracts": "2026.8.2",
57
+ "@cleocode/core": "2026.8.2"
58
58
  },
59
59
  "peerDependencies": {
60
- "@cleocode/core": "2026.8.1"
60
+ "@cleocode/core": "2026.8.2"
61
61
  },
62
62
  "peerDependenciesMeta": {
63
63
  "@cleocode/core": {
@@ -1 +0,0 @@
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) and agent-definition files\n * (cleo-subagent.md, seed agent profiles) per provider's native folder.\n */\n\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport type { InjectionCheckResult, InjectionStatus, Provider } from '../../types.js';\nimport { getProvider, getProviderInstructionReferences } 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// ── Block parsing ──────────────────────────────────────────────────────────\n\n/**\n * A single parsed CAAMP block extracted from a file.\n *\n * @public\n */\nexport interface CaampBlock {\n /** Raw text of the entire block including markers. */\n raw: string;\n /** Trimmed content between the markers. */\n content: string;\n /** Zero-based character offset of the start of the block in the file. */\n startIndex: number;\n /** Zero-based character offset immediately after the block in the file. */\n endIndex: number;\n}\n\n/**\n * Parse all CAAMP blocks from a file's content string.\n *\n * Returns an array of {@link CaampBlock} objects in order of appearance.\n * Blocks with malformed markers (START without matching END) are silently\n * skipped to avoid crashing on corrupted files.\n *\n * @param fileContent - Raw text content of the file\n * @returns Array of parsed CAAMP blocks\n *\n * @public\n */\nexport function parseCaampBlocks(fileContent: string): CaampBlock[] {\n const blocks: CaampBlock[] = [];\n const pattern = /<!-- CAAMP:START -->([\\s\\S]*?)<!-- CAAMP:END -->/g;\n\n for (let match = pattern.exec(fileContent); match !== null; match = pattern.exec(fileContent)) {\n const raw = match[0];\n const innerContent = match[1] ?? '';\n blocks.push({\n raw,\n content: innerContent.trim(),\n startIndex: match.index,\n endIndex: match.index + raw.length,\n });\n }\n\n return blocks;\n}\n\n/**\n * Result of deduplicating CAAMP blocks in a single file.\n *\n * @public\n */\nexport interface DedupeResult {\n /** Absolute path to the file that was processed. */\n filePath: string;\n /** Number of duplicate blocks removed. */\n removed: number;\n /** Number of unique blocks kept. */\n kept: number;\n /** `true` if the file was modified on disk; `false` if it was already clean. */\n modified: boolean;\n}\n\n/**\n * Deduplicate CAAMP blocks in a file by content.\n *\n * Groups all `<!-- CAAMP:START -->...<!-- CAAMP:END -->` blocks by their\n * trimmed inner content. For each group that has more than one block, keeps\n * only the **last** occurrence (most recently written) and removes the earlier\n * duplicates. Blocks with distinct contents are preserved in their original\n * relative order.\n *\n * Idempotent: calling this on an already-clean file returns `modified: false`\n * and makes no filesystem writes.\n *\n * @param filePath - Absolute path to the file to deduplicate\n * @returns Dedup summary\n *\n * @remarks\n * \"Last occurrence wins\" matches the behaviour of CLEO's injection chain,\n * which writes the canonical `@~/.local/share/cleo/…` path on every session.\n * Stale temp-path blocks from earlier sessions therefore have earlier indices\n * and are removed, leaving the canonical block.\n *\n * @example\n * ```typescript\n * const result = await dedupeFile(\"/home/user/.agents/AGENTS.md\");\n * console.log(`Removed ${result.removed} duplicate(s)`);\n * ```\n *\n * @public\n */\nexport async function dedupeFile(filePath: string): Promise<DedupeResult> {\n if (!existsSync(filePath)) {\n return { filePath, removed: 0, kept: 0, modified: false };\n }\n\n const fileContent = await readFile(filePath, 'utf-8');\n const blocks = parseCaampBlocks(fileContent);\n\n if (blocks.length === 0) {\n return { filePath, removed: 0, kept: 0, modified: false };\n }\n\n // Group by trimmed content — last occurrence wins\n const lastByContent = new Map<string, CaampBlock>();\n for (const block of blocks) {\n lastByContent.set(block.content, block);\n }\n\n const keepSet = new Set<CaampBlock>(lastByContent.values());\n const removed = blocks.length - keepSet.size;\n\n if (removed === 0) {\n // Already clean\n return { filePath, removed: 0, kept: blocks.length, modified: false };\n }\n\n // Rebuild file content: walk through original text, emit blocks that are\n // in keepSet and skip duplicates. Non-block text between blocks is preserved.\n let result = '';\n let cursor = 0;\n\n for (const block of blocks) {\n // Emit any non-block text before this block\n result += fileContent.slice(cursor, block.startIndex);\n cursor = block.endIndex;\n\n if (keepSet.has(block)) {\n result += block.raw;\n }\n // Removed duplicates contribute nothing — surrounding whitespace is\n // normalized by the final collapse step below.\n }\n\n // Emit any trailing text after the last block\n result += fileContent.slice(cursor);\n\n // Normalize: collapse 3+ consecutive newlines → 2, trim trailing whitespace\n result = result.replace(/\\n{3,}/g, '\\n\\n').trimEnd() + '\\n';\n\n await writeFile(filePath, result, 'utf-8');\n\n return { filePath, removed, kept: keepSet.size, modified: true };\n}\n\n/**\n * Deduplicate CAAMP blocks across multiple files.\n *\n * Runs {@link dedupeFile} on each path in order and collects results.\n * Files that do not exist are skipped silently (their result has `removed: 0`).\n *\n * @param filePaths - Array of absolute file paths to process\n * @returns Array of results, one per input path\n *\n * @example\n * ```typescript\n * const results = await dedupeFiles([\n * \"/home/user/.agents/AGENTS.md\",\n * \"/project/AGENTS.md\",\n * ]);\n * const totalRemoved = results.reduce((n, r) => n + r.removed, 0);\n * console.log(`Removed ${totalRemoved} duplicate(s) across ${results.length} files`);\n * ```\n *\n * @public\n */\nexport async function dedupeFiles(filePaths: string[]): Promise<DedupeResult[]> {\n const results: DedupeResult[] = [];\n for (const filePath of filePaths) {\n results.push(await dedupeFile(filePath));\n }\n return results;\n}\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].replace(MARKER_START, '').replace(MARKER_END, '').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 ? `${block}\\n\\n${updated}` : `${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 =\n 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 =\n 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 /**\n * `@` references to inject (e.g. `[\"@AGENTS.md\"]`).\n *\n * When omitted or `undefined`, the references declared in the CAAMP provider\n * registry (`provider.instructionReferences`) are used as the default. Callers\n * that supply an explicit array always take precedence over the registry default.\n *\n * @defaultValue Registry `instructionReferences` for the provider\n */\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 =\n scope === 'global'\n ? join(provider.pathGlobal, provider.instructFile)\n : join(projectDir, provider.instructFile);\n\n // Fall back to the registry default when the caller omits references.\n const references = options.references ?? getProviderInstructionReferences(providerId);\n\n const template: InjectionTemplate = {\n 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 =\n 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 // Fall back to the registry default when the caller omits references.\n const references = options.references ?? getProviderInstructionReferences(providerId);\n\n const template: InjectionTemplate = {\n 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// ── Per-Provider Agent Folder API ─────────────────────────────────\n\n/**\n * Known provider IDs that have a defined agent folder path.\n *\n * @public\n */\nexport type KnownProviderAgentFolderId =\n | 'claude-code'\n | 'claude-sdk'\n | 'opencode'\n | 'codex'\n | 'cursor'\n | 'pi'\n | 'kimi'\n | 'gemini-cli'\n | 'openai-sdk';\n\n/**\n * Resolve the native agent-definition folder path for a given provider.\n *\n * Each AI provider reads agent-definition files (e.g. `cleo-subagent.md`,\n * seed agent profiles) from its own platform-specific directory. This\n * function returns the correct path per provider so the CAAMP injector can\n * write agent files to the right location for every enabled provider.\n *\n * Follows XDG conventions (`~/.config/<provider>/agents/`) for providers\n * that do not have a pre-existing dotfolder convention. Claude Code and\n * Claude SDK both share `~/.claude/agents/` to match the Claude Code\n * native agent-loading path.\n *\n * Returns `null` for unknown provider IDs so callers can handle the gap\n * without throwing.\n *\n * @param providerId - Provider ID from the CAAMP registry (e.g. `\"claude-code\"`, `\"opencode\"`)\n * @returns Absolute path to the provider's agent folder, or `null` if the provider is unknown\n *\n * @example\n * ```typescript\n * const folder = getProviderAgentFolder(\"claude-code\");\n * // => \"/home/user/.claude/agents\"\n *\n * const folder2 = getProviderAgentFolder(\"opencode\");\n * // => \"/home/user/.config/opencode/agents\"\n *\n * const folder3 = getProviderAgentFolder(\"unknown-provider\");\n * // => null\n * ```\n *\n * @public\n */\nexport function getProviderAgentFolder(providerId: string): string | null {\n const home = homedir();\n\n switch (providerId as KnownProviderAgentFolderId) {\n case 'claude-code':\n case 'claude-sdk':\n return join(home, '.claude', 'agents');\n case 'opencode':\n return join(home, '.config', 'opencode', 'agents');\n case 'codex':\n return join(home, '.config', 'codex', 'agents');\n case 'cursor':\n return join(home, '.cursor', 'agents');\n case 'pi':\n return join(home, '.config', 'pi', 'agents');\n case 'kimi':\n return join(home, '.config', 'kimi', 'agents');\n case 'gemini-cli':\n return join(home, '.config', 'gemini', 'agents');\n case 'openai-sdk':\n return join(home, '.config', 'openai', 'agents');\n default:\n return null;\n }\n}\n\n/**\n * Result of writing an agent-definition file to a single provider's agent folder.\n *\n * @public\n */\nexport interface WriteAgentFileResult {\n /** Provider ID the file was written for. */\n providerId: string;\n /** Absolute path to the written agent-definition file. */\n filePath: string;\n /** Action taken. */\n action: 'created' | 'added' | 'consolidated' | 'updated' | 'intact';\n}\n\n/**\n * Options for writing agent-definition files to provider agent folders.\n *\n * @public\n */\nexport interface WriteAgentFileOptions {\n /**\n * File name for the agent-definition file (e.g. `\"cleo-subagent.md\"`).\n * This name is used as-is inside each provider's agent folder.\n */\n fileName: string;\n /** Content to inject between CAAMP markers in the agent-definition file. */\n content: string;\n /**\n * If `true`, skip writing to providers whose agent folder does not yet exist.\n * If `false` (default), the folder is created automatically.\n *\n * @defaultValue false\n */\n skipMissingFolders?: boolean;\n}\n\n/**\n * Write an agent-definition file to every enabled provider's native agent folder.\n *\n * For each provider ID supplied, the file is written to the provider's native\n * agent-definition directory (resolved via {@link getProviderAgentFolder}).\n * Writing is idempotent — if the file already exists with matching content the\n * action is `\"intact\"` and the file is not modified. This ensures that existing\n * `~/.claude/agents/cleo-subagent.md` installs from prior versions are preserved\n * without clobbering.\n *\n * Providers whose folder cannot be resolved (unknown provider IDs) are silently\n * skipped. Providers whose folder does not yet exist on disk are created\n * automatically unless `skipMissingFolders` is set to `true`.\n *\n * @param providerIds - Array of provider IDs to write agent files for\n * @param options - File name, content, and folder-creation behaviour\n * @returns Array of write results, one per provider that was successfully processed\n *\n * @example\n * ```typescript\n * const results = await writeAgentFileToAllProviders(\n * [\"claude-code\", \"opencode\", \"cursor\"],\n * {\n * fileName: \"cleo-subagent.md\",\n * content: \"## CLEO Subagent\\nYou are a CLEO subagent...\",\n * },\n * );\n * for (const r of results) {\n * console.log(`${r.providerId}: ${r.action} → ${r.filePath}`);\n * }\n * ```\n *\n * @public\n */\nexport async function writeAgentFileToAllProviders(\n providerIds: string[],\n options: WriteAgentFileOptions,\n): Promise<WriteAgentFileResult[]> {\n const results: WriteAgentFileResult[] = [];\n const processed = new Set<string>();\n\n for (const providerId of providerIds) {\n const folder = getProviderAgentFolder(providerId);\n if (folder === null) {\n // Unknown provider — skip silently; caller can detect by comparing\n // providerIds.length to results.length.\n continue;\n }\n\n const filePath = join(folder, options.fileName);\n\n // Deduplicate by resolved file path — claude-code and claude-sdk share\n // the same folder so we only write once.\n if (processed.has(filePath)) {\n // Still push a result so the caller sees all providers reflected.\n const existingResult = results.find((r) => r.filePath === filePath);\n if (existingResult) {\n results.push({ providerId, filePath, action: existingResult.action });\n }\n continue;\n }\n processed.add(filePath);\n\n if (options.skipMissingFolders === true && !existsSync(folder)) {\n // Folder does not exist and caller requested we skip rather than create.\n continue;\n }\n\n const action = await inject(filePath, options.content);\n results.push({ providerId, filePath, action });\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 DetectionMethod,\n Provider,\n ProviderCapabilities,\n ProviderHarnessCapability,\n ProviderHooksCapability,\n ProviderMcpCapability,\n ProviderSkillsCapability,\n ProviderSpawnCapability,\n} from '../../types.js';\nimport {\n type PathScope,\n resolveProviderSkillsDir,\n resolveProvidersRegistryPath,\n resolveRegistryTemplatePath,\n} from '../paths/standard.js';\nimport type {\n HookEvent,\n ProviderPriority,\n ProviderRegistry,\n ProviderStatus,\n RegistryCapabilities,\n RegistryHarnessCapability,\n RegistryHooksCapability,\n RegistryMcpIntegration,\n RegistryProvider,\n RegistrySpawnCapability,\n SkillsPrecedence,\n} 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 hookConfigPathProject: null,\n hookFormat: null,\n nativeEventCatalog: 'canonical',\n canInjectSystemPrompt: false,\n canBlockTools: false,\n};\n\nconst DEFAULT_SPAWN_CAPABILITY: ProviderSpawnCapability = {\n supportsSubagents: false,\n supportsProgrammaticSpawn: false,\n supportsInterAgentComms: false,\n supportsParallelSpawn: false,\n spawnMechanism: null,\n spawnCommand: null,\n};\n\nfunction resolveMcpCapability(raw: RegistryMcpIntegration): ProviderMcpCapability {\n return {\n configKey: raw.configKey,\n configFormat: raw.configFormat,\n configPathGlobal: resolveRegistryTemplatePath(raw.configPathGlobal),\n configPathProject: raw.configPathProject,\n supportedTransports: [...raw.supportedTransports],\n supportsHeaders: raw.supportsHeaders,\n };\n}\n\nfunction resolveHarnessCapability(raw: RegistryHarnessCapability): ProviderHarnessCapability {\n return {\n kind: raw.kind,\n spawnTargets: [...raw.spawnTargets],\n supportsConductorLoop: raw.supportsConductorLoop,\n supportsStageGuidance: raw.supportsStageGuidance,\n supportsCantBridge: raw.supportsCantBridge,\n extensionsPath: resolveRegistryTemplatePath(raw.extensionsPath),\n globalExtensionsHub: raw.globalExtensionsHub\n ? resolveRegistryTemplatePath(raw.globalExtensionsHub)\n : null,\n };\n}\n\nfunction resolveHooksCapability(raw: RegistryHooksCapability): ProviderHooksCapability {\n return {\n supported: [...raw.supported],\n hookConfigPath: raw.hookConfigPath ? resolveRegistryTemplatePath(raw.hookConfigPath) : null,\n hookConfigPathProject: raw.hookConfigPathProject ?? null,\n hookFormat: raw.hookFormat,\n nativeEventCatalog: raw.nativeEventCatalog ?? 'canonical',\n canInjectSystemPrompt: raw.canInjectSystemPrompt ?? false,\n canBlockTools: raw.canBlockTools ?? false,\n };\n}\n\nfunction resolveSpawnCapability(raw: RegistrySpawnCapability): ProviderSpawnCapability {\n return {\n supportsSubagents: raw.supportsSubagents,\n supportsProgrammaticSpawn: raw.supportsProgrammaticSpawn,\n supportsInterAgentComms: raw.supportsInterAgentComms,\n supportsParallelSpawn: raw.supportsParallelSpawn,\n spawnMechanism: raw.spawnMechanism,\n spawnCommand: raw.spawnCommand ? [...raw.spawnCommand] : null,\n };\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 ? resolveHooksCapability(raw.hooks)\n : { ...DEFAULT_HOOKS_CAPABILITY, supported: [] };\n\n const spawn: ProviderSpawnCapability = raw?.spawn\n ? resolveSpawnCapability(raw.spawn)\n : { ...DEFAULT_SPAWN_CAPABILITY };\n\n const mcp: ProviderMcpCapability | null = raw?.mcp ? resolveMcpCapability(raw.mcp) : null;\n\n const harness: ProviderHarnessCapability | null = raw?.harness\n ? resolveHarnessCapability(raw.harness)\n : null;\n\n return { mcp, harness, 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 instructionReferences: raw.instructionReferences ? [...raw.instructionReferences] : [],\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 priority: raw.priority,\n status: raw.status,\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 * Callers filtering by `\"primary\"` should expect zero or one result; the\n * registry loader does not enforce the single-primary invariant.\n *\n * @param priority - Priority level to filter by (`\"primary\"`, `\"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 * Get the single primary harness provider, if any is registered.\n *\n * @remarks\n * Returns the provider with `priority === \"primary\"`. By convention a\n * registry defines at most one primary harness; this function returns\n * the first match if the invariant is violated and logs no warning. Use\n * {@link getProvidersByPriority} instead if you need to diagnose\n * duplicates.\n *\n * @returns The primary provider, or `undefined` if none is registered\n *\n * @example\n * ```typescript\n * const primary = getPrimaryProvider();\n * if (primary) {\n * console.log(`Primary harness: ${primary.toolName}`);\n * }\n * ```\n *\n * @public\n */\nexport function getPrimaryProvider(): Provider | undefined {\n return getAllProviders().find((p) => p.priority === 'primary');\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. `\"2.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 =\n 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 let current: unknown = provider.capabilities;\n for (const part of parts) {\n if (current == null || typeof current !== 'object') return false;\n current = (current as Record<string, unknown>)[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` and `spawnCommand` fields are excluded from the flag\n * type since they are not boolean checks.\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' | 'spawnCommand'>,\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/**\n * Get the default `@` instruction references for a provider from the registry.\n *\n * Returns the `instructionReferences` array declared in `providers/registry.json`\n * for the given provider ID or alias. These references are the canonical defaults\n * used by {@link ensureProviderInstructionFile} when no explicit `references`\n * argument is supplied by the caller.\n *\n * @remarks\n * The return value is a fresh copy of the registry array — mutating it has no\n * effect on the cached registry state. If the provider is not found or it has\n * no `instructionReferences` entry, an empty array is returned so callers\n * never receive `undefined`.\n *\n * @param idOrAlias - Provider ID (e.g. `\"claude-code\"`) or alias (e.g. `\"claude\"`)\n * @returns Array of `@`-prefixed instruction reference strings, or `[]` if none\n *\n * @example\n * ```typescript\n * const refs = getProviderInstructionReferences(\"claude-code\");\n * // [\"@~/.cleo/templates/CLEO-INJECTION.md\", \"@.cleo/memory-bridge.md\"]\n *\n * const unknown = getProviderInstructionReferences(\"no-such-provider\");\n * // []\n * ```\n *\n * @public\n */\nexport function getProviderInstructionReferences(idOrAlias: string): string[] {\n const provider = getProvider(idOrAlias);\n return provider?.instructionReferences ? [...provider.instructionReferences] : [];\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 mcp, harness, skills, hooks, and spawn\n * 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"]}