@cleocode/caamp 2026.9.7 → 2026.9.9
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-6KBUDJZI.js → chunk-52ZWZXEN.js} +2 -2
- package/dist/{chunk-3IQUGSIV.js → chunk-G3CEXEW2.js} +207 -40
- package/dist/chunk-G3CEXEW2.js.map +1 -0
- package/dist/cli.js +5 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +87 -9
- package/dist/index.js +223 -3
- package/dist/index.js.map +1 -1
- package/dist/{injector-6YGSK3B6.js → injector-X5FN7WMR.js} +2 -2
- package/package.json +7 -7
- package/dist/chunk-3IQUGSIV.js.map +0 -1
- /package/dist/{chunk-6KBUDJZI.js.map → chunk-52ZWZXEN.js.map} +0 -0
- /package/dist/{injector-6YGSK3B6.js.map → injector-X5FN7WMR.js.map} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { CaampInjectionAction } from '@cleocode/contracts/caamp-markers';
|
|
1
|
+
import { InstructionDeliveryFinding, CaampInjectionAction, InstructionDelivery } from '@cleocode/contracts/caamp-markers';
|
|
2
|
+
import { PackageArtifactBudgets, PackageArtifactRequirement, PackageArtifactFile, PackageFilesEntry, PackageArtifactInventory, PackageArtifactPolicy, PackageArtifactValidation } from '@cleocode/contracts/package-artifact';
|
|
2
3
|
import { WorktreeHandle } from '@cleocode/cant';
|
|
3
4
|
import { PlatformPaths, SystemInfo } from '@cleocode/paths';
|
|
4
5
|
export { PlatformPaths, SystemInfo } from '@cleocode/paths';
|
|
@@ -1228,6 +1229,10 @@ type InjectionStatus = 'current' | 'outdated' | 'missing' | 'none';
|
|
|
1228
1229
|
* @public
|
|
1229
1230
|
*/
|
|
1230
1231
|
interface InjectionCheckResult {
|
|
1232
|
+
/** Deterministic delivery defects, independently of marker integrity. */
|
|
1233
|
+
deliveryFindings?: InstructionDeliveryFinding[];
|
|
1234
|
+
/** File inspection cannot establish live provider behavior. */
|
|
1235
|
+
liveEvaluation?: 'unverified';
|
|
1231
1236
|
/** Absolute path to the instruction file. */
|
|
1232
1237
|
file: string;
|
|
1233
1238
|
/** Provider ID that owns this instruction file. */
|
|
@@ -1502,6 +1507,56 @@ interface InstructionUpdateSummary {
|
|
|
1502
1507
|
*/
|
|
1503
1508
|
declare function updateInstructionsSingleOperation(providers: Provider[], content: string, scope?: Scope, projectDir?: string): Promise<InstructionUpdateSummary>;
|
|
1504
1509
|
|
|
1510
|
+
/**
|
|
1511
|
+
* Pure semantic validation of npm-produced package inventories.
|
|
1512
|
+
*
|
|
1513
|
+
* Code placed in `packages/caamp/` per Package-Boundary Check — verified
|
|
1514
|
+
* against AGENTS.md. No filesystem, process, model, or runtime-store access.
|
|
1515
|
+
*/
|
|
1516
|
+
|
|
1517
|
+
/** Existing CLI upper budgets: 20 MiB packed, 36 MiB unpacked, and 800 files. */
|
|
1518
|
+
declare const CLEO_ARTIFACT_BUDGETS: Readonly<PackageArtifactBudgets>;
|
|
1519
|
+
/** Required CLI and adapter-node resources, independent of historical byte/file-count floors. */
|
|
1520
|
+
declare const CLEO_ARTIFACT_REQUIREMENTS: readonly PackageArtifactRequirement[];
|
|
1521
|
+
/**
|
|
1522
|
+
* Classify a manifest files entry without evaluating exclusions as disk paths.
|
|
1523
|
+
*
|
|
1524
|
+
* @param entry - Original npm manifest entry.
|
|
1525
|
+
* @returns Classification only; actual selected content must come from the packer.
|
|
1526
|
+
* @example
|
|
1527
|
+
* ```ts
|
|
1528
|
+
* classifyPackageFilesEntry('!dist/index.js.map').kind; // 'exclusion'
|
|
1529
|
+
* ```
|
|
1530
|
+
*/
|
|
1531
|
+
declare function classifyPackageFilesEntry(entry: string): PackageFilesEntry;
|
|
1532
|
+
/**
|
|
1533
|
+
* Validate nonempty semantic resources, inventory identity, expected hashes and upper budgets.
|
|
1534
|
+
*
|
|
1535
|
+
* @param inventory - Packer-produced evidence or an explicitly identified fixture.
|
|
1536
|
+
* @param policy - Independently specified resources, expected files and cost ceilings.
|
|
1537
|
+
* @returns A copied evidence receipt; valid means only the supplied checks passed.
|
|
1538
|
+
* @example
|
|
1539
|
+
* ```ts
|
|
1540
|
+
* const result = validatePackageArtifact(inventory, {
|
|
1541
|
+
* requirements: CLEO_ARTIFACT_REQUIREMENTS,
|
|
1542
|
+
* budgets: CLEO_ARTIFACT_BUDGETS,
|
|
1543
|
+
* });
|
|
1544
|
+
* // result.runtime remains 'not-assessed', even when result.valid is true.
|
|
1545
|
+
* ```
|
|
1546
|
+
*/
|
|
1547
|
+
declare function validatePackageArtifact(inventory: PackageArtifactInventory, policy: PackageArtifactPolicy): PackageArtifactValidation;
|
|
1548
|
+
/**
|
|
1549
|
+
* Reject declaration and stray JavaScript output absent from the published CLI bundle.
|
|
1550
|
+
*
|
|
1551
|
+
* @param files - Actual selected package files, not a development directory listing.
|
|
1552
|
+
* @returns Concrete build-shape failures; this does not load the bundle.
|
|
1553
|
+
* @example
|
|
1554
|
+
* ```ts
|
|
1555
|
+
* assertCleoShippedBuildShape([{ path: 'dist/cli/index.js', size: 1 }]); // []
|
|
1556
|
+
* ```
|
|
1557
|
+
*/
|
|
1558
|
+
declare function assertCleoShippedBuildShape(files: readonly PackageArtifactFile[]): string[];
|
|
1559
|
+
|
|
1505
1560
|
/**
|
|
1506
1561
|
* Three-tier scope helper for Pi harness operations.
|
|
1507
1562
|
*
|
|
@@ -4759,11 +4814,11 @@ interface ReconcileResult {
|
|
|
4759
4814
|
* any others are removed. Replacing in place matters: prepending instead
|
|
4760
4815
|
* would walk the block up the file on every run, and would separate it from
|
|
4761
4816
|
* any heading a user wrote above it.
|
|
4762
|
-
* 4.
|
|
4763
|
-
*
|
|
4764
|
-
*
|
|
4765
|
-
*
|
|
4766
|
-
*
|
|
4817
|
+
* 4. Every byte outside CAAMP blocks is preserved, including indentation,
|
|
4818
|
+
* CRLF, BOM, blank lines and trailing whitespace. Only newly inserted block
|
|
4819
|
+
* separators are added; existing user text is never trimmed or tidied.
|
|
4820
|
+
* 5. Nested or unmatched markers are ambiguous ownership and reject mutation.
|
|
4821
|
+
* No guessed region is removed or expanded to consume user content.
|
|
4767
4822
|
*
|
|
4768
4823
|
* This function is pure — it performs no I/O, which is what makes the
|
|
4769
4824
|
* behaviour straightforward to test exhaustively.
|
|
@@ -4772,6 +4827,7 @@ interface ReconcileResult {
|
|
|
4772
4827
|
* @param desiredContent - Body the single surviving block should carry
|
|
4773
4828
|
* @param insert - Placement when the file has no block yet
|
|
4774
4829
|
* @returns The reconciled content plus what was found on the way
|
|
4830
|
+
* @throws When existing or desired markers have ambiguous ownership.
|
|
4775
4831
|
*
|
|
4776
4832
|
* @example
|
|
4777
4833
|
* ```typescript
|
|
@@ -4820,6 +4876,7 @@ declare function mergeBlockBodies(blocks: readonly CaampBlock[]): string;
|
|
|
4820
4876
|
*
|
|
4821
4877
|
* @param existing - Current file contents
|
|
4822
4878
|
* @returns The repaired content plus what was found on the way
|
|
4879
|
+
* @throws When marker ownership is ambiguous; callers must preserve the original file.
|
|
4823
4880
|
*
|
|
4824
4881
|
* @example
|
|
4825
4882
|
* ```typescript
|
|
@@ -5080,8 +5137,9 @@ declare function inject(filePath: string, content: string): Promise<CaampInjecti
|
|
|
5080
5137
|
* @returns `true` if a CAAMP block was found and removed, `false` otherwise
|
|
5081
5138
|
*
|
|
5082
5139
|
* @remarks
|
|
5083
|
-
*
|
|
5084
|
-
*
|
|
5140
|
+
* Retains every byte outside the marker spans, including whitespace-only
|
|
5141
|
+
* content. Deletes the file only when no outside bytes remain. Ambiguous
|
|
5142
|
+
* marker ownership rejects removal before any file write.
|
|
5085
5143
|
*
|
|
5086
5144
|
* Blocks whose markers are damaged are healed first, so uninstall removes them
|
|
5087
5145
|
* too rather than leaving orphaned fragments behind.
|
|
@@ -5165,6 +5223,8 @@ interface EnsureProviderInstructionFileOptions {
|
|
|
5165
5223
|
content?: string[];
|
|
5166
5224
|
/** Whether this is a global or project-level file. @defaultValue `"project"` */
|
|
5167
5225
|
scope?: 'project' | 'global';
|
|
5226
|
+
/** Embed resolved sources; reference-only delivery requires an explicitly verified provider. */
|
|
5227
|
+
delivery?: 'self-contained' | 'verified-references';
|
|
5168
5228
|
}
|
|
5169
5229
|
/**
|
|
5170
5230
|
* Result of ensuring a provider instruction file.
|
|
@@ -5481,6 +5541,24 @@ declare function generateSkillsSection(skillNames: string[]): string;
|
|
|
5481
5541
|
* @public
|
|
5482
5542
|
*/
|
|
5483
5543
|
declare function groupByInstructFile(providers: Provider[]): Map<string, Provider[]>;
|
|
5544
|
+
/**
|
|
5545
|
+
* Expand instruction references into bounded, self-contained managed content.
|
|
5546
|
+
*
|
|
5547
|
+
* Code placed in `packages/caamp/` per Package-Boundary Check — verified against AGENTS.md.
|
|
5548
|
+
* Missing files and cycles are explicit findings; callers must refuse incomplete writes.
|
|
5549
|
+
* Marker lines are removed from embedded files so nested managed blocks cannot corrupt
|
|
5550
|
+
* the destination. References inside fenced examples are preserved as examples.
|
|
5551
|
+
*
|
|
5552
|
+
* @param content - Managed content containing standalone reference lines.
|
|
5553
|
+
* @param baseDir - Directory against which the first references resolve.
|
|
5554
|
+
* @returns Resolved bootstrap and deterministic delivery diagnostics.
|
|
5555
|
+
* @example
|
|
5556
|
+
* ```typescript
|
|
5557
|
+
* const delivery = await resolveInstructionDelivery('@AGENTS.md', '/project');
|
|
5558
|
+
* ```
|
|
5559
|
+
* @public
|
|
5560
|
+
*/
|
|
5561
|
+
declare function resolveInstructionDelivery(content: string, baseDir: string): Promise<InstructionDelivery>;
|
|
5484
5562
|
|
|
5485
5563
|
/**
|
|
5486
5564
|
* Simple logger with verbose/quiet mode support.
|
|
@@ -8881,4 +8959,4 @@ declare function parseSource(input: string): ParsedSource;
|
|
|
8881
8959
|
*/
|
|
8882
8960
|
declare function isMarketplaceScoped(input: string): boolean;
|
|
8883
8961
|
|
|
8884
|
-
export { type AuditFinding, type AuditResult, type AuditRule, type AuditSeverity, type BatchInstallOptions, type BatchInstallResult, type BlockInsertPosition, CANONICAL_HOOK_EVENTS, 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, type EnsureProviderInstructionFileOptions, type EnsureProviderInstructionFileResult, type ExclusivityMode, type FileLockOptions, 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, 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 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 SkillRowData, type SkillRowSourceType, type SkillsPrecedence, type SourceType, type SpawnAdapter, type SpawnMechanism, type SpawnOptions, type SpawnResult, type SubagentHandle, type SubagentResult, type SubagentTask, type TransportType, type ValidateCantProfileResult, type ValidationIssue, type ValidationResult, type WriteAgentFileOptions, type WriteAgentFileResult, _resetPlatformPathsCache, assertNotTornRead, blockPattern, buildBlock, buildHookMatrix, buildInjectionContent, buildLibraryFromFiles, buildSkillsMap, catalog, checkAllInjections, checkAllSkillIntegrity, checkAllSkillUpdates, checkInjection, checkSkillIntegrity, checkSkillUpdate, clearRegisteredLibrary, dedupeFile, dedupeFiles, deepMerge, detectAllProviders, detectMcpInstallations, detectProjectProviders, detectProvider, discoverSkill, discoverSkills, ensureAllProviderInstructionFiles, ensureDir, ensureProviderInstructionFile, 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, installSkill, instructionFileCascade, isCaampOwnedSkill, 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, resetDetectionCache, resetExclusivityModeOverride, resolveAlias, resolveDefaultTargetProviders, resolveMcpConfigPath, resolveNativeEvent, resolveProviderSkillsDirs, resolveRegistryTemplatePath, scanDirectory, scanFile, scoreSkillRecommendation, searchSkills, selectProvidersByMinimumPriority, setExclusivityMode, setQuiet, setVerbose, shouldOverrideSkill, supportsHook, toCanonical, toNative, toNativeBatch, toSarif, tokenizeCriteriaValue, translateToAll, updateInstructionsSingleOperation, validateInstructionIntegrity, validateRecommendationCriteria, validateSkill, withFileLock, writeAgentFileToAllProviders, writeConfig };
|
|
8962
|
+
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, type EnsureProviderInstructionFileOptions, type EnsureProviderInstructionFileResult, type ExclusivityMode, type FileLockOptions, 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, 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 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 SkillRowData, type SkillRowSourceType, type SkillsPrecedence, type SourceType, type SpawnAdapter, type SpawnMechanism, type SpawnOptions, type SpawnResult, type SubagentHandle, type SubagentResult, type SubagentTask, 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, checkInjection, checkSkillIntegrity, checkSkillUpdate, classifyPackageFilesEntry, clearRegisteredLibrary, dedupeFile, dedupeFiles, deepMerge, detectAllProviders, detectMcpInstallations, detectProjectProviders, detectProvider, discoverSkill, discoverSkills, ensureAllProviderInstructionFiles, ensureDir, ensureProviderInstructionFile, 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, installSkill, instructionFileCascade, isCaampOwnedSkill, 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, resetDetectionCache, resetExclusivityModeOverride, resolveAlias, resolveDefaultTargetProviders, resolveInstructionDelivery, resolveMcpConfigPath, resolveNativeEvent, resolveProviderSkillsDirs, resolveRegistryTemplatePath, scanDirectory, scanFile, scoreSkillRecommendation, searchSkills, selectProvidersByMinimumPriority, setExclusivityMode, setQuiet, setVerbose, shouldOverrideSkill, supportsHook, toCanonical, toNative, toNativeBatch, toSarif, tokenizeCriteriaValue, translateToAll, updateInstructionsSingleOperation, validateInstructionIntegrity, validatePackageArtifact, validateRecommendationCriteria, validateSkill, withFileLock, writeAgentFileToAllProviders, writeConfig };
|
package/dist/index.js
CHANGED
|
@@ -71,7 +71,7 @@ import {
|
|
|
71
71
|
validateRecommendationCriteria,
|
|
72
72
|
validateSkill,
|
|
73
73
|
writeConfig
|
|
74
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-52ZWZXEN.js";
|
|
75
75
|
import {
|
|
76
76
|
assertNotTornRead,
|
|
77
77
|
blockPattern,
|
|
@@ -120,9 +120,10 @@ import {
|
|
|
120
120
|
repairContent,
|
|
121
121
|
repairInstructionFiles,
|
|
122
122
|
resolveAlias,
|
|
123
|
+
resolveInstructionDelivery,
|
|
123
124
|
withFileLock,
|
|
124
125
|
writeAgentFileToAllProviders
|
|
125
|
-
} from "./chunk-
|
|
126
|
+
} from "./chunk-G3CEXEW2.js";
|
|
126
127
|
import {
|
|
127
128
|
CANONICAL_HOOK_EVENTS,
|
|
128
129
|
HOOK_CATEGORIES,
|
|
@@ -168,6 +169,219 @@ import {
|
|
|
168
169
|
resolveRegistryTemplatePath
|
|
169
170
|
} from "./chunk-HDZYZTR2.js";
|
|
170
171
|
|
|
172
|
+
// src/core/artifacts/validation.ts
|
|
173
|
+
import { posix } from "path";
|
|
174
|
+
var CLEO_ARTIFACT_BUDGETS = Object.freeze({
|
|
175
|
+
packedBytes: 20 * 1024 * 1024,
|
|
176
|
+
unpackedBytes: 36 * 1024 * 1024,
|
|
177
|
+
fileCount: 800
|
|
178
|
+
});
|
|
179
|
+
var CLEO_ARTIFACT_REQUIREMENTS = Object.freeze([
|
|
180
|
+
{ id: "cli-entry", path: "dist/cli/index.js", match: "exact" },
|
|
181
|
+
{ id: "studio-server-entry", path: "studio-dist/index.js", match: "exact" },
|
|
182
|
+
{ id: "studio-handler", path: "studio-dist/handler.js", match: "exact" },
|
|
183
|
+
{ id: "studio-server", path: "studio-dist/server/index.js", match: "exact" },
|
|
184
|
+
{ id: "studio-manifest", path: "studio-dist/server/manifest.js", match: "exact" },
|
|
185
|
+
{
|
|
186
|
+
id: "studio-client-start",
|
|
187
|
+
path: "studio-dist/client/_app/immutable/entry/start.*.js",
|
|
188
|
+
match: "glob"
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
id: "studio-client-app",
|
|
192
|
+
path: "studio-dist/client/_app/immutable/entry/app.*.js",
|
|
193
|
+
match: "glob"
|
|
194
|
+
}
|
|
195
|
+
]);
|
|
196
|
+
var SHA256 = /^[a-f0-9]{64}$/;
|
|
197
|
+
var GLOB = /[*?{}[\]]|[+@!]\(/;
|
|
198
|
+
function pathProblem(path) {
|
|
199
|
+
if (!path || path.trim() !== path) return "Path is empty or has surrounding whitespace.";
|
|
200
|
+
if (path.includes("\\") || /[\x00-\x1f\x7f]/.test(path))
|
|
201
|
+
return "Path is not a portable POSIX package path.";
|
|
202
|
+
if (posix.isAbsolute(path) || /^[A-Za-z]:/.test(path))
|
|
203
|
+
return "Path must be relative to the package.";
|
|
204
|
+
if (path.split("/").some((part) => !part || part === "." || part === "..")) {
|
|
205
|
+
return "Path must not contain empty, current-directory, or parent-directory segments.";
|
|
206
|
+
}
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
function classifyPackageFilesEntry(entry) {
|
|
210
|
+
const exclusion = entry.startsWith("!");
|
|
211
|
+
const pattern = (exclusion ? entry.slice(1) : entry).replace(/^\.\//, "").replace(/\/$/, "");
|
|
212
|
+
const reason = pattern.startsWith("!") ? "Repeated exclusion markers are not assessed." : pathProblem(pattern);
|
|
213
|
+
return {
|
|
214
|
+
entry,
|
|
215
|
+
pattern,
|
|
216
|
+
kind: reason ? "invalid" : exclusion ? "exclusion" : GLOB.test(pattern) ? "glob" : "literal",
|
|
217
|
+
reason
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
function fileProblems(file) {
|
|
221
|
+
const problems = [];
|
|
222
|
+
const pathError = pathProblem(file.path);
|
|
223
|
+
if (pathError) problems.push(pathError);
|
|
224
|
+
if (!Number.isSafeInteger(file.size) || file.size < 0)
|
|
225
|
+
problems.push("File size must be a nonnegative safe integer.");
|
|
226
|
+
if (file.sha256 !== void 0 && !SHA256.test(file.sha256))
|
|
227
|
+
problems.push("File SHA-256 must be 64 lowercase hexadecimal characters.");
|
|
228
|
+
return problems;
|
|
229
|
+
}
|
|
230
|
+
function validatePackageArtifact(inventory, policy) {
|
|
231
|
+
const issues = [];
|
|
232
|
+
const add = (code, subject, message) => {
|
|
233
|
+
issues.push({ code, subject, message });
|
|
234
|
+
};
|
|
235
|
+
if (!inventory.packageName.trim() || !inventory.version.trim()) {
|
|
236
|
+
add("invalid-inventory", "identity", "Package name and version must be recorded.");
|
|
237
|
+
}
|
|
238
|
+
if (!["npm-pack", "npm-pack-dry-run", "fixture"].includes(inventory.source)) {
|
|
239
|
+
add("invalid-inventory", "source", "Inventory provenance is not recognized.");
|
|
240
|
+
}
|
|
241
|
+
if (!Number.isSafeInteger(inventory.packedBytes) || inventory.packedBytes < 0) {
|
|
242
|
+
add("invalid-inventory", "packedBytes", "Packed bytes must be a nonnegative safe integer.");
|
|
243
|
+
}
|
|
244
|
+
if (inventory.tarballSha256 !== void 0 && !SHA256.test(inventory.tarballSha256)) {
|
|
245
|
+
add(
|
|
246
|
+
"invalid-inventory",
|
|
247
|
+
"tarballSha256",
|
|
248
|
+
"Tarball SHA-256 must be 64 lowercase hexadecimal characters."
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
if (inventory.source === "npm-pack-dry-run" && inventory.tarballSha256 !== void 0) {
|
|
252
|
+
add(
|
|
253
|
+
"invalid-inventory",
|
|
254
|
+
"tarballSha256",
|
|
255
|
+
"A dry run cannot establish a retained tarball hash."
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
const files = /* @__PURE__ */ new Map();
|
|
259
|
+
let unpackedBytes = 0;
|
|
260
|
+
for (const file of inventory.files) {
|
|
261
|
+
for (const problem of fileProblems(file)) add("invalid-inventory", file.path, problem);
|
|
262
|
+
if (files.has(file.path)) add("invalid-inventory", file.path, "Duplicate inventory path.");
|
|
263
|
+
files.set(file.path, file);
|
|
264
|
+
if (unpackedBytes !== null) {
|
|
265
|
+
const total = unpackedBytes + file.size;
|
|
266
|
+
unpackedBytes = Number.isSafeInteger(total) && file.size >= 0 ? total : null;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (unpackedBytes === null)
|
|
270
|
+
add("invalid-inventory", "unpackedBytes", "File bytes cannot be safely totaled.");
|
|
271
|
+
const entries = (policy.filesEntries ?? []).map(classifyPackageFilesEntry);
|
|
272
|
+
for (const entry of entries) {
|
|
273
|
+
if (entry.reason) add("invalid-policy", entry.entry, entry.reason);
|
|
274
|
+
}
|
|
275
|
+
if (!policy.requirements.length)
|
|
276
|
+
add("invalid-policy", "requirements", "At least one semantic content requirement is required.");
|
|
277
|
+
const ids = /* @__PURE__ */ new Set();
|
|
278
|
+
const requirements = policy.requirements.map((requirement) => {
|
|
279
|
+
const invalid = pathProblem(requirement.path);
|
|
280
|
+
const duplicate = ids.has(requirement.id);
|
|
281
|
+
ids.add(requirement.id);
|
|
282
|
+
if (!requirement.id.trim() || duplicate || invalid || !["exact", "glob"].includes(requirement.match)) {
|
|
283
|
+
add(
|
|
284
|
+
"invalid-policy",
|
|
285
|
+
requirement.id,
|
|
286
|
+
invalid ?? "Requirement identity or match mode is invalid or duplicated."
|
|
287
|
+
);
|
|
288
|
+
return { id: requirement.id, matchedPaths: [], satisfied: false };
|
|
289
|
+
}
|
|
290
|
+
const matches = inventory.files.filter(
|
|
291
|
+
(file) => requirement.match === "exact" ? file.path === requirement.path : posix.matchesGlob(file.path, requirement.path)
|
|
292
|
+
);
|
|
293
|
+
if (!matches.length)
|
|
294
|
+
add(
|
|
295
|
+
"missing",
|
|
296
|
+
requirement.id,
|
|
297
|
+
`Required resource ${requirement.path} is absent from the selected inventory.`
|
|
298
|
+
);
|
|
299
|
+
for (const file of matches) {
|
|
300
|
+
if (file.size === 0) add("empty", file.path, `Required resource ${requirement.id} is empty.`);
|
|
301
|
+
}
|
|
302
|
+
return {
|
|
303
|
+
id: requirement.id,
|
|
304
|
+
matchedPaths: matches.map((file) => file.path),
|
|
305
|
+
satisfied: matches.length > 0 && matches.every((file) => file.size > 0)
|
|
306
|
+
};
|
|
307
|
+
});
|
|
308
|
+
for (const pattern of policy.forbiddenPatterns ?? []) {
|
|
309
|
+
const invalid = pathProblem(pattern);
|
|
310
|
+
if (invalid) {
|
|
311
|
+
add("invalid-policy", pattern, invalid);
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
for (const file of inventory.files) {
|
|
315
|
+
if (posix.matchesGlob(file.path, pattern))
|
|
316
|
+
add("forbidden", file.path, `Selected file matches forbidden pattern ${pattern}.`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
let hashComparison = "not-requested";
|
|
320
|
+
for (const expected of policy.expectedFiles ?? []) {
|
|
321
|
+
const problems = fileProblems(expected);
|
|
322
|
+
for (const problem of problems) add("invalid-policy", expected.path, problem);
|
|
323
|
+
const actual = files.get(expected.path);
|
|
324
|
+
if (!actual) add("missing", expected.path, "An independently expected file is missing.");
|
|
325
|
+
else if (actual.size !== expected.size)
|
|
326
|
+
add("mismatch", expected.path, "File bytes differ from independently expected inventory.");
|
|
327
|
+
if (expected.sha256 !== void 0) {
|
|
328
|
+
if (hashComparison !== "failed") hashComparison = "matched";
|
|
329
|
+
if (problems.length || actual?.sha256 !== expected.sha256) {
|
|
330
|
+
hashComparison = "failed";
|
|
331
|
+
add(
|
|
332
|
+
"mismatch",
|
|
333
|
+
expected.path,
|
|
334
|
+
"Actual hash is missing or differs from the independently expected SHA-256."
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
for (const [field, limit] of Object.entries(policy.budgets)) {
|
|
340
|
+
if (!Number.isSafeInteger(limit) || limit < 0)
|
|
341
|
+
add("invalid-policy", field, "Budget must be a nonnegative safe integer.");
|
|
342
|
+
}
|
|
343
|
+
if (inventory.packedBytes > policy.budgets.packedBytes)
|
|
344
|
+
add("budget", "packedBytes", "Packed bytes exceed the configured upper budget.");
|
|
345
|
+
if (unpackedBytes !== null && unpackedBytes > policy.budgets.unpackedBytes)
|
|
346
|
+
add("budget", "unpackedBytes", "Unpacked bytes exceed the configured upper budget.");
|
|
347
|
+
if (inventory.files.length > policy.budgets.fileCount)
|
|
348
|
+
add("budget", "fileCount", "Selected file count exceeds the configured upper budget.");
|
|
349
|
+
return {
|
|
350
|
+
valid: issues.length === 0,
|
|
351
|
+
inventory: { ...inventory, files: inventory.files.map((file) => ({ ...file })) },
|
|
352
|
+
unpackedBytes,
|
|
353
|
+
issues,
|
|
354
|
+
filesEntries: entries,
|
|
355
|
+
requirements,
|
|
356
|
+
hashComparison,
|
|
357
|
+
runtime: "not-assessed",
|
|
358
|
+
limitations: [
|
|
359
|
+
"Manifest entries are classified only; the supplied packer inventory is the content authority.",
|
|
360
|
+
"Hashes are recorded and compared to supplied expected evidence; this validator does not read or authenticate tarball bytes.",
|
|
361
|
+
"Installability, module/dependency resolution, local-reference closure and native/dynamic runtime behavior are not assessed."
|
|
362
|
+
]
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
function assertCleoShippedBuildShape(files) {
|
|
366
|
+
const reasons = [];
|
|
367
|
+
const dist = files.filter((file) => file.path.startsWith("dist/"));
|
|
368
|
+
const declarations = dist.filter(
|
|
369
|
+
(file) => file.path.endsWith(".d.ts") || file.path.endsWith(".d.ts.map")
|
|
370
|
+
);
|
|
371
|
+
if (declarations.length)
|
|
372
|
+
reasons.push(
|
|
373
|
+
`${declarations.length} declaration file(s) under dist/ \u2014 the esbuild bundle emits none`
|
|
374
|
+
);
|
|
375
|
+
const stray = dist.filter(
|
|
376
|
+
(file) => file.path.endsWith(".js") && file.path !== "dist/cli/index.js"
|
|
377
|
+
);
|
|
378
|
+
if (stray.length)
|
|
379
|
+
reasons.push(
|
|
380
|
+
`${stray.length} .js file(s) under dist/ outside the declared entry dist/cli/index.js, e.g. ${stray[0]?.path}`
|
|
381
|
+
);
|
|
382
|
+
return reasons;
|
|
383
|
+
}
|
|
384
|
+
|
|
171
385
|
// src/core/skills/integrity.ts
|
|
172
386
|
import { existsSync, lstatSync, readlinkSync } from "fs";
|
|
173
387
|
import { join, resolve } from "path";
|
|
@@ -285,7 +499,7 @@ function shouldOverrideSkill(skillName, incomingSource, existingEntry) {
|
|
|
285
499
|
return true;
|
|
286
500
|
}
|
|
287
501
|
async function validateInstructionIntegrity(providers, projectDir, scope, expectedContent) {
|
|
288
|
-
const { checkAllInjections: checkAllInjections2 } = await import("./injector-
|
|
502
|
+
const { checkAllInjections: checkAllInjections2 } = await import("./injector-X5FN7WMR.js");
|
|
289
503
|
const results = await checkAllInjections2(providers, projectDir, scope, expectedContent);
|
|
290
504
|
const issues = [];
|
|
291
505
|
for (const result of results) {
|
|
@@ -313,6 +527,8 @@ async function validateInstructionIntegrity(providers, projectDir, scope, expect
|
|
|
313
527
|
}
|
|
314
528
|
export {
|
|
315
529
|
CANONICAL_HOOK_EVENTS,
|
|
530
|
+
CLEO_ARTIFACT_BUDGETS,
|
|
531
|
+
CLEO_ARTIFACT_REQUIREMENTS,
|
|
316
532
|
DEFAULT_EXCLUSIVITY_MODE,
|
|
317
533
|
EXCLUSIVITY_MODE_ENV_VAR,
|
|
318
534
|
HOOK_CATEGORIES,
|
|
@@ -321,6 +537,7 @@ export {
|
|
|
321
537
|
PiRequiredError,
|
|
322
538
|
RECOMMENDATION_ERROR_CODES,
|
|
323
539
|
_resetPlatformPathsCache,
|
|
540
|
+
assertCleoShippedBuildShape,
|
|
324
541
|
assertNotTornRead,
|
|
325
542
|
blockPattern,
|
|
326
543
|
buildBlock,
|
|
@@ -335,6 +552,7 @@ export {
|
|
|
335
552
|
checkInjection,
|
|
336
553
|
checkSkillIntegrity,
|
|
337
554
|
checkSkillUpdate,
|
|
555
|
+
classifyPackageFilesEntry,
|
|
338
556
|
clearRegisteredLibrary,
|
|
339
557
|
dedupeFile,
|
|
340
558
|
dedupeFiles,
|
|
@@ -450,6 +668,7 @@ export {
|
|
|
450
668
|
resetExclusivityModeOverride,
|
|
451
669
|
resolveAlias,
|
|
452
670
|
resolveDefaultTargetProviders,
|
|
671
|
+
resolveInstructionDelivery,
|
|
453
672
|
resolveMcpConfigPath,
|
|
454
673
|
resolveNativeEvent,
|
|
455
674
|
resolveProviderSkillsDirs,
|
|
@@ -472,6 +691,7 @@ export {
|
|
|
472
691
|
translateToAll,
|
|
473
692
|
updateInstructionsSingleOperation,
|
|
474
693
|
validateInstructionIntegrity,
|
|
694
|
+
validatePackageArtifact,
|
|
475
695
|
validateRecommendationCriteria,
|
|
476
696
|
validateSkill,
|
|
477
697
|
withFileLock,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/skills/integrity.ts"],"sourcesContent":["/**\n * Skill integrity checking\n *\n * Validates that installed skills have intact symlinks, correct canonical paths,\n * and enforces ct-* prefix priority for CAAMP-shipped skills.\n */\n\nimport { existsSync, lstatSync, readlinkSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { resolveSkillsRoot } from '@cleocode/core/skills/skill-root.js';\nimport type { LockEntry, Provider } from '../../types.js';\nimport { readLockFile } from '../lock-utils.js';\nimport { resolveProviderSkillsDirs } from '../paths/standard.js';\n\n/** CAAMP-reserved skill prefix. Skills with this prefix are owned by CAAMP. */\nconst CAAMP_SKILL_PREFIX = 'ct-';\n\n/**\n * Status of a single skill's integrity check.\n *\n * @public\n */\nexport type SkillIntegrityStatus =\n | 'intact'\n | 'broken-symlink'\n | 'missing-canonical'\n | 'missing-link'\n | 'not-tracked'\n | 'tampered';\n\n/**\n * Result of checking a single skill's integrity.\n *\n * @public\n */\nexport interface SkillIntegrityResult {\n /** Skill name. */\n name: string;\n /** Overall integrity status. */\n status: SkillIntegrityStatus;\n /** Whether the canonical directory exists. */\n canonicalExists: boolean;\n /** Expected canonical path from lock file. */\n canonicalPath: string | null;\n /** Provider link statuses — which agents have valid symlinks. */\n linkStatuses: Array<{\n providerId: string;\n linkPath: string;\n exists: boolean;\n isSymlink: boolean;\n pointsToCanonical: boolean;\n }>;\n /** Whether this is a CAAMP-reserved (ct-*) skill. */\n isCaampOwned: boolean;\n /** Human-readable issue description, if any. */\n issue?: string;\n}\n\n/**\n * Check whether a skill name is reserved by CAAMP (ct-* prefix).\n *\n * @remarks\n * Skills with the `ct-` prefix are considered CAAMP-owned and receive\n * special treatment during installation conflict resolution.\n *\n * @param skillName - Skill name to check\n * @returns `true` if the skill name starts with `ct-`\n *\n * @example\n * ```typescript\n * isCaampOwnedSkill(\"ct-research-agent\"); // true\n * isCaampOwnedSkill(\"my-custom-skill\"); // false\n * ```\n *\n * @public\n */\nexport function isCaampOwnedSkill(skillName: string): boolean {\n return skillName.startsWith(CAAMP_SKILL_PREFIX);\n}\n\n/**\n * Check the integrity of a single installed skill.\n *\n * @remarks\n * Validates that the canonical directory exists on disk, the lock file entry\n * matches the actual state, and symlinks from provider skill directories\n * point to the canonical path.\n *\n * @param skillName - Name of the skill to check\n * @param providers - Providers to check symlinks for\n * @param scope - Whether to check global or project links\n * @param projectDir - Project directory (for project scope)\n * @returns Integrity check result\n *\n * @example\n * ```typescript\n * const result = await checkSkillIntegrity(\"ct-research-agent\", providers, \"global\");\n * if (result.status !== \"intact\") {\n * console.log(`Issue: ${result.issue}`);\n * }\n * ```\n *\n * @public\n */\nexport async function checkSkillIntegrity(\n skillName: string,\n providers: Provider[],\n scope: 'global' | 'project' = 'global',\n projectDir?: string,\n): Promise<SkillIntegrityResult> {\n const lock = await readLockFile();\n const entry = lock.skills[skillName];\n const isCaampOwned = isCaampOwnedSkill(skillName);\n\n // Not tracked in lock file\n if (!entry) {\n const canonicalPath = join(resolveSkillsRoot(), skillName);\n return {\n name: skillName,\n status: 'not-tracked',\n canonicalExists: existsSync(canonicalPath),\n canonicalPath: null,\n linkStatuses: [],\n isCaampOwned,\n issue: 'Skill is not tracked in the CAAMP lock file',\n };\n }\n\n const canonicalPath = entry.canonicalPath;\n const canonicalExists = existsSync(canonicalPath);\n\n // Check symlinks for each provider\n const linkStatuses: SkillIntegrityResult['linkStatuses'] = [];\n\n for (const provider of providers) {\n const targetDirs = resolveProviderSkillsDirs(provider, scope, projectDir);\n for (const skillsDir of targetDirs) {\n if (!skillsDir) continue;\n\n const linkPath = join(skillsDir, skillName);\n const exists = existsSync(linkPath);\n let isSymlink = false;\n let pointsToCanonical = false;\n\n if (exists) {\n try {\n const stat = lstatSync(linkPath);\n isSymlink = stat.isSymbolicLink();\n if (isSymlink) {\n const target = resolve(readlinkSync(linkPath));\n pointsToCanonical = target === resolve(canonicalPath);\n }\n } catch {\n // Can't stat — treat as broken\n }\n }\n\n linkStatuses.push({\n providerId: provider.id,\n linkPath,\n exists,\n isSymlink,\n pointsToCanonical,\n });\n }\n }\n\n // Determine overall status\n if (!canonicalExists) {\n return {\n name: skillName,\n status: 'missing-canonical',\n canonicalExists,\n canonicalPath,\n linkStatuses,\n isCaampOwned,\n issue: `Canonical directory missing: ${canonicalPath}`,\n };\n }\n\n const brokenLinks = linkStatuses.filter((l) => !l.exists);\n const tamperedLinks = linkStatuses.filter((l) => l.exists && !l.pointsToCanonical);\n\n if (tamperedLinks.length > 0) {\n return {\n name: skillName,\n status: 'tampered',\n canonicalExists,\n canonicalPath,\n linkStatuses,\n isCaampOwned,\n issue: `${tamperedLinks.length} link(s) do not point to canonical path`,\n };\n }\n\n if (brokenLinks.length > 0) {\n return {\n name: skillName,\n status: 'broken-symlink',\n canonicalExists,\n canonicalPath,\n linkStatuses,\n isCaampOwned,\n issue: `${brokenLinks.length} symlink(s) missing`,\n };\n }\n\n return {\n name: skillName,\n status: 'intact',\n canonicalExists,\n canonicalPath,\n linkStatuses,\n isCaampOwned,\n };\n}\n\n/**\n * Check integrity of all tracked skills.\n *\n * @remarks\n * Iterates over every skill in the lock file and runs\n * {@link checkSkillIntegrity} on each.\n *\n * @param providers - Providers to check symlinks for\n * @param scope - Whether to check global or project links\n * @param projectDir - Project directory (for project scope)\n * @returns Map of skill name to integrity result\n *\n * @example\n * ```typescript\n * const results = await checkAllSkillIntegrity(providers);\n * for (const [name, result] of results) {\n * console.log(`${name}: ${result.status}`);\n * }\n * ```\n *\n * @public\n */\nexport async function checkAllSkillIntegrity(\n providers: Provider[],\n scope: 'global' | 'project' = 'global',\n projectDir?: string,\n): Promise<Map<string, SkillIntegrityResult>> {\n const lock = await readLockFile();\n const results = new Map<string, SkillIntegrityResult>();\n\n for (const skillName of Object.keys(lock.skills)) {\n const result = await checkSkillIntegrity(skillName, providers, scope, projectDir);\n results.set(skillName, result);\n }\n\n return results;\n}\n\n/**\n * Resolve a skill name conflict where a user-installed skill collides\n * with a CAAMP-owned (ct-*) skill.\n *\n * @remarks\n * CAAMP-owned skills always win. Returns `true` if the incoming skill\n * should take precedence over the existing installation.\n *\n * @param skillName - Skill name to check\n * @param incomingSource - Source of the incoming skill installation\n * @param existingEntry - Existing lock entry, if any\n * @returns `true` if the incoming installation should proceed\n *\n * @example\n * ```typescript\n * const proceed = shouldOverrideSkill(\"ct-research-agent\", \"library\", existingEntry);\n * if (proceed) {\n * // Safe to install/override\n * }\n * ```\n *\n * @public\n */\nexport function shouldOverrideSkill(\n skillName: string,\n incomingSource: string,\n existingEntry: LockEntry | undefined,\n): boolean {\n // No existing entry — always allow\n if (!existingEntry) return true;\n\n // For ct-* skills, CAAMP package source always wins\n if (isCaampOwnedSkill(skillName)) {\n // If incoming is from CAAMP package (library source), it always wins\n if (existingEntry.sourceType === 'library') return true;\n // If existing is from CAAMP but incoming is user, CAAMP wins (block user)\n return true;\n }\n\n // Non-ct-* skills: user always wins\n return true;\n}\n\n/**\n * Validate instruction file injection status across all providers.\n *\n * @remarks\n * Checks that CAAMP blocks exist and are current in all relevant\n * instruction files (CLAUDE.md, AGENTS.md, GEMINI.md).\n *\n * @param providers - Providers to check\n * @param projectDir - Project directory\n * @param scope - Whether to check global or project files\n * @param expectedContent - Expected CAAMP block content\n * @returns Array of file paths with issues\n *\n * @example\n * ```typescript\n * const issues = await validateInstructionIntegrity(providers, process.cwd(), \"project\");\n * for (const issue of issues) {\n * console.log(`${issue.providerId}: ${issue.issue} (${issue.file})`);\n * }\n * ```\n *\n * @public\n */\nexport async function validateInstructionIntegrity(\n providers: Provider[],\n projectDir: string,\n scope: 'project' | 'global',\n expectedContent?: string,\n): Promise<Array<{ file: string; providerId: string; issue: string }>> {\n const { checkAllInjections } = await import('../instructions/injector.js');\n const results = await checkAllInjections(providers, projectDir, scope, expectedContent);\n const issues: Array<{ file: string; providerId: string; issue: string }> = [];\n\n for (const result of results) {\n if (result.status === 'missing') {\n issues.push({\n file: result.file,\n providerId: result.provider,\n issue: 'Instruction file does not exist',\n });\n } else if (result.status === 'none') {\n issues.push({\n file: result.file,\n providerId: result.provider,\n issue: 'No CAAMP injection block found',\n });\n } else if (result.status === 'outdated') {\n issues.push({\n file: result.file,\n providerId: result.provider,\n issue: 'CAAMP injection block is outdated',\n });\n }\n }\n\n return issues;\n}\n"],"mappings":"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","names":["canonicalPath","checkAllInjections"]}
|
|
1
|
+
{"version":3,"sources":["../src/core/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"]}
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
removeInjection,
|
|
14
14
|
repairInstructionFiles,
|
|
15
15
|
writeAgentFileToAllProviders
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-G3CEXEW2.js";
|
|
17
17
|
import "./chunk-HDZYZTR2.js";
|
|
18
18
|
export {
|
|
19
19
|
checkAllInjections,
|
|
@@ -31,4 +31,4 @@ export {
|
|
|
31
31
|
repairInstructionFiles,
|
|
32
32
|
writeAgentFileToAllProviders
|
|
33
33
|
};
|
|
34
|
-
//# sourceMappingURL=injector-
|
|
34
|
+
//# sourceMappingURL=injector-X5FN7WMR.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.9",
|
|
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/cant": "2026.9.
|
|
54
|
-
"@cleocode/core": "2026.9.
|
|
55
|
-
"@cleocode/
|
|
56
|
-
"@cleocode/
|
|
57
|
-
"@cleocode/
|
|
53
|
+
"@cleocode/cant": "2026.9.9",
|
|
54
|
+
"@cleocode/core": "2026.9.9",
|
|
55
|
+
"@cleocode/lafs": "2026.9.9",
|
|
56
|
+
"@cleocode/contracts": "2026.9.9",
|
|
57
|
+
"@cleocode/paths": "2026.9.9"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
|
-
"@cleocode/core": "2026.9.
|
|
60
|
+
"@cleocode/core": "2026.9.9"
|
|
61
61
|
},
|
|
62
62
|
"peerDependenciesMeta": {
|
|
63
63
|
"@cleocode/core": {
|