import { readFileSync, writeFileSync } from "node:fs"; import { join } from "node:path"; const MANIFEST_FILE = ".skills.json"; const MANIFEST_VERSION = 1; export interface ManifestEntry { version: string; installedAt: string; platform: string; contentHash?: string; } export interface Manifest { version: number; skills: Record; } function manifestPath(): string { return join(process.cwd(), MANIFEST_FILE); } export function readManifest(): Manifest { try { const raw = readFileSync(manifestPath(), "utf-8"); const parsed = JSON.parse(raw); if (!parsed.skills || typeof parsed.skills !== "object") { return { version: MANIFEST_VERSION, skills: {} }; } // Ensure version field exists (migrate from old format) if (!parsed.version) { parsed.version = MANIFEST_VERSION; } // Ensure all entries have platform field (migrate from old format) for (const entry of Object.values(parsed.skills) as ManifestEntry[]) { if (!entry.platform) { entry.platform = "claude-code"; } } return parsed as Manifest; } catch { return { version: MANIFEST_VERSION, skills: {} }; } } export function writeManifest(manifest: Manifest): void { manifest.version = MANIFEST_VERSION; writeFileSync(manifestPath(), JSON.stringify(manifest, null, 2) + "\n"); } export function addToManifest( slug: string, version: string, platform = "claude-code", contentHash?: string, ): void { const manifest = readManifest(); manifest.skills[slug] = { version, installedAt: new Date().toISOString(), platform, ...(contentHash && { contentHash }), }; writeManifest(manifest); } export function removeFromManifest(slug: string): boolean { const manifest = readManifest(); if (!(slug in manifest.skills)) return false; delete manifest.skills[slug]; writeManifest(manifest); return true; }