@cleocode/caamp 2026.9.20 → 2026.9.22
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-QC6CHW72.js → chunk-3OL6CAMT.js} +69 -10
- package/dist/chunk-3OL6CAMT.js.map +1 -0
- package/dist/{chunk-JELNPPLN.js → chunk-UIXTFV35.js} +128 -1
- package/dist/chunk-UIXTFV35.js.map +1 -0
- package/dist/cli.js +6 -4
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +142 -8
- package/dist/index.js +11 -3
- package/dist/index.js.map +1 -1
- package/dist/{injector-7NNSGPGQ.js → injector-KSFK5LF2.js} +2 -2
- package/package.json +7 -7
- package/dist/chunk-JELNPPLN.js.map +0 -1
- package/dist/chunk-QC6CHW72.js.map +0 -1
- /package/dist/{injector-7NNSGPGQ.js.map → injector-KSFK5LF2.js.map} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -124,6 +124,62 @@ type RegistryHookCatalog = 'canonical' | 'pi';
|
|
|
124
124
|
* @public
|
|
125
125
|
*/
|
|
126
126
|
type SpawnMechanism = 'native' | 'native-child-process' | 'mcp' | 'cli' | 'api';
|
|
127
|
+
/**
|
|
128
|
+
* Whether a provider exposes a structured-question ("ask the human") tool.
|
|
129
|
+
*
|
|
130
|
+
* - `native` — the harness ships a built-in tool that renders selectable options.
|
|
131
|
+
* - `none` — verified absent from the harness's built-in tool set.
|
|
132
|
+
* - `unknown` — not verified from docs or source; never guessed.
|
|
133
|
+
*
|
|
134
|
+
* @public
|
|
135
|
+
*/
|
|
136
|
+
type AskToolStatus = 'native' | 'none' | 'unknown';
|
|
137
|
+
/**
|
|
138
|
+
* Registry record of a provider's structured-question tool.
|
|
139
|
+
*
|
|
140
|
+
* @remarks
|
|
141
|
+
* Data only. `source` says where the fact was verified so a stale entry can be
|
|
142
|
+
* re-checked; `caveat` records availability limits (mode gates, subagent
|
|
143
|
+
* restrictions). When `toolName` is `null` the agent uses
|
|
144
|
+
* {@link HitlRequestFallback} instead.
|
|
145
|
+
*
|
|
146
|
+
* @public
|
|
147
|
+
*/
|
|
148
|
+
interface ProviderAskTool {
|
|
149
|
+
/** Verification status of the ask tool. */
|
|
150
|
+
status: AskToolStatus;
|
|
151
|
+
/** Exact tool name the model calls, or `null` when none is known. */
|
|
152
|
+
toolName: string | null;
|
|
153
|
+
/** Availability limits, or `null` when none are known. */
|
|
154
|
+
caveat: string | null;
|
|
155
|
+
/** Where the fact was verified (doc URL, source path, or binary inspected). */
|
|
156
|
+
source: string;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Fallback when a provider has no (known) ask tool: the agent emits ONE LAFS
|
|
160
|
+
* envelope with this operation carrying the payload fields, then stops.
|
|
161
|
+
*
|
|
162
|
+
* @public
|
|
163
|
+
*/
|
|
164
|
+
interface HitlRequestFallback {
|
|
165
|
+
/** LAFS operation name of the envelope. */
|
|
166
|
+
operation: 'hitl.request';
|
|
167
|
+
/** Payload fields the envelope `data` carries. */
|
|
168
|
+
fields: readonly ['question', 'options', 'recommended'];
|
|
169
|
+
/** Shape of each option entry. */
|
|
170
|
+
optionFields: readonly ['label', 'description'];
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Resolved ask-tool answer for one provider.
|
|
174
|
+
*
|
|
175
|
+
* @public
|
|
176
|
+
*/
|
|
177
|
+
interface ResolvedProviderAskTool extends ProviderAskTool {
|
|
178
|
+
/** Canonical provider id (aliases resolved). */
|
|
179
|
+
providerId: string;
|
|
180
|
+
/** The `hitl.request` fallback; use it whenever `toolName` is `null`. */
|
|
181
|
+
fallback: HitlRequestFallback;
|
|
182
|
+
}
|
|
127
183
|
|
|
128
184
|
/**
|
|
129
185
|
* SkillLibrary interface - SDK standard contract for skill libraries.
|
|
@@ -266,6 +322,24 @@ interface SkillLibraryManifestSkill {
|
|
|
266
322
|
requires_session: boolean;
|
|
267
323
|
requires_epic: boolean;
|
|
268
324
|
};
|
|
325
|
+
/** Delivery class from SKILL.md `metadata.tier` (T12648). */
|
|
326
|
+
deliveryTier?: 'core' | 'on-demand' | 'internal';
|
|
327
|
+
/** Install mode from SKILL.md `metadata.install` (T12648). */
|
|
328
|
+
install?: 'harness' | 'internal';
|
|
329
|
+
/** Whether this is a core skill (catalog field, T12653). */
|
|
330
|
+
core?: boolean;
|
|
331
|
+
/** Catalog category (T12653). */
|
|
332
|
+
category?: SkillLibraryEntry['category'];
|
|
333
|
+
/** Associated protocol name (T12653). */
|
|
334
|
+
protocol?: string | null;
|
|
335
|
+
/** Direct dependency skill names (T12653). */
|
|
336
|
+
dependencies?: string[];
|
|
337
|
+
/** Shared resource names (T12653). */
|
|
338
|
+
sharedResources?: string[];
|
|
339
|
+
/** Compatible agent/context types (T12653). */
|
|
340
|
+
compatibility?: string[];
|
|
341
|
+
/** SPDX license identifier (T12653). */
|
|
342
|
+
license?: string;
|
|
269
343
|
}
|
|
270
344
|
/**
|
|
271
345
|
* Full manifest structure for a skill library.
|
|
@@ -3232,10 +3306,11 @@ declare function updateJsonConfigFile(filePath: string, mutate: (config: Record<
|
|
|
3232
3306
|
/**
|
|
3233
3307
|
* Skill installer - canonical + symlink model
|
|
3234
3308
|
*
|
|
3235
|
-
* Skills are stored once in a canonical location (
|
|
3236
|
-
*
|
|
3237
|
-
*
|
|
3238
|
-
*
|
|
3309
|
+
* Skills are stored once in a canonical location (`<cleoHome>/skills/<name>/`,
|
|
3310
|
+
* the platform data dir from `resolveSkillsRoot()`; T12598) and linked to each
|
|
3311
|
+
* target agent's skills directory. Every link is verified to resolve after it
|
|
3312
|
+
* is written; where a link cannot be created or does not resolve (Windows
|
|
3313
|
+
* without Developer Mode, filesystems without symlinks) the skill is copied.
|
|
3239
3314
|
*
|
|
3240
3315
|
* @task T9659
|
|
3241
3316
|
* @epic T9571
|
|
@@ -7591,6 +7666,47 @@ declare function getProviderCapabilities(idOrAlias: string): ProviderCapabilitie
|
|
|
7591
7666
|
* @public
|
|
7592
7667
|
*/
|
|
7593
7668
|
declare function providerSupportsById(idOrAlias: string, capabilityPath: string): boolean;
|
|
7669
|
+
/**
|
|
7670
|
+
* The fallback every agent uses when its provider has no known ask tool: emit
|
|
7671
|
+
* ONE LAFS envelope `hitl.request` with `{question, options[{label,
|
|
7672
|
+
* description}], recommended}` in `data`, then stop.
|
|
7673
|
+
*
|
|
7674
|
+
* @public
|
|
7675
|
+
*/
|
|
7676
|
+
declare const HITL_REQUEST_FALLBACK: HitlRequestFallback;
|
|
7677
|
+
/**
|
|
7678
|
+
* Structured-question ("ask the human") tool per provider id.
|
|
7679
|
+
*
|
|
7680
|
+
* @remarks
|
|
7681
|
+
* DATA, keyed by the canonical id in `providers/registry.json`; every registry
|
|
7682
|
+
* provider has an entry (a test enforces it). Only verified names are
|
|
7683
|
+
* recorded — anything not found in docs or source is `unknown`, never
|
|
7684
|
+
* invented. Researched 2026-09-27 for T12482.
|
|
7685
|
+
*
|
|
7686
|
+
* @public
|
|
7687
|
+
*/
|
|
7688
|
+
declare const PROVIDER_ASK_TOOLS: Readonly<Record<string, ProviderAskTool>>;
|
|
7689
|
+
/**
|
|
7690
|
+
* Resolve the structured-question tool for a provider, with the
|
|
7691
|
+
* `hitl.request` fallback attached.
|
|
7692
|
+
*
|
|
7693
|
+
* @remarks
|
|
7694
|
+
* Canonical ids are looked up directly (no registry load); anything else is
|
|
7695
|
+
* alias-resolved through the registry. An id with no entry resolves to
|
|
7696
|
+
* `unknown` so callers always get an answer and a fallback.
|
|
7697
|
+
*
|
|
7698
|
+
* @param idOrAlias - Provider ID or alias (e.g. `"claude"`)
|
|
7699
|
+
* @returns The ask-tool record, its canonical provider id and the fallback
|
|
7700
|
+
*
|
|
7701
|
+
* @example
|
|
7702
|
+
* ```typescript
|
|
7703
|
+
* getProviderAskTool('claude').toolName; // "AskUserQuestion"
|
|
7704
|
+
* getProviderAskTool('aider').toolName; // null -> use fallback (hitl.request)
|
|
7705
|
+
* ```
|
|
7706
|
+
*
|
|
7707
|
+
* @public
|
|
7708
|
+
*/
|
|
7709
|
+
declare function getProviderAskTool(idOrAlias: string): ResolvedProviderAskTool;
|
|
7594
7710
|
|
|
7595
7711
|
/**
|
|
7596
7712
|
* Spawn adapter interface for provider-neutral subagent orchestration.
|
|
@@ -7794,7 +7910,7 @@ declare function registerSkillLibrary(library: SkillLibrary): void;
|
|
|
7794
7910
|
* @remarks
|
|
7795
7911
|
* Tries two strategies in order: first attempts module-based loading if
|
|
7796
7912
|
* the directory contains an `index.js`, then falls back to file-based
|
|
7797
|
-
* loading from
|
|
7913
|
+
* loading from `skills.json` or `skills/manifest.json`. Replaces any previously
|
|
7798
7914
|
* registered library on success.
|
|
7799
7915
|
*
|
|
7800
7916
|
* @param root - Absolute path to the skill library root directory
|
|
@@ -8983,12 +9099,30 @@ declare function validateInstructionIntegrity(providers: Provider[], projectDir:
|
|
|
8983
9099
|
* @public
|
|
8984
9100
|
*/
|
|
8985
9101
|
declare function loadLibraryFromModule(root: string): SkillLibrary;
|
|
9102
|
+
/**
|
|
9103
|
+
* Derive a catalog entry from a `skills/manifest.json` entry.
|
|
9104
|
+
*
|
|
9105
|
+
* @remarks
|
|
9106
|
+
* The CLEO skills package ships no `skills.json` (T12653): its manifest is
|
|
9107
|
+
* generated from SKILL.md frontmatter and carries every catalog field. The
|
|
9108
|
+
* manifest `path` names the skill directory, so the catalog path appends
|
|
9109
|
+
* `SKILL.md`. `core` falls back to `deliveryTier === 'core'` and absent list
|
|
9110
|
+
* fields default to empty, so an older manifest still maps.
|
|
9111
|
+
*
|
|
9112
|
+
* @param skill - One manifest skill entry.
|
|
9113
|
+
* @returns The equivalent catalog entry.
|
|
9114
|
+
*
|
|
9115
|
+
* @public
|
|
9116
|
+
*/
|
|
9117
|
+
declare function catalogEntryFromManifest(skill: SkillLibraryManifestSkill): SkillLibraryEntry;
|
|
8986
9118
|
/**
|
|
8987
9119
|
* Build a SkillLibrary from raw files in a directory.
|
|
8988
9120
|
*
|
|
8989
9121
|
* @remarks
|
|
8990
9122
|
* Constructs a full SkillLibrary implementation by reading:
|
|
8991
|
-
* - `skills.json` for catalog entries
|
|
9123
|
+
* - `skills.json` for catalog entries, when present (legacy and third-party
|
|
9124
|
+
* libraries); otherwise the catalog is derived from `skills/manifest.json`
|
|
9125
|
+
* entries via {@link catalogEntryFromManifest} (T12653)
|
|
8992
9126
|
* - `skills/manifest.json` for dispatch matrix
|
|
8993
9127
|
* - `profiles/*.json` for profile definitions
|
|
8994
9128
|
* - `skills/<name>/SKILL.md` for skill content
|
|
@@ -8997,7 +9131,7 @@ declare function loadLibraryFromModule(root: string): SkillLibrary;
|
|
|
8997
9131
|
*
|
|
8998
9132
|
* @param root - Absolute path to the library root directory
|
|
8999
9133
|
* @returns A SkillLibrary instance backed by filesystem reads
|
|
9000
|
-
* @throws If skills.json is
|
|
9134
|
+
* @throws If neither skills.json nor skills/manifest.json is found at the root
|
|
9001
9135
|
*
|
|
9002
9136
|
* @example
|
|
9003
9137
|
* ```typescript
|
|
@@ -9733,4 +9867,4 @@ declare function parseSource(input: string): ParsedSource;
|
|
|
9733
9867
|
*/
|
|
9734
9868
|
declare function isMarketplaceScoped(input: string): boolean;
|
|
9735
9869
|
|
|
9736
|
-
export { type AuditFinding, type AuditResult, type AuditRule, type AuditSeverity, type BatchInstallOptions, type BatchInstallResult, type BlockInsertPosition, CANONICAL_HOOK_EVENTS, CLEO_ARTIFACT_BUDGETS, CLEO_ARTIFACT_REQUIREMENTS, type CaampBlock, type CaampLockFile, type CanonicalEventDefinition, type CanonicalHookEvent, type CantProfileCounts, type CantProfileEntry, type CantValidationDiagnostic, type ConfigFormat, type CrossProviderMatrix, type CtDispatchMatrix, type CtManifest, type CtManifestSkill, type CtProfileDefinition, type CtSkillEntry, type CtValidationIssue, type CtValidationResult, DEFAULT_EXCLUSIVITY_MODE, type DedupeResult, type DetectionCacheOptions, type DetectionResult, EXCLUSIVITY_MODE_ENV_VAR, EmbeddedDeliveryDowngradeError, type EnsureProviderInstructionFileOptions, type EnsureProviderInstructionFileResult, type EnsureProviderRuleFileOptions, type EnsureProviderRuleFileResult, type ExclusivityMode, type FileLockOptions, type GatedSkillInstallOptions, type GatedSkillInstallResult, type GlobalInstructionOptions, type GlobalOptions, HOOK_CATEGORIES, type Harness, type HarnessScope, type HookCategory, type HookEvent, type HookHandlerType, type HookMapping, type HookSupportResult, type HookSystemType, type InjectionCheckResult, type InjectionStatus, type InjectionTemplate, type InstallMcpServerOptions, type InstallMcpServerResult, type InstallSkillOptions, type InstructionUpdateSummary, JsonConfigParseError, type KnownProviderAgentFolderId, type LockEntry, MarketplaceClient, type MarketplaceResult, type MarketplaceSearchResult, type MarketplaceSkill, type McpConfigFormat, type McpDetectionEntry, type McpScope, type McpServerConfig, type McpServerEntriesByProvider, type McpServerEntry, type McpTransportType, type NormalizeResult, type NormalizedHookEvent, type NormalizedRecommendationCriteria, type ParsedSource, PiHarness, PiRequiredError, type Provider, type ProviderCapabilities, type ProviderHarnessCapability, type ProviderHookProfile, type ProviderHookSummary, type ProviderHooksCapability, type ProviderMcpCapability, 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 ReconcileResult, type RegistryHarnessKind, type RegistryHookCatalog, type RegistryHookFormat, type RemoveMcpServerOptions, type RemoveMcpServerResult, type RepairResult, type ResolveDefaultTargetProvidersOptions, type ResolvedSkillSource, type SkillBatchOperation, type SkillEntry, type SkillGateModules, SkillInstallError, type SkillInstallErrorCode, type SkillInstallErrorDetails, type SkillInstallGateOptions, type SkillInstallGateReport, 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 SkillRowData, type SkillRowSourceType, type SkillSourceProgress, type SkillsPrecedence, type SourceType, type SpawnAdapter, type SpawnMechanism, type SpawnOptions, type SpawnResult, type SubagentHandle, type SubagentResult, type SubagentTask, type SyncGlobalInstructionsOptions, type TransportType, type ValidateCantProfileResult, type ValidationIssue, type ValidationResult, type WriteAgentFileOptions, type WriteAgentFileResult, _resetPlatformPathsCache, assertCleoShippedBuildShape, assertNotTornRead, blockPattern, buildBlock, buildHookMatrix, buildInjectionContent, buildLibraryFromFiles, buildSkillsMap, catalog, checkAllInjections, checkAllSkillIntegrity, checkAllSkillUpdates, checkGlobalInstructionStaleness, checkInjection, checkSkillIntegrity, checkSkillUpdate, classifyPackageFilesEntry, clearRegisteredLibrary, dedupeFile, dedupeFiles, deepMerge, detectAllProviders, detectMcpInstallations, detectProjectProviders, detectProvider, discoverSkill, discoverSkills, ensureAllProviderInstructionFiles, ensureDir, ensureProviderInstructionFile, ensureProviderRuleFile, formatSkillRecommendations, generateInjectionContent, generateSkillsSection, getAgentsConfigPath, getAgentsHome, getAgentsInstructFile, getAgentsLinksDir, getAgentsMcpDir, getAgentsMcpServersPath, getAgentsSpecDir, getAgentsWikiDir, getAllCanonicalEvents, getAllHarnesses, getAllProviders, getCanonicalEvent, getCanonicalEventsByCategory, getCommonEvents, getCommonHookEvents, getEffectiveSkillsPaths, getExclusivityMode, getHarnessFor, getHookConfigPath, getHookMappingsVersion, getHookSupport, getHookSystemType, getInstalledProviders, getInstructionFiles, getLockFilePath, getMappedProviderIds, getNestedValue, getPlatformLocations, getPlatformPaths, getPrimaryHarness, getPrimaryProvider, getProjectAgentsDir, getProvider, getProviderAgentFolder, getProviderCapabilities, getProviderCount, getProviderHookProfile, getProviderInstructionReferences, getProviderOnlyEvents, getProviderSummary, getProvidersByHookEvent, getProvidersByInstructFile, getProvidersByPriority, getProvidersBySkillsPrecedence, getProvidersBySpawnCapability, getProvidersByStatus, getProvidersForEvent, getRegistryVersion, getSpawnCapableProviders, getSupportedEvents, getSystemInfo, getTrackedSkills, getUnsupportedEvents, groupByInstructFile, inferSkillSourceType, inject, injectAll, installBatchWithRollback, installMcpServer, installResolvedSkill, installSkill, installSkillFromSource, instructionFileCascade, isCaampOwnedSkill, isEmbeddedDelivery, isExclusivityMode, isMarketplaceScoped, isQuiet, isVerbose, listAllMcpServers, listCanonicalSkills, listMcpServers, loadLibraryFromModule, mergeBlockBodies, normalizeMarkers, normalizeRecommendationCriteria, parseBlocks, parseCaampBlocks, parseInjectionContent, parseSkillFile, parseSource, providerSupports, providerSupportsById, rankSkills, readConfig, recommendSkills, reconcile, recordSkillInstall, registerSkillLibrary, registerSkillLibraryFromPath, removeConfig, removeInjection, removeMcpServer, removeMcpServerFromAll, removeSkill, removeSkillFromLock, repairContent, repairInstructionFiles, replaceDirectoryFromSource, resetDetectionCache, resetExclusivityModeOverride, resetRegistry, resolveAlias, resolveDefaultTargetProviders, resolveGlobalInstructionPath, resolveInstructionDelivery, resolveMcpConfigPath, resolveNativeEvent, resolveProviderSkillsDirs, resolveRegistryTemplatePath, resolveSkillSource, runSkillInstallGate, scanDirectory, scanFile, scoreSkillRecommendation, searchSkills, selectProvidersByMinimumPriority, setExclusivityMode, setQuiet, setVerbose, shouldOverrideSkill, stageSkillCopy, supportsHook, swapIntoPlace, syncGlobalInstructions, toCanonical, toNative, toNativeBatch, toSarif, tokenizeCriteriaValue, translateToAll, updateInstructionsSingleOperation, updateJsonConfigFile, validateInstructionIntegrity, validatePackageArtifact, validateRecommendationCriteria, validateSkill, withFileLock, writeAgentFileToAllProviders, writeConfig };
|
|
9870
|
+
export { type AskToolStatus, type AuditFinding, type AuditResult, type AuditRule, type AuditSeverity, type BatchInstallOptions, type BatchInstallResult, type BlockInsertPosition, CANONICAL_HOOK_EVENTS, CLEO_ARTIFACT_BUDGETS, CLEO_ARTIFACT_REQUIREMENTS, type CaampBlock, type CaampLockFile, type CanonicalEventDefinition, type CanonicalHookEvent, type CantProfileCounts, type CantProfileEntry, type CantValidationDiagnostic, type ConfigFormat, type CrossProviderMatrix, type CtDispatchMatrix, type CtManifest, type CtManifestSkill, type CtProfileDefinition, type CtSkillEntry, type CtValidationIssue, type CtValidationResult, DEFAULT_EXCLUSIVITY_MODE, type DedupeResult, type DetectionCacheOptions, type DetectionResult, EXCLUSIVITY_MODE_ENV_VAR, EmbeddedDeliveryDowngradeError, type EnsureProviderInstructionFileOptions, type EnsureProviderInstructionFileResult, type EnsureProviderRuleFileOptions, type EnsureProviderRuleFileResult, type ExclusivityMode, type FileLockOptions, type GatedSkillInstallOptions, type GatedSkillInstallResult, type GlobalInstructionOptions, type GlobalOptions, HITL_REQUEST_FALLBACK, HOOK_CATEGORIES, type Harness, type HarnessScope, type HitlRequestFallback, type HookCategory, type HookEvent, type HookHandlerType, type HookMapping, type HookSupportResult, type HookSystemType, type InjectionCheckResult, type InjectionStatus, type InjectionTemplate, type InstallMcpServerOptions, type InstallMcpServerResult, type InstallSkillOptions, type InstructionUpdateSummary, JsonConfigParseError, type KnownProviderAgentFolderId, type LockEntry, MarketplaceClient, type MarketplaceResult, type MarketplaceSearchResult, type MarketplaceSkill, type McpConfigFormat, type McpDetectionEntry, type McpScope, type McpServerConfig, type McpServerEntriesByProvider, type McpServerEntry, type McpTransportType, type NormalizeResult, type NormalizedHookEvent, type NormalizedRecommendationCriteria, PROVIDER_ASK_TOOLS, type ParsedSource, PiHarness, PiRequiredError, type Provider, type ProviderAskTool, type ProviderCapabilities, type ProviderHarnessCapability, type ProviderHookProfile, type ProviderHookSummary, type ProviderHooksCapability, type ProviderMcpCapability, 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 ReconcileResult, type RegistryHarnessKind, type RegistryHookCatalog, type RegistryHookFormat, type RemoveMcpServerOptions, type RemoveMcpServerResult, type RepairResult, type ResolveDefaultTargetProvidersOptions, type ResolvedProviderAskTool, type ResolvedSkillSource, type SkillBatchOperation, type SkillEntry, type SkillGateModules, SkillInstallError, type SkillInstallErrorCode, type SkillInstallErrorDetails, type SkillInstallGateOptions, type SkillInstallGateReport, 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 SkillRowData, type SkillRowSourceType, type SkillSourceProgress, type SkillsPrecedence, type SourceType, type SpawnAdapter, type SpawnMechanism, type SpawnOptions, type SpawnResult, type SubagentHandle, type SubagentResult, type SubagentTask, type SyncGlobalInstructionsOptions, type TransportType, type ValidateCantProfileResult, type ValidationIssue, type ValidationResult, type WriteAgentFileOptions, type WriteAgentFileResult, _resetPlatformPathsCache, assertCleoShippedBuildShape, assertNotTornRead, blockPattern, buildBlock, buildHookMatrix, buildInjectionContent, buildLibraryFromFiles, buildSkillsMap, catalog, catalogEntryFromManifest, checkAllInjections, checkAllSkillIntegrity, checkAllSkillUpdates, checkGlobalInstructionStaleness, checkInjection, checkSkillIntegrity, checkSkillUpdate, classifyPackageFilesEntry, clearRegisteredLibrary, dedupeFile, dedupeFiles, deepMerge, detectAllProviders, detectMcpInstallations, detectProjectProviders, detectProvider, discoverSkill, discoverSkills, ensureAllProviderInstructionFiles, ensureDir, ensureProviderInstructionFile, ensureProviderRuleFile, formatSkillRecommendations, generateInjectionContent, generateSkillsSection, getAgentsConfigPath, getAgentsHome, getAgentsInstructFile, getAgentsLinksDir, getAgentsMcpDir, getAgentsMcpServersPath, getAgentsSpecDir, getAgentsWikiDir, getAllCanonicalEvents, getAllHarnesses, getAllProviders, getCanonicalEvent, getCanonicalEventsByCategory, getCommonEvents, getCommonHookEvents, getEffectiveSkillsPaths, getExclusivityMode, getHarnessFor, getHookConfigPath, getHookMappingsVersion, getHookSupport, getHookSystemType, getInstalledProviders, getInstructionFiles, getLockFilePath, getMappedProviderIds, getNestedValue, getPlatformLocations, getPlatformPaths, getPrimaryHarness, getPrimaryProvider, getProjectAgentsDir, getProvider, getProviderAgentFolder, getProviderAskTool, getProviderCapabilities, getProviderCount, getProviderHookProfile, getProviderInstructionReferences, getProviderOnlyEvents, getProviderSummary, getProvidersByHookEvent, getProvidersByInstructFile, getProvidersByPriority, getProvidersBySkillsPrecedence, getProvidersBySpawnCapability, getProvidersByStatus, getProvidersForEvent, getRegistryVersion, getSpawnCapableProviders, getSupportedEvents, getSystemInfo, getTrackedSkills, getUnsupportedEvents, groupByInstructFile, inferSkillSourceType, inject, injectAll, installBatchWithRollback, installMcpServer, installResolvedSkill, installSkill, installSkillFromSource, instructionFileCascade, isCaampOwnedSkill, isEmbeddedDelivery, isExclusivityMode, isMarketplaceScoped, isQuiet, isVerbose, listAllMcpServers, listCanonicalSkills, listMcpServers, loadLibraryFromModule, mergeBlockBodies, normalizeMarkers, normalizeRecommendationCriteria, parseBlocks, parseCaampBlocks, parseInjectionContent, parseSkillFile, parseSource, providerSupports, providerSupportsById, rankSkills, readConfig, recommendSkills, reconcile, recordSkillInstall, registerSkillLibrary, registerSkillLibraryFromPath, removeConfig, removeInjection, removeMcpServer, removeMcpServerFromAll, removeSkill, removeSkillFromLock, repairContent, repairInstructionFiles, replaceDirectoryFromSource, resetDetectionCache, resetExclusivityModeOverride, resetRegistry, resolveAlias, resolveDefaultTargetProviders, resolveGlobalInstructionPath, resolveInstructionDelivery, resolveMcpConfigPath, resolveNativeEvent, resolveProviderSkillsDirs, resolveRegistryTemplatePath, resolveSkillSource, runSkillInstallGate, scanDirectory, scanFile, scoreSkillRecommendation, searchSkills, selectProvidersByMinimumPriority, setExclusivityMode, setQuiet, setVerbose, shouldOverrideSkill, stageSkillCopy, supportsHook, swapIntoPlace, syncGlobalInstructions, toCanonical, toNative, toNativeBatch, toSarif, tokenizeCriteriaValue, translateToAll, updateInstructionsSingleOperation, updateJsonConfigFile, validateInstructionIntegrity, validatePackageArtifact, validateRecommendationCriteria, validateSkill, withFileLock, writeAgentFileToAllProviders, writeConfig };
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
RECOMMENDATION_ERROR_CODES,
|
|
8
8
|
SkillInstallError,
|
|
9
9
|
buildLibraryFromFiles,
|
|
10
|
+
catalogEntryFromManifest,
|
|
10
11
|
catalog_exports,
|
|
11
12
|
checkAllSkillUpdates,
|
|
12
13
|
checkGlobalInstructionStaleness,
|
|
@@ -81,10 +82,12 @@ import {
|
|
|
81
82
|
validateRecommendationCriteria,
|
|
82
83
|
validateSkill,
|
|
83
84
|
writeConfig
|
|
84
|
-
} from "./chunk-
|
|
85
|
+
} from "./chunk-3OL6CAMT.js";
|
|
85
86
|
import {
|
|
86
87
|
EmbeddedDeliveryDowngradeError,
|
|
88
|
+
HITL_REQUEST_FALLBACK,
|
|
87
89
|
JsonConfigParseError,
|
|
90
|
+
PROVIDER_ASK_TOOLS,
|
|
88
91
|
assertNotTornRead,
|
|
89
92
|
blockPattern,
|
|
90
93
|
buildBlock,
|
|
@@ -106,6 +109,7 @@ import {
|
|
|
106
109
|
getPrimaryProvider,
|
|
107
110
|
getProvider,
|
|
108
111
|
getProviderAgentFolder,
|
|
112
|
+
getProviderAskTool,
|
|
109
113
|
getProviderCapabilities,
|
|
110
114
|
getProviderCount,
|
|
111
115
|
getProviderInstructionReferences,
|
|
@@ -140,7 +144,7 @@ import {
|
|
|
140
144
|
updateJsonConfigFile,
|
|
141
145
|
withFileLock,
|
|
142
146
|
writeAgentFileToAllProviders
|
|
143
|
-
} from "./chunk-
|
|
147
|
+
} from "./chunk-UIXTFV35.js";
|
|
144
148
|
import {
|
|
145
149
|
CANONICAL_HOOK_EVENTS,
|
|
146
150
|
HOOK_CATEGORIES,
|
|
@@ -516,7 +520,7 @@ function shouldOverrideSkill(skillName, incomingSource, existingEntry) {
|
|
|
516
520
|
return true;
|
|
517
521
|
}
|
|
518
522
|
async function validateInstructionIntegrity(providers, projectDir, scope, expectedContent) {
|
|
519
|
-
const { checkAllInjections: checkAllInjections2 } = await import("./injector-
|
|
523
|
+
const { checkAllInjections: checkAllInjections2 } = await import("./injector-KSFK5LF2.js");
|
|
520
524
|
const results = await checkAllInjections2(providers, projectDir, scope, expectedContent);
|
|
521
525
|
const issues = [];
|
|
522
526
|
for (const result of results) {
|
|
@@ -549,9 +553,11 @@ export {
|
|
|
549
553
|
DEFAULT_EXCLUSIVITY_MODE,
|
|
550
554
|
EXCLUSIVITY_MODE_ENV_VAR,
|
|
551
555
|
EmbeddedDeliveryDowngradeError,
|
|
556
|
+
HITL_REQUEST_FALLBACK,
|
|
552
557
|
HOOK_CATEGORIES,
|
|
553
558
|
JsonConfigParseError,
|
|
554
559
|
MarketplaceClient,
|
|
560
|
+
PROVIDER_ASK_TOOLS,
|
|
555
561
|
PiHarness,
|
|
556
562
|
PiRequiredError,
|
|
557
563
|
RECOMMENDATION_ERROR_CODES,
|
|
@@ -566,6 +572,7 @@ export {
|
|
|
566
572
|
buildLibraryFromFiles,
|
|
567
573
|
buildSkillsMap,
|
|
568
574
|
catalog_exports as catalog,
|
|
575
|
+
catalogEntryFromManifest,
|
|
569
576
|
checkAllInjections,
|
|
570
577
|
checkAllSkillIntegrity,
|
|
571
578
|
checkAllSkillUpdates,
|
|
@@ -625,6 +632,7 @@ export {
|
|
|
625
632
|
getProjectAgentsDir,
|
|
626
633
|
getProvider,
|
|
627
634
|
getProviderAgentFolder,
|
|
635
|
+
getProviderAskTool,
|
|
628
636
|
getProviderCapabilities,
|
|
629
637
|
getProviderCount,
|
|
630
638
|
getProviderHookProfile,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/artifacts/validation.ts","../src/core/skills/integrity.ts"],"sourcesContent":["/**\n * Pure semantic validation of npm-produced package inventories.\n *\n * Code placed in `packages/caamp/` per Package-Boundary Check — verified\n * against AGENTS.md. No filesystem, process, model, or runtime-store access.\n */\n\nimport { posix } from 'node:path';\nimport type {\n PackageArtifactBudgets,\n PackageArtifactFile,\n PackageArtifactInventory,\n PackageArtifactIssue,\n PackageArtifactPolicy,\n PackageArtifactRequirement,\n PackageArtifactValidation,\n PackageFilesEntry,\n} from '@cleocode/contracts/package-artifact';\n\n/** Existing CLI upper budgets: 20 MiB packed, 36 MiB unpacked, and 800 files. */\nexport const CLEO_ARTIFACT_BUDGETS: Readonly<PackageArtifactBudgets> = Object.freeze({\n packedBytes: 20 * 1024 * 1024,\n unpackedBytes: 36 * 1024 * 1024,\n fileCount: 800,\n});\n\n/** Required CLI and adapter-node resources, independent of historical byte/file-count floors. */\nexport const CLEO_ARTIFACT_REQUIREMENTS: readonly PackageArtifactRequirement[] = Object.freeze([\n { id: 'cli-entry', path: 'dist/cli/index.js', match: 'exact' },\n { id: 'studio-server-entry', path: 'studio-dist/index.js', match: 'exact' },\n { id: 'studio-handler', path: 'studio-dist/handler.js', match: 'exact' },\n { id: 'studio-server', path: 'studio-dist/server/index.js', match: 'exact' },\n { id: 'studio-manifest', path: 'studio-dist/server/manifest.js', match: 'exact' },\n {\n id: 'studio-client-start',\n path: 'studio-dist/client/_app/immutable/entry/start.*.js',\n match: 'glob',\n },\n {\n id: 'studio-client-app',\n path: 'studio-dist/client/_app/immutable/entry/app.*.js',\n match: 'glob',\n },\n]);\n\nconst SHA256 = /^[a-f0-9]{64}$/;\nconst GLOB = /[*?{}[\\]]|[+@!]\\(/;\n\nfunction pathProblem(path: string): string | null {\n if (!path || path.trim() !== path) return 'Path is empty or has surrounding whitespace.';\n if (path.includes('\\\\') || /[\\x00-\\x1f\\x7f]/.test(path))\n return 'Path is not a portable POSIX package path.';\n if (posix.isAbsolute(path) || /^[A-Za-z]:/.test(path))\n return 'Path must be relative to the package.';\n if (path.split('/').some((part) => !part || part === '.' || part === '..')) {\n return 'Path must not contain empty, current-directory, or parent-directory segments.';\n }\n return null;\n}\n\n/**\n * Classify a manifest files entry without evaluating exclusions as disk paths.\n *\n * @param entry - Original npm manifest entry.\n * @returns Classification only; actual selected content must come from the packer.\n * @example\n * ```ts\n * classifyPackageFilesEntry('!dist/index.js.map').kind; // 'exclusion'\n * ```\n */\nexport function classifyPackageFilesEntry(entry: string): PackageFilesEntry {\n const exclusion = entry.startsWith('!');\n const pattern = (exclusion ? entry.slice(1) : entry).replace(/^\\.\\//, '').replace(/\\/$/, '');\n const reason = pattern.startsWith('!')\n ? 'Repeated exclusion markers are not assessed.'\n : pathProblem(pattern);\n return {\n entry,\n pattern,\n kind: reason ? 'invalid' : exclusion ? 'exclusion' : GLOB.test(pattern) ? 'glob' : 'literal',\n reason,\n };\n}\n\nfunction fileProblems(file: PackageArtifactFile): string[] {\n const problems: string[] = [];\n const pathError = pathProblem(file.path);\n if (pathError) problems.push(pathError);\n if (!Number.isSafeInteger(file.size) || file.size < 0)\n problems.push('File size must be a nonnegative safe integer.');\n if (file.sha256 !== undefined && !SHA256.test(file.sha256))\n problems.push('File SHA-256 must be 64 lowercase hexadecimal characters.');\n return problems;\n}\n\n/**\n * Validate nonempty semantic resources, inventory identity, expected hashes and upper budgets.\n *\n * @param inventory - Packer-produced evidence or an explicitly identified fixture.\n * @param policy - Independently specified resources, expected files and cost ceilings.\n * @returns A copied evidence receipt; valid means only the supplied checks passed.\n * @example\n * ```ts\n * const result = validatePackageArtifact(inventory, {\n * requirements: CLEO_ARTIFACT_REQUIREMENTS,\n * budgets: CLEO_ARTIFACT_BUDGETS,\n * });\n * // result.runtime remains 'not-assessed', even when result.valid is true.\n * ```\n */\nexport function validatePackageArtifact(\n inventory: PackageArtifactInventory,\n policy: PackageArtifactPolicy,\n): PackageArtifactValidation {\n const issues: PackageArtifactIssue[] = [];\n const add = (code: PackageArtifactIssue['code'], subject: string, message: string): void => {\n issues.push({ code, subject, message });\n };\n if (!inventory.packageName.trim() || !inventory.version.trim()) {\n add('invalid-inventory', 'identity', 'Package name and version must be recorded.');\n }\n if (!['npm-pack', 'npm-pack-dry-run', 'fixture'].includes(inventory.source)) {\n add('invalid-inventory', 'source', 'Inventory provenance is not recognized.');\n }\n if (!Number.isSafeInteger(inventory.packedBytes) || inventory.packedBytes < 0) {\n add('invalid-inventory', 'packedBytes', 'Packed bytes must be a nonnegative safe integer.');\n }\n if (inventory.tarballSha256 !== undefined && !SHA256.test(inventory.tarballSha256)) {\n add(\n 'invalid-inventory',\n 'tarballSha256',\n 'Tarball SHA-256 must be 64 lowercase hexadecimal characters.',\n );\n }\n if (inventory.source === 'npm-pack-dry-run' && inventory.tarballSha256 !== undefined) {\n add(\n 'invalid-inventory',\n 'tarballSha256',\n 'A dry run cannot establish a retained tarball hash.',\n );\n }\n const files = new Map<string, PackageArtifactFile>();\n let unpackedBytes: number | null = 0;\n for (const file of inventory.files) {\n for (const problem of fileProblems(file)) add('invalid-inventory', file.path, problem);\n if (files.has(file.path)) add('invalid-inventory', file.path, 'Duplicate inventory path.');\n files.set(file.path, file);\n if (unpackedBytes !== null) {\n const total: number = unpackedBytes + file.size;\n unpackedBytes = Number.isSafeInteger(total) && file.size >= 0 ? total : null;\n }\n }\n if (unpackedBytes === null)\n add('invalid-inventory', 'unpackedBytes', 'File bytes cannot be safely totaled.');\n const entries = (policy.filesEntries ?? []).map(classifyPackageFilesEntry);\n for (const entry of entries) {\n if (entry.reason) add('invalid-policy', entry.entry, entry.reason);\n }\n if (!policy.requirements.length)\n add('invalid-policy', 'requirements', 'At least one semantic content requirement is required.');\n const ids = new Set<string>();\n const requirements = policy.requirements.map((requirement) => {\n const invalid = pathProblem(requirement.path);\n const duplicate = ids.has(requirement.id);\n ids.add(requirement.id);\n if (\n !requirement.id.trim() ||\n duplicate ||\n invalid ||\n !['exact', 'glob'].includes(requirement.match)\n ) {\n add(\n 'invalid-policy',\n requirement.id,\n invalid ?? 'Requirement identity or match mode is invalid or duplicated.',\n );\n return { id: requirement.id, matchedPaths: [], satisfied: false };\n }\n const matches = inventory.files.filter((file) =>\n requirement.match === 'exact'\n ? file.path === requirement.path\n : posix.matchesGlob(file.path, requirement.path),\n );\n if (!matches.length)\n add(\n 'missing',\n requirement.id,\n `Required resource ${requirement.path} is absent from the selected inventory.`,\n );\n for (const file of matches) {\n if (file.size === 0) add('empty', file.path, `Required resource ${requirement.id} is empty.`);\n }\n return {\n id: requirement.id,\n matchedPaths: matches.map((file) => file.path),\n satisfied: matches.length > 0 && matches.every((file) => file.size > 0),\n };\n });\n for (const pattern of policy.forbiddenPatterns ?? []) {\n const invalid = pathProblem(pattern);\n if (invalid) {\n add('invalid-policy', pattern, invalid);\n continue;\n }\n for (const file of inventory.files) {\n if (posix.matchesGlob(file.path, pattern))\n add('forbidden', file.path, `Selected file matches forbidden pattern ${pattern}.`);\n }\n }\n let hashComparison: PackageArtifactValidation['hashComparison'] = 'not-requested';\n for (const expected of policy.expectedFiles ?? []) {\n const problems = fileProblems(expected);\n for (const problem of problems) add('invalid-policy', expected.path, problem);\n const actual = files.get(expected.path);\n if (!actual) add('missing', expected.path, 'An independently expected file is missing.');\n else if (actual.size !== expected.size)\n add('mismatch', expected.path, 'File bytes differ from independently expected inventory.');\n if (expected.sha256 !== undefined) {\n if (hashComparison !== 'failed') hashComparison = 'matched';\n if (problems.length || actual?.sha256 !== expected.sha256) {\n hashComparison = 'failed';\n add(\n 'mismatch',\n expected.path,\n 'Actual hash is missing or differs from the independently expected SHA-256.',\n );\n }\n }\n }\n for (const [field, limit] of Object.entries(policy.budgets)) {\n if (!Number.isSafeInteger(limit) || limit < 0)\n add('invalid-policy', field, 'Budget must be a nonnegative safe integer.');\n }\n if (inventory.packedBytes > policy.budgets.packedBytes)\n add('budget', 'packedBytes', 'Packed bytes exceed the configured upper budget.');\n if (unpackedBytes !== null && unpackedBytes > policy.budgets.unpackedBytes)\n add('budget', 'unpackedBytes', 'Unpacked bytes exceed the configured upper budget.');\n if (inventory.files.length > policy.budgets.fileCount)\n add('budget', 'fileCount', 'Selected file count exceeds the configured upper budget.');\n return {\n valid: issues.length === 0,\n inventory: { ...inventory, files: inventory.files.map((file) => ({ ...file })) },\n unpackedBytes,\n issues,\n filesEntries: entries,\n requirements,\n hashComparison,\n runtime: 'not-assessed',\n limitations: [\n 'Manifest entries are classified only; the supplied packer inventory is the content authority.',\n 'Hashes are recorded and compared to supplied expected evidence; this validator does not read or authenticate tarball bytes.',\n 'Installability, module/dependency resolution, local-reference closure and native/dynamic runtime behavior are not assessed.',\n ],\n };\n}\n\n/**\n * Reject declaration and stray JavaScript output absent from the published CLI bundle.\n *\n * @param files - Actual selected package files, not a development directory listing.\n * @returns Concrete build-shape failures; this does not load the bundle.\n * @example\n * ```ts\n * assertCleoShippedBuildShape([{ path: 'dist/cli/index.js', size: 1 }]); // []\n * ```\n */\nexport function assertCleoShippedBuildShape(files: readonly PackageArtifactFile[]): string[] {\n const reasons: string[] = [];\n const dist = files.filter((file) => file.path.startsWith('dist/'));\n const declarations = dist.filter(\n (file) => file.path.endsWith('.d.ts') || file.path.endsWith('.d.ts.map'),\n );\n if (declarations.length)\n reasons.push(\n `${declarations.length} declaration file(s) under dist/ — the esbuild bundle emits none`,\n );\n const stray = dist.filter(\n (file) => file.path.endsWith('.js') && file.path !== 'dist/cli/index.js',\n );\n if (stray.length)\n reasons.push(\n `${stray.length} .js file(s) under dist/ outside the declared entry dist/cli/index.js, e.g. ${stray[0]?.path}`,\n );\n return reasons;\n}\n","/**\n * Skill integrity checking\n *\n * Validates that installed skills have intact symlinks, correct canonical paths,\n * and enforces ct-* prefix priority for CAAMP-shipped skills.\n */\n\nimport { existsSync, lstatSync, readlinkSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { resolveSkillsRoot } from '@cleocode/core/skills/skill-root.js';\nimport type { LockEntry, Provider } from '../../types.js';\nimport { readLockFile } from '../lock-utils.js';\nimport { resolveProviderSkillsDirs } from '../paths/standard.js';\n\n/** CAAMP-reserved skill prefix. Skills with this prefix are owned by CAAMP. */\nconst CAAMP_SKILL_PREFIX = 'ct-';\n\n/**\n * Status of a single skill's integrity check.\n *\n * @public\n */\nexport type SkillIntegrityStatus =\n | 'intact'\n | 'broken-symlink'\n | 'missing-canonical'\n | 'missing-link'\n | 'not-tracked'\n | 'tampered';\n\n/**\n * Result of checking a single skill's integrity.\n *\n * @public\n */\nexport interface SkillIntegrityResult {\n /** Skill name. */\n name: string;\n /** Overall integrity status. */\n status: SkillIntegrityStatus;\n /** Whether the canonical directory exists. */\n canonicalExists: boolean;\n /** Expected canonical path from lock file. */\n canonicalPath: string | null;\n /** Provider link statuses — which agents have valid symlinks. */\n linkStatuses: Array<{\n providerId: string;\n linkPath: string;\n exists: boolean;\n isSymlink: boolean;\n pointsToCanonical: boolean;\n }>;\n /** Whether this is a CAAMP-reserved (ct-*) skill. */\n isCaampOwned: boolean;\n /** Human-readable issue description, if any. */\n issue?: string;\n}\n\n/**\n * Check whether a skill name is reserved by CAAMP (ct-* prefix).\n *\n * @remarks\n * Skills with the `ct-` prefix are considered CAAMP-owned and receive\n * special treatment during installation conflict resolution.\n *\n * @param skillName - Skill name to check\n * @returns `true` if the skill name starts with `ct-`\n *\n * @example\n * ```typescript\n * isCaampOwnedSkill(\"ct-research-agent\"); // true\n * isCaampOwnedSkill(\"my-custom-skill\"); // false\n * ```\n *\n * @public\n */\nexport function isCaampOwnedSkill(skillName: string): boolean {\n return skillName.startsWith(CAAMP_SKILL_PREFIX);\n}\n\n/**\n * Check the integrity of a single installed skill.\n *\n * @remarks\n * Validates that the canonical directory exists on disk, the lock file entry\n * matches the actual state, and symlinks from provider skill directories\n * point to the canonical path.\n *\n * @param skillName - Name of the skill to check\n * @param providers - Providers to check symlinks for\n * @param scope - Whether to check global or project links\n * @param projectDir - Project directory (for project scope)\n * @returns Integrity check result\n *\n * @example\n * ```typescript\n * const result = await checkSkillIntegrity(\"ct-research-agent\", providers, \"global\");\n * if (result.status !== \"intact\") {\n * console.log(`Issue: ${result.issue}`);\n * }\n * ```\n *\n * @public\n */\nexport async function checkSkillIntegrity(\n skillName: string,\n providers: Provider[],\n scope: 'global' | 'project' = 'global',\n projectDir?: string,\n): Promise<SkillIntegrityResult> {\n const lock = await readLockFile();\n const entry = lock.skills[skillName];\n const isCaampOwned = isCaampOwnedSkill(skillName);\n\n // Not tracked in lock file\n if (!entry) {\n const canonicalPath = join(resolveSkillsRoot(), skillName);\n return {\n name: skillName,\n status: 'not-tracked',\n canonicalExists: existsSync(canonicalPath),\n canonicalPath: null,\n linkStatuses: [],\n isCaampOwned,\n issue: 'Skill is not tracked in the CAAMP lock file',\n };\n }\n\n const canonicalPath = entry.canonicalPath;\n const canonicalExists = existsSync(canonicalPath);\n\n // Check symlinks for each provider\n const linkStatuses: SkillIntegrityResult['linkStatuses'] = [];\n\n for (const provider of providers) {\n const targetDirs = resolveProviderSkillsDirs(provider, scope, projectDir);\n for (const skillsDir of targetDirs) {\n if (!skillsDir) continue;\n\n const linkPath = join(skillsDir, skillName);\n const exists = existsSync(linkPath);\n let isSymlink = false;\n let pointsToCanonical = false;\n\n if (exists) {\n try {\n const stat = lstatSync(linkPath);\n isSymlink = stat.isSymbolicLink();\n if (isSymlink) {\n const target = resolve(readlinkSync(linkPath));\n pointsToCanonical = target === resolve(canonicalPath);\n }\n } catch {\n // Can't stat — treat as broken\n }\n }\n\n linkStatuses.push({\n providerId: provider.id,\n linkPath,\n exists,\n isSymlink,\n pointsToCanonical,\n });\n }\n }\n\n // Determine overall status\n if (!canonicalExists) {\n return {\n name: skillName,\n status: 'missing-canonical',\n canonicalExists,\n canonicalPath,\n linkStatuses,\n isCaampOwned,\n issue: `Canonical directory missing: ${canonicalPath}`,\n };\n }\n\n const brokenLinks = linkStatuses.filter((l) => !l.exists);\n const tamperedLinks = linkStatuses.filter((l) => l.exists && !l.pointsToCanonical);\n\n if (tamperedLinks.length > 0) {\n return {\n name: skillName,\n status: 'tampered',\n canonicalExists,\n canonicalPath,\n linkStatuses,\n isCaampOwned,\n issue: `${tamperedLinks.length} link(s) do not point to canonical path`,\n };\n }\n\n if (brokenLinks.length > 0) {\n return {\n name: skillName,\n status: 'broken-symlink',\n canonicalExists,\n canonicalPath,\n linkStatuses,\n isCaampOwned,\n issue: `${brokenLinks.length} symlink(s) missing`,\n };\n }\n\n return {\n name: skillName,\n status: 'intact',\n canonicalExists,\n canonicalPath,\n linkStatuses,\n isCaampOwned,\n };\n}\n\n/**\n * Check integrity of all tracked skills.\n *\n * @remarks\n * Iterates over every skill in the lock file and runs\n * {@link checkSkillIntegrity} on each.\n *\n * @param providers - Providers to check symlinks for\n * @param scope - Whether to check global or project links\n * @param projectDir - Project directory (for project scope)\n * @returns Map of skill name to integrity result\n *\n * @example\n * ```typescript\n * const results = await checkAllSkillIntegrity(providers);\n * for (const [name, result] of results) {\n * console.log(`${name}: ${result.status}`);\n * }\n * ```\n *\n * @public\n */\nexport async function checkAllSkillIntegrity(\n providers: Provider[],\n scope: 'global' | 'project' = 'global',\n projectDir?: string,\n): Promise<Map<string, SkillIntegrityResult>> {\n const lock = await readLockFile();\n const results = new Map<string, SkillIntegrityResult>();\n\n for (const skillName of Object.keys(lock.skills)) {\n const result = await checkSkillIntegrity(skillName, providers, scope, projectDir);\n results.set(skillName, result);\n }\n\n return results;\n}\n\n/**\n * Resolve a skill name conflict where a user-installed skill collides\n * with a CAAMP-owned (ct-*) skill.\n *\n * @remarks\n * CAAMP-owned skills always win. Returns `true` if the incoming skill\n * should take precedence over the existing installation.\n *\n * @param skillName - Skill name to check\n * @param incomingSource - Source of the incoming skill installation\n * @param existingEntry - Existing lock entry, if any\n * @returns `true` if the incoming installation should proceed\n *\n * @example\n * ```typescript\n * const proceed = shouldOverrideSkill(\"ct-research-agent\", \"library\", existingEntry);\n * if (proceed) {\n * // Safe to install/override\n * }\n * ```\n *\n * @public\n */\nexport function shouldOverrideSkill(\n skillName: string,\n incomingSource: string,\n existingEntry: LockEntry | undefined,\n): boolean {\n // No existing entry — always allow\n if (!existingEntry) return true;\n\n // For ct-* skills, CAAMP package source always wins\n if (isCaampOwnedSkill(skillName)) {\n // If incoming is from CAAMP package (library source), it always wins\n if (existingEntry.sourceType === 'library') return true;\n // If existing is from CAAMP but incoming is user, CAAMP wins (block user)\n return true;\n }\n\n // Non-ct-* skills: user always wins\n return true;\n}\n\n/**\n * Validate instruction file injection status across all providers.\n *\n * @remarks\n * Checks that CAAMP blocks exist and are current in all relevant\n * instruction files (CLAUDE.md, AGENTS.md, GEMINI.md).\n *\n * @param providers - Providers to check\n * @param projectDir - Project directory\n * @param scope - Whether to check global or project files\n * @param expectedContent - Expected CAAMP block content\n * @returns Array of file paths with issues\n *\n * @example\n * ```typescript\n * const issues = await validateInstructionIntegrity(providers, process.cwd(), \"project\");\n * for (const issue of issues) {\n * console.log(`${issue.providerId}: ${issue.issue} (${issue.file})`);\n * }\n * ```\n *\n * @public\n */\nexport async function validateInstructionIntegrity(\n providers: Provider[],\n projectDir: string,\n scope: 'project' | 'global',\n expectedContent?: string,\n): Promise<Array<{ file: string; providerId: string; issue: string }>> {\n const { checkAllInjections } = await import('../instructions/injector.js');\n const results = await checkAllInjections(providers, projectDir, scope, expectedContent);\n const issues: Array<{ file: string; providerId: string; issue: string }> = [];\n\n for (const result of results) {\n if (result.status === 'missing') {\n issues.push({\n file: result.file,\n providerId: result.provider,\n issue: 'Instruction file does not exist',\n });\n } else if (result.status === 'none') {\n issues.push({\n file: result.file,\n providerId: result.provider,\n issue: 'No CAAMP injection block found',\n });\n } else if (result.status === 'outdated') {\n issues.push({\n file: result.file,\n providerId: result.provider,\n issue: 'CAAMP injection block is outdated',\n });\n }\n }\n\n return issues;\n}\n"],"mappings":"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","names":["canonicalPath","checkAllInjections"]}
|
|
1
|
+
{"version":3,"sources":["../src/core/artifacts/validation.ts","../src/core/skills/integrity.ts"],"sourcesContent":["/**\n * Pure semantic validation of npm-produced package inventories.\n *\n * Code placed in `packages/caamp/` per Package-Boundary Check — verified\n * against AGENTS.md. No filesystem, process, model, or runtime-store access.\n */\n\nimport { posix } from 'node:path';\nimport type {\n PackageArtifactBudgets,\n PackageArtifactFile,\n PackageArtifactInventory,\n PackageArtifactIssue,\n PackageArtifactPolicy,\n PackageArtifactRequirement,\n PackageArtifactValidation,\n PackageFilesEntry,\n} from '@cleocode/contracts/package-artifact';\n\n/** Existing CLI upper budgets: 20 MiB packed, 36 MiB unpacked, and 800 files. */\nexport const CLEO_ARTIFACT_BUDGETS: Readonly<PackageArtifactBudgets> = Object.freeze({\n packedBytes: 20 * 1024 * 1024,\n unpackedBytes: 36 * 1024 * 1024,\n fileCount: 800,\n});\n\n/** Required CLI and adapter-node resources, independent of historical byte/file-count floors. */\nexport const CLEO_ARTIFACT_REQUIREMENTS: readonly PackageArtifactRequirement[] = Object.freeze([\n { id: 'cli-entry', path: 'dist/cli/index.js', match: 'exact' },\n { id: 'studio-server-entry', path: 'studio-dist/index.js', match: 'exact' },\n { id: 'studio-handler', path: 'studio-dist/handler.js', match: 'exact' },\n { id: 'studio-server', path: 'studio-dist/server/index.js', match: 'exact' },\n { id: 'studio-manifest', path: 'studio-dist/server/manifest.js', match: 'exact' },\n {\n id: 'studio-client-start',\n path: 'studio-dist/client/_app/immutable/entry/start.*.js',\n match: 'glob',\n },\n {\n id: 'studio-client-app',\n path: 'studio-dist/client/_app/immutable/entry/app.*.js',\n match: 'glob',\n },\n]);\n\nconst SHA256 = /^[a-f0-9]{64}$/;\nconst GLOB = /[*?{}[\\]]|[+@!]\\(/;\n\nfunction pathProblem(path: string): string | null {\n if (!path || path.trim() !== path) return 'Path is empty or has surrounding whitespace.';\n if (path.includes('\\\\') || /[\\x00-\\x1f\\x7f]/.test(path))\n return 'Path is not a portable POSIX package path.';\n if (posix.isAbsolute(path) || /^[A-Za-z]:/.test(path))\n return 'Path must be relative to the package.';\n if (path.split('/').some((part) => !part || part === '.' || part === '..')) {\n return 'Path must not contain empty, current-directory, or parent-directory segments.';\n }\n return null;\n}\n\n/**\n * Classify a manifest files entry without evaluating exclusions as disk paths.\n *\n * @param entry - Original npm manifest entry.\n * @returns Classification only; actual selected content must come from the packer.\n * @example\n * ```ts\n * classifyPackageFilesEntry('!dist/index.js.map').kind; // 'exclusion'\n * ```\n */\nexport function classifyPackageFilesEntry(entry: string): PackageFilesEntry {\n const exclusion = entry.startsWith('!');\n const pattern = (exclusion ? entry.slice(1) : entry).replace(/^\\.\\//, '').replace(/\\/$/, '');\n const reason = pattern.startsWith('!')\n ? 'Repeated exclusion markers are not assessed.'\n : pathProblem(pattern);\n return {\n entry,\n pattern,\n kind: reason ? 'invalid' : exclusion ? 'exclusion' : GLOB.test(pattern) ? 'glob' : 'literal',\n reason,\n };\n}\n\nfunction fileProblems(file: PackageArtifactFile): string[] {\n const problems: string[] = [];\n const pathError = pathProblem(file.path);\n if (pathError) problems.push(pathError);\n if (!Number.isSafeInteger(file.size) || file.size < 0)\n problems.push('File size must be a nonnegative safe integer.');\n if (file.sha256 !== undefined && !SHA256.test(file.sha256))\n problems.push('File SHA-256 must be 64 lowercase hexadecimal characters.');\n return problems;\n}\n\n/**\n * Validate nonempty semantic resources, inventory identity, expected hashes and upper budgets.\n *\n * @param inventory - Packer-produced evidence or an explicitly identified fixture.\n * @param policy - Independently specified resources, expected files and cost ceilings.\n * @returns A copied evidence receipt; valid means only the supplied checks passed.\n * @example\n * ```ts\n * const result = validatePackageArtifact(inventory, {\n * requirements: CLEO_ARTIFACT_REQUIREMENTS,\n * budgets: CLEO_ARTIFACT_BUDGETS,\n * });\n * // result.runtime remains 'not-assessed', even when result.valid is true.\n * ```\n */\nexport function validatePackageArtifact(\n inventory: PackageArtifactInventory,\n policy: PackageArtifactPolicy,\n): PackageArtifactValidation {\n const issues: PackageArtifactIssue[] = [];\n const add = (code: PackageArtifactIssue['code'], subject: string, message: string): void => {\n issues.push({ code, subject, message });\n };\n if (!inventory.packageName.trim() || !inventory.version.trim()) {\n add('invalid-inventory', 'identity', 'Package name and version must be recorded.');\n }\n if (!['npm-pack', 'npm-pack-dry-run', 'fixture'].includes(inventory.source)) {\n add('invalid-inventory', 'source', 'Inventory provenance is not recognized.');\n }\n if (!Number.isSafeInteger(inventory.packedBytes) || inventory.packedBytes < 0) {\n add('invalid-inventory', 'packedBytes', 'Packed bytes must be a nonnegative safe integer.');\n }\n if (inventory.tarballSha256 !== undefined && !SHA256.test(inventory.tarballSha256)) {\n add(\n 'invalid-inventory',\n 'tarballSha256',\n 'Tarball SHA-256 must be 64 lowercase hexadecimal characters.',\n );\n }\n if (inventory.source === 'npm-pack-dry-run' && inventory.tarballSha256 !== undefined) {\n add(\n 'invalid-inventory',\n 'tarballSha256',\n 'A dry run cannot establish a retained tarball hash.',\n );\n }\n const files = new Map<string, PackageArtifactFile>();\n let unpackedBytes: number | null = 0;\n for (const file of inventory.files) {\n for (const problem of fileProblems(file)) add('invalid-inventory', file.path, problem);\n if (files.has(file.path)) add('invalid-inventory', file.path, 'Duplicate inventory path.');\n files.set(file.path, file);\n if (unpackedBytes !== null) {\n const total: number = unpackedBytes + file.size;\n unpackedBytes = Number.isSafeInteger(total) && file.size >= 0 ? total : null;\n }\n }\n if (unpackedBytes === null)\n add('invalid-inventory', 'unpackedBytes', 'File bytes cannot be safely totaled.');\n const entries = (policy.filesEntries ?? []).map(classifyPackageFilesEntry);\n for (const entry of entries) {\n if (entry.reason) add('invalid-policy', entry.entry, entry.reason);\n }\n if (!policy.requirements.length)\n add('invalid-policy', 'requirements', 'At least one semantic content requirement is required.');\n const ids = new Set<string>();\n const requirements = policy.requirements.map((requirement) => {\n const invalid = pathProblem(requirement.path);\n const duplicate = ids.has(requirement.id);\n ids.add(requirement.id);\n if (\n !requirement.id.trim() ||\n duplicate ||\n invalid ||\n !['exact', 'glob'].includes(requirement.match)\n ) {\n add(\n 'invalid-policy',\n requirement.id,\n invalid ?? 'Requirement identity or match mode is invalid or duplicated.',\n );\n return { id: requirement.id, matchedPaths: [], satisfied: false };\n }\n const matches = inventory.files.filter((file) =>\n requirement.match === 'exact'\n ? file.path === requirement.path\n : posix.matchesGlob(file.path, requirement.path),\n );\n if (!matches.length)\n add(\n 'missing',\n requirement.id,\n `Required resource ${requirement.path} is absent from the selected inventory.`,\n );\n for (const file of matches) {\n if (file.size === 0) add('empty', file.path, `Required resource ${requirement.id} is empty.`);\n }\n return {\n id: requirement.id,\n matchedPaths: matches.map((file) => file.path),\n satisfied: matches.length > 0 && matches.every((file) => file.size > 0),\n };\n });\n for (const pattern of policy.forbiddenPatterns ?? []) {\n const invalid = pathProblem(pattern);\n if (invalid) {\n add('invalid-policy', pattern, invalid);\n continue;\n }\n for (const file of inventory.files) {\n if (posix.matchesGlob(file.path, pattern))\n add('forbidden', file.path, `Selected file matches forbidden pattern ${pattern}.`);\n }\n }\n let hashComparison: PackageArtifactValidation['hashComparison'] = 'not-requested';\n for (const expected of policy.expectedFiles ?? []) {\n const problems = fileProblems(expected);\n for (const problem of problems) add('invalid-policy', expected.path, problem);\n const actual = files.get(expected.path);\n if (!actual) add('missing', expected.path, 'An independently expected file is missing.');\n else if (actual.size !== expected.size)\n add('mismatch', expected.path, 'File bytes differ from independently expected inventory.');\n if (expected.sha256 !== undefined) {\n if (hashComparison !== 'failed') hashComparison = 'matched';\n if (problems.length || actual?.sha256 !== expected.sha256) {\n hashComparison = 'failed';\n add(\n 'mismatch',\n expected.path,\n 'Actual hash is missing or differs from the independently expected SHA-256.',\n );\n }\n }\n }\n for (const [field, limit] of Object.entries(policy.budgets)) {\n if (!Number.isSafeInteger(limit) || limit < 0)\n add('invalid-policy', field, 'Budget must be a nonnegative safe integer.');\n }\n if (inventory.packedBytes > policy.budgets.packedBytes)\n add('budget', 'packedBytes', 'Packed bytes exceed the configured upper budget.');\n if (unpackedBytes !== null && unpackedBytes > policy.budgets.unpackedBytes)\n add('budget', 'unpackedBytes', 'Unpacked bytes exceed the configured upper budget.');\n if (inventory.files.length > policy.budgets.fileCount)\n add('budget', 'fileCount', 'Selected file count exceeds the configured upper budget.');\n return {\n valid: issues.length === 0,\n inventory: { ...inventory, files: inventory.files.map((file) => ({ ...file })) },\n unpackedBytes,\n issues,\n filesEntries: entries,\n requirements,\n hashComparison,\n runtime: 'not-assessed',\n limitations: [\n 'Manifest entries are classified only; the supplied packer inventory is the content authority.',\n 'Hashes are recorded and compared to supplied expected evidence; this validator does not read or authenticate tarball bytes.',\n 'Installability, module/dependency resolution, local-reference closure and native/dynamic runtime behavior are not assessed.',\n ],\n };\n}\n\n/**\n * Reject declaration and stray JavaScript output absent from the published CLI bundle.\n *\n * @param files - Actual selected package files, not a development directory listing.\n * @returns Concrete build-shape failures; this does not load the bundle.\n * @example\n * ```ts\n * assertCleoShippedBuildShape([{ path: 'dist/cli/index.js', size: 1 }]); // []\n * ```\n */\nexport function assertCleoShippedBuildShape(files: readonly PackageArtifactFile[]): string[] {\n const reasons: string[] = [];\n const dist = files.filter((file) => file.path.startsWith('dist/'));\n const declarations = dist.filter(\n (file) => file.path.endsWith('.d.ts') || file.path.endsWith('.d.ts.map'),\n );\n if (declarations.length)\n reasons.push(\n `${declarations.length} declaration file(s) under dist/ — the esbuild bundle emits none`,\n );\n const stray = dist.filter(\n (file) => file.path.endsWith('.js') && file.path !== 'dist/cli/index.js',\n );\n if (stray.length)\n reasons.push(\n `${stray.length} .js file(s) under dist/ outside the declared entry dist/cli/index.js, e.g. ${stray[0]?.path}`,\n );\n return reasons;\n}\n","/**\n * Skill integrity checking\n *\n * Validates that installed skills have intact symlinks, correct canonical paths,\n * and enforces ct-* prefix priority for CAAMP-shipped skills.\n */\n\nimport { existsSync, lstatSync, readlinkSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { resolveSkillsRoot } from '@cleocode/core/skills/skill-root.js';\nimport type { LockEntry, Provider } from '../../types.js';\nimport { readLockFile } from '../lock-utils.js';\nimport { resolveProviderSkillsDirs } from '../paths/standard.js';\n\n/** CAAMP-reserved skill prefix. Skills with this prefix are owned by CAAMP. */\nconst CAAMP_SKILL_PREFIX = 'ct-';\n\n/**\n * Status of a single skill's integrity check.\n *\n * @public\n */\nexport type SkillIntegrityStatus =\n | 'intact'\n | 'broken-symlink'\n | 'missing-canonical'\n | 'missing-link'\n | 'not-tracked'\n | 'tampered';\n\n/**\n * Result of checking a single skill's integrity.\n *\n * @public\n */\nexport interface SkillIntegrityResult {\n /** Skill name. */\n name: string;\n /** Overall integrity status. */\n status: SkillIntegrityStatus;\n /** Whether the canonical directory exists. */\n canonicalExists: boolean;\n /** Expected canonical path from lock file. */\n canonicalPath: string | null;\n /** Provider link statuses — which agents have valid symlinks. */\n linkStatuses: Array<{\n providerId: string;\n linkPath: string;\n exists: boolean;\n isSymlink: boolean;\n pointsToCanonical: boolean;\n }>;\n /** Whether this is a CAAMP-reserved (ct-*) skill. */\n isCaampOwned: boolean;\n /** Human-readable issue description, if any. */\n issue?: string;\n}\n\n/**\n * Check whether a skill name is reserved by CAAMP (ct-* prefix).\n *\n * @remarks\n * Skills with the `ct-` prefix are considered CAAMP-owned and receive\n * special treatment during installation conflict resolution.\n *\n * @param skillName - Skill name to check\n * @returns `true` if the skill name starts with `ct-`\n *\n * @example\n * ```typescript\n * isCaampOwnedSkill(\"ct-research-agent\"); // true\n * isCaampOwnedSkill(\"my-custom-skill\"); // false\n * ```\n *\n * @public\n */\nexport function isCaampOwnedSkill(skillName: string): boolean {\n return skillName.startsWith(CAAMP_SKILL_PREFIX);\n}\n\n/**\n * Check the integrity of a single installed skill.\n *\n * @remarks\n * Validates that the canonical directory exists on disk, the lock file entry\n * matches the actual state, and symlinks from provider skill directories\n * point to the canonical path.\n *\n * @param skillName - Name of the skill to check\n * @param providers - Providers to check symlinks for\n * @param scope - Whether to check global or project links\n * @param projectDir - Project directory (for project scope)\n * @returns Integrity check result\n *\n * @example\n * ```typescript\n * const result = await checkSkillIntegrity(\"ct-research-agent\", providers, \"global\");\n * if (result.status !== \"intact\") {\n * console.log(`Issue: ${result.issue}`);\n * }\n * ```\n *\n * @public\n */\nexport async function checkSkillIntegrity(\n skillName: string,\n providers: Provider[],\n scope: 'global' | 'project' = 'global',\n projectDir?: string,\n): Promise<SkillIntegrityResult> {\n const lock = await readLockFile();\n const entry = lock.skills[skillName];\n const isCaampOwned = isCaampOwnedSkill(skillName);\n\n // Not tracked in lock file\n if (!entry) {\n const canonicalPath = join(resolveSkillsRoot(), skillName);\n return {\n name: skillName,\n status: 'not-tracked',\n canonicalExists: existsSync(canonicalPath),\n canonicalPath: null,\n linkStatuses: [],\n isCaampOwned,\n issue: 'Skill is not tracked in the CAAMP lock file',\n };\n }\n\n const canonicalPath = entry.canonicalPath;\n const canonicalExists = existsSync(canonicalPath);\n\n // Check symlinks for each provider\n const linkStatuses: SkillIntegrityResult['linkStatuses'] = [];\n\n for (const provider of providers) {\n const targetDirs = resolveProviderSkillsDirs(provider, scope, projectDir);\n for (const skillsDir of targetDirs) {\n if (!skillsDir) continue;\n\n const linkPath = join(skillsDir, skillName);\n const exists = existsSync(linkPath);\n let isSymlink = false;\n let pointsToCanonical = false;\n\n if (exists) {\n try {\n const stat = lstatSync(linkPath);\n isSymlink = stat.isSymbolicLink();\n if (isSymlink) {\n const target = resolve(readlinkSync(linkPath));\n pointsToCanonical = target === resolve(canonicalPath);\n }\n } catch {\n // Can't stat — treat as broken\n }\n }\n\n linkStatuses.push({\n providerId: provider.id,\n linkPath,\n exists,\n isSymlink,\n pointsToCanonical,\n });\n }\n }\n\n // Determine overall status\n if (!canonicalExists) {\n return {\n name: skillName,\n status: 'missing-canonical',\n canonicalExists,\n canonicalPath,\n linkStatuses,\n isCaampOwned,\n issue: `Canonical directory missing: ${canonicalPath}`,\n };\n }\n\n const brokenLinks = linkStatuses.filter((l) => !l.exists);\n const tamperedLinks = linkStatuses.filter((l) => l.exists && !l.pointsToCanonical);\n\n if (tamperedLinks.length > 0) {\n return {\n name: skillName,\n status: 'tampered',\n canonicalExists,\n canonicalPath,\n linkStatuses,\n isCaampOwned,\n issue: `${tamperedLinks.length} link(s) do not point to canonical path`,\n };\n }\n\n if (brokenLinks.length > 0) {\n return {\n name: skillName,\n status: 'broken-symlink',\n canonicalExists,\n canonicalPath,\n linkStatuses,\n isCaampOwned,\n issue: `${brokenLinks.length} symlink(s) missing`,\n };\n }\n\n return {\n name: skillName,\n status: 'intact',\n canonicalExists,\n canonicalPath,\n linkStatuses,\n isCaampOwned,\n };\n}\n\n/**\n * Check integrity of all tracked skills.\n *\n * @remarks\n * Iterates over every skill in the lock file and runs\n * {@link checkSkillIntegrity} on each.\n *\n * @param providers - Providers to check symlinks for\n * @param scope - Whether to check global or project links\n * @param projectDir - Project directory (for project scope)\n * @returns Map of skill name to integrity result\n *\n * @example\n * ```typescript\n * const results = await checkAllSkillIntegrity(providers);\n * for (const [name, result] of results) {\n * console.log(`${name}: ${result.status}`);\n * }\n * ```\n *\n * @public\n */\nexport async function checkAllSkillIntegrity(\n providers: Provider[],\n scope: 'global' | 'project' = 'global',\n projectDir?: string,\n): Promise<Map<string, SkillIntegrityResult>> {\n const lock = await readLockFile();\n const results = new Map<string, SkillIntegrityResult>();\n\n for (const skillName of Object.keys(lock.skills)) {\n const result = await checkSkillIntegrity(skillName, providers, scope, projectDir);\n results.set(skillName, result);\n }\n\n return results;\n}\n\n/**\n * Resolve a skill name conflict where a user-installed skill collides\n * with a CAAMP-owned (ct-*) skill.\n *\n * @remarks\n * CAAMP-owned skills always win. Returns `true` if the incoming skill\n * should take precedence over the existing installation.\n *\n * @param skillName - Skill name to check\n * @param incomingSource - Source of the incoming skill installation\n * @param existingEntry - Existing lock entry, if any\n * @returns `true` if the incoming installation should proceed\n *\n * @example\n * ```typescript\n * const proceed = shouldOverrideSkill(\"ct-research-agent\", \"library\", existingEntry);\n * if (proceed) {\n * // Safe to install/override\n * }\n * ```\n *\n * @public\n */\nexport function shouldOverrideSkill(\n skillName: string,\n incomingSource: string,\n existingEntry: LockEntry | undefined,\n): boolean {\n // No existing entry — always allow\n if (!existingEntry) return true;\n\n // For ct-* skills, CAAMP package source always wins\n if (isCaampOwnedSkill(skillName)) {\n // If incoming is from CAAMP package (library source), it always wins\n if (existingEntry.sourceType === 'library') return true;\n // If existing is from CAAMP but incoming is user, CAAMP wins (block user)\n return true;\n }\n\n // Non-ct-* skills: user always wins\n return true;\n}\n\n/**\n * Validate instruction file injection status across all providers.\n *\n * @remarks\n * Checks that CAAMP blocks exist and are current in all relevant\n * instruction files (CLAUDE.md, AGENTS.md, GEMINI.md).\n *\n * @param providers - Providers to check\n * @param projectDir - Project directory\n * @param scope - Whether to check global or project files\n * @param expectedContent - Expected CAAMP block content\n * @returns Array of file paths with issues\n *\n * @example\n * ```typescript\n * const issues = await validateInstructionIntegrity(providers, process.cwd(), \"project\");\n * for (const issue of issues) {\n * console.log(`${issue.providerId}: ${issue.issue} (${issue.file})`);\n * }\n * ```\n *\n * @public\n */\nexport async function validateInstructionIntegrity(\n providers: Provider[],\n projectDir: string,\n scope: 'project' | 'global',\n expectedContent?: string,\n): Promise<Array<{ file: string; providerId: string; issue: string }>> {\n const { checkAllInjections } = await import('../instructions/injector.js');\n const results = await checkAllInjections(providers, projectDir, scope, expectedContent);\n const issues: Array<{ file: string; providerId: string; issue: string }> = [];\n\n for (const result of results) {\n if (result.status === 'missing') {\n issues.push({\n file: result.file,\n providerId: result.provider,\n issue: 'Instruction file does not exist',\n });\n } else if (result.status === 'none') {\n issues.push({\n file: result.file,\n providerId: result.provider,\n issue: 'No CAAMP injection block found',\n });\n } else if (result.status === 'outdated') {\n issues.push({\n file: result.file,\n providerId: result.provider,\n issue: 'CAAMP injection block is outdated',\n });\n }\n }\n\n return issues;\n}\n"],"mappings":"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","names":["canonicalPath","checkAllInjections"]}
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
repairInstructionFiles,
|
|
16
16
|
resolveGlobalInstructionPath,
|
|
17
17
|
writeAgentFileToAllProviders
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-UIXTFV35.js";
|
|
19
19
|
import "./chunk-HDZYZTR2.js";
|
|
20
20
|
export {
|
|
21
21
|
checkAllInjections,
|
|
@@ -35,4 +35,4 @@ export {
|
|
|
35
35
|
resolveGlobalInstructionPath,
|
|
36
36
|
writeAgentFileToAllProviders
|
|
37
37
|
};
|
|
38
|
-
//# sourceMappingURL=injector-
|
|
38
|
+
//# sourceMappingURL=injector-KSFK5LF2.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cleocode/caamp",
|
|
3
|
-
"version": "2026.9.
|
|
3
|
+
"version": "2026.9.22",
|
|
4
4
|
"description": "Central AI Agent Managed Packages - unified provider registry and package manager for AI coding agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -50,14 +50,14 @@
|
|
|
50
50
|
"jsonc-parser": "^3.3.1",
|
|
51
51
|
"picocolors": "^1.1.1",
|
|
52
52
|
"simple-git": "3.33.0",
|
|
53
|
-
"@cleocode/
|
|
54
|
-
"@cleocode/
|
|
55
|
-
"@cleocode/
|
|
56
|
-
"@cleocode/
|
|
57
|
-
"@cleocode/
|
|
53
|
+
"@cleocode/cant": "2026.9.22",
|
|
54
|
+
"@cleocode/contracts": "2026.9.22",
|
|
55
|
+
"@cleocode/lafs": "2026.9.22",
|
|
56
|
+
"@cleocode/core": "2026.9.22",
|
|
57
|
+
"@cleocode/paths": "2026.9.22"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
|
-
"@cleocode/core": "2026.9.
|
|
60
|
+
"@cleocode/core": "2026.9.22"
|
|
61
61
|
},
|
|
62
62
|
"peerDependenciesMeta": {
|
|
63
63
|
"@cleocode/core": {
|