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

143 lines 4.43 kB
/** * Package Registry * * Manages ~/.aiwg/packages.yaml — the local registry of installed remote * packages (frameworks, addons, extensions installed via `aiwg install`). * * @implements #557 */ import { readFile, writeFile, mkdir, access } from 'fs/promises'; import { resolve, join } from 'path'; import { homedir } from 'os'; import { existsSync } from 'fs'; import { stringify, parse } from 'yaml'; const PACKAGES_FILENAME = 'packages.yaml'; /** * Empty registry template */ function emptyRegistry() { return { apiVersion: 'aiwg.io/v1', kind: 'PackageRegistry', packages: {}, }; } /** * Resolve ~/.aiwg directory path using the same resolution logic as user-config */ function resolveAiwgDir() { // Respect explicit override if (process.env.AIWG_CONFIG) return process.env.AIWG_CONFIG; const primary = join(homedir(), '.aiwg'); const xdg = join(homedir(), '.config', 'aiwg'); if (existsSync(primary)) return primary; if (existsSync(xdg)) return xdg; return primary; // default } /** * Get the path to packages.yaml */ export function getPackagesFilePath(configDir) { const dir = configDir || resolveAiwgDir(); return resolve(dir, PACKAGES_FILENAME); } /** * Read packages.yaml, returning an empty registry if the file does not exist */ export async function readPackageRegistry(configDir) { const filePath = getPackagesFilePath(configDir); try { await access(filePath); } catch { return emptyRegistry(); } const content = await readFile(filePath, 'utf-8'); const parsed = parse(content); if (!parsed || typeof parsed !== 'object') return emptyRegistry(); // Ensure packages map exists if (!parsed.packages) parsed.packages = {}; return parsed; } /** * Write packages.yaml, creating ~/.aiwg/ if needed */ export async function writePackageRegistry(registry, configDir) { const dir = configDir || resolveAiwgDir(); await mkdir(dir, { recursive: true }); const filePath = resolve(dir, PACKAGES_FILENAME); const content = stringify(registry, { lineWidth: 0 }); await writeFile(filePath, content, 'utf-8'); } /** * Get a single package entry by key (e.g. "roko/ring-methodology") */ export async function getPackageEntry(key, configDir) { const registry = await readPackageRegistry(configDir); return registry.packages[key]; } /** * Upsert a package entry */ export async function setPackageEntry(key, entry, configDir) { const registry = await readPackageRegistry(configDir); registry.packages[key] = entry; await writePackageRegistry(registry, configDir); } /** * Remove a package entry */ export async function removePackageEntry(key, configDir) { const registry = await readPackageRegistry(configDir); if (!registry.packages[key]) return false; delete registry.packages[key]; await writePackageRegistry(registry, configDir); return true; } /** * Record a deployment against an existing package entry */ export async function recordDeployment(key, record, configDir) { const registry = await readPackageRegistry(configDir); const entry = registry.packages[key]; if (!entry) return; if (!entry.deployedTo) entry.deployedTo = []; // Replace existing record for the same project+provider const idx = entry.deployedTo.findIndex((d) => d.projectPath === record.projectPath && d.provider === record.provider); if (idx >= 0) { entry.deployedTo[idx] = record; } else { entry.deployedTo.push(record); } registry.packages[key] = entry; await writePackageRegistry(registry, configDir); } /** * List all installed packages as PackageInfo summaries */ export async function listPackages(configDir) { const registry = await readPackageRegistry(configDir); return Object.entries(registry.packages).map(([key, entry]) => { const parts = key.split('/'); return { key, name: parts.length > 1 ? parts.slice(1).join('/') : key, owner: parts.length > 1 ? parts[0] : undefined, version: entry.version, type: entry.type, source: entry.source, installedAt: entry.installedAt, deployCount: entry.deployedTo?.length ?? 0, }; }); } //# sourceMappingURL=package-registry.js.map