@cleocode/caamp 1.8.0 → 1.9.0

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.
@@ -0,0 +1,56 @@
1
+ import {
2
+ CANONICAL_HOOK_EVENTS,
3
+ HOOK_CATEGORIES,
4
+ buildHookMatrix,
5
+ getAllCanonicalEvents,
6
+ getCanonicalEvent,
7
+ getCanonicalEventsByCategory,
8
+ getCommonEvents,
9
+ getHookConfigPath,
10
+ getHookMappingsVersion,
11
+ getHookSupport,
12
+ getHookSystemType,
13
+ getMappedProviderIds,
14
+ getProviderHookProfile,
15
+ getProviderOnlyEvents,
16
+ getProviderSummary,
17
+ getProvidersForEvent,
18
+ getSupportedEvents,
19
+ getUnsupportedEvents,
20
+ resetHookMappings,
21
+ resolveNativeEvent,
22
+ supportsHook,
23
+ toCanonical,
24
+ toNative,
25
+ toNativeBatch,
26
+ translateToAll
27
+ } from "./chunk-ER3FIOTM.js";
28
+ import "./chunk-TRIXT4T7.js";
29
+ export {
30
+ CANONICAL_HOOK_EVENTS,
31
+ HOOK_CATEGORIES,
32
+ buildHookMatrix,
33
+ getAllCanonicalEvents,
34
+ getCanonicalEvent,
35
+ getCanonicalEventsByCategory,
36
+ getCommonEvents,
37
+ getHookConfigPath,
38
+ getHookMappingsVersion,
39
+ getHookSupport,
40
+ getHookSystemType,
41
+ getMappedProviderIds,
42
+ getProviderHookProfile,
43
+ getProviderOnlyEvents,
44
+ getProviderSummary,
45
+ getProvidersForEvent,
46
+ getSupportedEvents,
47
+ getUnsupportedEvents,
48
+ resetHookMappings,
49
+ resolveNativeEvent,
50
+ supportsHook,
51
+ toCanonical,
52
+ toNative,
53
+ toNativeBatch,
54
+ translateToAll
55
+ };
56
+ //# sourceMappingURL=hooks-LV6VU7QJ.js.map
package/dist/index.d.ts CHANGED
@@ -1,5 +1,10 @@
1
1
  type SkillsPrecedence = "vendor-only" | "agents-canonical" | "agents-first" | "agents-supported" | "vendor-global-agents-project";
2
- type HookEvent = "onSessionStart" | "onSessionEnd" | "onToolStart" | "onToolComplete" | "onFileChange" | "onError" | "onPromptSubmit" | "onResponseComplete";
2
+ /**
3
+ * @deprecated Use `CanonicalHookEvent` from `../hooks/types.js` for the
4
+ * normalized CAAMP taxonomy. This type remains for backward compatibility
5
+ * with registry.json's `capabilities.hooks.supported` string arrays.
6
+ */
7
+ type HookEvent = string;
3
8
  type SpawnMechanism = "native" | "mcp" | "cli" | "api";
4
9
 
5
10
  /**
@@ -1446,7 +1451,7 @@ interface InstructionUpdateSummary {
1446
1451
  updatedFiles: number;
1447
1452
  actions: Array<{
1448
1453
  file: string;
1449
- action: "created" | "added" | "updated" | "intact";
1454
+ action: "created" | "added" | "consolidated" | "updated" | "intact";
1450
1455
  providers: string[];
1451
1456
  configFormats: ConfigFormat[];
1452
1457
  }>;
@@ -1490,8 +1495,8 @@ interface DualScopeConfigureResult {
1490
1495
  project: InstallResult[];
1491
1496
  };
1492
1497
  instructions: {
1493
- global?: Map<string, "created" | "added" | "updated" | "intact">;
1494
- project?: Map<string, "created" | "added" | "updated" | "intact">;
1498
+ global?: Map<string, "created" | "added" | "consolidated" | "updated" | "intact">;
1499
+ project?: Map<string, "created" | "added" | "consolidated" | "updated" | "intact">;
1495
1500
  };
1496
1501
  }
1497
1502
  /**
@@ -2811,6 +2816,7 @@ declare function checkInjection(filePath: string, expectedContent?: string): Pro
2811
2816
  * Behavior depends on the file state:
2812
2817
  * - File does not exist: creates the file with the injection block → `"created"`
2813
2818
  * - File exists without markers: prepends the injection block → `"added"`
2819
+ * - File exists with multiple markers (duplicates): consolidates into single block → `"consolidated"`
2814
2820
  * - File exists with markers, content differs: replaces the block → `"updated"`
2815
2821
  * - File exists with markers, content matches: no-op → `"intact"`
2816
2822
  *
@@ -2819,7 +2825,7 @@ declare function checkInjection(filePath: string, expectedContent?: string): Pro
2819
2825
  *
2820
2826
  * @param filePath - Absolute path to the instruction file
2821
2827
  * @param content - Content to inject between CAAMP markers
2822
- * @returns Action taken: `"created"`, `"added"`, `"updated"`, or `"intact"`
2828
+ * @returns Action taken: `"created"`, `"added"`, `"consolidated"`, `"updated"`, or `"intact"`
2823
2829
  *
2824
2830
  * @example
2825
2831
  * ```typescript
@@ -2827,7 +2833,7 @@ declare function checkInjection(filePath: string, expectedContent?: string): Pro
2827
2833
  * console.log(`File ${action}`); // "created" on first call, "intact" on subsequent
2828
2834
  * ```
2829
2835
  */
2830
- declare function inject(filePath: string, content: string): Promise<"created" | "added" | "updated" | "intact">;
2836
+ declare function inject(filePath: string, content: string): Promise<"created" | "added" | "consolidated" | "updated" | "intact">;
2831
2837
  /**
2832
2838
  * Remove the CAAMP injection block from an instruction file.
2833
2839
  *
@@ -2870,7 +2876,7 @@ declare function checkAllInjections(providers: Provider[], projectDir: string, s
2870
2876
  * @param projectDir - Absolute path to the project directory
2871
2877
  * @param scope - Whether to target project or global instruction files
2872
2878
  * @param content - Content to inject between CAAMP markers
2873
- * @returns Map of file path to action taken (`"created"`, `"added"`, `"updated"`, or `"intact"`)
2879
+ * @returns Map of file path to action taken (`"created"`, `"added"`, `"consolidated"`, `"updated"`, or `"intact"`)
2874
2880
  *
2875
2881
  * @example
2876
2882
  * ```typescript
@@ -2880,7 +2886,7 @@ declare function checkAllInjections(providers: Provider[], projectDir: string, s
2880
2886
  * }
2881
2887
  * ```
2882
2888
  */
2883
- declare function injectAll(providers: Provider[], projectDir: string, scope: "project" | "global", content: string): Promise<Map<string, "created" | "added" | "updated" | "intact">>;
2889
+ declare function injectAll(providers: Provider[], projectDir: string, scope: "project" | "global", content: string): Promise<Map<string, "created" | "added" | "consolidated" | "updated" | "intact">>;
2884
2890
  /**
2885
2891
  * Options for ensuring a provider instruction file.
2886
2892
  */
@@ -2901,7 +2907,7 @@ interface EnsureProviderInstructionFileResult {
2901
2907
  /** Instruction file name from the provider registry. */
2902
2908
  instructFile: string;
2903
2909
  /** Action taken. */
2904
- action: "created" | "added" | "updated" | "intact";
2910
+ action: "created" | "added" | "consolidated" | "updated" | "intact";
2905
2911
  /** Provider ID. */
2906
2912
  providerId: string;
2907
2913
  }
@@ -2929,7 +2935,7 @@ interface EnsureProviderInstructionFileResult {
2929
2935
  * references: ["@AGENTS.md"],
2930
2936
  * });
2931
2937
  * // result.filePath → "/project/CLAUDE.md"
2932
- * // result.action → "created" | "added" | "updated" | "intact"
2938
+ * // result.action → "created" | "added" | "consolidated" | "updated" | "intact"
2933
2939
  *
2934
2940
  * // Global scope:
2935
2941
  * const globalResult = await ensureProviderInstructionFile("claude-code", homedir(), {
@@ -3166,6 +3172,206 @@ declare function writeConfig(filePath: string, format: ConfigFormat, key: string
3166
3172
  */
3167
3173
  declare function removeConfig(filePath: string, format: ConfigFormat, key: string, serverName: string): Promise<boolean>;
3168
3174
 
3175
+ /**
3176
+ * CAAMP Hooks Normalizer - Type Definitions
3177
+ *
3178
+ * Defines the canonical CAAMP hook event taxonomy and provider mapping types.
3179
+ * CAAMP provides a unified hook interface across all providers — consumers
3180
+ * use canonical event names, and the normalizer translates to/from
3181
+ * provider-native names.
3182
+ */
3183
+ declare const HOOK_CATEGORIES: readonly ["session", "prompt", "tool", "agent", "context"];
3184
+ type HookCategory = (typeof HOOK_CATEGORIES)[number];
3185
+ declare const CANONICAL_HOOK_EVENTS: readonly ["SessionStart", "SessionEnd", "PromptSubmit", "ResponseComplete", "PreToolUse", "PostToolUse", "PostToolUseFailure", "PermissionRequest", "SubagentStart", "SubagentStop", "PreModel", "PostModel", "PreCompact", "PostCompact", "Notification", "ConfigChange"];
3186
+ type CanonicalHookEvent = (typeof CANONICAL_HOOK_EVENTS)[number];
3187
+ interface CanonicalEventDefinition {
3188
+ category: HookCategory;
3189
+ description: string;
3190
+ canBlock: boolean;
3191
+ }
3192
+ type HookSystemType = "config" | "plugin" | "none";
3193
+ type HookHandlerType = "command" | "http" | "prompt" | "agent" | "plugin";
3194
+ interface HookMapping {
3195
+ nativeName: string | null;
3196
+ supported: boolean;
3197
+ notes?: string;
3198
+ }
3199
+ interface ProviderHookProfile {
3200
+ hookSystem: HookSystemType;
3201
+ hookConfigPath: string | null;
3202
+ hookFormat: string | null;
3203
+ handlerTypes: HookHandlerType[];
3204
+ experimental: boolean;
3205
+ mappings: Record<CanonicalHookEvent, HookMapping>;
3206
+ providerOnlyEvents: string[];
3207
+ }
3208
+ interface NormalizedHookEvent {
3209
+ canonical: CanonicalHookEvent;
3210
+ native: string;
3211
+ providerId: string;
3212
+ category: HookCategory;
3213
+ canBlock: boolean;
3214
+ }
3215
+ interface HookSupportResult {
3216
+ canonical: CanonicalHookEvent;
3217
+ supported: boolean;
3218
+ native: string | null;
3219
+ notes?: string;
3220
+ }
3221
+ interface ProviderHookSummary {
3222
+ providerId: string;
3223
+ hookSystem: HookSystemType;
3224
+ experimental: boolean;
3225
+ supportedCount: number;
3226
+ totalCanonical: number;
3227
+ supported: CanonicalHookEvent[];
3228
+ unsupported: CanonicalHookEvent[];
3229
+ providerOnly: string[];
3230
+ coverage: number;
3231
+ }
3232
+ interface CrossProviderMatrix {
3233
+ events: CanonicalHookEvent[];
3234
+ providers: string[];
3235
+ matrix: Record<CanonicalHookEvent, Record<string, HookMapping>>;
3236
+ }
3237
+
3238
+ /**
3239
+ * CAAMP Hooks Normalizer
3240
+ *
3241
+ * Translates between CAAMP canonical hook events and provider-native
3242
+ * event names. Provides query functions for hook support, cross-provider
3243
+ * comparison, and event normalization.
3244
+ *
3245
+ * This module follows the same pattern as `src/core/mcp/transforms.ts` —
3246
+ * a translation layer that lets consumers use one canonical interface
3247
+ * while CAAMP handles provider-specific differences.
3248
+ */
3249
+
3250
+ /**
3251
+ * Get the canonical event definition (category, description, canBlock).
3252
+ */
3253
+ declare function getCanonicalEvent(event: CanonicalHookEvent): CanonicalEventDefinition;
3254
+ /**
3255
+ * Get all canonical event definitions.
3256
+ */
3257
+ declare function getAllCanonicalEvents(): Record<CanonicalHookEvent, CanonicalEventDefinition>;
3258
+ /**
3259
+ * Get canonical events filtered by category.
3260
+ */
3261
+ declare function getCanonicalEventsByCategory(category: HookCategory): CanonicalHookEvent[];
3262
+ /**
3263
+ * Get the full hook profile for a provider.
3264
+ */
3265
+ declare function getProviderHookProfile(providerId: string): ProviderHookProfile | undefined;
3266
+ /**
3267
+ * Get all provider IDs that have hook mappings.
3268
+ */
3269
+ declare function getMappedProviderIds(): string[];
3270
+ /**
3271
+ * Translate a CAAMP canonical event name to the provider's native name.
3272
+ *
3273
+ * @returns The native event name, or `null` if unsupported
3274
+ *
3275
+ * @example
3276
+ * ```typescript
3277
+ * toNative("PreToolUse", "claude-code"); // "PreToolUse"
3278
+ * toNative("PreToolUse", "gemini-cli"); // "BeforeTool"
3279
+ * toNative("PreToolUse", "cursor"); // "preToolUse"
3280
+ * toNative("PreToolUse", "kimi"); // null
3281
+ * ```
3282
+ */
3283
+ declare function toNative(canonical: CanonicalHookEvent, providerId: string): string | null;
3284
+ /**
3285
+ * Translate a provider-native event name to the CAAMP canonical name.
3286
+ *
3287
+ * @returns The canonical event name, or `null` if no mapping exists
3288
+ *
3289
+ * @example
3290
+ * ```typescript
3291
+ * toCanonical("BeforeTool", "gemini-cli"); // "PreToolUse"
3292
+ * toCanonical("stop", "cursor"); // "ResponseComplete"
3293
+ * toCanonical("UserPromptSubmit", "claude-code"); // "PromptSubmit"
3294
+ * ```
3295
+ */
3296
+ declare function toCanonical(nativeName: string, providerId: string): CanonicalHookEvent | null;
3297
+ /**
3298
+ * Batch-translate multiple canonical events to native names for a provider.
3299
+ *
3300
+ * @returns Array of normalized events (only supported ones included)
3301
+ */
3302
+ declare function toNativeBatch(canonicals: CanonicalHookEvent[], providerId: string): NormalizedHookEvent[];
3303
+ /**
3304
+ * Check if a provider supports a specific canonical hook event.
3305
+ */
3306
+ declare function supportsHook(canonical: CanonicalHookEvent, providerId: string): boolean;
3307
+ /**
3308
+ * Get full hook support details for a canonical event on a provider.
3309
+ */
3310
+ declare function getHookSupport(canonical: CanonicalHookEvent, providerId: string): HookSupportResult;
3311
+ /**
3312
+ * Get all supported canonical events for a provider.
3313
+ */
3314
+ declare function getSupportedEvents(providerId: string): CanonicalHookEvent[];
3315
+ /**
3316
+ * Get all unsupported canonical events for a provider.
3317
+ */
3318
+ declare function getUnsupportedEvents(providerId: string): CanonicalHookEvent[];
3319
+ /**
3320
+ * Get providers that support a specific canonical event.
3321
+ */
3322
+ declare function getProvidersForEvent(canonical: CanonicalHookEvent): string[];
3323
+ /**
3324
+ * Get canonical events common to all specified providers.
3325
+ */
3326
+ declare function getCommonEvents(providerIds: string[]): CanonicalHookEvent[];
3327
+ /**
3328
+ * Get a summary of hook support for a provider.
3329
+ */
3330
+ declare function getProviderSummary(providerId: string): ProviderHookSummary | undefined;
3331
+ /**
3332
+ * Build a cross-provider hook support matrix.
3333
+ *
3334
+ * Shows which canonical events are supported by which providers,
3335
+ * with native name translations.
3336
+ */
3337
+ declare function buildHookMatrix(providerIds?: string[]): CrossProviderMatrix;
3338
+ /**
3339
+ * Get the hook system type for a provider.
3340
+ */
3341
+ declare function getHookSystemType(providerId: string): HookSystemType;
3342
+ /**
3343
+ * Get the resolved hook config path for a provider.
3344
+ */
3345
+ declare function getHookConfigPath(providerId: string): string | null;
3346
+ /**
3347
+ * Get provider-only events (native events with no canonical mapping).
3348
+ */
3349
+ declare function getProviderOnlyEvents(providerId: string): string[];
3350
+ /**
3351
+ * Translate a canonical event to native names across multiple providers.
3352
+ * Returns only providers that support the event.
3353
+ *
3354
+ * @example
3355
+ * ```typescript
3356
+ * const result = translateToAll("PreToolUse", ["claude-code", "gemini-cli", "kimi"]);
3357
+ * // { "claude-code": "PreToolUse", "gemini-cli": "BeforeTool" }
3358
+ * // (kimi excluded — unsupported)
3359
+ * ```
3360
+ */
3361
+ declare function translateToAll(canonical: CanonicalHookEvent, providerIds: string[]): Record<string, string>;
3362
+ /**
3363
+ * Find the best canonical match for a native event name across all providers.
3364
+ * Useful when you have a native name but don't know which provider it's from.
3365
+ */
3366
+ declare function resolveNativeEvent(nativeName: string): Array<{
3367
+ providerId: string;
3368
+ canonical: CanonicalHookEvent;
3369
+ }>;
3370
+ /**
3371
+ * Get the version of the hook mappings data.
3372
+ */
3373
+ declare function getHookMappingsVersion(): string;
3374
+
3169
3375
  /**
3170
3376
  * Simple logger with verbose/quiet mode support.
3171
3377
  *
@@ -3225,4 +3431,4 @@ declare function isVerbose(): boolean;
3225
3431
  */
3226
3432
  declare function isQuiet(): boolean;
3227
3433
 
3228
- export { type AuditFinding, type AuditResult, type AuditRule, type AuditSeverity, type BatchInstallOptions, type BatchInstallResult, type CaampLockFile, type CleoChannel, type CleoProfileBuildResult, type ConfigFormat, type ConflictPolicy, type CtDispatchMatrix, type CtManifest, type CtManifestSkill, type CtProfileDefinition, type CtSkillEntry, type CtValidationIssue, type CtValidationResult, type DetectionCacheOptions, type DetectionResult, type DualScopeConfigureOptions, type DualScopeConfigureResult, type EnsureProviderInstructionFileOptions, type EnsureProviderInstructionFileResult, type GlobalOptions, type HookEvent, type InferredLockData, type InjectionCheckResult, type InjectionStatus, type InjectionTemplate, type InstallResult, type InstructionUpdateSummary, type LockEntry, MarketplaceClient, type MarketplaceResult, type MarketplaceSearchResult, type MarketplaceSkill, type McpBatchOperation, type McpConflict, type McpConflictCode, type McpPlanApplyResult, type McpServerConfig, type McpServerEntry, type NormalizedRecommendationCriteria, type ParsedSource, type PlatformPaths, type Provider, type ProviderCapabilities, type ProviderHooksCapability, type ProviderPriority, type ProviderSkillsCapability, type ProviderSpawnCapability, type ProviderStatus, RECOMMENDATION_ERROR_CODES, type RankedSkillRecommendation, type RecommendSkillsResult, type RecommendationCriteriaInput, type RecommendationErrorCode, type RecommendationOptions, type RecommendationReason, type RecommendationReasonCode, type RecommendationScoreBreakdown, type RecommendationValidationIssue, type RecommendationValidationResult, type RecommendationWeights, type ReconcileOptions, type ReconcileResult, type SkillBatchOperation, type SkillEntry, type SkillInstallResult, type SkillIntegrityResult, type SkillIntegrityStatus, type SkillLibrary, type SkillLibraryDispatchMatrix, type SkillLibraryEntry, type SkillLibraryManifest, type SkillLibraryManifestSkill, type SkillLibraryProfile, type SkillLibraryValidationIssue, type SkillLibraryValidationResult, type SkillMetadata, type SkillsPrecedence, type SourceType, type SpawnAdapter, type SpawnMechanism, type SpawnOptions, type SpawnResult, type SystemInfo, type TransportType, type ValidationIssue, type ValidationResult, _resetPlatformPathsCache, applyMcpInstallWithPolicy, buildCleoProfile, buildInjectionContent, buildLibraryFromFiles, buildServerConfig, buildSkillsMap, catalog, checkAllInjections, checkAllSkillIntegrity, checkAllSkillUpdates, checkCommandReachability, checkInjection, checkSkillIntegrity, checkSkillUpdate, clearRegisteredLibrary, configureProviderGlobalAndProject, deepMerge, detectAllProviders, detectMcpConfigConflicts, detectProjectProviders, detectProvider, discoverSkill, discoverSkills, ensureAllProviderInstructionFiles, ensureDir, ensureProviderInstructionFile, extractVersionTag, formatSkillRecommendations, generateInjectionContent, generateSkillsSection, getAgentsConfigPath, getAgentsHome, getAgentsInstructFile, getAgentsLinksDir, getAgentsMcpDir, getAgentsMcpServersPath, getAgentsSpecDir, getAgentsWikiDir, getAllProviders, getCanonicalSkillsDir, getCommonHookEvents, getEffectiveSkillsPaths, getInstalledProviders, getInstructionFiles, getLastSelectedAgents, getLockFilePath, getNestedValue, getPlatformLocations, getPlatformPaths, getProjectAgentsDir, getProvider, getProviderCapabilities, getProviderCount, getProvidersByHookEvent, getProvidersByInstructFile, getProvidersByPriority, getProvidersBySkillsPrecedence, getProvidersBySpawnCapability, getProvidersByStatus, getRegistryVersion, getSpawnCapableProviders, getSystemInfo, getTrackedMcpServers, getTrackedSkills, getTransform, groupByInstructFile, inferCleoLockData, inject, injectAll, installBatchWithRollback, installMcpServer, installMcpServerToAll, installSkill, isCaampOwnedSkill, isCleoSource, isMarketplaceScoped, isQuiet, isVerbose, listAgentsMcpServers, listAllMcpServers, listCanonicalSkills, listMcpServers, loadLibraryFromModule, normalizeCleoChannel, normalizeRecommendationCriteria, parseEnvAssignments, parseInjectionContent, parseSkillFile, parseSource, providerSupports, providerSupportsById, rankSkills, readConfig, readLockFile, recommendSkills, reconcileCleoLock, recordMcpInstall, recordSkillInstall, registerSkillLibrary, registerSkillLibraryFromPath, removeConfig, removeInjection, removeMcpFromLock, removeMcpServer, removeSkill, removeSkillFromLock, resetDetectionCache, resolveAlias, resolveChannelFromServerName, resolveCleoServerName, resolveConfigPath, resolveProviderSkillsDirs, resolveRegistryTemplatePath, saveLastSelectedAgents, scanDirectory, scanFile, scoreSkillRecommendation, searchSkills, selectProvidersByMinimumPriority, setQuiet, setVerbose, shouldOverrideSkill, toSarif, tokenizeCriteriaValue, updateInstructionsSingleOperation, validateInstructionIntegrity, validateRecommendationCriteria, validateSkill, writeConfig };
3434
+ export { type AuditFinding, type AuditResult, type AuditRule, type AuditSeverity, type BatchInstallOptions, type BatchInstallResult, CANONICAL_HOOK_EVENTS, type CaampLockFile, type CanonicalEventDefinition, type CanonicalHookEvent, type CleoChannel, type CleoProfileBuildResult, type ConfigFormat, type ConflictPolicy, type CrossProviderMatrix, type CtDispatchMatrix, type CtManifest, type CtManifestSkill, type CtProfileDefinition, type CtSkillEntry, type CtValidationIssue, type CtValidationResult, type DetectionCacheOptions, type DetectionResult, type DualScopeConfigureOptions, type DualScopeConfigureResult, type EnsureProviderInstructionFileOptions, type EnsureProviderInstructionFileResult, type GlobalOptions, HOOK_CATEGORIES, type HookCategory, type HookEvent, type HookHandlerType, type HookMapping, type HookSupportResult, type HookSystemType, type InferredLockData, type InjectionCheckResult, type InjectionStatus, type InjectionTemplate, type InstallResult, type InstructionUpdateSummary, type LockEntry, MarketplaceClient, type MarketplaceResult, type MarketplaceSearchResult, type MarketplaceSkill, type McpBatchOperation, type McpConflict, type McpConflictCode, type McpPlanApplyResult, type McpServerConfig, type McpServerEntry, type NormalizedHookEvent, type NormalizedRecommendationCriteria, type ParsedSource, type PlatformPaths, type Provider, type ProviderCapabilities, type ProviderHookProfile, type ProviderHookSummary, type ProviderHooksCapability, type ProviderPriority, type ProviderSkillsCapability, type ProviderSpawnCapability, type ProviderStatus, RECOMMENDATION_ERROR_CODES, type RankedSkillRecommendation, type RecommendSkillsResult, type RecommendationCriteriaInput, type RecommendationErrorCode, type RecommendationOptions, type RecommendationReason, type RecommendationReasonCode, type RecommendationScoreBreakdown, type RecommendationValidationIssue, type RecommendationValidationResult, type RecommendationWeights, type ReconcileOptions, type ReconcileResult, type SkillBatchOperation, type SkillEntry, type SkillInstallResult, type SkillIntegrityResult, type SkillIntegrityStatus, type SkillLibrary, type SkillLibraryDispatchMatrix, type SkillLibraryEntry, type SkillLibraryManifest, type SkillLibraryManifestSkill, type SkillLibraryProfile, type SkillLibraryValidationIssue, type SkillLibraryValidationResult, type SkillMetadata, type SkillsPrecedence, type SourceType, type SpawnAdapter, type SpawnMechanism, type SpawnOptions, type SpawnResult, type SystemInfo, type TransportType, type ValidationIssue, type ValidationResult, _resetPlatformPathsCache, applyMcpInstallWithPolicy, buildCleoProfile, buildHookMatrix, buildInjectionContent, buildLibraryFromFiles, buildServerConfig, buildSkillsMap, catalog, checkAllInjections, checkAllSkillIntegrity, checkAllSkillUpdates, checkCommandReachability, checkInjection, checkSkillIntegrity, checkSkillUpdate, clearRegisteredLibrary, configureProviderGlobalAndProject, deepMerge, detectAllProviders, detectMcpConfigConflicts, detectProjectProviders, detectProvider, discoverSkill, discoverSkills, ensureAllProviderInstructionFiles, ensureDir, ensureProviderInstructionFile, extractVersionTag, formatSkillRecommendations, generateInjectionContent, generateSkillsSection, getAgentsConfigPath, getAgentsHome, getAgentsInstructFile, getAgentsLinksDir, getAgentsMcpDir, getAgentsMcpServersPath, getAgentsSpecDir, getAgentsWikiDir, getAllCanonicalEvents, getAllProviders, getCanonicalEvent, getCanonicalEventsByCategory, getCanonicalSkillsDir, getCommonEvents, getCommonHookEvents, getEffectiveSkillsPaths, getHookConfigPath, getHookMappingsVersion, getHookSupport, getHookSystemType, getInstalledProviders, getInstructionFiles, getLastSelectedAgents, getLockFilePath, getMappedProviderIds, getNestedValue, getPlatformLocations, getPlatformPaths, getProjectAgentsDir, getProvider, getProviderCapabilities, getProviderCount, getProviderHookProfile, getProviderOnlyEvents, getProviderSummary, getProvidersByHookEvent, getProvidersByInstructFile, getProvidersByPriority, getProvidersBySkillsPrecedence, getProvidersBySpawnCapability, getProvidersByStatus, getProvidersForEvent, getRegistryVersion, getSpawnCapableProviders, getSupportedEvents, getSystemInfo, getTrackedMcpServers, getTrackedSkills, getTransform, getUnsupportedEvents, groupByInstructFile, inferCleoLockData, inject, injectAll, installBatchWithRollback, installMcpServer, installMcpServerToAll, installSkill, isCaampOwnedSkill, isCleoSource, isMarketplaceScoped, isQuiet, isVerbose, listAgentsMcpServers, listAllMcpServers, listCanonicalSkills, listMcpServers, loadLibraryFromModule, normalizeCleoChannel, normalizeRecommendationCriteria, parseEnvAssignments, parseInjectionContent, parseSkillFile, parseSource, providerSupports, providerSupportsById, rankSkills, readConfig, readLockFile, recommendSkills, reconcileCleoLock, recordMcpInstall, recordSkillInstall, registerSkillLibrary, registerSkillLibraryFromPath, removeConfig, removeInjection, removeMcpFromLock, removeMcpServer, removeSkill, removeSkillFromLock, resetDetectionCache, resolveAlias, resolveChannelFromServerName, resolveCleoServerName, resolveConfigPath, resolveNativeEvent, resolveProviderSkillsDirs, resolveRegistryTemplatePath, saveLastSelectedAgents, scanDirectory, scanFile, scoreSkillRecommendation, searchSkills, selectProvidersByMinimumPriority, setQuiet, setVerbose, shouldOverrideSkill, supportsHook, toCanonical, toNative, toNativeBatch, toSarif, tokenizeCriteriaValue, translateToAll, updateInstructionsSingleOperation, validateInstructionIntegrity, validateRecommendationCriteria, validateSkill, writeConfig };
package/dist/index.js CHANGED
@@ -78,9 +78,8 @@ import {
78
78
  validateRecommendationCriteria,
79
79
  validateSkill,
80
80
  writeConfig
81
- } from "./chunk-YWO4I7LI.js";
81
+ } from "./chunk-OLJZ23W3.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-MFWBR2NY.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-ER3FIOTM.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-ZVRDBY6L.js";
159
+ } from "./chunk-TRIXT4T7.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-XGI7NNZA.js");
277
+ const { checkAllInjections: checkAllInjections2 } = await import("./injector-P2OL6RK3.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 */\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"]}
@@ -6,7 +6,8 @@ import {
6
6
  inject,
7
7
  injectAll,
8
8
  removeInjection
9
- } from "./chunk-ZVRDBY6L.js";
9
+ } from "./chunk-MFWBR2NY.js";
10
+ import "./chunk-TRIXT4T7.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-XGI7NNZA.js.map
20
+ //# sourceMappingURL=injector-P2OL6RK3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}