@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/chunk-J7UN457C.js +244 -0
- package/dist/chunk-J7UN457C.js.map +1 -0
- package/dist/{chunk-CPHF5IM4.js → chunk-O7IVK5JY.js} +20 -290
- package/dist/chunk-O7IVK5JY.js.map +1 -0
- package/dist/chunk-TI6WOJDG.js +276 -0
- package/dist/chunk-TI6WOJDG.js.map +1 -0
- package/dist/{chunk-LDTYDQGR.js → chunk-ZF4W3K5H.js} +40 -5
- package/dist/chunk-ZF4W3K5H.js.map +1 -0
- package/dist/cli.js +205 -87
- package/dist/cli.js.map +1 -1
- package/dist/hooks-E2XQ7TQG.js +56 -0
- package/dist/index.d.ts +4427 -928
- package/dist/index.js +71 -19
- package/dist/index.js.map +1 -1
- package/dist/{injector-TIUEM4X2.js → injector-NSDP5Z2P.js} +3 -2
- package/dist/injector-NSDP5Z2P.js.map +1 -0
- package/package.json +1 -1
- package/providers/hook-mappings.json +302 -0
- package/providers/registry.json +599 -156
- package/dist/chunk-CPHF5IM4.js.map +0 -1
- package/dist/chunk-LDTYDQGR.js.map +0 -1
- /package/dist/{injector-TIUEM4X2.js.map → hooks-E2XQ7TQG.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -78,9 +78,8 @@ import {
|
|
|
78
78
|
validateRecommendationCriteria,
|
|
79
79
|
validateSkill,
|
|
80
80
|
writeConfig
|
|
81
|
-
} from "./chunk-
|
|
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-
|
|
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-
|
|
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":"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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 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-
|
|
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-
|
|
20
|
+
//# sourceMappingURL=injector-NSDP5Z2P.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
CHANGED
|
@@ -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
|
+
}
|