UNPKG

aiwg

Version:

Deployment tool and support utility for AI context. Copies agents, skills, commands, rules, and behaviors into the paths each AI platform reads (Claude Code, Codex, Copilot, Cursor, Warp, OpenClaw, and 6 more) so one source of truth works across 10 platfo

110 lines 4.09 kB
/** * Marketplace Local Cache * * Manages the ~/.aiwg/marketplace-cache/ directory that stores fetched plugins. * * Layout: ~/.aiwg/marketplace-cache/<source>/<packageId>/<version>/ * * @implements #787 */ import fs from 'fs'; import path from 'path'; import os from 'os'; /** * Resolve the cache root. Supports AIWG_CACHE_DIR override for testing. */ export function getCacheRoot() { if (process.env.AIWG_CACHE_DIR) { return process.env.AIWG_CACHE_DIR; } return path.join(os.homedir(), '.aiwg', 'marketplace-cache'); } /** * Resolve the path for a specific package version */ export function getPackagePath(source, packageId, version) { // Sanitize package ID for filesystem safety (replace / and : with -) const safePackageId = packageId.replace(/[/:]/g, '__'); return path.join(getCacheRoot(), source, safePackageId, version); } /** * Check whether a package version is cached */ export function isCached(source, packageId, version) { const packagePath = getPackagePath(source, packageId, version); const manifestPath = path.join(packagePath, 'manifest.json'); return fs.existsSync(manifestPath); } /** * Write a package bundle to the cache */ export function cachePackage(bundle) { const packagePath = getPackagePath(bundle.metadata.source, bundle.metadata.name, bundle.metadata.version); fs.mkdirSync(packagePath, { recursive: true }); // Write normalized manifest fs.writeFileSync(path.join(packagePath, 'manifest.json'), JSON.stringify(bundle.metadata, null, 2) + '\n', 'utf-8'); // Write raw source manifest for update detection fs.writeFileSync(path.join(packagePath, 'raw-manifest.json'), JSON.stringify(bundle.rawManifest, null, 2) + '\n', 'utf-8'); // Note: actual artifact files are expected to be in bundle.localPath already; // in a complete implementation we'd copy them into packagePath here. return packagePath; } export function listCachedPackages() { const root = getCacheRoot(); if (!fs.existsSync(root)) return []; const entries = []; // Walk <source>/<packageId>/<version>/manifest.json const sources = fs.readdirSync(root); for (const source of sources) { const sourcePath = path.join(root, source); if (!fs.statSync(sourcePath).isDirectory()) continue; const packages = fs.readdirSync(sourcePath); for (const pkg of packages) { const pkgPath = path.join(sourcePath, pkg); if (!fs.statSync(pkgPath).isDirectory()) continue; const versions = fs.readdirSync(pkgPath); for (const version of versions) { const manifestPath = path.join(pkgPath, version, 'manifest.json'); if (!fs.existsSync(manifestPath)) continue; try { const metadata = JSON.parse(fs.readFileSync(manifestPath, 'utf-8')); const stat = fs.statSync(manifestPath); entries.push({ source: source, packageId: pkg.replace(/__/g, '/'), version, cachedAt: stat.mtime, metadata, }); } catch { // Skip malformed entries } } } } return entries; } /** * Remove a specific cached package (all versions or a specific one) */ export function uncachePackage(source, packageId, version) { const safePackageId = packageId.replace(/[/:]/g, '__'); const pkgPath = path.join(getCacheRoot(), source, safePackageId); if (version) { const versionPath = path.join(pkgPath, version); if (!fs.existsSync(versionPath)) return false; fs.rmSync(versionPath, { recursive: true, force: true }); return true; } if (!fs.existsSync(pkgPath)) return false; fs.rmSync(pkgPath, { recursive: true, force: true }); return true; } //# sourceMappingURL=cache.js.map