@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.
package/dist/index.js CHANGED
@@ -78,9 +78,8 @@ import {
78
78
  validateRecommendationCriteria,
79
79
  validateSkill,
80
80
  writeConfig
81
- } from "./chunk-LDTYDQGR.js";
81
+ } from "./chunk-ZF4W3K5H.js";
82
82
  import {
83
- _resetPlatformPathsCache,
84
83
  buildInjectionContent,
85
84
  buildSkillsMap,
86
85
  checkAllInjections,
@@ -89,23 +88,10 @@ import {
89
88
  ensureProviderInstructionFile,
90
89
  generateInjectionContent,
91
90
  generateSkillsSection,
92
- getAgentsConfigPath,
93
- getAgentsHome,
94
- getAgentsInstructFile,
95
- getAgentsLinksDir,
96
- getAgentsMcpDir,
97
- getAgentsMcpServersPath,
98
- getAgentsSpecDir,
99
- getAgentsWikiDir,
100
91
  getAllProviders,
101
- getCanonicalSkillsDir,
102
92
  getCommonHookEvents,
103
93
  getEffectiveSkillsPaths,
104
94
  getInstructionFiles,
105
- getLockFilePath,
106
- getPlatformLocations,
107
- getPlatformPaths,
108
- getProjectAgentsDir,
109
95
  getProvider,
110
96
  getProviderCapabilities,
111
97
  getProviderCount,
@@ -117,7 +103,6 @@ import {
117
103
  getProvidersByStatus,
118
104
  getRegistryVersion,
119
105
  getSpawnCapableProviders,
120
- getSystemInfo,
121
106
  groupByInstructFile,
122
107
  inject,
123
108
  injectAll,
@@ -125,10 +110,53 @@ import {
125
110
  providerSupports,
126
111
  providerSupportsById,
127
112
  removeInjection,
128
- resolveAlias,
113
+ resolveAlias
114
+ } from "./chunk-O7IVK5JY.js";
115
+ import {
116
+ CANONICAL_HOOK_EVENTS,
117
+ HOOK_CATEGORIES,
118
+ buildHookMatrix,
119
+ getAllCanonicalEvents,
120
+ getCanonicalEvent,
121
+ getCanonicalEventsByCategory,
122
+ getCommonEvents,
123
+ getHookConfigPath,
124
+ getHookMappingsVersion,
125
+ getHookSupport,
126
+ getHookSystemType,
127
+ getMappedProviderIds,
128
+ getProviderHookProfile,
129
+ getProviderOnlyEvents,
130
+ getProviderSummary,
131
+ getProvidersForEvent,
132
+ getSupportedEvents,
133
+ getUnsupportedEvents,
134
+ resolveNativeEvent,
135
+ supportsHook,
136
+ toCanonical,
137
+ toNative,
138
+ toNativeBatch,
139
+ translateToAll
140
+ } from "./chunk-J7UN457C.js";
141
+ import {
142
+ _resetPlatformPathsCache,
143
+ getAgentsConfigPath,
144
+ getAgentsHome,
145
+ getAgentsInstructFile,
146
+ getAgentsLinksDir,
147
+ getAgentsMcpDir,
148
+ getAgentsMcpServersPath,
149
+ getAgentsSpecDir,
150
+ getAgentsWikiDir,
151
+ getCanonicalSkillsDir,
152
+ getLockFilePath,
153
+ getPlatformLocations,
154
+ getPlatformPaths,
155
+ getProjectAgentsDir,
156
+ getSystemInfo,
129
157
  resolveProviderSkillsDirs,
130
158
  resolveRegistryTemplatePath
131
- } from "./chunk-CPHF5IM4.js";
159
+ } from "./chunk-TI6WOJDG.js";
132
160
 
133
161
  // src/core/skills/integrity.ts
134
162
  import { existsSync, lstatSync, readlinkSync } from "fs";
@@ -246,7 +274,7 @@ function shouldOverrideSkill(skillName, incomingSource, existingEntry) {
246
274
  return true;
247
275
  }
248
276
  async function validateInstructionIntegrity(providers, projectDir, scope, expectedContent) {
249
- const { checkAllInjections: checkAllInjections2 } = await import("./injector-TIUEM4X2.js");
277
+ const { checkAllInjections: checkAllInjections2 } = await import("./injector-NSDP5Z2P.js");
250
278
  const results = await checkAllInjections2(providers, projectDir, scope, expectedContent);
251
279
  const issues = [];
252
280
  for (const result of results) {
@@ -273,11 +301,14 @@ async function validateInstructionIntegrity(providers, projectDir, scope, expect
273
301
  return issues;
274
302
  }
275
303
  export {
304
+ CANONICAL_HOOK_EVENTS,
305
+ HOOK_CATEGORIES,
276
306
  MarketplaceClient,
277
307
  RECOMMENDATION_ERROR_CODES,
278
308
  _resetPlatformPathsCache,
279
309
  applyMcpInstallWithPolicy,
280
310
  buildCleoProfile,
311
+ buildHookMatrix,
281
312
  buildInjectionContent,
282
313
  buildLibraryFromFiles,
283
314
  buildServerConfig,
@@ -314,14 +345,23 @@ export {
314
345
  getAgentsMcpServersPath,
315
346
  getAgentsSpecDir,
316
347
  getAgentsWikiDir,
348
+ getAllCanonicalEvents,
317
349
  getAllProviders,
350
+ getCanonicalEvent,
351
+ getCanonicalEventsByCategory,
318
352
  getCanonicalSkillsDir,
353
+ getCommonEvents,
319
354
  getCommonHookEvents,
320
355
  getEffectiveSkillsPaths,
356
+ getHookConfigPath,
357
+ getHookMappingsVersion,
358
+ getHookSupport,
359
+ getHookSystemType,
321
360
  getInstalledProviders,
322
361
  getInstructionFiles,
323
362
  getLastSelectedAgents,
324
363
  getLockFilePath,
364
+ getMappedProviderIds,
325
365
  getNestedValue,
326
366
  getPlatformLocations,
327
367
  getPlatformPaths,
@@ -329,18 +369,24 @@ export {
329
369
  getProvider,
330
370
  getProviderCapabilities,
331
371
  getProviderCount,
372
+ getProviderHookProfile,
373
+ getProviderOnlyEvents,
374
+ getProviderSummary,
332
375
  getProvidersByHookEvent,
333
376
  getProvidersByInstructFile,
334
377
  getProvidersByPriority,
335
378
  getProvidersBySkillsPrecedence,
336
379
  getProvidersBySpawnCapability,
337
380
  getProvidersByStatus,
381
+ getProvidersForEvent,
338
382
  getRegistryVersion,
339
383
  getSpawnCapableProviders,
384
+ getSupportedEvents,
340
385
  getSystemInfo,
341
386
  getTrackedMcpServers,
342
387
  getTrackedSkills,
343
388
  getTransform,
389
+ getUnsupportedEvents,
344
390
  groupByInstructFile,
345
391
  inferCleoLockData,
346
392
  inject,
@@ -387,6 +433,7 @@ export {
387
433
  resolveChannelFromServerName,
388
434
  resolveCleoServerName,
389
435
  resolveConfigPath,
436
+ resolveNativeEvent,
390
437
  resolveProviderSkillsDirs,
391
438
  resolveRegistryTemplatePath,
392
439
  saveLastSelectedAgents,
@@ -398,8 +445,13 @@ export {
398
445
  setQuiet,
399
446
  setVerbose,
400
447
  shouldOverrideSkill,
448
+ supportsHook,
449
+ toCanonical,
450
+ toNative,
451
+ toNativeBatch,
401
452
  toSarif,
402
453
  tokenizeCriteriaValue,
454
+ translateToAll,
403
455
  updateInstructionsSingleOperation,
404
456
  validateInstructionIntegrity,
405
457
  validateRecommendationCriteria,
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 type { LockEntry, Provider } from \"../../types.js\";\nimport { getCanonicalSkillsDir, resolveProviderSkillsDirs } from \"../paths/standard.js\";\nimport { readLockFile, updateLockFile } from \"../lock-utils.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 */\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 */\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 * @param skillName - Skill name to check\n * @returns `true` if the skill name starts with `ct-`\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 * Validates:\n * - Canonical directory exists on disk\n * - Lock file entry matches actual state\n * - Symlinks from provider skill directories 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 */\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(getCanonicalSkillsDir(), 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 * @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 */\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 * 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 */\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 * Checks that CAAMP blocks exist and are current in all relevant\n * instruction files.\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 */\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOA,SAAS,YAAY,WAAW,oBAAoB;AACpD,SAAS,MAAM,eAAe;AAM9B,IAAM,qBAAqB;AA6CpB,SAAS,kBAAkB,WAA4B;AAC5D,SAAO,UAAU,WAAW,kBAAkB;AAChD;AAgBA,eAAsB,oBACpB,WACA,WACA,QAA8B,UAC9B,YAC+B;AAC/B,QAAM,OAAO,MAAM,aAAa;AAChC,QAAM,QAAQ,KAAK,OAAO,SAAS;AACnC,QAAM,eAAe,kBAAkB,SAAS;AAGhD,MAAI,CAAC,OAAO;AACV,UAAMA,iBAAgB,KAAK,sBAAsB,GAAG,SAAS;AAC7D,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,iBAAiB,WAAWA,cAAa;AAAA,MACzC,eAAe;AAAA,MACf,cAAc,CAAC;AAAA,MACf;AAAA,MACA,OAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,gBAAgB,MAAM;AAC5B,QAAM,kBAAkB,WAAW,aAAa;AAGhD,QAAM,eAAqD,CAAC;AAE5D,aAAW,YAAY,WAAW;AAChC,UAAM,aAAa,0BAA0B,UAAU,OAAO,UAAU;AACxE,eAAW,aAAa,YAAY;AAClC,UAAI,CAAC,UAAW;AAEhB,YAAM,WAAW,KAAK,WAAW,SAAS;AAC1C,YAAM,SAAS,WAAW,QAAQ;AAClC,UAAI,YAAY;AAChB,UAAI,oBAAoB;AAExB,UAAI,QAAQ;AACV,YAAI;AACF,gBAAM,OAAO,UAAU,QAAQ;AAC/B,sBAAY,KAAK,eAAe;AAChC,cAAI,WAAW;AACb,kBAAM,SAAS,QAAQ,aAAa,QAAQ,CAAC;AAC7C,gCAAoB,WAAW,QAAQ,aAAa;AAAA,UACtD;AAAA,QACF,QAAQ;AAAA,QAER;AAAA,MACF;AAEA,mBAAa,KAAK;AAAA,QAChB,YAAY,SAAS;AAAA,QACrB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAGA,MAAI,CAAC,iBAAiB;AACpB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,gCAAgC,aAAa;AAAA,IACtD;AAAA,EACF;AAEA,QAAM,cAAc,aAAa,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM;AACxD,QAAM,gBAAgB,aAAa,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,iBAAiB;AAEjF,MAAI,cAAc,SAAS,GAAG;AAC5B,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,GAAG,cAAc,MAAM;AAAA,IAChC;AAAA,EACF;AAEA,MAAI,YAAY,SAAS,GAAG;AAC1B,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,GAAG,YAAY,MAAM;AAAA,IAC9B;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAUA,eAAsB,uBACpB,WACA,QAA8B,UAC9B,YAC4C;AAC5C,QAAM,OAAO,MAAM,aAAa;AAChC,QAAM,UAAU,oBAAI,IAAkC;AAEtD,aAAW,aAAa,OAAO,KAAK,KAAK,MAAM,GAAG;AAChD,UAAM,SAAS,MAAM,oBAAoB,WAAW,WAAW,OAAO,UAAU;AAChF,YAAQ,IAAI,WAAW,MAAM;AAAA,EAC/B;AAEA,SAAO;AACT;AAcO,SAAS,oBACd,WACA,gBACA,eACS;AAET,MAAI,CAAC,cAAe,QAAO;AAG3B,MAAI,kBAAkB,SAAS,GAAG;AAEhC,QAAI,cAAc,eAAe,UAAW,QAAO;AAEnD,WAAO;AAAA,EACT;AAGA,SAAO;AACT;AAcA,eAAsB,6BACpB,WACA,YACA,OACA,iBACqE;AACrE,QAAM,EAAE,oBAAAC,oBAAmB,IAAI,MAAM,OAAO,wBAA6B;AACzE,QAAM,UAAU,MAAMA,oBAAmB,WAAW,YAAY,OAAO,eAAe;AACtF,QAAM,SAAqE,CAAC;AAE5E,aAAW,UAAU,SAAS;AAC5B,QAAI,OAAO,WAAW,WAAW;AAC/B,aAAO,KAAK;AAAA,QACV,MAAM,OAAO;AAAA,QACb,YAAY,OAAO;AAAA,QACnB,OAAO;AAAA,MACT,CAAC;AAAA,IACH,WAAW,OAAO,WAAW,QAAQ;AACnC,aAAO,KAAK;AAAA,QACV,MAAM,OAAO;AAAA,QACb,YAAY,OAAO;AAAA,QACnB,OAAO;AAAA,MACT,CAAC;AAAA,IACH,WAAW,OAAO,WAAW,YAAY;AACvC,aAAO,KAAK;AAAA,QACV,MAAM,OAAO;AAAA,QACb,YAAY,OAAO;AAAA,QACnB,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;","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 type { LockEntry, Provider } from \"../../types.js\";\nimport { getCanonicalSkillsDir, resolveProviderSkillsDirs } from \"../paths/standard.js\";\nimport { readLockFile, updateLockFile } from \"../lock-utils.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(getCanonicalSkillsDir(), 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"]}
@@ -6,7 +6,8 @@ import {
6
6
  inject,
7
7
  injectAll,
8
8
  removeInjection
9
- } from "./chunk-CPHF5IM4.js";
9
+ } from "./chunk-O7IVK5JY.js";
10
+ import "./chunk-TI6WOJDG.js";
10
11
  export {
11
12
  checkAllInjections,
12
13
  checkInjection,
@@ -16,4 +17,4 @@ export {
16
17
  injectAll,
17
18
  removeInjection
18
19
  };
19
- //# sourceMappingURL=injector-TIUEM4X2.js.map
20
+ //# sourceMappingURL=injector-NSDP5Z2P.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cleocode/caamp",
3
- "version": "1.8.1",
3
+ "version": "1.9.1",
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": {
@@ -0,0 +1,302 @@
1
+ {
2
+ "$schema": "./hook-mappings.schema.json",
3
+ "version": "1.0.0",
4
+ "lastUpdated": "2026-03-24",
5
+ "description": "CAAMP canonical hook event mappings to provider-native event names",
6
+ "canonicalEvents": {
7
+ "SessionStart": {
8
+ "category": "session",
9
+ "description": "Session begins, resumes, or is cleared",
10
+ "canBlock": false
11
+ },
12
+ "SessionEnd": {
13
+ "category": "session",
14
+ "description": "Session terminates or exits",
15
+ "canBlock": false
16
+ },
17
+ "PromptSubmit": {
18
+ "category": "prompt",
19
+ "description": "User submits a prompt, before agent processes it",
20
+ "canBlock": true
21
+ },
22
+ "ResponseComplete": {
23
+ "category": "prompt",
24
+ "description": "Agent finishes responding to a turn",
25
+ "canBlock": false
26
+ },
27
+ "PreToolUse": {
28
+ "category": "tool",
29
+ "description": "Before a tool call executes (can block/modify)",
30
+ "canBlock": true
31
+ },
32
+ "PostToolUse": {
33
+ "category": "tool",
34
+ "description": "After a tool call succeeds",
35
+ "canBlock": false
36
+ },
37
+ "PostToolUseFailure": {
38
+ "category": "tool",
39
+ "description": "After a tool call fails or times out",
40
+ "canBlock": false
41
+ },
42
+ "PermissionRequest": {
43
+ "category": "tool",
44
+ "description": "Permission dialog appears for a tool action",
45
+ "canBlock": true
46
+ },
47
+ "SubagentStart": {
48
+ "category": "agent",
49
+ "description": "A subagent is spawned",
50
+ "canBlock": true
51
+ },
52
+ "SubagentStop": {
53
+ "category": "agent",
54
+ "description": "A subagent finishes execution",
55
+ "canBlock": false
56
+ },
57
+ "PreModel": {
58
+ "category": "agent",
59
+ "description": "Before sending a request to the LLM",
60
+ "canBlock": true
61
+ },
62
+ "PostModel": {
63
+ "category": "agent",
64
+ "description": "After receiving an LLM response",
65
+ "canBlock": false
66
+ },
67
+ "PreCompact": {
68
+ "category": "context",
69
+ "description": "Before context window compaction",
70
+ "canBlock": false
71
+ },
72
+ "PostCompact": {
73
+ "category": "context",
74
+ "description": "After context window compaction completes",
75
+ "canBlock": false
76
+ },
77
+ "Notification": {
78
+ "category": "context",
79
+ "description": "System notification or alert is emitted",
80
+ "canBlock": false
81
+ },
82
+ "ConfigChange": {
83
+ "category": "context",
84
+ "description": "Configuration file changes during a session",
85
+ "canBlock": false
86
+ }
87
+ },
88
+ "providerMappings": {
89
+ "claude-code": {
90
+ "hookSystem": "config",
91
+ "hookConfigPath": "$HOME/.claude/settings.json",
92
+ "hookFormat": "json",
93
+ "handlerTypes": ["command", "http", "prompt", "agent"],
94
+ "experimental": false,
95
+ "mappings": {
96
+ "SessionStart": { "nativeName": "SessionStart", "supported": true },
97
+ "SessionEnd": { "nativeName": "SessionEnd", "supported": true },
98
+ "PromptSubmit": { "nativeName": "UserPromptSubmit", "supported": true },
99
+ "ResponseComplete": { "nativeName": "Stop", "supported": true },
100
+ "PreToolUse": { "nativeName": "PreToolUse", "supported": true },
101
+ "PostToolUse": { "nativeName": "PostToolUse", "supported": true },
102
+ "PostToolUseFailure": { "nativeName": "PostToolUseFailure", "supported": true },
103
+ "PermissionRequest": { "nativeName": "PermissionRequest", "supported": true },
104
+ "SubagentStart": { "nativeName": "SubagentStart", "supported": true },
105
+ "SubagentStop": { "nativeName": "SubagentStop", "supported": true },
106
+ "PreModel": { "nativeName": null, "supported": false },
107
+ "PostModel": { "nativeName": null, "supported": false },
108
+ "PreCompact": { "nativeName": "PreCompact", "supported": true },
109
+ "PostCompact": { "nativeName": "PostCompact", "supported": true },
110
+ "Notification": { "nativeName": "Notification", "supported": true },
111
+ "ConfigChange": { "nativeName": "ConfigChange", "supported": true }
112
+ },
113
+ "providerOnlyEvents": [
114
+ "StopFailure",
115
+ "TeammateIdle",
116
+ "TaskCompleted",
117
+ "InstructionsLoaded",
118
+ "WorktreeCreate",
119
+ "WorktreeRemove",
120
+ "Elicitation",
121
+ "ElicitationResult"
122
+ ]
123
+ },
124
+ "cursor": {
125
+ "hookSystem": "config",
126
+ "hookConfigPath": ".cursor/hooks.json",
127
+ "hookFormat": "json",
128
+ "handlerTypes": ["command", "prompt"],
129
+ "experimental": true,
130
+ "mappings": {
131
+ "SessionStart": { "nativeName": "sessionStart", "supported": true },
132
+ "SessionEnd": { "nativeName": "sessionEnd", "supported": true },
133
+ "PromptSubmit": { "nativeName": "beforeSubmitPrompt", "supported": true },
134
+ "ResponseComplete": { "nativeName": "stop", "supported": true },
135
+ "PreToolUse": { "nativeName": "preToolUse", "supported": true },
136
+ "PostToolUse": { "nativeName": "postToolUse", "supported": true },
137
+ "PostToolUseFailure": { "nativeName": "postToolUseFailure", "supported": true },
138
+ "PermissionRequest": { "nativeName": null, "supported": false },
139
+ "SubagentStart": { "nativeName": "subagentStart", "supported": true },
140
+ "SubagentStop": { "nativeName": "subagentStop", "supported": true },
141
+ "PreModel": { "nativeName": null, "supported": false },
142
+ "PostModel": { "nativeName": null, "supported": false },
143
+ "PreCompact": { "nativeName": "preCompact", "supported": true },
144
+ "PostCompact": { "nativeName": null, "supported": false },
145
+ "Notification": { "nativeName": null, "supported": false },
146
+ "ConfigChange": { "nativeName": null, "supported": false }
147
+ },
148
+ "providerOnlyEvents": [
149
+ "beforeShellExecution",
150
+ "afterShellExecution",
151
+ "beforeMCPExecution",
152
+ "afterMCPExecution",
153
+ "beforeReadFile",
154
+ "afterFileEdit",
155
+ "afterAgentResponse",
156
+ "afterAgentThought",
157
+ "beforeTabFileRead",
158
+ "afterTabFileEdit"
159
+ ]
160
+ },
161
+ "gemini-cli": {
162
+ "hookSystem": "config",
163
+ "hookConfigPath": "$HOME/.gemini/settings.json",
164
+ "hookFormat": "json",
165
+ "handlerTypes": ["command"],
166
+ "experimental": false,
167
+ "mappings": {
168
+ "SessionStart": { "nativeName": "SessionStart", "supported": true },
169
+ "SessionEnd": { "nativeName": "SessionEnd", "supported": true },
170
+ "PromptSubmit": { "nativeName": "BeforeAgent", "supported": true },
171
+ "ResponseComplete": { "nativeName": "AfterAgent", "supported": true },
172
+ "PreToolUse": { "nativeName": "BeforeTool", "supported": true },
173
+ "PostToolUse": { "nativeName": "AfterTool", "supported": true },
174
+ "PostToolUseFailure": { "nativeName": null, "supported": false },
175
+ "PermissionRequest": { "nativeName": null, "supported": false },
176
+ "SubagentStart": { "nativeName": null, "supported": false },
177
+ "SubagentStop": { "nativeName": null, "supported": false },
178
+ "PreModel": { "nativeName": "BeforeModel", "supported": true },
179
+ "PostModel": { "nativeName": "AfterModel", "supported": true },
180
+ "PreCompact": { "nativeName": "PreCompress", "supported": true },
181
+ "PostCompact": { "nativeName": null, "supported": false },
182
+ "Notification": { "nativeName": "Notification", "supported": true },
183
+ "ConfigChange": { "nativeName": null, "supported": false }
184
+ },
185
+ "providerOnlyEvents": [
186
+ "BeforeToolSelection"
187
+ ]
188
+ },
189
+ "codex": {
190
+ "hookSystem": "config",
191
+ "hookConfigPath": ".codex/hooks.json",
192
+ "hookFormat": "json",
193
+ "handlerTypes": ["command"],
194
+ "experimental": true,
195
+ "mappings": {
196
+ "SessionStart": { "nativeName": "SessionStart", "supported": true },
197
+ "SessionEnd": { "nativeName": null, "supported": false },
198
+ "PromptSubmit": { "nativeName": "UserPromptSubmit", "supported": true },
199
+ "ResponseComplete": { "nativeName": "Stop", "supported": true },
200
+ "PreToolUse": { "nativeName": null, "supported": false },
201
+ "PostToolUse": { "nativeName": null, "supported": false },
202
+ "PostToolUseFailure": { "nativeName": null, "supported": false },
203
+ "PermissionRequest": { "nativeName": null, "supported": false },
204
+ "SubagentStart": { "nativeName": null, "supported": false },
205
+ "SubagentStop": { "nativeName": null, "supported": false },
206
+ "PreModel": { "nativeName": null, "supported": false },
207
+ "PostModel": { "nativeName": null, "supported": false },
208
+ "PreCompact": { "nativeName": null, "supported": false },
209
+ "PostCompact": { "nativeName": null, "supported": false },
210
+ "Notification": { "nativeName": null, "supported": false },
211
+ "ConfigChange": { "nativeName": null, "supported": false }
212
+ },
213
+ "providerOnlyEvents": []
214
+ },
215
+ "opencode": {
216
+ "hookSystem": "plugin",
217
+ "hookConfigPath": ".opencode/plugins/",
218
+ "hookFormat": "javascript",
219
+ "handlerTypes": ["plugin"],
220
+ "experimental": false,
221
+ "mappings": {
222
+ "SessionStart": { "nativeName": "event:session.created", "supported": true, "notes": "Via bus event subscriber" },
223
+ "SessionEnd": { "nativeName": "event:session.deleted", "supported": true, "notes": "Via bus event subscriber" },
224
+ "PromptSubmit": { "nativeName": "chat.message", "supported": true },
225
+ "ResponseComplete": { "nativeName": "event:session.idle", "supported": true, "notes": "Via bus event subscriber" },
226
+ "PreToolUse": { "nativeName": "tool.execute.before", "supported": true },
227
+ "PostToolUse": { "nativeName": "tool.execute.after", "supported": true },
228
+ "PostToolUseFailure": { "nativeName": null, "supported": false },
229
+ "PermissionRequest": { "nativeName": "permission.ask", "supported": true },
230
+ "SubagentStart": { "nativeName": null, "supported": false },
231
+ "SubagentStop": { "nativeName": null, "supported": false },
232
+ "PreModel": { "nativeName": "chat.params", "supported": true, "notes": "Modify LLM params before request" },
233
+ "PostModel": { "nativeName": null, "supported": false },
234
+ "PreCompact": { "nativeName": "experimental.session.compacting", "supported": true },
235
+ "PostCompact": { "nativeName": "event:session.compacted", "supported": true, "notes": "Via bus event subscriber" },
236
+ "Notification": { "nativeName": null, "supported": false },
237
+ "ConfigChange": { "nativeName": null, "supported": false }
238
+ },
239
+ "providerOnlyEvents": [
240
+ "chat.headers",
241
+ "shell.env",
242
+ "tool.definition",
243
+ "command.execute.before",
244
+ "experimental.chat.messages.transform",
245
+ "experimental.chat.system.transform",
246
+ "experimental.text.complete"
247
+ ]
248
+ },
249
+ "kimi": {
250
+ "hookSystem": "none",
251
+ "hookConfigPath": null,
252
+ "hookFormat": null,
253
+ "handlerTypes": [],
254
+ "experimental": false,
255
+ "mappings": {
256
+ "SessionStart": { "nativeName": null, "supported": false },
257
+ "SessionEnd": { "nativeName": null, "supported": false },
258
+ "PromptSubmit": { "nativeName": null, "supported": false },
259
+ "ResponseComplete": { "nativeName": null, "supported": false },
260
+ "PreToolUse": { "nativeName": null, "supported": false },
261
+ "PostToolUse": { "nativeName": null, "supported": false },
262
+ "PostToolUseFailure": { "nativeName": null, "supported": false },
263
+ "PermissionRequest": { "nativeName": null, "supported": false },
264
+ "SubagentStart": { "nativeName": null, "supported": false },
265
+ "SubagentStop": { "nativeName": null, "supported": false },
266
+ "PreModel": { "nativeName": null, "supported": false },
267
+ "PostModel": { "nativeName": null, "supported": false },
268
+ "PreCompact": { "nativeName": null, "supported": false },
269
+ "PostCompact": { "nativeName": null, "supported": false },
270
+ "Notification": { "nativeName": null, "supported": false },
271
+ "ConfigChange": { "nativeName": null, "supported": false }
272
+ },
273
+ "providerOnlyEvents": []
274
+ },
275
+ "antigravity": {
276
+ "hookSystem": "none",
277
+ "hookConfigPath": null,
278
+ "hookFormat": null,
279
+ "handlerTypes": [],
280
+ "experimental": false,
281
+ "mappings": {
282
+ "SessionStart": { "nativeName": null, "supported": false },
283
+ "SessionEnd": { "nativeName": null, "supported": false },
284
+ "PromptSubmit": { "nativeName": null, "supported": false },
285
+ "ResponseComplete": { "nativeName": null, "supported": false },
286
+ "PreToolUse": { "nativeName": null, "supported": false },
287
+ "PostToolUse": { "nativeName": null, "supported": false },
288
+ "PostToolUseFailure": { "nativeName": null, "supported": false },
289
+ "PermissionRequest": { "nativeName": null, "supported": false },
290
+ "SubagentStart": { "nativeName": null, "supported": false },
291
+ "SubagentStop": { "nativeName": null, "supported": false },
292
+ "PreModel": { "nativeName": null, "supported": false },
293
+ "PostModel": { "nativeName": null, "supported": false },
294
+ "PreCompact": { "nativeName": null, "supported": false },
295
+ "PostCompact": { "nativeName": null, "supported": false },
296
+ "Notification": { "nativeName": null, "supported": false },
297
+ "ConfigChange": { "nativeName": null, "supported": false }
298
+ },
299
+ "providerOnlyEvents": []
300
+ }
301
+ }
302
+ }